Skip to content

Commit d00dbc4

Browse files
authored
Add export! macros (#77)
* Add export macros This adds two macros that wrap wit_bindgen::generate! with appropriate path, world, exports, and with options: - `wasi::cli::run::export!` for `wasi:cli/run` - `wasi::http::incoming_handler::export!` for `wasi:http/incoming-handler` * Regenerate bindings with wit-bindgen 0.19.2 * Rename and test examples * Update docs: wasm32-wasi-preview{1,2} to wasm32-wasip{1,2} * Add Export Macros section to root docs * Add note about wasm32-wasi command compat * ci: Add wasm32-unknown-unknown target
1 parent 8c5c76f commit d00dbc4

File tree

7 files changed

+556
-735
lines changed

7 files changed

+556
-735
lines changed

.github/workflows/main.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
- uses: actions/checkout@v4
1313
- name: Install Rust
1414
run: rustup update ${{ matrix.rust }} && rustup default ${{ matrix.rust }} && rustup component add rustfmt
15-
- run: rustup target add wasm32-wasi
15+
- run: rustup target add wasm32-wasi wasm32-unknown-unknown
1616
- run: cargo build
1717
- run: cargo build --no-default-features
1818
- run: cargo build --target wasm32-wasi
@@ -29,6 +29,11 @@ jobs:
2929
- run: curl -LO https://github.com/bytecodealliance/wasmtime/releases/download/v17.0.0/wasi_snapshot_preview1.command.wasm
3030
- run: wasm-tools component new ./target/wasm32-wasi/debug/examples/hello-world.wasm --adapt ./wasi_snapshot_preview1.command.wasm -o component.wasm
3131
- run: wasmtime run component.wasm
32+
- run: cargo build --examples --target wasm32-unknown-unknown --features macros
33+
- run: wasm-tools component new ./target/wasm32-unknown-unknown/debug/examples/cli_command.wasm -o component.wasm
34+
- run: wasmtime run component.wasm
35+
- run: wasm-tools component new ./target/wasm32-unknown-unknown/debug/examples/http_proxy.wasm -o component.wasm
36+
- run: wasm-tools component targets wit component.wasm -w wasi:http/proxy
3237

3338

3439
rustfmt:

Cargo.toml

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,28 @@ compiler_builtins = { version = "0.1", optional = true }
1919
core = { version = "1.0", optional = true, package = "rustc-std-workspace-core" }
2020
rustc-std-workspace-alloc = { version = "1.0", optional = true }
2121

22+
[build-dependencies]
23+
quote = { version = "1.0", optional = true }
24+
2225
[features]
2326
default = ["std"]
2427
std = []
28+
macros = ["quote", "wit-bindgen/macros"]
2529
# Unstable feature to support being a libstd dependency
2630
rustc-dep-of-std = ["compiler_builtins", "core", "rustc-std-workspace-alloc"]
2731

32+
[package.metadata.docs.rs]
33+
features = ["macros"]
34+
35+
[[example]]
36+
name = "cli-command"
37+
crate-type = ["cdylib"]
38+
required-features = ["macros"]
39+
40+
[[example]]
41+
name = "http-proxy"
42+
crate-type = ["cdylib"]
43+
required-features = ["macros"]
44+
2845
[badges]
29-
maintenance = { status = "experimental" }
46+
maintenance = { status = "experimental" }

build.rs

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
fn main() {
2+
#[cfg(feature = "macros")]
3+
generate_macros();
4+
}
5+
6+
#[cfg(feature = "macros")]
7+
fn generate_macros() {
8+
use std::path::Path;
9+
10+
let crate_root = std::env::var_os("CARGO_MANIFEST_DIR").unwrap();
11+
let wit_path = Path::new(&crate_root)
12+
.join("wit")
13+
.to_str()
14+
.expect("project path must be valid UTF-8")
15+
.to_string();
16+
17+
fn write_macro(filename: &str, contents: impl ToString) {
18+
let out_dir = std::env::var_os("OUT_DIR").unwrap();
19+
let dest_path = Path::new(&out_dir).join(filename);
20+
std::fs::write(dest_path, contents.to_string()).unwrap();
21+
}
22+
23+
write_macro(
24+
"cli_run_export.rs",
25+
quote::quote! {
26+
#[doc(hidden)]
27+
#[macro_export]
28+
macro_rules! cli_run_export {
29+
($export_impl:path) => {
30+
::wasi::macros::wit_bindgen::generate!({
31+
path: #wit_path,
32+
world: "wasi:cli/command",
33+
exports: {
34+
"wasi:cli/run": $export_impl,
35+
},
36+
with: {
37+
"wasi:cli/[email protected]": ::wasi::cli::environment,
38+
"wasi:cli/[email protected]": ::wasi::cli::exit,
39+
"wasi:cli/[email protected]": ::wasi::cli::stderr,
40+
"wasi:cli/[email protected]": ::wasi::cli::stdin,
41+
"wasi:cli/[email protected]": ::wasi::cli::stdout,
42+
"wasi:cli/[email protected]": ::wasi::cli::terminal_input,
43+
"wasi:cli/[email protected]": ::wasi::cli::terminal_output,
44+
"wasi:cli/[email protected]": ::wasi::cli::terminal_stderr,
45+
"wasi:cli/[email protected]": ::wasi::cli::terminal_stdin,
46+
"wasi:cli/[email protected]": ::wasi::cli::terminal_stdout,
47+
"wasi:clocks/[email protected]": ::wasi::clocks::monotonic_clock,
48+
"wasi:clocks/[email protected]": ::wasi::clocks::wall_clock,
49+
"wasi:filesystem/[email protected]": ::wasi::filesystem::preopens,
50+
"wasi:filesystem/[email protected]": ::wasi::filesystem::types,
51+
"wasi:io/[email protected]": ::wasi::io::error,
52+
"wasi:io/[email protected]": ::wasi::io::poll,
53+
"wasi:io/[email protected]": ::wasi::io::streams,
54+
"wasi:random/[email protected]": ::wasi::random::insecure_seed,
55+
"wasi:random/[email protected]": ::wasi::random::insecure,
56+
"wasi:random/[email protected]": ::wasi::random::random,
57+
"wasi:sockets/[email protected]": ::wasi::sockets::instance_network,
58+
"wasi:sockets/[email protected]": ::wasi::sockets::ip_name_lookup,
59+
"wasi:sockets/[email protected]": ::wasi::sockets::network,
60+
"wasi:sockets/[email protected]": ::wasi::sockets::tcp_create_socket,
61+
"wasi:sockets/[email protected]": ::wasi::sockets::tcp,
62+
"wasi:sockets/[email protected]": ::wasi::sockets::udp_create_socket,
63+
"wasi:sockets/[email protected]": ::wasi::sockets::udp,
64+
},
65+
runtime_path: "::wasi::macros::wit_bindgen::rt",
66+
});
67+
}
68+
}
69+
},
70+
);
71+
72+
write_macro(
73+
"http_incoming_handler_export.rs",
74+
quote::quote! {
75+
#[doc(hidden)]
76+
#[macro_export]
77+
macro_rules! http_incoming_handler_export {
78+
($export_impl:path) => {
79+
::wasi::macros::wit_bindgen::generate!({
80+
path: #wit_path,
81+
world: "wasi:http/proxy",
82+
exports: {
83+
"wasi:http/incoming-handler": $export_impl,
84+
},
85+
with: {
86+
"wasi:cli/[email protected]": ::wasi::cli::stderr,
87+
"wasi:cli/[email protected]": ::wasi::cli::stdin,
88+
"wasi:cli/[email protected]": ::wasi::cli::stdout,
89+
"wasi:clocks/[email protected]": ::wasi::clocks::monotonic_clock,
90+
"wasi:clocks/[email protected]": ::wasi::clocks::wall_clock,
91+
"wasi:http/[email protected]": ::wasi::http::outgoing_handler,
92+
"wasi:http/[email protected]": ::wasi::http::types,
93+
"wasi:io/[email protected]": ::wasi::io::error,
94+
"wasi:io/[email protected]": ::wasi::io::poll,
95+
"wasi:io/[email protected]": ::wasi::io::streams,
96+
"wasi:random/[email protected]": ::wasi::random::random,
97+
},
98+
runtime_path: "::wasi::macros::wit_bindgen::rt",
99+
});
100+
}
101+
}
102+
},
103+
);
104+
println!("cargo:rerun-if-changed=build.rs");
105+
}

examples/cli-command.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
wasi::cli::run::export!(Example);
2+
3+
struct Example;
4+
5+
impl exports::wasi::cli::run::Guest for Example {
6+
fn run() -> Result<(), ()> {
7+
let stdout = wasi::cli::stdout::get_stdout();
8+
stdout.blocking_write_and_flush(b"Hello, WASI!").unwrap();
9+
Ok(())
10+
}
11+
}

examples/http-proxy.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
use wasi::http::types::{
2+
Fields, IncomingRequest, OutgoingBody, OutgoingResponse, ResponseOutparam,
3+
};
4+
5+
wasi::http::incoming_handler::export!(Example);
6+
7+
struct Example;
8+
9+
impl exports::wasi::http::incoming_handler::Guest for Example {
10+
fn handle(_request: IncomingRequest, response_out: ResponseOutparam) {
11+
let resp = OutgoingResponse::new(Fields::new());
12+
let body = resp.body().unwrap();
13+
14+
ResponseOutparam::set(response_out, Ok(resp));
15+
16+
let out = body.write().unwrap();
17+
out.blocking_write_and_flush(b"Hello, WASI!").unwrap();
18+
drop(out);
19+
20+
OutgoingBody::finish(body, None).unwrap();
21+
}
22+
}

0 commit comments

Comments
 (0)