diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 406eec57..adce96af 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -3,7 +3,7 @@ name: Tests on: pull_request: push: - branches: [ master ] + branches: [master] jobs: native_tests: @@ -119,6 +119,44 @@ jobs: wasm-pack test --node crates/$x --no-default-features done + test-history-wasi: + name: Test gloo-history WASI + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + rust-version: [1.64, stable, nightly] + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ matrix.rust-version }} + target: wasm32-wasi + + - name: Install wasmtime + run: | + wget https://github.com/bytecodealliance/wasmtime/releases/download/v15.0.1/wasmtime-v15.0.1-x86_64-linux.tar.xz + tar xf wasmtime-v15.0.1-x86_64-linux.tar.xz + mv wasmtime-v15.0.1-x86_64-linux/wasmtime ~/wasmtime + rm -rf wasmtime-v15.0.1-x86_64-linux.tar.xz wasmtime-v15.0.1-x86_64-linux + chmod +x ~/wasmtime + + - uses: actions/cache@v3 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + target + key: cargo-${{ runner.os }}-node-tests-${{ hashFiles('**/Cargo.toml') }} + restore-keys: | + cargo-${{ runner.os }}-node-tests- + cargo-${{ runner.os }}- + + - name: Build and run example history-wasi + run: | + cargo build --package example-history-wasi --target wasm32-wasi + ~/wasmtime --trap-unknown-imports target/wasm32-wasi/debug/example-history-wasi.wasm + test-worker: name: Test gloo-worker runs-on: ubuntu-latest @@ -126,7 +164,7 @@ jobs: fail-fast: false matrix: # example: [ markdown, prime ] - example: [ markdown ] + example: [markdown] rust-version: [1.64, stable, nightly] steps: - uses: actions/checkout@v4 @@ -167,7 +205,6 @@ jobs: run: | wasm-pack test --headless --chrome --firefox examples/${{ matrix.example }} - test-net: strategy: fail-fast: false @@ -208,9 +245,9 @@ jobs: - name: Run browser tests env: - HTTPBIN_URL: "http://localhost:8080" - WS_ECHO_SERVER_URL: "ws://localhost:8081" - SSE_ECHO_SERVER_URL: "http://localhost:8081/.sse" + HTTPBIN_URL: 'http://localhost:8080' + WS_ECHO_SERVER_URL: 'ws://localhost:8081' + SSE_ECHO_SERVER_URL: 'http://localhost:8081/.sse' run: | cd crates/net wasm-pack test --chrome --firefox --headless --all-features @@ -222,7 +259,7 @@ jobs: - name: Run native tests env: - HTTPBIN_URL: "http://localhost:8080" - WS_ECHO_SERVER_URL: "ws://localhost:8081" - SSE_ECHO_SERVER_URL: "http://localhost:8081/.sse" + HTTPBIN_URL: 'http://localhost:8080' + WS_ECHO_SERVER_URL: 'ws://localhost:8081' + SSE_ECHO_SERVER_URL: 'http://localhost:8081/.sse' run: cargo test -p gloo-net --all-features diff --git a/Cargo.lock b/Cargo.lock index 0b1a2c60..f5b74ad6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -256,6 +256,13 @@ dependencies = [ "yew", ] +[[package]] +name = "example-history-wasi" +version = "0.1.0" +dependencies = [ + "gloo 0.10.0", +] + [[package]] name = "example-markdown" version = "0.1.0" @@ -453,7 +460,7 @@ dependencies = [ "gloo-dialogs 0.2.0", "gloo-events 0.2.0", "gloo-file 0.3.0", - "gloo-history 0.2.0", + "gloo-history 0.2.1", "gloo-net 0.4.0", "gloo-render 0.2.0", "gloo-storage 0.3.0", @@ -573,7 +580,7 @@ dependencies = [ [[package]] name = "gloo-history" -version = "0.2.0" +version = "0.2.1" dependencies = [ "getrandom", "gloo-events 0.2.0", diff --git a/Cargo.toml b/Cargo.toml index c002e966..0cb03fd0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -77,6 +77,7 @@ members = [ "examples/markdown", "examples/clock", "examples/file-hash", + "examples/history-wasi", "examples/prime", ] diff --git a/crates/history/Cargo.toml b/crates/history/Cargo.toml index bb44afc1..b9b5ba90 100644 --- a/crates/history/Cargo.toml +++ b/crates/history/Cargo.toml @@ -12,7 +12,6 @@ categories = ["api-bindings", "history", "wasm"] rust-version = "1.64" [dependencies] -wasm-bindgen = "0.2" gloo-utils = { version = "0.2.0", path = "../utils" } gloo-events = { version = "0.2.0", path = "../events" } serde = { version = "1", features = ["derive"] } @@ -20,7 +19,10 @@ serde-wasm-bindgen = "0.6.0" serde_urlencoded = { version = "0.7", optional = true } thiserror = { version = "1.0", optional = true } -[dependencies.web-sys] +[target.'cfg(not(target_os = "wasi"))'.dependencies] +wasm-bindgen = "0.2" + +[target.'cfg(not(target_os = "wasi"))'.dependencies.web-sys] version = "0.3" features = ["History", "Window", "Location", "Url"] diff --git a/crates/history/src/any.rs b/crates/history/src/any.rs index 74e9ec43..288325c5 100644 --- a/crates/history/src/any.rs +++ b/crates/history/src/any.rs @@ -1,6 +1,8 @@ use std::borrow::Cow; +#[cfg(not(target_os = "wasi"))] use crate::browser::BrowserHistory; +#[cfg(not(target_os = "wasi"))] use crate::hash::HashHistory; use crate::history::History; use crate::listener::HistoryListener; @@ -13,8 +15,10 @@ use crate::{error::HistoryResult, query::ToQuery}; #[derive(Clone, PartialEq, Debug)] pub enum AnyHistory { /// A Browser History. + #[cfg(not(target_os = "wasi"))] Browser(BrowserHistory), /// A Hash History + #[cfg(not(target_os = "wasi"))] Hash(HashHistory), /// A Memory History Memory(MemoryHistory), @@ -23,7 +27,9 @@ pub enum AnyHistory { impl History for AnyHistory { fn len(&self) -> usize { match self { + #[cfg(not(target_os = "wasi"))] Self::Browser(m) => m.len(), + #[cfg(not(target_os = "wasi"))] Self::Hash(m) => m.len(), Self::Memory(m) => m.len(), } @@ -31,7 +37,9 @@ impl History for AnyHistory { fn go(&self, delta: isize) { match self { + #[cfg(not(target_os = "wasi"))] Self::Browser(m) => m.go(delta), + #[cfg(not(target_os = "wasi"))] Self::Hash(m) => m.go(delta), Self::Memory(m) => m.go(delta), } @@ -39,7 +47,9 @@ impl History for AnyHistory { fn push<'a>(&self, route: impl Into>) { match self { + #[cfg(not(target_os = "wasi"))] Self::Browser(m) => m.push(route), + #[cfg(not(target_os = "wasi"))] Self::Hash(m) => m.push(route), Self::Memory(m) => m.push(route), } @@ -47,7 +57,9 @@ impl History for AnyHistory { fn replace<'a>(&self, route: impl Into>) { match self { + #[cfg(not(target_os = "wasi"))] Self::Browser(m) => m.replace(route), + #[cfg(not(target_os = "wasi"))] Self::Hash(m) => m.replace(route), Self::Memory(m) => m.replace(route), } @@ -58,7 +70,9 @@ impl History for AnyHistory { T: 'static, { match self { + #[cfg(not(target_os = "wasi"))] Self::Browser(m) => m.push_with_state(route, state), + #[cfg(not(target_os = "wasi"))] Self::Hash(m) => m.push_with_state(route, state), Self::Memory(m) => m.push_with_state(route, state), } @@ -69,7 +83,9 @@ impl History for AnyHistory { T: 'static, { match self { + #[cfg(not(target_os = "wasi"))] Self::Browser(m) => m.replace_with_state(route, state), + #[cfg(not(target_os = "wasi"))] Self::Hash(m) => m.replace_with_state(route, state), Self::Memory(m) => m.replace_with_state(route, state), } @@ -85,7 +101,9 @@ impl History for AnyHistory { Q: ToQuery, { match self { + #[cfg(not(target_os = "wasi"))] Self::Browser(m) => m.push_with_query(route, query), + #[cfg(not(target_os = "wasi"))] Self::Hash(m) => m.push_with_query(route, query), Self::Memory(m) => m.push_with_query(route, query), } @@ -100,7 +118,9 @@ impl History for AnyHistory { Q: ToQuery, { match self { + #[cfg(not(target_os = "wasi"))] Self::Browser(m) => m.replace_with_query(route, query), + #[cfg(not(target_os = "wasi"))] Self::Hash(m) => m.replace_with_query(route, query), Self::Memory(m) => m.replace_with_query(route, query), } @@ -118,7 +138,9 @@ impl History for AnyHistory { T: 'static, { match self { + #[cfg(not(target_os = "wasi"))] Self::Browser(m) => m.push_with_query_and_state(route, query, state), + #[cfg(not(target_os = "wasi"))] Self::Hash(m) => m.push_with_query_and_state(route, query, state), Self::Memory(m) => m.push_with_query_and_state(route, query, state), } @@ -136,7 +158,9 @@ impl History for AnyHistory { T: 'static, { match self { + #[cfg(not(target_os = "wasi"))] Self::Browser(m) => m.replace_with_query_and_state(route, query, state), + #[cfg(not(target_os = "wasi"))] Self::Hash(m) => m.replace_with_query_and_state(route, query, state), Self::Memory(m) => m.replace_with_query_and_state(route, query, state), } @@ -147,7 +171,9 @@ impl History for AnyHistory { CB: Fn() + 'static, { match self { + #[cfg(not(target_os = "wasi"))] Self::Browser(m) => m.listen(callback), + #[cfg(not(target_os = "wasi"))] Self::Hash(m) => m.listen(callback), Self::Memory(m) => m.listen(callback), } @@ -155,19 +181,23 @@ impl History for AnyHistory { fn location(&self) -> Location { match self { + #[cfg(not(target_os = "wasi"))] Self::Browser(m) => m.location(), + #[cfg(not(target_os = "wasi"))] Self::Hash(m) => m.location(), Self::Memory(m) => m.location(), } } } +#[cfg(not(target_os = "wasi"))] impl From for AnyHistory { fn from(m: BrowserHistory) -> AnyHistory { AnyHistory::Browser(m) } } +#[cfg(not(target_os = "wasi"))] impl From for AnyHistory { fn from(m: HashHistory) -> AnyHistory { AnyHistory::Hash(m) diff --git a/crates/history/src/lib.rs b/crates/history/src/lib.rs index 9f508808..7d5777ff 100644 --- a/crates/history/src/lib.rs +++ b/crates/history/src/lib.rs @@ -4,9 +4,11 @@ #![deny(missing_docs, missing_debug_implementations)] mod any; +#[cfg(not(target_os = "wasi"))] mod browser; #[cfg(feature = "query")] mod error; +#[cfg(not(target_os = "wasi"))] mod hash; mod history; mod listener; @@ -18,7 +20,9 @@ mod state; mod utils; pub use any::AnyHistory; +#[cfg(not(target_os = "wasi"))] pub use browser::BrowserHistory; +#[cfg(not(target_os = "wasi"))] pub use hash::HashHistory; pub use memory::MemoryHistory; diff --git a/crates/history/src/state.rs b/crates/history/src/state.rs index 255c5ced..7386a421 100644 --- a/crates/history/src/state.rs +++ b/crates/history/src/state.rs @@ -1,3 +1,5 @@ +#![cfg(not(target_os = "wasi"))] + use std::any::Any; use std::collections::HashMap; use std::rc::Rc; diff --git a/crates/history/src/utils.rs b/crates/history/src/utils.rs index 24422d48..8aa4f346 100644 --- a/crates/history/src/utils.rs +++ b/crates/history/src/utils.rs @@ -2,16 +2,17 @@ use std::cell::RefCell; use std::rc::{Rc, Weak}; use std::sync::atomic::{AtomicU32, Ordering}; +#[cfg(not(target_os = "wasi"))] use wasm_bindgen::throw_str; -#[cfg(not(target_arch = "wasm32"))] +#[cfg(any(not(target_arch = "wasm32"), target_os = "wasi"))] pub(crate) fn get_id() -> u32 { static ID_CTR: AtomicU32 = AtomicU32::new(0); ID_CTR.fetch_add(1, Ordering::SeqCst) } -#[cfg(target_arch = "wasm32")] +#[cfg(all(target_arch = "wasm32", not(target_os = "wasi")))] pub(crate) fn get_id() -> u32 { static ID_CTR: AtomicU32 = AtomicU32::new(0); static INIT: std::sync::Once = std::sync::Once::new(); @@ -30,19 +31,28 @@ pub(crate) fn get_id() -> u32 { pub(crate) fn assert_absolute_path(path: &str) { if !path.starts_with('/') { + #[cfg(not(target_os = "wasi"))] throw_str("You cannot use relative path with this history type."); + #[cfg(target_os = "wasi")] + panic!("You cannot use relative path with this history type."); } } pub(crate) fn assert_no_query(path: &str) { if path.contains('?') { + #[cfg(not(target_os = "wasi"))] throw_str("You cannot have query in path, try use a variant of this method with `_query`."); + #[cfg(target_os = "wasi")] + panic!("You cannot have query in path, try use a variant of this method with `_query`."); } } pub(crate) fn assert_no_fragment(path: &str) { if path.contains('#') { + #[cfg(not(target_os = "wasi"))] throw_str("You cannot use fragments (hash) in memory history."); + #[cfg(target_os = "wasi")] + panic!("You cannot use fragments (hash) in memory history."); } } diff --git a/crates/history/tests/query.rs b/crates/history/tests/query.rs index 28ffb75b..a7fc176e 100644 --- a/crates/history/tests/query.rs +++ b/crates/history/tests/query.rs @@ -1,8 +1,8 @@ #![cfg(feature = "query")] -#[cfg(target_arch = "wasm32")] +#[cfg(all(target_arch = "wasm32", not(target_os = "wasi")))] use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure}; -#[cfg(target_arch = "wasm32")] +#[cfg(all(target_arch = "wasm32", not(target_os = "wasi")))] wasm_bindgen_test_configure!(run_in_browser); use gloo_history::query::*; diff --git a/examples/history-wasi/Cargo.toml b/examples/history-wasi/Cargo.toml new file mode 100644 index 00000000..78522958 --- /dev/null +++ b/examples/history-wasi/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "example-history-wasi" +version = "0.1.0" +authors = ["Rust and WebAssembly Working Group"] +edition = "2021" +publish = false +rust-version = "1.64" + +[dependencies] +gloo = { path = "../..", default-features = false, features = ["history"] } diff --git a/examples/history-wasi/README.md b/examples/history-wasi/README.md new file mode 100644 index 00000000..817b3de2 --- /dev/null +++ b/examples/history-wasi/README.md @@ -0,0 +1,10 @@ +# History example on WASI + +This is a simple example showcasing the Gloo History on WASI. + +You can run this example with: + +```bash +cargo build --manifest-path examples/history-wasi/Cargo.toml --target wasm32-wasi +wasmtime examples/history-wasi/target/wasm32-wasi/debug/example-history-wasi.wasm +``` diff --git a/examples/history-wasi/src/main.rs b/examples/history-wasi/src/main.rs new file mode 100644 index 00000000..a15f1b6e --- /dev/null +++ b/examples/history-wasi/src/main.rs @@ -0,0 +1,23 @@ +use gloo::history::{History, MemoryHistory}; + +fn main() { + let history = MemoryHistory::new(); + println!("Current path: {}", history.location().path()); + assert_eq!(history.location().path(), "/"); + + history.push("/home"); + println!("Current path: {}", history.location().path()); + assert_eq!(history.location().path(), "/home"); + + history.push("/about"); + println!("Current path: {}", history.location().path()); + assert_eq!(history.location().path(), "/about"); + + history.push("/contact"); + println!("Current path: {}", history.location().path()); + assert_eq!(history.location().path(), "/contact"); + + history.go(-2); + println!("Current path: {}", history.location().path()); + assert_eq!(history.location().path(), "/home"); +}