diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 1362609..9681c60 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -54,6 +54,9 @@ jobs: - name: wstd tests run: cargo test -p wstd -p wstd-axum --target wasm32-wasip2 -- --nocapture + - name: p3 wstd tests + run: cargo test -p wstd -p wstd-axum --target wasm32-wasip2 --no-default-features --features p3 -- --nocapture + - name: test-programs tests run: cargo test -p test-programs -- --nocapture if: steps.creds.outcome == 'success' diff --git a/Cargo.toml b/Cargo.toml index 386afa8..90a90cd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,9 +13,16 @@ repository.workspace = true rust-version.workspace = true [features] -default = ["json"] +default = ["json", "p2"] json = ["dep:serde", "dep:serde_json"] +# WASI backend selection. Exactly one of these must be enabled. +p2 = ["dep:wasip2"] +p3 = ["dep:wasip3"] + +[build-dependencies] +cfg_aliases.workspace = true + [dependencies] anyhow.workspace = true async-task.workspace = true @@ -27,9 +34,11 @@ http.workspace = true itoa.workspace = true pin-project-lite.workspace = true slab.workspace = true -wasip2.workspace = true wstd-macro.workspace = true +wasip2 = { workspace = true, optional = true } +wasip3 = { workspace = true, optional = true } + # optional serde = { workspace = true, optional = true } serde_json = { workspace = true, optional = true } @@ -43,6 +52,62 @@ humantime.workspace = true serde = { workspace = true, features = ["derive"] } serde_json.workspace = true +[[test]] +name = "http_first_byte_timeout" +required-features = ["p2"] + +[[test]] +name = "http_get" +required-features = ["p2"] + +[[test]] +name = "http_get_json" +required-features = ["p2"] + +[[test]] +name = "http_handle_error_code" +required-features = ["p2"] + +[[test]] +name = "http_post" +required-features = ["p2"] + +[[test]] +name = "http_post_json" +required-features = ["p2"] + +[[test]] +name = "http_timeout" +required-features = ["p2"] + +[[test]] +name = "sleep" +required-features = ["p2"] + +[[example]] +name = "complex_http_client" +required-features = ["p2"] + +[[example]] +name = "http_client" +required-features = ["p2"] + +[[example]] +name = "http_server" +required-features = ["p2"] + +[[example]] +name = "http_server_proxy" +required-features = ["p2"] + +[[example]] +name = "tcp_echo_server" +required-features = ["p2"] + +[[example]] +name = "tcp_stream_client" +required-features = ["p2"] + [workspace] members = [ "axum", @@ -72,6 +137,7 @@ async-task = "4.7" axum = { version = "0.8.6", default-features = false } bytes = "1.10.1" cargo_metadata = "0.22" +cfg_aliases = "0.2" clap = { version = "4.5.26", features = ["derive"] } futures-core = "0.3.19" futures-lite = "1.12.0" @@ -95,13 +161,13 @@ test-programs = { path = "test-programs" } tower-service = "0.3.3" ureq = { version = "3.1", default-features = false, features = ["json"] } wasip2 = "1.0" -wstd = { path = ".", version = "=0.6.8" } +wasip3 = "0.8" +wstd = { path = ".", version = "=0.6.8", default-features = false } wstd-axum = { path = "./axum", version = "=0.6.8" } wstd-axum-macro = { path = "./axum/macro", version = "=0.6.8" } wstd-macro = { path = "./macro", version = "=0.6.8" } [package.metadata.docs.rs] -all-features = true targets = [ "wasm32-wasip2" ] diff --git a/axum/Cargo.toml b/axum/Cargo.toml index 154a021..a27ce78 100644 --- a/axum/Cargo.toml +++ b/axum/Cargo.toml @@ -13,12 +13,32 @@ rust-version.workspace = true [dependencies] axum.workspace = true tower-service.workspace = true -wstd.workspace = true +wstd = { workspace = true, features = ["json"] } wstd-axum-macro.workspace = true +[features] +default = ["p2"] +p2 = ["wstd/p2"] +p3 = ["wstd/p3"] + +[build-dependencies] +cfg_aliases.workspace = true + [dev-dependencies] anyhow.workspace = true futures-concurrency.workspace = true serde = { workspace = true, features = ["derive"] } serde_qs.workspace = true axum = { workspace = true, features = ["query", "json", "macros"] } + +[[example]] +name = "hello_world" +required-features = ["p2"] + +[[example]] +name = "hello_world_nomacro" +required-features = ["p2"] + +[[example]] +name = "weather" +required-features = ["p2"] diff --git a/axum/build.rs b/axum/build.rs new file mode 100644 index 0000000..5a5f457 --- /dev/null +++ b/axum/build.rs @@ -0,0 +1,10 @@ +use cfg_aliases::cfg_aliases; + +fn main() { + cfg_aliases! { + // TODO https://github.com/bytecodealliance/wstd/issues/147: Swap these + // to use `target_env` instead. + p2: { feature = "p2" }, + p3: { feature = "p3" }, + } +} diff --git a/axum/src/lib.rs b/axum/src/lib.rs index 3272b91..c730fd2 100644 --- a/axum/src/lib.rs +++ b/axum/src/lib.rs @@ -1,3 +1,4 @@ +#![cfg(p2)] //! Support for the [`axum`] web server framework in wasi-http components, via //! [`wstd`]. //! diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..5a5f457 --- /dev/null +++ b/build.rs @@ -0,0 +1,10 @@ +use cfg_aliases::cfg_aliases; + +fn main() { + cfg_aliases! { + // TODO https://github.com/bytecodealliance/wstd/issues/147: Swap these + // to use `target_env` instead. + p2: { feature = "p2" }, + p3: { feature = "p3" }, + } +} diff --git a/src/lib.rs b/src/lib.rs index ebc673d..64ac672 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,7 +18,7 @@ //! **TCP echo server** //! //! ```rust,no_run -#![doc = include_str!("../examples/tcp_echo_server.rs")] +#![cfg_attr(p2, doc = include_str!("../examples/tcp_echo_server.rs"))] //! ``` //! //! **HTTP Client** @@ -30,7 +30,7 @@ //! **HTTP Server** //! //! ```rust,no_run -#![doc = include_str!("../examples/http_server.rs")] +#![cfg_attr(p2, doc = include_str!("../examples/http_server.rs"))] //! ``` //! //! # Design Decisions @@ -55,30 +55,52 @@ //! These are unique capabilities provided by WASI 0.2, and because this library //! is specific to that are exposed from here. +// Exactly one WASI backend must be selected. See the `p2`/`p3` features. +#[cfg(all(p2, p3))] +compile_error!( + "the `p2` and `p3` features are mutually exclusive — enable exactly one WASI backend" +); +#[cfg(not(any(p2, p3)))] +compile_error!("exactly one of the `p2` or `p3` features must be enabled"); + +#[cfg(p2)] pub mod future; +#[cfg(p2)] #[macro_use] pub mod http; +#[cfg(p2)] pub mod io; pub mod iter; +#[cfg(p2)] pub mod net; +#[cfg(p2)] pub mod rand; +#[cfg(p2)] pub mod runtime; +#[cfg(p2)] pub mod task; +#[cfg(p2)] pub mod time; -pub use wstd_macro::attr_macro_http_server as http_server; -pub use wstd_macro::attr_macro_main as main; -pub use wstd_macro::attr_macro_test as test; +#[cfg(p2)] +pub use wstd_macro::{ + attr_macro_http_server as http_server, attr_macro_main as main, attr_macro_test as test, +}; -// Re-export the wasip2 crate for use only by `wstd-macro` macros. The proc -// macros need to generate code that uses these definitions, but we don't want -// to treat it as part of our public API with regards to semver, so we keep it -// under `__internal` as well as doc(hidden) to indicate it is private. +// Re-export the active WASI backend crate for use only by `wstd-macro` macros. +// The proc macros need to generate code that uses these definitions, but we +// don't want to treat it as part of our public API with regards to semver, so +// we keep it under `__internal` as well as doc(hidden) to indicate it is +// private. #[doc(hidden)] pub mod __internal { + #[cfg(p2)] pub use wasip2; + #[cfg(p3)] + pub use wasip3; } +#[cfg(p2)] pub mod prelude { pub use crate::future::FutureExt as _; pub use crate::io::AsyncRead as _;