diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8ea281b9..128b012a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -143,7 +143,7 @@ jobs: sanitizer: runs-on: ubuntu-latest - name: ubuntu / nightly / sanitizer + name: ubuntu / nightly / sanitizer steps: - uses: actions/checkout@v4 with: @@ -246,14 +246,12 @@ jobs: os: ubuntu-latest rust: stable target: wasm32-wasip1 - features: full-async - no-build: true + features: full-async-wasi - task: bindings os: ubuntu-latest rust: nightly target: wasm32-wasip2 - features: full-async - no-build: true + features: full-async-wasi # Test features - task: features @@ -410,6 +408,9 @@ jobs: echo 'rustflags = ["-C", "linker=loongarch64-linux-gnu-gcc-14"]' >> ~/.cargo/config.toml echo "/musl/bin" >> $GITHUB_PATH + - name: Setup wasmtime for wasm32-wasip1 and wasm32-wasip2 + if: matrix.target == 'wasm32-wasip1' || matrix.target == 'wasm32-wasip2' + uses: bytecodealliance/actions/wasmtime/setup@v1 - name: Setup msys2 toolchains if: startsWith(matrix.os, 'windows') && endsWith(matrix.target, '-gnu') uses: msys2/setup-msys2@v2 @@ -475,7 +476,7 @@ jobs: timeout-minutes: 12 env: RUST_BACKTRACE: full - run: cargo test ${{ matrix.optimization && '--release' || '' }} --all --target ${{ matrix.target }} --no-default-features --features ${{ matrix.features }} + run: ${{ matrix.target == 'wasm32-wasip1' && 'CARGO_TARGET_WASM32_WASIP1_RUNNER=wasmtime' || '' }} ${{ matrix.target == 'wasm32-wasip2' && 'CARGO_TARGET_WASM32_WASIP2_RUNNER=wasmtime' || '' }} cargo test ${{ matrix.optimization && '--release' || '' }} --all ${{ (matrix.target == 'wasm32-wasip1' || matrix.target == 'wasm32-wasip2') && '--exclude module-loader' || '' }} --target ${{ matrix.target }} --no-default-features --features ${{ matrix.features }} update-bindings: if: ${{ github.event_name != 'pull_request' && !startsWith(github.ref, 'refs/tags/') }} diff --git a/Cargo.toml b/Cargo.toml index b90af182..22417878 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,19 +39,17 @@ rquickjs-macro = { workspace = true, optional = true } default = [] # Almost all features excluding "parallel" and support for async runtimes -full = [ - "chrono", - "loader", - "dyn-load", - "either", - "indexmap", - "macro", - "phf", -] +full = ["chrono", "loader", "dyn-load", "either", "indexmap", "macro", "phf"] + +# A version of full designed for wasm32-wasip1 and wasm32-wasip2 (simply excludes dyn-load) +full-wasi = ["chrono", "loader", "either", "indexmap", "macro", "phf"] # Almost all features excluding "parallel" full-async = ["full", "futures"] +# A version of full-async designed for wasm32-wasip1 and wasm32-wasip2 +full-async-wasi = ["full-wasi", "futures"] + # Chrono support. chrono = ["rquickjs-core/chrono"] @@ -82,7 +80,6 @@ dyn-load = ["rquickjs-core/dyn-load"] rust-alloc = ["rquickjs-core/rust-alloc"] - # Enable helper macros macro = ["rquickjs-macro"] diff --git a/README.md b/README.md index 349e252d..1f782dc6 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,8 @@ See below for a list of supported platforms. | x86_64-pc-windows-mvsc | ✅ | ✅ | ❌ experimental! | | x86_64-apple-darwin | ✅ | ✅ | ✅ | | aarch64-apple-darwin | ✅ | ❌ | ✅ | -| wasm32-wasi | ✅ | ❌ | ✅ | +| wasm32-wasip1 | ✅ | ✅ | ✅ | +| wasm32-wasip2 | ✅ | ✅ | ✅ | | other | ❌ | ❌ | Unknown | ## License diff --git a/core/Cargo.toml b/core/Cargo.toml index 6dfaba78..be0c06cd 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -25,8 +25,13 @@ relative-path = { version = "1.9", optional = true } [dev-dependencies] -futures-rs = { package = "futures", version = "0.3"} -tokio = { version = "1.0", default-features = false, features = ["rt", "rt-multi-thread", "time", "macros", "sync"] } +futures-rs = { package = "futures", version = "0.3" } +tokio = { version = "1.0", default-features = false, features = [ + "rt", + "time", + "macros", + "sync", +] } rquickjs.path = "../" approx = "0.5" trybuild = "1.0.23" @@ -45,7 +50,7 @@ full-async = ["full", "futures"] bindgen = ["rquickjs-sys/bindgen"] # Enable support of parallel execution -parallel = [] +parallel = ["tokio/rt-multi-thread"] # Enable user-defined module loader support loader = ["relative-path"] @@ -92,5 +97,3 @@ properties = [] classes = [] array-buffer = [] allocator = [] - - diff --git a/core/src/runtime/async.rs b/core/src/runtime/async.rs index f96abb92..cdb31e3a 100644 --- a/core/src/runtime/async.rs +++ b/core/src/runtime/async.rs @@ -346,14 +346,16 @@ macro_rules! async_test_case { ($name:ident => ($rt:ident,$ctx:ident) { $($t:tt)* }) => { #[test] fn $name() { - let rt = if cfg!(feature = "parallel") { - tokio::runtime::Builder::new_multi_thread() - } else { - tokio::runtime::Builder::new_current_thread() - } - .enable_all() - .build() - .unwrap(); + #[cfg(feature = "parallel")] + let mut new_thread = tokio::runtime::Builder::new_multi_thread(); + + #[cfg(not(feature = "parallel"))] + let mut new_thread = tokio::runtime::Builder::new_current_thread(); + + let rt = new_thread + .enable_all() + .build() + .unwrap(); #[cfg(feature = "parallel")] { diff --git a/core/src/value/convert/from.rs b/core/src/value/convert/from.rs index 278047ef..300a826f 100644 --- a/core/src/value/convert/from.rs +++ b/core/src/value/convert/from.rs @@ -411,6 +411,9 @@ chrono_from_js_impls! { #[cfg(test)] mod test { + #[cfg(target_arch = "wasm32")] + use super::Error; + #[test] fn js_to_system_time() { use crate::{Context, Runtime}; @@ -426,11 +429,26 @@ mod test { res.duration_since(SystemTime::UNIX_EPOCH).unwrap() ); - let res: SystemTime = ctx.eval("new Date(-123456789)").unwrap(); - assert_eq!( - Duration::from_millis(123456789), - SystemTime::UNIX_EPOCH.duration_since(res).unwrap() - ); + #[cfg(not(target_arch = "wasm32"))] + { + let res: SystemTime = ctx.eval("new Date(-123456789)").unwrap(); + assert_eq!( + Duration::from_millis(123456789), + SystemTime::UNIX_EPOCH.duration_since(res).unwrap() + ); + } + + // wasm32-wasip1 and wasm32-wasip2 do not support SystemTime before the Unix Epoch + #[cfg(target_arch = "wasm32")] + { + let res: Error = ctx + .eval::("new Date(-123456789)") + .unwrap_err(); + assert_eq!( + "Error converting from js 'Date' into type 'SystemTime': Timestamp too small", + res.to_string() + ); + } }); } diff --git a/core/src/value/convert/into.rs b/core/src/value/convert/into.rs index 37ed95d6..4ec9fe3d 100644 --- a/core/src/value/convert/into.rs +++ b/core/src/value/convert/into.rs @@ -545,7 +545,9 @@ mod test { #[test] fn system_time_to_js() { use crate::{Context, IntoJs, Runtime}; - use std::time::{Duration, SystemTime}; + #[cfg(not(target_arch = "wasm32"))] + use std::time::Duration; + use std::time::SystemTime; let runtime = Runtime::new().unwrap(); let ctx = Context::full(&runtime).unwrap(); @@ -563,18 +565,23 @@ mod test { assert_eq!(millis, res as _); }); - let ts = SystemTime::UNIX_EPOCH - Duration::from_millis(123456); - let millis = SystemTime::UNIX_EPOCH - .duration_since(ts) - .unwrap() - .as_millis(); - - ctx.with(|ctx| { - let globs = ctx.globals(); - globs.set("ts", ts.into_js(&ctx).unwrap()).unwrap(); - let res: i64 = ctx.eval("ts.getTime()").unwrap(); - assert_eq!(-(millis as i64), res as _); - }); + // wasm32-wasip1 and wasm32-wasip2 do not support SystemTime before the Unix epoch. + // The subtraction from the Unix epoch would panic with: overflow when subtracting duration from instant + #[cfg(not(target_arch = "wasm32"))] + { + let ts = SystemTime::UNIX_EPOCH - Duration::from_millis(123456); + let millis = SystemTime::UNIX_EPOCH + .duration_since(ts) + .unwrap() + .as_millis(); + + ctx.with(|ctx| { + let globs = ctx.globals(); + globs.set("ts", ts.into_js(&ctx).unwrap()).unwrap(); + let res: i64 = ctx.eval("ts.getTime()").unwrap(); + assert_eq!(-(millis as i64), res as _); + }); + } } #[cfg(feature = "chrono")] diff --git a/tests/compile.rs b/tests/compile.rs index 65dde4f7..0866c745 100644 --- a/tests/compile.rs +++ b/tests/compile.rs @@ -1,12 +1,58 @@ +#[cfg(target_arch = "wasm32")] +#[path = "macros/pass_class.rs"] +pub mod pass_class; + +#[cfg(target_arch = "wasm32")] +#[path = "macros/pass_method.rs"] +pub mod pass_method; + +#[cfg(target_arch = "wasm32")] +#[path = "macros/pass_module.rs"] +pub mod pass_module; + +#[cfg(target_arch = "wasm32")] +#[path = "macros/pass_trace.rs"] +pub mod pass_trace; + #[cfg(feature = "macro")] -#[test] -fn macros() { - let t = trybuild::TestCases::new(); - t.pass("tests/macros/pass_*.rs"); - #[cfg(feature = "compile-tests")] - t.compile_fail("tests/compile_fail/*.rs"); - #[cfg(all(feature = "futures", feature = "compile-tests"))] - t.compile_fail("tests/async_compile_fail/*.rs"); - #[cfg(all(feature = "futures", feature = "parallel", feature = "compile-tests"))] - t.compile_fail("tests/async_parallel_compile_fail/*.rs"); +mod macro_tests { + #[cfg(target_arch = "wasm32")] + use crate::{pass_class, pass_method, pass_module, pass_trace}; + + #[cfg(not(target_arch = "wasm32"))] + #[test] + fn macros() { + let t = trybuild::TestCases::new(); + t.pass("tests/macros/pass_*.rs"); + #[cfg(feature = "compile-tests")] + t.compile_fail("tests/compile_fail/*.rs"); + #[cfg(all(feature = "futures", feature = "compile-tests"))] + t.compile_fail("tests/async_compile_fail/*.rs"); + #[cfg(all(feature = "futures", feature = "parallel", feature = "compile-tests"))] + t.compile_fail("tests/async_parallel_compile_fail/*.rs"); + } + + #[cfg(target_arch = "wasm32")] + #[test] + fn macros_pass_class() { + pass_class::main(); + } + + #[cfg(target_arch = "wasm32")] + #[test] + fn macros_pass_method() { + pass_method::main(); + } + + #[cfg(target_arch = "wasm32")] + #[test] + fn macros_pass_module() { + pass_module::main(); + } + + #[cfg(target_arch = "wasm32")] + #[test] + fn macros_pass_trace() { + pass_trace::main(); + } } diff --git a/tests/macros/pass_module.rs b/tests/macros/pass_module.rs index b8e7afe9..f518dfd0 100644 --- a/tests/macros/pass_module.rs +++ b/tests/macros/pass_module.rs @@ -87,7 +87,7 @@ mod test_mod { } } -fn main() { +pub fn main() { assert_eq!(test_mod::ignore_function(), 4); let rt = Runtime::new().unwrap(); let ctx = Context::full(&rt).unwrap(); diff --git a/tests/macros/pass_trace.rs b/tests/macros/pass_trace.rs index 92de9998..ca14d1a1 100644 --- a/tests/macros/pass_trace.rs +++ b/tests/macros/pass_trace.rs @@ -79,7 +79,7 @@ impl<'js> JsClass<'js> for TraceEnum { } } -fn main() { +pub fn main() { let rt = Runtime::new().unwrap(); let ctx = Context::full(&rt).unwrap();