Skip to content
Merged

Docs #12

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
name: Deploy Documentation

on:
push:
branches: [main]
workflow_dispatch:

permissions:
contents: read
pages: write
id-token: write

concurrency:
group: "pages"
cancel-in-progress: true

jobs:
build:
name: Build Rustdoc
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y \
libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev \
libxkbcommon-dev libssl-dev libgtk-3-dev libatk1.0-dev \
libglib2.0-dev libpango1.0-dev libgdk-pixbuf-2.0-dev \
libasound2-dev

- uses: dtolnay/rust-toolchain@stable

- uses: Swatinem/rust-cache@v2

- name: Build documentation
run: |
cargo doc --no-deps \
-p oxide-docs \
-p oxide-sdk \
-p oxide-browser
env:
RUSTDOCFLAGS: >-
--html-in-header oxide-docs/rustdoc-header.html
-Z unstable-options
--default-theme dark

- name: Create landing page
run: cp oxide-docs/index.html target/doc/index.html

- name: Add .nojekyll
run: touch target/doc/.nojekyll

- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: target/doc

deploy:
name: Deploy to GitHub Pages
needs: build
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
members = [
"oxide-browser",
"oxide-sdk",
"oxide-docs",
"examples/hello-oxide",
"examples/audio-player",
"examples/timer-demo",
Expand Down
4 changes: 4 additions & 0 deletions oxide-browser/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ version = "0.2.0"
edition = "2021"
description = "A binary-first browser that fetches and runs .wasm modules in a secure sandbox"

[lib]
name = "oxide_browser"
path = "src/lib.rs"

[[bin]]
name = "oxide"
path = "src/main.rs"
Expand Down
42 changes: 41 additions & 1 deletion oxide-browser/src/bookmarks.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,30 @@
//! Persistent bookmarks for the Oxide browser.
//!
//! Entries are stored in a [`sled`] embedded database under a dedicated [`sled::Tree`]
//! named `"bookmarks"`. Each record is keyed by URL; values hold the serialized
//! title, favorite flag, and creation time. For UI code that may run on multiple
//! threads, use [`SharedBookmarkStore`] and initialize the store when the
//! database is available.

use std::sync::{Arc, Mutex};
use std::time::{SystemTime, UNIX_EPOCH};

use anyhow::{Context, Result};

/// A saved bookmark: canonical URL, display title, favorite flag, and creation time.
///
/// The URL is the primary key in [`BookmarkStore`]. New bookmarks from [`BookmarkStore::add`]
/// start with [`Bookmark::is_favorite`] set to `false` and [`Bookmark::created_at_ms`] set
/// to the current time in milliseconds since the UNIX epoch.
#[derive(Clone, Debug)]
pub struct Bookmark {
/// Canonical bookmark URL; also the sled key for this entry.
pub url: String,
/// User-visible title (may differ from the page title at save time).
pub title: String,
/// When `true`, this bookmark is included in favorite-only listings.
pub is_favorite: bool,
/// Creation instant as milliseconds since [`UNIX_EPOCH`].
pub created_at_ms: u64,
}

Expand Down Expand Up @@ -46,20 +63,27 @@ impl Bookmark {
}
}

/// Persistent bookmark storage backed by a sled tree.
/// Persistent bookmark storage backed by a [`sled::Tree`] in an open [`sled::Db`].
///
/// The tree name is `"bookmarks"`. Keys are URL byte strings; values are an internal
/// binary encoding of title, favorite bit, and timestamp (see [`Bookmark`]).
#[derive(Clone)]
pub struct BookmarkStore {
tree: sled::Tree,
}

impl BookmarkStore {
/// Opens the bookmarks tree in `db`, creating it if it does not exist.
pub fn open(db: &sled::Db) -> Result<Self> {
let tree = db
.open_tree("bookmarks")
.context("failed to open bookmarks tree")?;
Ok(Self { tree })
}

/// Inserts a new bookmark for `url` with the given `title`, or overwrites the existing entry.
///
/// The bookmark is stored as not favorited with a fresh [`Bookmark::created_at_ms`].
pub fn add(&self, url: &str, title: &str) -> Result<()> {
let bm = Bookmark {
url: url.to_string(),
Expand All @@ -73,17 +97,23 @@ impl BookmarkStore {
Ok(())
}

/// Removes the bookmark for `url`, if present.
pub fn remove(&self, url: &str) -> Result<()> {
self.tree
.remove(url.as_bytes())
.context("failed to remove bookmark")?;
Ok(())
}

/// Returns whether a bookmark exists for `url`.
pub fn contains(&self, url: &str) -> bool {
self.tree.contains_key(url.as_bytes()).unwrap_or(false)
}

/// Flips the favorite flag for the bookmark at `url` and returns the new value.
///
/// If the URL is missing or the stored value cannot be decoded, returns `Ok(false)` without
/// changing storage.
pub fn toggle_favorite(&self, url: &str) -> Result<bool> {
if let Some(data) = self
.tree
Expand All @@ -102,6 +132,9 @@ impl BookmarkStore {
Ok(false)
}

/// Returns whether the bookmark at `url` is marked as a favorite.
///
/// Missing or corrupt entries are treated as not favorited.
#[allow(dead_code)]
pub fn is_favorite(&self, url: &str) -> bool {
self.tree
Expand All @@ -113,6 +146,7 @@ impl BookmarkStore {
.unwrap_or(false)
}

/// Returns every bookmark, ordered by [`Bookmark::created_at_ms`] descending (newest first).
pub fn list_all(&self) -> Vec<Bookmark> {
let mut bookmarks = Vec::new();
for (key, val) in self.tree.iter().flatten() {
Expand All @@ -126,6 +160,7 @@ impl BookmarkStore {
bookmarks
}

/// Returns only bookmarks with [`Bookmark::is_favorite`] set, in the same order as [`Self::list_all`].
#[allow(dead_code)]
pub fn list_favorites(&self) -> Vec<Bookmark> {
self.list_all()
Expand All @@ -135,8 +170,13 @@ impl BookmarkStore {
}
}

/// Thread-safe handle to an optional [`BookmarkStore`]: [`Arc`] wrapped [`Mutex`] of [`Option`].
///
/// Use `None` before the sled database is opened; replace with `Some(store)` after
/// [`BookmarkStore::open`]. Lock the mutex when reading or updating bookmarks from worker threads.
pub type SharedBookmarkStore = Arc<Mutex<Option<BookmarkStore>>>;

/// Creates a shared bookmark store initialized to `None` (no database opened yet).
pub fn new_shared() -> SharedBookmarkStore {
Arc::new(Mutex::new(None))
}
Expand Down
Loading
Loading