Skip to content

Commit

Permalink
Add export! macros (#77)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
lann authored Feb 28, 2024
1 parent 8c5c76f commit d00dbc4
Show file tree
Hide file tree
Showing 7 changed files with 556 additions and 735 deletions.
7 changes: 6 additions & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
- uses: actions/checkout@v4
- name: Install Rust
run: rustup update ${{ matrix.rust }} && rustup default ${{ matrix.rust }} && rustup component add rustfmt
- run: rustup target add wasm32-wasi
- run: rustup target add wasm32-wasi wasm32-unknown-unknown
- run: cargo build
- run: cargo build --no-default-features
- run: cargo build --target wasm32-wasi
Expand All @@ -29,6 +29,11 @@ jobs:
- run: curl -LO https://github.com/bytecodealliance/wasmtime/releases/download/v17.0.0/wasi_snapshot_preview1.command.wasm
- run: wasm-tools component new ./target/wasm32-wasi/debug/examples/hello-world.wasm --adapt ./wasi_snapshot_preview1.command.wasm -o component.wasm
- run: wasmtime run component.wasm
- run: cargo build --examples --target wasm32-unknown-unknown --features macros
- run: wasm-tools component new ./target/wasm32-unknown-unknown/debug/examples/cli_command.wasm -o component.wasm
- run: wasmtime run component.wasm
- run: wasm-tools component new ./target/wasm32-unknown-unknown/debug/examples/http_proxy.wasm -o component.wasm
- run: wasm-tools component targets wit component.wasm -w wasi:http/proxy


rustfmt:
Expand Down
19 changes: 18 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,28 @@ compiler_builtins = { version = "0.1", optional = true }
core = { version = "1.0", optional = true, package = "rustc-std-workspace-core" }
rustc-std-workspace-alloc = { version = "1.0", optional = true }

[build-dependencies]
quote = { version = "1.0", optional = true }

[features]
default = ["std"]
std = []
macros = ["quote", "wit-bindgen/macros"]
# Unstable feature to support being a libstd dependency
rustc-dep-of-std = ["compiler_builtins", "core", "rustc-std-workspace-alloc"]

[package.metadata.docs.rs]
features = ["macros"]

[[example]]
name = "cli-command"
crate-type = ["cdylib"]
required-features = ["macros"]

[[example]]
name = "http-proxy"
crate-type = ["cdylib"]
required-features = ["macros"]

[badges]
maintenance = { status = "experimental" }
maintenance = { status = "experimental" }
105 changes: 105 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
fn main() {
#[cfg(feature = "macros")]
generate_macros();
}

#[cfg(feature = "macros")]
fn generate_macros() {
use std::path::Path;

let crate_root = std::env::var_os("CARGO_MANIFEST_DIR").unwrap();
let wit_path = Path::new(&crate_root)
.join("wit")
.to_str()
.expect("project path must be valid UTF-8")
.to_string();

fn write_macro(filename: &str, contents: impl ToString) {
let out_dir = std::env::var_os("OUT_DIR").unwrap();
let dest_path = Path::new(&out_dir).join(filename);
std::fs::write(dest_path, contents.to_string()).unwrap();
}

write_macro(
"cli_run_export.rs",
quote::quote! {
#[doc(hidden)]
#[macro_export]
macro_rules! cli_run_export {
($export_impl:path) => {
::wasi::macros::wit_bindgen::generate!({
path: #wit_path,
world: "wasi:cli/command",
exports: {
"wasi:cli/run": $export_impl,
},
with: {
"wasi:cli/environment@0.2.0": ::wasi::cli::environment,
"wasi:cli/exit@0.2.0": ::wasi::cli::exit,
"wasi:cli/stderr@0.2.0": ::wasi::cli::stderr,
"wasi:cli/stdin@0.2.0": ::wasi::cli::stdin,
"wasi:cli/stdout@0.2.0": ::wasi::cli::stdout,
"wasi:cli/terminal-input@0.2.0": ::wasi::cli::terminal_input,
"wasi:cli/terminal-output@0.2.0": ::wasi::cli::terminal_output,
"wasi:cli/terminal-stderr@0.2.0": ::wasi::cli::terminal_stderr,
"wasi:cli/terminal-stdin@0.2.0": ::wasi::cli::terminal_stdin,
"wasi:cli/terminal-stdout@0.2.0": ::wasi::cli::terminal_stdout,
"wasi:clocks/monotonic-clock@0.2.0": ::wasi::clocks::monotonic_clock,
"wasi:clocks/wall-clock@0.2.0": ::wasi::clocks::wall_clock,
"wasi:filesystem/preopens@0.2.0": ::wasi::filesystem::preopens,
"wasi:filesystem/types@0.2.0": ::wasi::filesystem::types,
"wasi:io/error@0.2.0": ::wasi::io::error,
"wasi:io/poll@0.2.0": ::wasi::io::poll,
"wasi:io/streams@0.2.0": ::wasi::io::streams,
"wasi:random/insecure-seed@0.2.0": ::wasi::random::insecure_seed,
"wasi:random/insecure@0.2.0": ::wasi::random::insecure,
"wasi:random/random@0.2.0": ::wasi::random::random,
"wasi:sockets/instance-network@0.2.0": ::wasi::sockets::instance_network,
"wasi:sockets/ip-name-lookup@0.2.0": ::wasi::sockets::ip_name_lookup,
"wasi:sockets/network@0.2.0": ::wasi::sockets::network,
"wasi:sockets/tcp-create-socket@0.2.0": ::wasi::sockets::tcp_create_socket,
"wasi:sockets/tcp@0.2.0": ::wasi::sockets::tcp,
"wasi:sockets/udp-create-socket@0.2.0": ::wasi::sockets::udp_create_socket,
"wasi:sockets/udp@0.2.0": ::wasi::sockets::udp,
},
runtime_path: "::wasi::macros::wit_bindgen::rt",
});
}
}
},
);

write_macro(
"http_incoming_handler_export.rs",
quote::quote! {
#[doc(hidden)]
#[macro_export]
macro_rules! http_incoming_handler_export {
($export_impl:path) => {
::wasi::macros::wit_bindgen::generate!({
path: #wit_path,
world: "wasi:http/proxy",
exports: {
"wasi:http/incoming-handler": $export_impl,
},
with: {
"wasi:cli/stderr@0.2.0": ::wasi::cli::stderr,
"wasi:cli/stdin@0.2.0": ::wasi::cli::stdin,
"wasi:cli/stdout@0.2.0": ::wasi::cli::stdout,
"wasi:clocks/monotonic-clock@0.2.0": ::wasi::clocks::monotonic_clock,
"wasi:clocks/wall-clock@0.2.0": ::wasi::clocks::wall_clock,
"wasi:http/outgoing-handler@0.2.0": ::wasi::http::outgoing_handler,
"wasi:http/types@0.2.0": ::wasi::http::types,
"wasi:io/error@0.2.0": ::wasi::io::error,
"wasi:io/poll@0.2.0": ::wasi::io::poll,
"wasi:io/streams@0.2.0": ::wasi::io::streams,
"wasi:random/random@0.2.0": ::wasi::random::random,
},
runtime_path: "::wasi::macros::wit_bindgen::rt",
});
}
}
},
);
println!("cargo:rerun-if-changed=build.rs");
}
11 changes: 11 additions & 0 deletions examples/cli-command.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
wasi::cli::run::export!(Example);

struct Example;

impl exports::wasi::cli::run::Guest for Example {
fn run() -> Result<(), ()> {
let stdout = wasi::cli::stdout::get_stdout();
stdout.blocking_write_and_flush(b"Hello, WASI!").unwrap();
Ok(())
}
}
22 changes: 22 additions & 0 deletions examples/http-proxy.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use wasi::http::types::{
Fields, IncomingRequest, OutgoingBody, OutgoingResponse, ResponseOutparam,
};

wasi::http::incoming_handler::export!(Example);

struct Example;

impl exports::wasi::http::incoming_handler::Guest for Example {
fn handle(_request: IncomingRequest, response_out: ResponseOutparam) {
let resp = OutgoingResponse::new(Fields::new());
let body = resp.body().unwrap();

ResponseOutparam::set(response_out, Ok(resp));

let out = body.write().unwrap();
out.blocking_write_and_flush(b"Hello, WASI!").unwrap();
drop(out);

OutgoingBody::finish(body, None).unwrap();
}
}
Loading

0 comments on commit d00dbc4

Please sign in to comment.