Skip to content

Commit cb69069

Browse files
Merge pull request #87 from spinframework/wasip3
Add support for WASI P3
2 parents c1cfa4f + 0aa0165 commit cb69069

File tree

23 files changed

+2515
-79
lines changed

23 files changed

+2515
-79
lines changed

Cargo.lock

Lines changed: 372 additions & 74 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,22 +17,24 @@ The Spin Rust SDK makes it easy to build Spin components in Rust.
1717
name = "spin_sdk"
1818

1919
[dependencies]
20-
anyhow = "1"
20+
anyhow = { workspace = true }
2121
async-trait = "0.1.74"
2222
chrono = "0.4.38"
2323
form_urlencoded = "1.0"
2424
postgres_range = { version = "0.11.1", optional = true }
2525
rust_decimal = { version = "1.37.2", default-features = false, optional = true }
2626
spin-executor = { version = "5.0.0", path = "crates/executor" }
2727
spin-macro = { version = "5.0.0", path = "crates/macro" }
28-
thiserror = "1.0.37"
28+
spin-wasip3-http = { version = "5.0.0", path = "crates/spin-wasip3-http", optional = true }
29+
spin-wasip3-http-macro = { version = "5.0.0", path = "crates/spin-wasip3-http-macro", optional = true }
30+
thiserror = { workspace = true }
2931
uuid = { version = "1.18.0", optional = true }
3032
wit-bindgen = { workspace = true }
3133
routefinder = "0.5.3"
3234
once_cell = { workspace = true }
3335
futures = { workspace = true }
34-
bytes = "1"
35-
hyperium = { package = "http", version = "1.0.0" }
36+
bytes = { workspace = true }
37+
hyperium = { workspace = true }
3638
serde_json = { version = "1.0.96", optional = true }
3739
serde = { version = "1.0.163", optional = true }
3840
wasi = { workspace = true }
@@ -42,6 +44,7 @@ default = ["export-sdk-language", "json", "postgres4-types"]
4244
export-sdk-language = []
4345
json = ["dep:serde", "dep:serde_json"]
4446
postgres4-types = ["dep:rust_decimal", "dep:uuid", "dep:postgres_range", "json"]
47+
wasip3-unstable = ["dep:spin-wasip3-http", "dep:spin-wasip3-http-macro"]
4548

4649
[workspace]
4750
resolver = "2"
@@ -65,6 +68,9 @@ members = [
6568
"examples/variables",
6669
"examples/wasi-http-streaming-outgoing-body",
6770
"examples/wasi-http-streaming-file",
71+
"examples/wasip3-http-axum-router",
72+
"examples/wasip3-http-hello-world",
73+
"examples/wasip3-http-send-request",
6874
"test-cases/simple-http",
6975
"test-cases/simple-redis",
7076
"crates/*",
@@ -92,12 +98,18 @@ authors = ["Spin Framework Maintainers <cncf-spin-maintainers@lists.cncf.io>"]
9298
edition = "2021"
9399
license = "Apache-2.0 WITH LLVM-exception"
94100
repository = "https://github.com/spinframework/spin-rust-sdk"
95-
rust-version = "1.78"
101+
rust-version = "1.86"
96102
homepage = "https://spinframework.dev/rust-components"
97103

98104
[workspace.dependencies]
105+
anyhow = "1"
106+
hyperium = { package = "http", version = "1.3.1" }
107+
http-body = "1.0.1"
108+
http-body-util = "0.1.3"
109+
bytes = "1.10.1"
99110
wit-bindgen = "0.43.0"
100111
futures = "0.3.28"
101112
once_cell = "1.18.0"
113+
thiserror = "2.0.17"
102114
# Pin to the last version that targeted WASI 0.2.0
103115
wasi = "=0.13.1"
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
[package]
2+
name = "spin-wasip3-http-macro"
3+
version.workspace = true
4+
authors.workspace = true
5+
edition.workspace = true
6+
license.workspace = true
7+
repository.workspace = true
8+
rust-version.workspace = true
9+
homepage.workspace = true
10+
description = """
11+
Rust procedural macros for Spin and WASIp3
12+
"""
13+
14+
[lib]
15+
name = "spin_wasip3_http_macro"
16+
proc-macro = true
17+
18+
[dependencies]
19+
proc-macro2 = "1"
20+
quote = "1.0"
21+
syn = { version = "1.0", features = [ "full" ]}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
use proc_macro::TokenStream;
2+
use quote::quote;
3+
4+
/// Marks an `async fn` as an HTTP component entrypoint for Spin.
5+
///
6+
/// The `#[http_service]` attribute designates an asynchronous function as the
7+
/// handler for incoming HTTP requests in a Spin component using the WASI Preview 3
8+
/// (`wasip3`) HTTP ABI.
9+
///
10+
/// When applied, this macro generates the necessary boilerplate to export the
11+
/// function to the Spin runtime as a valid HTTP handler. The function must be
12+
/// declared `async` and take a single argument implementing
13+
/// [`FromRequest`](::spin_sdk::http_wasip3::FromRequest), typically
14+
/// [`Request`](::spin_sdk::http_wasip3::Request), and must return a type that
15+
/// implements [`IntoResponse`](::spin_sdk::http_wasip3::IntoResponse).
16+
///
17+
/// # Requirements
18+
///
19+
/// - The annotated function **must** be `async`.
20+
/// - The function’s parameter type must implement [`FromRequest`].
21+
/// - The return type must implement [`IntoResponse`].
22+
///
23+
/// If the function is not asynchronous, the macro emits a compile-time error.
24+
///
25+
/// # Example
26+
///
27+
/// ```ignore
28+
/// use spin_sdk::http_wasip3::{http_service, Request, IntoResponse};
29+
///
30+
/// #[http_service]
31+
/// async fn my_handler(request: Request) -> impl IntoResponse {
32+
/// // Your logic goes here
33+
/// }
34+
/// ```
35+
///
36+
/// # Generated Code
37+
///
38+
/// The macro expands into a module containing a `Spin` struct that implements the
39+
/// WASI `http.handler/Guest` interface, wiring the annotated function as the
40+
/// handler’s entrypoint. This allows the function to be invoked automatically
41+
/// by the Spin runtime when HTTP requests are received.
42+
#[proc_macro_attribute]
43+
pub fn http_service(_attr: TokenStream, item: TokenStream) -> TokenStream {
44+
let func = syn::parse_macro_input!(item as syn::ItemFn);
45+
46+
if func.sig.asyncness.is_none() {
47+
return syn::Error::new_spanned(
48+
func.sig.fn_token,
49+
"the `#[http_component]` function must be `async`",
50+
)
51+
.to_compile_error()
52+
.into();
53+
}
54+
55+
let func_name = &func.sig.ident;
56+
57+
quote!(
58+
#func
59+
mod __spin_wasip3_http {
60+
use ::spin_sdk::http_wasip3::IntoResponse;
61+
62+
struct Spin;
63+
::spin_sdk::http_wasip3::wasip3::http::proxy::export!(Spin);
64+
65+
impl ::spin_sdk::http_wasip3::wasip3::exports::http::handler::Guest for self::Spin {
66+
async fn handle(request: ::spin_sdk::http_wasip3::wasip3::http::types::Request) -> Result<::spin_sdk::http_wasip3::wasip3::http::types::Response, ::spin_sdk::http_wasip3::wasip3::http::types::ErrorCode> {
67+
let request = <::spin_sdk::http_wasip3::Request as ::spin_sdk::http_wasip3::FromRequest>::from_request(request)?;
68+
::spin_sdk::http_wasip3::IntoResponse::into_response(super::#func_name(request).await)
69+
}
70+
}
71+
}
72+
)
73+
.into()
74+
}

crates/spin-wasip3-http/Cargo.toml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[package]
2+
name = "spin-wasip3-http"
3+
version.workspace = true
4+
authors.workspace = true
5+
edition.workspace = true
6+
license.workspace = true
7+
repository.workspace = true
8+
rust-version.workspace = true
9+
homepage.workspace = true
10+
11+
[dependencies]
12+
anyhow = { workspace = true }
13+
bytes = { workspace = true }
14+
http-body = { workspace = true }
15+
http-body-util = { workspace = true }
16+
hyperium = { workspace = true }
17+
wasip3 = { version = "0.2.1", features = ["http-compat"] }

0 commit comments

Comments
 (0)