Add a wasmtime::component::bindgen! macro (#5317)
* Import Wasmtime support from the `wit-bindgen` repo This commit imports the `wit-bindgen-gen-host-wasmtime-rust` crate from the `wit-bindgen` repository into the upstream Wasmtime repository. I've chosen to not import the full history here since the crate is relatively small and doesn't have a ton of complexity. While the history of the crate is quite long the current iteration of the crate's history is relatively short so there's not a ton of import there anyway. The thinking is that this can now continue to evolve in-tree. * Refactor `wasmtime-component-macro` a bit Make room for a `wit_bindgen` macro to slot in. * Add initial support for a `bindgen` macro * Add tests for `wasmtime::component::bindgen!` * Improve error forgetting `async` feature * Add end-to-end tests for bindgen * Add an audit of `unicase` * Add a license to the test-helpers crate * Add vet entry for `pulldown-cmark` * Update publish script with new crate * Try to fix publish script * Update audits * Update lock file
This commit is contained in:
54
Cargo.lock
generated
54
Cargo.lock
generated
@@ -472,6 +472,14 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "component-macro-test-helpers"
|
||||||
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "component-test-util"
|
name = "component-test-util"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
@@ -2235,6 +2243,17 @@ dependencies = [
|
|||||||
"cc",
|
"cc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pulldown-cmark"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"memchr",
|
||||||
|
"unicase",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quick-error"
|
name = "quick-error"
|
||||||
version = "1.2.3"
|
version = "1.2.3"
|
||||||
@@ -2969,6 +2988,15 @@ version = "1.15.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
|
checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicase"
|
||||||
|
version = "2.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
|
||||||
|
dependencies = [
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-bidi"
|
name = "unicode-bidi"
|
||||||
version = "0.3.8"
|
version = "0.3.8"
|
||||||
@@ -3496,10 +3524,15 @@ dependencies = [
|
|||||||
name = "wasmtime-component-macro"
|
name = "wasmtime-component-macro"
|
||||||
version = "5.0.0"
|
version = "5.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"component-macro-test-helpers",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn",
|
||||||
|
"tracing",
|
||||||
|
"wasmtime",
|
||||||
"wasmtime-component-util",
|
"wasmtime-component-util",
|
||||||
|
"wasmtime-wit-bindgen",
|
||||||
|
"wit-parser",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3757,6 +3790,14 @@ dependencies = [
|
|||||||
"winch-codegen",
|
"winch-codegen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasmtime-wit-bindgen"
|
||||||
|
version = "5.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"heck",
|
||||||
|
"wit-parser",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wast"
|
name = "wast"
|
||||||
version = "35.0.2"
|
version = "35.0.2"
|
||||||
@@ -3986,6 +4027,19 @@ dependencies = [
|
|||||||
"windows-sys",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wit-parser"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "893834cffb239f88413eead7cf91862a6f24c2233afae15d7808256d8c58f91e"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"id-arena",
|
||||||
|
"indexmap",
|
||||||
|
"pulldown-cmark",
|
||||||
|
"unicode-xid",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "witx"
|
name = "witx"
|
||||||
version = "0.9.1"
|
version = "0.9.1"
|
||||||
|
|||||||
@@ -133,6 +133,7 @@ wasi-tokio = { path = "crates/wasi-common/tokio", version = "=5.0.0" }
|
|||||||
wasi-cap-std-sync = { path = "crates/wasi-common/cap-std-sync", version = "=5.0.0" }
|
wasi-cap-std-sync = { path = "crates/wasi-common/cap-std-sync", version = "=5.0.0" }
|
||||||
wasmtime-fuzzing = { path = "crates/fuzzing" }
|
wasmtime-fuzzing = { path = "crates/fuzzing" }
|
||||||
wasmtime-jit-icache-coherence = { path = "crates/jit-icache-coherence", version = "=5.0.0" }
|
wasmtime-jit-icache-coherence = { path = "crates/jit-icache-coherence", version = "=5.0.0" }
|
||||||
|
wasmtime-wit-bindgen = { path = "crates/wit-bindgen", version = "=5.0.0" }
|
||||||
|
|
||||||
cranelift-wasm = { path = "cranelift/wasm", version = "0.92.0" }
|
cranelift-wasm = { path = "cranelift/wasm", version = "0.92.0" }
|
||||||
cranelift-codegen = { path = "cranelift/codegen", version = "0.92.0" }
|
cranelift-codegen = { path = "cranelift/codegen", version = "0.92.0" }
|
||||||
@@ -162,6 +163,7 @@ wasmprinter = "0.2.44"
|
|||||||
wasm-encoder = "0.20.0"
|
wasm-encoder = "0.20.0"
|
||||||
wasm-smith = "0.11.9"
|
wasm-smith = "0.11.9"
|
||||||
wasm-mutate = "0.2.12"
|
wasm-mutate = "0.2.12"
|
||||||
|
wit-parser = "0.3"
|
||||||
windows-sys = "0.42.0"
|
windows-sys = "0.42.0"
|
||||||
env_logger = "0.9"
|
env_logger = "0.9"
|
||||||
rustix = "0.36.0"
|
rustix = "0.36.0"
|
||||||
@@ -179,6 +181,7 @@ tracing = "0.1.26"
|
|||||||
bitflags = "1.2"
|
bitflags = "1.2"
|
||||||
thiserror = "1.0.15"
|
thiserror = "1.0.15"
|
||||||
async-trait = "0.1.42"
|
async-trait = "0.1.42"
|
||||||
|
heck = "0.4"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = [
|
default = [
|
||||||
|
|||||||
@@ -12,12 +12,24 @@ edition.workspace = true
|
|||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
proc-macro = true
|
proc-macro = true
|
||||||
|
test = false
|
||||||
|
doctest = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
proc-macro2 = "1.0"
|
proc-macro2 = "1.0"
|
||||||
quote = "1.0"
|
quote = "1.0"
|
||||||
syn = { version = "1.0", features = ["extra-traits"] }
|
syn = { version = "1.0", features = ["extra-traits"] }
|
||||||
wasmtime-component-util = { workspace = true }
|
wasmtime-component-util = { workspace = true }
|
||||||
|
wasmtime-wit-bindgen = { workspace = true }
|
||||||
|
wit-parser = { workspace = true }
|
||||||
|
|
||||||
[badges]
|
[badges]
|
||||||
maintenance = { status = "actively-developed" }
|
maintenance = { status = "actively-developed" }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
wasmtime = { path = '../wasmtime', features = ['component-model'] }
|
||||||
|
component-macro-test-helpers = { path = 'test-helpers' }
|
||||||
|
tracing = { workspace = true }
|
||||||
|
|
||||||
|
[features]
|
||||||
|
async = []
|
||||||
|
|||||||
137
crates/component-macro/src/bindgen.rs
Normal file
137
crates/component-macro/src/bindgen.rs
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
use proc_macro2::{Span, TokenStream};
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
use syn::parse::{Error, Parse, ParseStream, Result};
|
||||||
|
use syn::punctuated::Punctuated;
|
||||||
|
use syn::token;
|
||||||
|
use syn::Token;
|
||||||
|
use wasmtime_wit_bindgen::Opts;
|
||||||
|
use wit_parser::World;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Config {
|
||||||
|
opts: Opts, // ...
|
||||||
|
world: World,
|
||||||
|
files: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn expand(input: &Config) -> Result<TokenStream> {
|
||||||
|
if !cfg!(feature = "async") && input.opts.async_ {
|
||||||
|
return Err(Error::new(
|
||||||
|
Span::call_site(),
|
||||||
|
"cannot enable async bindings unless `async` crate feature is active",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let src = input.opts.generate(&input.world);
|
||||||
|
let mut contents = src.parse::<TokenStream>().unwrap();
|
||||||
|
|
||||||
|
// Include a dummy `include_str!` for any files we read so rustc knows that
|
||||||
|
// we depend on the contents of those files.
|
||||||
|
let cwd = std::env::var("CARGO_MANIFEST_DIR").unwrap();
|
||||||
|
for file in input.files.iter() {
|
||||||
|
contents.extend(
|
||||||
|
format!(
|
||||||
|
"const _: &str = include_str!(r#\"{}\"#);\n",
|
||||||
|
Path::new(&cwd).join(file).display()
|
||||||
|
)
|
||||||
|
.parse::<TokenStream>()
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(contents)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for Config {
|
||||||
|
fn parse(input: ParseStream<'_>) -> Result<Self> {
|
||||||
|
let call_site = Span::call_site();
|
||||||
|
let mut world = None;
|
||||||
|
let mut ret = Config::default();
|
||||||
|
|
||||||
|
if input.peek(token::Brace) {
|
||||||
|
let content;
|
||||||
|
syn::braced!(content in input);
|
||||||
|
let fields = Punctuated::<Opt, Token![,]>::parse_terminated(&content)?;
|
||||||
|
for field in fields.into_pairs() {
|
||||||
|
match field.into_value() {
|
||||||
|
Opt::Path(path) => {
|
||||||
|
if world.is_some() {
|
||||||
|
return Err(Error::new(path.span(), "cannot specify second world"));
|
||||||
|
}
|
||||||
|
world = Some(ret.parse(path)?);
|
||||||
|
}
|
||||||
|
Opt::Inline(span, w) => {
|
||||||
|
if world.is_some() {
|
||||||
|
return Err(Error::new(span, "cannot specify second world"));
|
||||||
|
}
|
||||||
|
world = Some(w);
|
||||||
|
}
|
||||||
|
Opt::Tracing(val) => ret.opts.tracing = val,
|
||||||
|
Opt::Async(val) => ret.opts.async_ = val,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let s = input.parse::<syn::LitStr>()?;
|
||||||
|
world = Some(ret.parse(s)?);
|
||||||
|
}
|
||||||
|
ret.world = world.ok_or_else(|| {
|
||||||
|
Error::new(
|
||||||
|
call_site,
|
||||||
|
"must specify a `*.wit` file to generate bindings for",
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
Ok(ret)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Config {
|
||||||
|
fn parse(&mut self, path: syn::LitStr) -> Result<World> {
|
||||||
|
let span = path.span();
|
||||||
|
let path = path.value();
|
||||||
|
let manifest_dir = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap());
|
||||||
|
let path = manifest_dir.join(path);
|
||||||
|
self.files.push(path.to_str().unwrap().to_string());
|
||||||
|
World::parse_file(path).map_err(|e| Error::new(span, e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod kw {
|
||||||
|
syn::custom_keyword!(path);
|
||||||
|
syn::custom_keyword!(inline);
|
||||||
|
syn::custom_keyword!(tracing);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Opt {
|
||||||
|
Path(syn::LitStr),
|
||||||
|
Inline(Span, World),
|
||||||
|
Tracing(bool),
|
||||||
|
Async(bool),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for Opt {
|
||||||
|
fn parse(input: ParseStream<'_>) -> Result<Self> {
|
||||||
|
let l = input.lookahead1();
|
||||||
|
if l.peek(kw::path) {
|
||||||
|
input.parse::<kw::path>()?;
|
||||||
|
input.parse::<Token![:]>()?;
|
||||||
|
Ok(Opt::Path(input.parse()?))
|
||||||
|
} else if l.peek(kw::inline) {
|
||||||
|
let span = input.parse::<kw::inline>()?.span;
|
||||||
|
input.parse::<Token![:]>()?;
|
||||||
|
let s = input.parse::<syn::LitStr>()?;
|
||||||
|
let world =
|
||||||
|
World::parse("<macro-input>", &s.value()).map_err(|e| Error::new(s.span(), e))?;
|
||||||
|
Ok(Opt::Inline(span, world))
|
||||||
|
} else if l.peek(kw::tracing) {
|
||||||
|
input.parse::<kw::tracing>()?;
|
||||||
|
input.parse::<Token![:]>()?;
|
||||||
|
Ok(Opt::Tracing(input.parse::<syn::LitBool>()?.value))
|
||||||
|
} else if l.peek(Token![async]) {
|
||||||
|
input.parse::<Token![async]>()?;
|
||||||
|
input.parse::<Token![:]>()?;
|
||||||
|
Ok(Opt::Async(input.parse::<syn::LitBool>()?.value))
|
||||||
|
} else {
|
||||||
|
Err(l.error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1191
crates/component-macro/src/component.rs
Normal file
1191
crates/component-macro/src/component.rs
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
13
crates/component-macro/test-helpers/Cargo.toml
Normal file
13
crates/component-macro/test-helpers/Cargo.toml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
[package]
|
||||||
|
name = "component-macro-test-helpers"
|
||||||
|
version = "0.0.0"
|
||||||
|
edition.workspace = true
|
||||||
|
publish = false
|
||||||
|
license = "Apache-2.0 WITH LLVM-exception"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
proc-macro = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
proc-macro2 = "1.0"
|
||||||
|
quote = "1.0"
|
||||||
23
crates/component-macro/test-helpers/src/lib.rs
Normal file
23
crates/component-macro/test-helpers/src/lib.rs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
use proc_macro::TokenStream;
|
||||||
|
use proc_macro2::{Ident, Span};
|
||||||
|
use quote::quote;
|
||||||
|
|
||||||
|
#[proc_macro]
|
||||||
|
pub fn foreach(input: TokenStream) -> TokenStream {
|
||||||
|
let input = proc_macro2::TokenStream::from(input);
|
||||||
|
let mut cwd = std::env::current_dir().unwrap();
|
||||||
|
cwd.push("crates/component-macro/tests/codegen");
|
||||||
|
let mut result = Vec::new();
|
||||||
|
for f in cwd.read_dir().unwrap() {
|
||||||
|
let f = f.unwrap().path();
|
||||||
|
if f.extension().and_then(|s| s.to_str()) == Some("wit") {
|
||||||
|
let name = f.file_stem().unwrap().to_str().unwrap();
|
||||||
|
let name = Ident::new(&name.replace("-", "_"), Span::call_site());
|
||||||
|
let path = f.to_str().unwrap();
|
||||||
|
result.push(quote! {
|
||||||
|
#input!(#name #path);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(quote!( #(#result)*)).into()
|
||||||
|
}
|
||||||
24
crates/component-macro/tests/codegen.rs
Normal file
24
crates/component-macro/tests/codegen.rs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
macro_rules! gentest {
|
||||||
|
($id:ident $path:tt) => {
|
||||||
|
mod $id {
|
||||||
|
mod normal {
|
||||||
|
wasmtime::component::bindgen!($path);
|
||||||
|
}
|
||||||
|
mod async_ {
|
||||||
|
wasmtime::component::bindgen!({
|
||||||
|
path: $path,
|
||||||
|
async: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
mod tracing {
|
||||||
|
wasmtime::component::bindgen!({
|
||||||
|
path: $path,
|
||||||
|
tracing: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ...
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
component_macro_test_helpers::foreach!(gentest);
|
||||||
12
crates/component-macro/tests/codegen/char.wit
Normal file
12
crates/component-macro/tests/codegen/char.wit
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
interface chars {
|
||||||
|
/// A function that accepts a character
|
||||||
|
take-char: func(x: char)
|
||||||
|
/// A function that returns a character
|
||||||
|
return-char: func() -> char
|
||||||
|
}
|
||||||
|
|
||||||
|
world the-world {
|
||||||
|
import imports: chars
|
||||||
|
export exports: chars
|
||||||
|
default export chars
|
||||||
|
}
|
||||||
39
crates/component-macro/tests/codegen/conventions.wit
Normal file
39
crates/component-macro/tests/codegen/conventions.wit
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
// hello 🐱 world
|
||||||
|
|
||||||
|
interface conventions {
|
||||||
|
kebab-case: func()
|
||||||
|
|
||||||
|
record ludicrous-speed {
|
||||||
|
how-fast-are-you-going: u32,
|
||||||
|
i-am-going-extremely-slow: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
foo: func(x: ludicrous-speed)
|
||||||
|
%function-with-dashes: func()
|
||||||
|
%function-with-no-weird-characters: func()
|
||||||
|
|
||||||
|
apple: func()
|
||||||
|
apple-pear: func()
|
||||||
|
apple-pear-grape: func()
|
||||||
|
a0: func()
|
||||||
|
|
||||||
|
// Comment out identifiers that collide when mapped to snake_case, for now; see
|
||||||
|
// https://github.com/WebAssembly/component-model/issues/118
|
||||||
|
//APPLE: func()
|
||||||
|
//APPLE-pear-GRAPE: func()
|
||||||
|
//apple-PEAR-grape: func()
|
||||||
|
|
||||||
|
is-XML: func()
|
||||||
|
|
||||||
|
%explicit: func()
|
||||||
|
%explicit-kebab: func()
|
||||||
|
|
||||||
|
// Identifiers with the same name as keywords are quoted.
|
||||||
|
%bool: func()
|
||||||
|
}
|
||||||
|
|
||||||
|
world the-world {
|
||||||
|
import imports: conventions
|
||||||
|
export exports: conventions
|
||||||
|
default export conventions
|
||||||
|
}
|
||||||
1
crates/component-macro/tests/codegen/empty.wit
Normal file
1
crates/component-macro/tests/codegen/empty.wit
Normal file
@@ -0,0 +1 @@
|
|||||||
|
world empty {}
|
||||||
54
crates/component-macro/tests/codegen/flags.wit
Normal file
54
crates/component-macro/tests/codegen/flags.wit
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
interface flegs {
|
||||||
|
flags flag1 {
|
||||||
|
b0,
|
||||||
|
}
|
||||||
|
|
||||||
|
flags flag2 {
|
||||||
|
b0, b1,
|
||||||
|
}
|
||||||
|
|
||||||
|
flags flag4 {
|
||||||
|
b0, b1, b2, b3,
|
||||||
|
}
|
||||||
|
|
||||||
|
flags flag8 {
|
||||||
|
b0, b1, b2, b3, b4, b5, b6, b7,
|
||||||
|
}
|
||||||
|
|
||||||
|
flags flag16 {
|
||||||
|
b0, b1, b2, b3, b4, b5, b6, b7,
|
||||||
|
b8, b9, b10, b11, b12, b13, b14, b15,
|
||||||
|
}
|
||||||
|
|
||||||
|
flags flag32 {
|
||||||
|
b0, b1, b2, b3, b4, b5, b6, b7,
|
||||||
|
b8, b9, b10, b11, b12, b13, b14, b15,
|
||||||
|
b16, b17, b18, b19, b20, b21, b22, b23,
|
||||||
|
b24, b25, b26, b27, b28, b29, b30, b31,
|
||||||
|
}
|
||||||
|
|
||||||
|
flags flag64 {
|
||||||
|
b0, b1, b2, b3, b4, b5, b6, b7,
|
||||||
|
b8, b9, b10, b11, b12, b13, b14, b15,
|
||||||
|
b16, b17, b18, b19, b20, b21, b22, b23,
|
||||||
|
b24, b25, b26, b27, b28, b29, b30, b31,
|
||||||
|
b32, b33, b34, b35, b36, b37, b38, b39,
|
||||||
|
b40, b41, b42, b43, b44, b45, b46, b47,
|
||||||
|
b48, b49, b50, b51, b52, b53, b54, b55,
|
||||||
|
b56, b57, b58, b59, b60, b61, b62, b63,
|
||||||
|
}
|
||||||
|
|
||||||
|
roundtrip-flag1: func(x: flag1) -> flag1
|
||||||
|
roundtrip-flag2: func(x: flag2) -> flag2
|
||||||
|
roundtrip-flag4: func(x: flag4) -> flag4
|
||||||
|
roundtrip-flag8: func(x: flag8) -> flag8
|
||||||
|
roundtrip-flag16: func(x: flag16) -> flag16
|
||||||
|
roundtrip-flag32: func(x: flag32) -> flag32
|
||||||
|
roundtrip-flag64: func(x: flag64) -> flag64
|
||||||
|
}
|
||||||
|
|
||||||
|
world the-flags {
|
||||||
|
import import-flags: flegs
|
||||||
|
export export-flags: flegs
|
||||||
|
default export flegs
|
||||||
|
}
|
||||||
12
crates/component-macro/tests/codegen/floats.wit
Normal file
12
crates/component-macro/tests/codegen/floats.wit
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
interface floats {
|
||||||
|
float32-param: func(x: float32)
|
||||||
|
float64-param: func(x: float64)
|
||||||
|
float32-result: func() -> float32
|
||||||
|
float64-result: func() -> float64
|
||||||
|
}
|
||||||
|
|
||||||
|
world the-world {
|
||||||
|
import imports: floats
|
||||||
|
export exports: floats
|
||||||
|
default export floats
|
||||||
|
}
|
||||||
39
crates/component-macro/tests/codegen/integers.wit
Normal file
39
crates/component-macro/tests/codegen/integers.wit
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
interface integers {
|
||||||
|
a1: func(x: u8)
|
||||||
|
a2: func(x: s8)
|
||||||
|
a3: func(x: u16)
|
||||||
|
a4: func(x: s16)
|
||||||
|
a5: func(x: u32)
|
||||||
|
a6: func(x: s32)
|
||||||
|
a7: func(x: u64)
|
||||||
|
a8: func(x: s64)
|
||||||
|
|
||||||
|
a9: func(
|
||||||
|
p1: u8,
|
||||||
|
p2: s8,
|
||||||
|
p3: u16,
|
||||||
|
p4: s16,
|
||||||
|
p5: u32,
|
||||||
|
p6: s32,
|
||||||
|
p7: u64,
|
||||||
|
p8: s64,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
r1: func() -> u8
|
||||||
|
r2: func() -> s8
|
||||||
|
r3: func() -> u16
|
||||||
|
r4: func() -> s16
|
||||||
|
r5: func() -> u32
|
||||||
|
r6: func() -> s32
|
||||||
|
r7: func() -> u64
|
||||||
|
r8: func() -> s64
|
||||||
|
|
||||||
|
pair-ret: func() -> tuple<s64, u8>
|
||||||
|
}
|
||||||
|
|
||||||
|
world the-world {
|
||||||
|
import imports: integers
|
||||||
|
export exports: integers
|
||||||
|
default export integers
|
||||||
|
}
|
||||||
84
crates/component-macro/tests/codegen/lists.wit
Normal file
84
crates/component-macro/tests/codegen/lists.wit
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
interface lists {
|
||||||
|
list-u8-param: func(x: list<u8>)
|
||||||
|
list-u16-param: func(x: list<u16>)
|
||||||
|
list-u32-param: func(x: list<u32>)
|
||||||
|
list-u64-param: func(x: list<u64>)
|
||||||
|
list-s8-param: func(x: list<s8>)
|
||||||
|
list-s16-param: func(x: list<s16>)
|
||||||
|
list-s32-param: func(x: list<s32>)
|
||||||
|
list-s64-param: func(x: list<s64>)
|
||||||
|
list-float32-param: func(x: list<float32>)
|
||||||
|
list-float64-param: func(x: list<float64>)
|
||||||
|
|
||||||
|
list-u8-ret: func() -> list<u8>
|
||||||
|
list-u16-ret: func() -> list<u16>
|
||||||
|
list-u32-ret: func() -> list<u32>
|
||||||
|
list-u64-ret: func() -> list<u64>
|
||||||
|
list-s8-ret: func() -> list<s8>
|
||||||
|
list-s16-ret: func() -> list<s16>
|
||||||
|
list-s32-ret: func() -> list<s32>
|
||||||
|
list-s64-ret: func() -> list<s64>
|
||||||
|
list-float32-ret: func() -> list<float32>
|
||||||
|
list-float64-ret: func() -> list<float64>
|
||||||
|
|
||||||
|
tuple-list: func(x: list<tuple<u8, s8>>) -> list<tuple<s64, u32>>
|
||||||
|
string-list-arg: func(a: list<string>)
|
||||||
|
string-list-ret: func() -> list<string>
|
||||||
|
tuple-string-list: func(x: list<tuple<u8, string>>) -> list<tuple<string, u8>>
|
||||||
|
string-list: func(x: list<string>) -> list<string>
|
||||||
|
|
||||||
|
record some-record {
|
||||||
|
x: string,
|
||||||
|
y: other-record,
|
||||||
|
z: list<other-record>,
|
||||||
|
c1: u32,
|
||||||
|
c2: u64,
|
||||||
|
c3: s32,
|
||||||
|
c4: s64,
|
||||||
|
}
|
||||||
|
record other-record {
|
||||||
|
a1: u32,
|
||||||
|
a2: u64,
|
||||||
|
a3: s32,
|
||||||
|
a4: s64,
|
||||||
|
b: string,
|
||||||
|
c: list<u8>,
|
||||||
|
}
|
||||||
|
record-list: func(x: list<some-record>) -> list<other-record>
|
||||||
|
record-list-reverse: func(x: list<other-record>) -> list<some-record>
|
||||||
|
|
||||||
|
variant some-variant {
|
||||||
|
a(string),
|
||||||
|
b,
|
||||||
|
c(u32),
|
||||||
|
d(list<other-variant>),
|
||||||
|
}
|
||||||
|
variant other-variant {
|
||||||
|
a,
|
||||||
|
b(u32),
|
||||||
|
c(string),
|
||||||
|
}
|
||||||
|
variant-list: func(x: list<some-variant>) -> list<other-variant>
|
||||||
|
|
||||||
|
type load-store-all-sizes = list<tuple<
|
||||||
|
string,
|
||||||
|
u8,
|
||||||
|
s8,
|
||||||
|
u16,
|
||||||
|
s16,
|
||||||
|
u32,
|
||||||
|
s32,
|
||||||
|
u64,
|
||||||
|
s64,
|
||||||
|
float32,
|
||||||
|
float64,
|
||||||
|
char,
|
||||||
|
>>
|
||||||
|
load-store-everything: func(a: load-store-all-sizes) -> load-store-all-sizes
|
||||||
|
}
|
||||||
|
|
||||||
|
world the-lists {
|
||||||
|
import import-lists: lists
|
||||||
|
export export-lists: lists
|
||||||
|
default export lists
|
||||||
|
}
|
||||||
51
crates/component-macro/tests/codegen/many-arguments.wit
Normal file
51
crates/component-macro/tests/codegen/many-arguments.wit
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
interface manyarg {
|
||||||
|
many-args: func(
|
||||||
|
a1: u64,
|
||||||
|
a2: u64,
|
||||||
|
a3: u64,
|
||||||
|
a4: u64,
|
||||||
|
a5: u64,
|
||||||
|
a6: u64,
|
||||||
|
a7: u64,
|
||||||
|
a8: u64,
|
||||||
|
a9: u64,
|
||||||
|
a10: u64,
|
||||||
|
a11: u64,
|
||||||
|
a12: u64,
|
||||||
|
a13: u64,
|
||||||
|
a14: u64,
|
||||||
|
a15: u64,
|
||||||
|
a16: u64,
|
||||||
|
)
|
||||||
|
|
||||||
|
record big-struct {
|
||||||
|
a1: string,
|
||||||
|
a2: string,
|
||||||
|
a3: string,
|
||||||
|
a4: string,
|
||||||
|
a5: string,
|
||||||
|
a6: string,
|
||||||
|
a7: string,
|
||||||
|
a8: string,
|
||||||
|
a9: string,
|
||||||
|
a10: string,
|
||||||
|
a11: string,
|
||||||
|
a12: string,
|
||||||
|
a13: string,
|
||||||
|
a14: string,
|
||||||
|
a15: string,
|
||||||
|
a16: string,
|
||||||
|
a17: string,
|
||||||
|
a18: string,
|
||||||
|
a19: string,
|
||||||
|
a20: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
big-argument: func(x: big-struct)
|
||||||
|
}
|
||||||
|
|
||||||
|
world the-world {
|
||||||
|
import imports: manyarg
|
||||||
|
export exports: manyarg
|
||||||
|
default export manyarg
|
||||||
|
}
|
||||||
13
crates/component-macro/tests/codegen/multi-return.wit
Normal file
13
crates/component-macro/tests/codegen/multi-return.wit
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
interface multi-return {
|
||||||
|
mra: func()
|
||||||
|
mrb: func() -> ()
|
||||||
|
mrc: func() -> u32
|
||||||
|
mrd: func() -> (a: u32)
|
||||||
|
mre: func() -> (a: u32, b: float32)
|
||||||
|
}
|
||||||
|
|
||||||
|
world the-world {
|
||||||
|
import imports: multi-return
|
||||||
|
export exports: multi-return
|
||||||
|
default export multi-return
|
||||||
|
}
|
||||||
60
crates/component-macro/tests/codegen/records.wit
Normal file
60
crates/component-macro/tests/codegen/records.wit
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
interface records {
|
||||||
|
tuple-arg: func(x: tuple<char, u32>)
|
||||||
|
tuple-result: func() -> tuple<char, u32>
|
||||||
|
|
||||||
|
record empty {}
|
||||||
|
|
||||||
|
empty-arg: func(x: empty)
|
||||||
|
empty-result: func() -> empty
|
||||||
|
|
||||||
|
/// A record containing two scalar fields
|
||||||
|
/// that both have the same type
|
||||||
|
record scalars {
|
||||||
|
/// The first field, named a
|
||||||
|
a: u32,
|
||||||
|
/// The second field, named b
|
||||||
|
b: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
scalar-arg: func(x: scalars)
|
||||||
|
scalar-result: func() -> scalars
|
||||||
|
|
||||||
|
/// A record that is really just flags
|
||||||
|
/// All of the fields are bool
|
||||||
|
record really-flags {
|
||||||
|
a: bool,
|
||||||
|
b: bool,
|
||||||
|
c: bool,
|
||||||
|
d: bool,
|
||||||
|
e: bool,
|
||||||
|
f: bool,
|
||||||
|
g: bool,
|
||||||
|
h: bool,
|
||||||
|
i: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
flags-arg: func(x: really-flags)
|
||||||
|
flags-result: func() -> really-flags
|
||||||
|
|
||||||
|
record aggregates {
|
||||||
|
a: scalars,
|
||||||
|
b: u32,
|
||||||
|
c: empty,
|
||||||
|
d: string,
|
||||||
|
e: really-flags,
|
||||||
|
}
|
||||||
|
|
||||||
|
aggregate-arg: func(x: aggregates)
|
||||||
|
aggregate-result: func() -> aggregates
|
||||||
|
|
||||||
|
type tuple-typedef = tuple<s32>
|
||||||
|
type int-typedef = s32
|
||||||
|
type tuple-typedef2 = tuple<int-typedef>
|
||||||
|
typedef-inout: func(e: tuple-typedef2) -> s32
|
||||||
|
}
|
||||||
|
|
||||||
|
world the-world {
|
||||||
|
import imports: records
|
||||||
|
export exports: records
|
||||||
|
default export records
|
||||||
|
}
|
||||||
16
crates/component-macro/tests/codegen/simple-functions.wit
Normal file
16
crates/component-macro/tests/codegen/simple-functions.wit
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
interface simple {
|
||||||
|
f1: func()
|
||||||
|
f2: func(a: u32)
|
||||||
|
f3: func(a: u32, b: u32)
|
||||||
|
|
||||||
|
f4: func() -> u32
|
||||||
|
f5: func() -> tuple<u32, u32>
|
||||||
|
|
||||||
|
f6: func(a: u32, b: u32, c: u32) -> tuple<u32, u32, u32>
|
||||||
|
}
|
||||||
|
|
||||||
|
world the-world {
|
||||||
|
import imports: simple
|
||||||
|
export exports: simple
|
||||||
|
default export simple
|
||||||
|
}
|
||||||
13
crates/component-macro/tests/codegen/simple-lists.wit
Normal file
13
crates/component-macro/tests/codegen/simple-lists.wit
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
interface simple-lists {
|
||||||
|
simple-list1: func(l: list<u32>)
|
||||||
|
simple-list2: func() -> list<u32>
|
||||||
|
// TODO: reenable this when smw implements this
|
||||||
|
// simple-list3: func(a: list<u32>, b: list<u32>) -> tuple<list<u32>, list<u32>>
|
||||||
|
simple-list4: func(l: list<list<u32>>) -> list<list<u32>>
|
||||||
|
}
|
||||||
|
|
||||||
|
world my-world {
|
||||||
|
import imports: simple-lists
|
||||||
|
export exports: simple-lists
|
||||||
|
default export simple-lists
|
||||||
|
}
|
||||||
14
crates/component-macro/tests/codegen/small-anonymous.wit
Normal file
14
crates/component-macro/tests/codegen/small-anonymous.wit
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
interface anon {
|
||||||
|
enum error {
|
||||||
|
success,
|
||||||
|
failure,
|
||||||
|
}
|
||||||
|
|
||||||
|
option-test: func() -> result<option<string>, error>
|
||||||
|
}
|
||||||
|
|
||||||
|
world the-world {
|
||||||
|
import imports: anon
|
||||||
|
export exports: anon
|
||||||
|
default export anon
|
||||||
|
}
|
||||||
5
crates/component-macro/tests/codegen/smoke-default.wit
Normal file
5
crates/component-macro/tests/codegen/smoke-default.wit
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
world the-world {
|
||||||
|
default export interface {
|
||||||
|
y: func()
|
||||||
|
}
|
||||||
|
}
|
||||||
5
crates/component-macro/tests/codegen/smoke-export.wit
Normal file
5
crates/component-macro/tests/codegen/smoke-export.wit
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
world the-world {
|
||||||
|
export the-name: interface {
|
||||||
|
y: func()
|
||||||
|
}
|
||||||
|
}
|
||||||
5
crates/component-macro/tests/codegen/smoke.wit
Normal file
5
crates/component-macro/tests/codegen/smoke.wit
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
world the-world {
|
||||||
|
import imports: interface {
|
||||||
|
y: func()
|
||||||
|
}
|
||||||
|
}
|
||||||
11
crates/component-macro/tests/codegen/strings.wit
Normal file
11
crates/component-macro/tests/codegen/strings.wit
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
interface strings {
|
||||||
|
a: func(x: string)
|
||||||
|
b: func() -> string
|
||||||
|
c: func(a: string, b: string) -> string
|
||||||
|
}
|
||||||
|
|
||||||
|
world the-world {
|
||||||
|
import imports: strings
|
||||||
|
export exports: strings
|
||||||
|
default export strings
|
||||||
|
}
|
||||||
65
crates/component-macro/tests/codegen/unions.wit
Normal file
65
crates/component-macro/tests/codegen/unions.wit
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
interface unions {
|
||||||
|
/// A union of all of the integral types
|
||||||
|
union all-integers {
|
||||||
|
/// Bool is equivalent to a 1 bit integer
|
||||||
|
/// and is treated that way in some languages
|
||||||
|
bool,
|
||||||
|
u8, u16, u32, u64,
|
||||||
|
s8, s16, s32, s64
|
||||||
|
}
|
||||||
|
union all-floats {
|
||||||
|
float32, float64
|
||||||
|
}
|
||||||
|
union all-text {
|
||||||
|
char, string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the same case as the input but with 1 added
|
||||||
|
add-one-integer: func(num: all-integers) -> all-integers
|
||||||
|
// Returns the same case as the input but with 1 added
|
||||||
|
add-one-float: func(num: all-floats) -> all-floats
|
||||||
|
// Returns the same case as the input but with the first character replaced
|
||||||
|
replace-first-char: func(text: all-text, letter: char) -> all-text
|
||||||
|
|
||||||
|
// Returns the index of the case provided
|
||||||
|
identify-integer: func(num: all-integers) -> u8
|
||||||
|
// Returns the index of the case provided
|
||||||
|
identify-float: func(num: all-floats) -> u8
|
||||||
|
// Returns the index of the case provided
|
||||||
|
identify-text: func(text: all-text) -> u8
|
||||||
|
|
||||||
|
union duplicated-s32 {
|
||||||
|
/// The first s32
|
||||||
|
s32,
|
||||||
|
/// The second s32
|
||||||
|
s32,
|
||||||
|
/// The third s32
|
||||||
|
s32
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the same case as the input but with 1 added
|
||||||
|
add-one-duplicated: func(num: duplicated-s32) -> duplicated-s32
|
||||||
|
|
||||||
|
// Returns the index of the case provided
|
||||||
|
identify-duplicated: func(num: duplicated-s32) -> u8
|
||||||
|
|
||||||
|
/// A type containing numeric types that are distinct in most languages
|
||||||
|
union distinguishable-num {
|
||||||
|
/// A Floating Point Number
|
||||||
|
float64,
|
||||||
|
/// A Signed Integer
|
||||||
|
s64
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the same case as the input but with 1 added
|
||||||
|
add-one-distinguishable-num: func(num: distinguishable-num) -> distinguishable-num
|
||||||
|
|
||||||
|
// Returns the index of the case provided
|
||||||
|
identify-distinguishable-num: func(num: distinguishable-num) -> u8
|
||||||
|
}
|
||||||
|
|
||||||
|
world the-unions {
|
||||||
|
import import-unions: unions
|
||||||
|
export export-unions: unions
|
||||||
|
default export unions
|
||||||
|
}
|
||||||
146
crates/component-macro/tests/codegen/variants.wit
Normal file
146
crates/component-macro/tests/codegen/variants.wit
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
interface variants {
|
||||||
|
enum e1 {
|
||||||
|
a,
|
||||||
|
}
|
||||||
|
|
||||||
|
e1-arg: func(x: e1)
|
||||||
|
e1-result: func() -> e1
|
||||||
|
|
||||||
|
union u1 {
|
||||||
|
u32,
|
||||||
|
float32,
|
||||||
|
}
|
||||||
|
|
||||||
|
u1-arg: func(x: u1)
|
||||||
|
u1-result: func() -> u1
|
||||||
|
|
||||||
|
record empty {}
|
||||||
|
|
||||||
|
variant v1 {
|
||||||
|
a,
|
||||||
|
b(u1),
|
||||||
|
c(e1),
|
||||||
|
d(string),
|
||||||
|
e(empty),
|
||||||
|
f,
|
||||||
|
g(u32),
|
||||||
|
}
|
||||||
|
|
||||||
|
v1-arg: func(x: v1)
|
||||||
|
v1-result: func() -> v1
|
||||||
|
|
||||||
|
bool-arg: func(x: bool)
|
||||||
|
bool-result: func() -> bool
|
||||||
|
|
||||||
|
option-arg: func(
|
||||||
|
a: option<bool>,
|
||||||
|
b: option<tuple<>>,
|
||||||
|
c: option<u32>,
|
||||||
|
d: option<e1>,
|
||||||
|
e: option<float32>,
|
||||||
|
f: option<u1>,
|
||||||
|
g: option<option<bool>>,
|
||||||
|
)
|
||||||
|
option-result: func() -> tuple<
|
||||||
|
option<bool>,
|
||||||
|
option<tuple<>>,
|
||||||
|
option<u32>,
|
||||||
|
option<e1>,
|
||||||
|
option<float32>,
|
||||||
|
option<u1>,
|
||||||
|
option<option<bool>>,
|
||||||
|
>
|
||||||
|
|
||||||
|
variant casts1 {
|
||||||
|
a(s32),
|
||||||
|
b(float32),
|
||||||
|
}
|
||||||
|
|
||||||
|
variant casts2 {
|
||||||
|
a(float64),
|
||||||
|
b(float32),
|
||||||
|
}
|
||||||
|
|
||||||
|
variant casts3 {
|
||||||
|
a(float64),
|
||||||
|
b(u64),
|
||||||
|
}
|
||||||
|
|
||||||
|
variant casts4 {
|
||||||
|
a(u32),
|
||||||
|
b(s64),
|
||||||
|
}
|
||||||
|
|
||||||
|
variant casts5 {
|
||||||
|
a(float32),
|
||||||
|
b(s64),
|
||||||
|
}
|
||||||
|
|
||||||
|
variant casts6 {
|
||||||
|
a(tuple<float32, u32>),
|
||||||
|
b(tuple<u32, u32>),
|
||||||
|
}
|
||||||
|
|
||||||
|
casts: func(
|
||||||
|
a: casts1,
|
||||||
|
b: casts2,
|
||||||
|
c: casts3,
|
||||||
|
d: casts4,
|
||||||
|
e: casts5,
|
||||||
|
f: casts6,
|
||||||
|
) -> tuple<
|
||||||
|
casts1,
|
||||||
|
casts2,
|
||||||
|
casts3,
|
||||||
|
casts4,
|
||||||
|
casts5,
|
||||||
|
casts6,
|
||||||
|
>
|
||||||
|
|
||||||
|
result-arg: func(
|
||||||
|
a: result,
|
||||||
|
b: result<_, e1>,
|
||||||
|
c: result<e1>,
|
||||||
|
d: result<tuple<>, tuple<>>,
|
||||||
|
e: result<u32, v1>,
|
||||||
|
f: result<string, list<u8>>,
|
||||||
|
)
|
||||||
|
result-result: func() -> tuple<
|
||||||
|
result,
|
||||||
|
result<_, e1>,
|
||||||
|
result<e1>,
|
||||||
|
result<tuple<>, tuple<>>,
|
||||||
|
result<u32, v1>,
|
||||||
|
result<string, list<u8>>,
|
||||||
|
>
|
||||||
|
|
||||||
|
enum my-errno {
|
||||||
|
bad1,
|
||||||
|
bad2,
|
||||||
|
}
|
||||||
|
|
||||||
|
return-result-sugar: func() -> result<s32, my-errno>
|
||||||
|
return-result-sugar2: func() -> result<_, my-errno>
|
||||||
|
return-result-sugar3: func() -> result<my-errno, my-errno>
|
||||||
|
return-result-sugar4: func() -> result<tuple<s32, u32>, my-errno>
|
||||||
|
return-option-sugar: func() -> option<s32>
|
||||||
|
return-option-sugar2: func() -> option<my-errno>
|
||||||
|
|
||||||
|
result-simple: func() -> result<u32, s32>
|
||||||
|
|
||||||
|
record is-clone {
|
||||||
|
v1: v1,
|
||||||
|
}
|
||||||
|
|
||||||
|
is-clone-arg: func(a: is-clone)
|
||||||
|
is-clone-return: func() -> is-clone
|
||||||
|
|
||||||
|
return-named-option: func() -> (a: option<u8>)
|
||||||
|
return-named-result: func() -> (a: result<u8, my-errno>)
|
||||||
|
}
|
||||||
|
|
||||||
|
world my-world {
|
||||||
|
import imports: variants
|
||||||
|
export exports: variants
|
||||||
|
default export variants
|
||||||
|
}
|
||||||
@@ -88,7 +88,12 @@ cache = ["dep:wasmtime-cache"]
|
|||||||
|
|
||||||
# Enables support for "async stores" as well as defining host functions as
|
# Enables support for "async stores" as well as defining host functions as
|
||||||
# `async fn` and calling functions asynchronously.
|
# `async fn` and calling functions asynchronously.
|
||||||
async = ["dep:wasmtime-fiber", "wasmtime-runtime/async", "dep:async-trait"]
|
async = [
|
||||||
|
"dep:wasmtime-fiber",
|
||||||
|
"wasmtime-runtime/async",
|
||||||
|
"dep:async-trait",
|
||||||
|
"wasmtime-component-macro?/async",
|
||||||
|
]
|
||||||
|
|
||||||
# Enables support for the pooling instance allocation strategy
|
# Enables support for the pooling instance allocation strategy
|
||||||
pooling-allocator = ["wasmtime-runtime/pooling-allocator"]
|
pooling-allocator = ["wasmtime-runtime/pooling-allocator"]
|
||||||
|
|||||||
126
crates/wasmtime/src/component/error.rs
Normal file
126
crates/wasmtime/src/component/error.rs
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
/// Type alias for the standard library [`Result`](std::result::Result) type
|
||||||
|
/// to specifie [`Error`] as the error payload.
|
||||||
|
pub type Result<A, E> = std::result::Result<A, Error<E>>;
|
||||||
|
|
||||||
|
/// Error type used by the [`bindgen!`](crate::component::bindgen) macro.
|
||||||
|
///
|
||||||
|
/// This error type represents either the typed error `T` specified here or a
|
||||||
|
/// trap, represented with [`anyhow::Error`].
|
||||||
|
pub struct Error<T> {
|
||||||
|
err: anyhow::Error,
|
||||||
|
ty: std::marker::PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Error<T> {
|
||||||
|
/// Creates a new typed version of this error from the `T` specified.
|
||||||
|
///
|
||||||
|
/// This error, if it makes its way to the guest, will be returned to the
|
||||||
|
/// guest and the guest will be able to act upon it.
|
||||||
|
///
|
||||||
|
/// Alternatively errors can be created with [`Error::trap`] which will
|
||||||
|
/// cause the guest to trap and be unable to act upon it.
|
||||||
|
pub fn new(err: T) -> Error<T>
|
||||||
|
where
|
||||||
|
T: std::error::Error + Send + Sync + 'static,
|
||||||
|
{
|
||||||
|
Error {
|
||||||
|
err: err.into(),
|
||||||
|
ty: std::marker::PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a custom "trap" which will abort guest execution and have the
|
||||||
|
/// specified `err` as the payload context returned from the original
|
||||||
|
/// invocation.
|
||||||
|
///
|
||||||
|
/// Note that if `err` here actually has type `T` then the error will not be
|
||||||
|
/// considered a trap and will instead be dynamically detected as a normal
|
||||||
|
/// error to communicate to the original module.
|
||||||
|
pub fn trap(err: impl std::error::Error + Send + Sync + 'static) -> Error<T> {
|
||||||
|
Error {
|
||||||
|
err: anyhow::Error::from(err),
|
||||||
|
ty: std::marker::PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Attempts to dynamically downcast this error internally to the `T`
|
||||||
|
/// representation.
|
||||||
|
///
|
||||||
|
/// If this error is internally represented as a `T` then `Ok(val)` will be
|
||||||
|
/// returned. If this error is instead represented as a trap then
|
||||||
|
/// `Err(trap)` will be returned instead.
|
||||||
|
pub fn downcast(self) -> anyhow::Result<T>
|
||||||
|
where
|
||||||
|
T: std::error::Error + Send + Sync + 'static,
|
||||||
|
{
|
||||||
|
self.err.downcast::<T>()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Attempts to dynamically downcast this error to peek at the inner
|
||||||
|
/// contents of `T` if present.
|
||||||
|
pub fn downcast_ref(&self) -> Option<&T>
|
||||||
|
where
|
||||||
|
T: std::error::Error + Send + Sync + 'static,
|
||||||
|
{
|
||||||
|
self.err.downcast_ref::<T>()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Attempts to dynamically downcast this error to peek at the inner
|
||||||
|
/// contents of `T` if present.
|
||||||
|
pub fn downcast_mut(&mut self) -> Option<&mut T>
|
||||||
|
where
|
||||||
|
T: std::error::Error + Send + Sync + 'static,
|
||||||
|
{
|
||||||
|
self.err.downcast_mut::<T>()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts this error into an `anyhow::Error` which loses the `T` type
|
||||||
|
/// information tagged to this error.
|
||||||
|
pub fn into_inner(self) -> anyhow::Error {
|
||||||
|
self.err
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Same as [`anyhow::Error::context`], attaches a contextual message to
|
||||||
|
/// this error.
|
||||||
|
pub fn context<C>(self, context: C) -> Error<T>
|
||||||
|
where
|
||||||
|
C: std::fmt::Display + Send + Sync + 'static,
|
||||||
|
{
|
||||||
|
self.err.context(context).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> std::ops::Deref for Error<T> {
|
||||||
|
type Target = dyn std::error::Error + Send + Sync + 'static;
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
self.err.deref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T> std::ops::DerefMut for Error<T> {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
self.err.deref_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> std::fmt::Display for Error<T> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
self.err.fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> std::fmt::Debug for Error<T> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
self.err.fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> std::error::Error for Error<T> {}
|
||||||
|
|
||||||
|
impl<T> From<anyhow::Error> for Error<T> {
|
||||||
|
fn from(err: anyhow::Error) -> Error<T> {
|
||||||
|
Error {
|
||||||
|
err,
|
||||||
|
ty: std::marker::PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
//! probably buggy implementation of the component model.
|
//! probably buggy implementation of the component model.
|
||||||
|
|
||||||
mod component;
|
mod component;
|
||||||
|
mod error;
|
||||||
mod func;
|
mod func;
|
||||||
mod instance;
|
mod instance;
|
||||||
mod linker;
|
mod linker;
|
||||||
@@ -13,6 +14,7 @@ mod store;
|
|||||||
pub mod types;
|
pub mod types;
|
||||||
mod values;
|
mod values;
|
||||||
pub use self::component::Component;
|
pub use self::component::Component;
|
||||||
|
pub use self::error::{Error, Result};
|
||||||
pub use self::func::{
|
pub use self::func::{
|
||||||
ComponentNamedList, ComponentType, Func, Lift, Lower, TypedFunc, WasmList, WasmStr,
|
ComponentNamedList, ComponentType, Func, Lift, Lower, TypedFunc, WasmList, WasmStr,
|
||||||
};
|
};
|
||||||
@@ -20,7 +22,7 @@ pub use self::instance::{ExportInstance, Exports, Instance, InstancePre};
|
|||||||
pub use self::linker::{Linker, LinkerInstance};
|
pub use self::linker::{Linker, LinkerInstance};
|
||||||
pub use self::types::Type;
|
pub use self::types::Type;
|
||||||
pub use self::values::Val;
|
pub use self::values::Val;
|
||||||
pub use wasmtime_component_macro::{flags, ComponentType, Lift, Lower};
|
pub use wasmtime_component_macro::{bindgen, flags, ComponentType, Lift, Lower};
|
||||||
|
|
||||||
// These items are expected to be used by an eventual
|
// These items are expected to be used by an eventual
|
||||||
// `#[derive(ComponentType)]`, they are not part of Wasmtime's API stability
|
// `#[derive(ComponentType)]`, they are not part of Wasmtime's API stability
|
||||||
@@ -35,6 +37,8 @@ pub mod __internal {
|
|||||||
pub use crate::map_maybe_uninit;
|
pub use crate::map_maybe_uninit;
|
||||||
pub use crate::store::StoreOpaque;
|
pub use crate::store::StoreOpaque;
|
||||||
pub use anyhow;
|
pub use anyhow;
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
pub use async_trait::async_trait;
|
||||||
pub use wasmtime_environ;
|
pub use wasmtime_environ;
|
||||||
pub use wasmtime_environ::component::{CanonicalAbiInfo, ComponentTypes, InterfaceType};
|
pub use wasmtime_environ::component::{CanonicalAbiInfo, ComponentTypes, InterfaceType};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ include = ["src/**/*", "README.md", "LICENSE"]
|
|||||||
witx = { version = "0.9.1", path = "../../wasi-common/WASI/tools/witx" }
|
witx = { version = "0.9.1", path = "../../wasi-common/WASI/tools/witx" }
|
||||||
quote = "1.0"
|
quote = "1.0"
|
||||||
proc-macro2 = "1.0"
|
proc-macro2 = "1.0"
|
||||||
heck = "0.4"
|
heck = { workspace = true }
|
||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true }
|
||||||
syn = { version = "1.0", features = ["full"] }
|
syn = { version = "1.0", features = ["full"] }
|
||||||
shellexpand = "2.0"
|
shellexpand = "2.0"
|
||||||
|
|||||||
13
crates/wit-bindgen/Cargo.toml
Normal file
13
crates/wit-bindgen/Cargo.toml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
[package]
|
||||||
|
name = "wasmtime-wit-bindgen"
|
||||||
|
version.workspace = true
|
||||||
|
authors.workspace = true
|
||||||
|
description = "Internal `*.wit` support for the `wasmtime` crate's macros"
|
||||||
|
license = "Apache-2.0 WITH LLVM-exception"
|
||||||
|
repository = "https://github.com/bytecodealliance/wasmtime"
|
||||||
|
documentation = "https://docs.rs/wasmtime-wit-bindgen/"
|
||||||
|
edition.workspace = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
heck = { workspace = true }
|
||||||
|
wit-parser = { workspace = true }
|
||||||
1143
crates/wit-bindgen/src/lib.rs
Normal file
1143
crates/wit-bindgen/src/lib.rs
Normal file
File diff suppressed because it is too large
Load Diff
412
crates/wit-bindgen/src/rust.rs
Normal file
412
crates/wit-bindgen/src/rust.rs
Normal file
@@ -0,0 +1,412 @@
|
|||||||
|
use crate::types::TypeInfo;
|
||||||
|
use heck::*;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::fmt::Write;
|
||||||
|
use wit_parser::*;
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
|
pub enum TypeMode {
|
||||||
|
Owned,
|
||||||
|
AllBorrowed(&'static str),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait RustGenerator<'a> {
|
||||||
|
fn iface(&self) -> &'a Interface;
|
||||||
|
|
||||||
|
fn push_str(&mut self, s: &str);
|
||||||
|
fn info(&self, ty: TypeId) -> TypeInfo;
|
||||||
|
fn default_param_mode(&self) -> TypeMode;
|
||||||
|
|
||||||
|
fn print_ty(&mut self, ty: &Type, mode: TypeMode) {
|
||||||
|
match ty {
|
||||||
|
Type::Id(t) => self.print_tyid(*t, mode),
|
||||||
|
Type::Bool => self.push_str("bool"),
|
||||||
|
Type::U8 => self.push_str("u8"),
|
||||||
|
Type::U16 => self.push_str("u16"),
|
||||||
|
Type::U32 => self.push_str("u32"),
|
||||||
|
Type::U64 => self.push_str("u64"),
|
||||||
|
Type::S8 => self.push_str("i8"),
|
||||||
|
Type::S16 => self.push_str("i16"),
|
||||||
|
Type::S32 => self.push_str("i32"),
|
||||||
|
Type::S64 => self.push_str("i64"),
|
||||||
|
Type::Float32 => self.push_str("f32"),
|
||||||
|
Type::Float64 => self.push_str("f64"),
|
||||||
|
Type::Char => self.push_str("char"),
|
||||||
|
Type::String => match mode {
|
||||||
|
TypeMode::AllBorrowed(lt) => {
|
||||||
|
self.push_str("&");
|
||||||
|
if lt != "'_" {
|
||||||
|
self.push_str(lt);
|
||||||
|
self.push_str(" ");
|
||||||
|
}
|
||||||
|
self.push_str("str");
|
||||||
|
}
|
||||||
|
TypeMode::Owned => self.push_str("String"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_optional_ty(&mut self, ty: Option<&Type>, mode: TypeMode) {
|
||||||
|
match ty {
|
||||||
|
Some(ty) => self.print_ty(ty, mode),
|
||||||
|
None => self.push_str("()"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_tyid(&mut self, id: TypeId, mode: TypeMode) {
|
||||||
|
let info = self.info(id);
|
||||||
|
let lt = self.lifetime_for(&info, mode);
|
||||||
|
let ty = &self.iface().types[id];
|
||||||
|
if ty.name.is_some() {
|
||||||
|
let name = if lt.is_some() {
|
||||||
|
self.param_name(id)
|
||||||
|
} else {
|
||||||
|
self.result_name(id)
|
||||||
|
};
|
||||||
|
self.push_str(&name);
|
||||||
|
|
||||||
|
// If the type recursively owns data and it's a
|
||||||
|
// variant/record/list, then we need to place the
|
||||||
|
// lifetime parameter on the type as well.
|
||||||
|
if info.has_list && needs_generics(self.iface(), &ty.kind) {
|
||||||
|
self.print_generics(lt);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
fn needs_generics(iface: &Interface, ty: &TypeDefKind) -> bool {
|
||||||
|
match ty {
|
||||||
|
TypeDefKind::Variant(_)
|
||||||
|
| TypeDefKind::Record(_)
|
||||||
|
| TypeDefKind::Option(_)
|
||||||
|
| TypeDefKind::Result(_)
|
||||||
|
| TypeDefKind::Future(_)
|
||||||
|
| TypeDefKind::Stream(_)
|
||||||
|
| TypeDefKind::List(_)
|
||||||
|
| TypeDefKind::Flags(_)
|
||||||
|
| TypeDefKind::Enum(_)
|
||||||
|
| TypeDefKind::Tuple(_)
|
||||||
|
| TypeDefKind::Union(_) => true,
|
||||||
|
TypeDefKind::Type(Type::Id(t)) => needs_generics(iface, &iface.types[*t].kind),
|
||||||
|
TypeDefKind::Type(Type::String) => true,
|
||||||
|
TypeDefKind::Type(_) => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match &ty.kind {
|
||||||
|
TypeDefKind::List(t) => self.print_list(t, mode),
|
||||||
|
|
||||||
|
TypeDefKind::Option(t) => {
|
||||||
|
self.push_str("Option<");
|
||||||
|
self.print_ty(t, mode);
|
||||||
|
self.push_str(">");
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeDefKind::Result(r) => {
|
||||||
|
self.push_str("Result<");
|
||||||
|
self.print_optional_ty(r.ok.as_ref(), mode);
|
||||||
|
self.push_str(",");
|
||||||
|
self.print_optional_ty(r.err.as_ref(), mode);
|
||||||
|
self.push_str(">");
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeDefKind::Variant(_) => panic!("unsupported anonymous variant"),
|
||||||
|
|
||||||
|
// Tuple-like records are mapped directly to Rust tuples of
|
||||||
|
// types. Note the trailing comma after each member to
|
||||||
|
// appropriately handle 1-tuples.
|
||||||
|
TypeDefKind::Tuple(t) => {
|
||||||
|
self.push_str("(");
|
||||||
|
for ty in t.types.iter() {
|
||||||
|
self.print_ty(ty, mode);
|
||||||
|
self.push_str(",");
|
||||||
|
}
|
||||||
|
self.push_str(")");
|
||||||
|
}
|
||||||
|
TypeDefKind::Record(_) => {
|
||||||
|
panic!("unsupported anonymous type reference: record")
|
||||||
|
}
|
||||||
|
TypeDefKind::Flags(_) => {
|
||||||
|
panic!("unsupported anonymous type reference: flags")
|
||||||
|
}
|
||||||
|
TypeDefKind::Enum(_) => {
|
||||||
|
panic!("unsupported anonymous type reference: enum")
|
||||||
|
}
|
||||||
|
TypeDefKind::Union(_) => {
|
||||||
|
panic!("unsupported anonymous type reference: union")
|
||||||
|
}
|
||||||
|
TypeDefKind::Future(ty) => {
|
||||||
|
self.push_str("Future<");
|
||||||
|
self.print_optional_ty(ty.as_ref(), mode);
|
||||||
|
self.push_str(">");
|
||||||
|
}
|
||||||
|
TypeDefKind::Stream(stream) => {
|
||||||
|
self.push_str("Stream<");
|
||||||
|
self.print_optional_ty(stream.element.as_ref(), mode);
|
||||||
|
self.push_str(",");
|
||||||
|
self.print_optional_ty(stream.end.as_ref(), mode);
|
||||||
|
self.push_str(">");
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeDefKind::Type(t) => self.print_ty(t, mode),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_list(&mut self, ty: &Type, mode: TypeMode) {
|
||||||
|
match mode {
|
||||||
|
TypeMode::AllBorrowed(lt) => {
|
||||||
|
self.push_str("&");
|
||||||
|
if lt != "'_" {
|
||||||
|
self.push_str(lt);
|
||||||
|
self.push_str(" ");
|
||||||
|
}
|
||||||
|
self.push_str("[");
|
||||||
|
self.print_ty(ty, mode);
|
||||||
|
self.push_str("]");
|
||||||
|
}
|
||||||
|
TypeMode::Owned => {
|
||||||
|
self.push_str("Vec<");
|
||||||
|
self.print_ty(ty, mode);
|
||||||
|
self.push_str(">");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_generics(&mut self, lifetime: Option<&str>) {
|
||||||
|
if lifetime.is_none() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.push_str("<");
|
||||||
|
if let Some(lt) = lifetime {
|
||||||
|
self.push_str(lt);
|
||||||
|
self.push_str(",");
|
||||||
|
}
|
||||||
|
self.push_str(">");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn modes_of(&self, ty: TypeId) -> Vec<(String, TypeMode)> {
|
||||||
|
let info = self.info(ty);
|
||||||
|
let mut result = Vec::new();
|
||||||
|
if info.param {
|
||||||
|
result.push((self.param_name(ty), self.default_param_mode()));
|
||||||
|
}
|
||||||
|
if info.result && (!info.param || self.uses_two_names(&info)) {
|
||||||
|
result.push((self.result_name(ty), TypeMode::Owned));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Writes the camel-cased 'name' of the passed type to `out`, as used to name union variants.
|
||||||
|
fn write_name(&self, ty: &Type, out: &mut String) {
|
||||||
|
match ty {
|
||||||
|
Type::Bool => out.push_str("Bool"),
|
||||||
|
Type::U8 => out.push_str("U8"),
|
||||||
|
Type::U16 => out.push_str("U16"),
|
||||||
|
Type::U32 => out.push_str("U32"),
|
||||||
|
Type::U64 => out.push_str("U64"),
|
||||||
|
Type::S8 => out.push_str("I8"),
|
||||||
|
Type::S16 => out.push_str("I16"),
|
||||||
|
Type::S32 => out.push_str("I32"),
|
||||||
|
Type::S64 => out.push_str("I64"),
|
||||||
|
Type::Float32 => out.push_str("F32"),
|
||||||
|
Type::Float64 => out.push_str("F64"),
|
||||||
|
Type::Char => out.push_str("Char"),
|
||||||
|
Type::String => out.push_str("String"),
|
||||||
|
Type::Id(id) => {
|
||||||
|
let ty = &self.iface().types[*id];
|
||||||
|
match &ty.name {
|
||||||
|
Some(name) => out.push_str(&name.to_upper_camel_case()),
|
||||||
|
None => match &ty.kind {
|
||||||
|
TypeDefKind::Option(ty) => {
|
||||||
|
out.push_str("Optional");
|
||||||
|
self.write_name(ty, out);
|
||||||
|
}
|
||||||
|
TypeDefKind::Result(_) => out.push_str("Result"),
|
||||||
|
TypeDefKind::Tuple(_) => out.push_str("Tuple"),
|
||||||
|
TypeDefKind::List(ty) => {
|
||||||
|
self.write_name(ty, out);
|
||||||
|
out.push_str("List")
|
||||||
|
}
|
||||||
|
TypeDefKind::Future(ty) => {
|
||||||
|
self.write_optional_name(ty.as_ref(), out);
|
||||||
|
out.push_str("Future");
|
||||||
|
}
|
||||||
|
TypeDefKind::Stream(s) => {
|
||||||
|
self.write_optional_name(s.element.as_ref(), out);
|
||||||
|
self.write_optional_name(s.end.as_ref(), out);
|
||||||
|
out.push_str("Stream");
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeDefKind::Type(ty) => self.write_name(ty, out),
|
||||||
|
TypeDefKind::Record(_) => out.push_str("Record"),
|
||||||
|
TypeDefKind::Flags(_) => out.push_str("Flags"),
|
||||||
|
TypeDefKind::Variant(_) => out.push_str("Variant"),
|
||||||
|
TypeDefKind::Enum(_) => out.push_str("Enum"),
|
||||||
|
TypeDefKind::Union(_) => out.push_str("Union"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_optional_name(&self, ty: Option<&Type>, out: &mut String) {
|
||||||
|
match ty {
|
||||||
|
Some(ty) => self.write_name(ty, out),
|
||||||
|
None => out.push_str("()"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the names for the cases of the passed union.
|
||||||
|
fn union_case_names(&self, union: &Union) -> Vec<String> {
|
||||||
|
enum UsedState<'a> {
|
||||||
|
/// This name has been used once before.
|
||||||
|
///
|
||||||
|
/// Contains a reference to the name given to the first usage so that a suffix can be added to it.
|
||||||
|
Once(&'a mut String),
|
||||||
|
/// This name has already been used multiple times.
|
||||||
|
///
|
||||||
|
/// Contains the number of times this has already been used.
|
||||||
|
Multiple(usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
// A `Vec` of the names we're assigning each of the union's cases in order.
|
||||||
|
let mut case_names = vec![String::new(); union.cases.len()];
|
||||||
|
// A map from case names to their `UsedState`.
|
||||||
|
let mut used = HashMap::new();
|
||||||
|
for (case, name) in union.cases.iter().zip(case_names.iter_mut()) {
|
||||||
|
self.write_name(&case.ty, name);
|
||||||
|
|
||||||
|
match used.get_mut(name.as_str()) {
|
||||||
|
None => {
|
||||||
|
// Initialise this name's `UsedState`, with a mutable reference to this name
|
||||||
|
// in case we have to add a suffix to it later.
|
||||||
|
used.insert(name.clone(), UsedState::Once(name));
|
||||||
|
// Since this is the first (and potentially only) usage of this name,
|
||||||
|
// we don't need to add a suffix here.
|
||||||
|
}
|
||||||
|
Some(state) => match state {
|
||||||
|
UsedState::Multiple(n) => {
|
||||||
|
// Add a suffix of the index of this usage.
|
||||||
|
write!(name, "{n}").unwrap();
|
||||||
|
// Add one to the number of times this type has been used.
|
||||||
|
*n += 1;
|
||||||
|
}
|
||||||
|
UsedState::Once(first) => {
|
||||||
|
// Add a suffix of 0 to the first usage.
|
||||||
|
first.push('0');
|
||||||
|
// We now get a suffix of 1.
|
||||||
|
name.push('1');
|
||||||
|
// Then update the state.
|
||||||
|
*state = UsedState::Multiple(2);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case_names
|
||||||
|
}
|
||||||
|
|
||||||
|
fn param_name(&self, ty: TypeId) -> String {
|
||||||
|
let info = self.info(ty);
|
||||||
|
let name = self.iface().types[ty]
|
||||||
|
.name
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.to_upper_camel_case();
|
||||||
|
if self.uses_two_names(&info) {
|
||||||
|
format!("{}Param", name)
|
||||||
|
} else {
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn result_name(&self, ty: TypeId) -> String {
|
||||||
|
let info = self.info(ty);
|
||||||
|
let name = self.iface().types[ty]
|
||||||
|
.name
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.to_upper_camel_case();
|
||||||
|
if self.uses_two_names(&info) {
|
||||||
|
format!("{}Result", name)
|
||||||
|
} else {
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn uses_two_names(&self, info: &TypeInfo) -> bool {
|
||||||
|
info.has_list
|
||||||
|
&& info.param
|
||||||
|
&& info.result
|
||||||
|
&& match self.default_param_mode() {
|
||||||
|
TypeMode::AllBorrowed(_) => true,
|
||||||
|
TypeMode::Owned => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lifetime_for(&self, info: &TypeInfo, mode: TypeMode) -> Option<&'static str> {
|
||||||
|
match mode {
|
||||||
|
TypeMode::AllBorrowed(s) if info.has_list => Some(s),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_rust_ident(name: &str) -> String {
|
||||||
|
match name {
|
||||||
|
// Escape Rust keywords.
|
||||||
|
// Source: https://doc.rust-lang.org/reference/keywords.html
|
||||||
|
"as" => "as_".into(),
|
||||||
|
"break" => "break_".into(),
|
||||||
|
"const" => "const_".into(),
|
||||||
|
"continue" => "continue_".into(),
|
||||||
|
"crate" => "crate_".into(),
|
||||||
|
"else" => "else_".into(),
|
||||||
|
"enum" => "enum_".into(),
|
||||||
|
"extern" => "extern_".into(),
|
||||||
|
"false" => "false_".into(),
|
||||||
|
"fn" => "fn_".into(),
|
||||||
|
"for" => "for_".into(),
|
||||||
|
"if" => "if_".into(),
|
||||||
|
"impl" => "impl_".into(),
|
||||||
|
"in" => "in_".into(),
|
||||||
|
"let" => "let_".into(),
|
||||||
|
"loop" => "loop_".into(),
|
||||||
|
"match" => "match_".into(),
|
||||||
|
"mod" => "mod_".into(),
|
||||||
|
"move" => "move_".into(),
|
||||||
|
"mut" => "mut_".into(),
|
||||||
|
"pub" => "pub_".into(),
|
||||||
|
"ref" => "ref_".into(),
|
||||||
|
"return" => "return_".into(),
|
||||||
|
"self" => "self_".into(),
|
||||||
|
"static" => "static_".into(),
|
||||||
|
"struct" => "struct_".into(),
|
||||||
|
"super" => "super_".into(),
|
||||||
|
"trait" => "trait_".into(),
|
||||||
|
"true" => "true_".into(),
|
||||||
|
"type" => "type_".into(),
|
||||||
|
"unsafe" => "unsafe_".into(),
|
||||||
|
"use" => "use_".into(),
|
||||||
|
"where" => "where_".into(),
|
||||||
|
"while" => "while_".into(),
|
||||||
|
"async" => "async_".into(),
|
||||||
|
"await" => "await_".into(),
|
||||||
|
"dyn" => "dyn_".into(),
|
||||||
|
"abstract" => "abstract_".into(),
|
||||||
|
"become" => "become_".into(),
|
||||||
|
"box" => "box_".into(),
|
||||||
|
"do" => "do_".into(),
|
||||||
|
"final" => "final_".into(),
|
||||||
|
"macro" => "macro_".into(),
|
||||||
|
"override" => "override_".into(),
|
||||||
|
"priv" => "priv_".into(),
|
||||||
|
"typeof" => "typeof_".into(),
|
||||||
|
"unsized" => "unsized_".into(),
|
||||||
|
"virtual" => "virtual_".into(),
|
||||||
|
"yield" => "yield_".into(),
|
||||||
|
"try" => "try_".into(),
|
||||||
|
s => s.to_snake_case(),
|
||||||
|
}
|
||||||
|
}
|
||||||
130
crates/wit-bindgen/src/source.rs
Normal file
130
crates/wit-bindgen/src/source.rs
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
use std::fmt::{self, Write};
|
||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
|
/// Helper structure to maintain indentation automatically when printing.
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Source {
|
||||||
|
s: String,
|
||||||
|
indent: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Source {
|
||||||
|
pub fn push_str(&mut self, src: &str) {
|
||||||
|
let lines = src.lines().collect::<Vec<_>>();
|
||||||
|
for (i, line) in lines.iter().enumerate() {
|
||||||
|
let trimmed = line.trim();
|
||||||
|
if trimmed.starts_with('}') && self.s.ends_with(" ") {
|
||||||
|
self.s.pop();
|
||||||
|
self.s.pop();
|
||||||
|
}
|
||||||
|
self.s.push_str(if lines.len() == 1 {
|
||||||
|
line
|
||||||
|
} else {
|
||||||
|
line.trim_start()
|
||||||
|
});
|
||||||
|
if trimmed.ends_with('{') {
|
||||||
|
self.indent += 1;
|
||||||
|
}
|
||||||
|
if trimmed.starts_with('}') {
|
||||||
|
// Note that a `saturating_sub` is used here to prevent a panic
|
||||||
|
// here in the case of invalid code being generated in debug
|
||||||
|
// mode. It's typically easier to debug those issues through
|
||||||
|
// looking at the source code rather than getting a panic.
|
||||||
|
self.indent = self.indent.saturating_sub(1);
|
||||||
|
}
|
||||||
|
if i != lines.len() - 1 || src.ends_with('\n') {
|
||||||
|
self.newline();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn indent(&mut self, amt: usize) {
|
||||||
|
self.indent += amt;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deindent(&mut self, amt: usize) {
|
||||||
|
self.indent -= amt;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn newline(&mut self) {
|
||||||
|
self.s.push('\n');
|
||||||
|
for _ in 0..self.indent {
|
||||||
|
self.s.push_str(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_mut_string(&mut self) -> &mut String {
|
||||||
|
&mut self.s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Write for Source {
|
||||||
|
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||||
|
self.push_str(s);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for Source {
|
||||||
|
type Target = str;
|
||||||
|
fn deref(&self) -> &str {
|
||||||
|
&self.s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Source> for String {
|
||||||
|
fn from(s: Source) -> String {
|
||||||
|
s.s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::Source;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn simple_append() {
|
||||||
|
let mut s = Source::default();
|
||||||
|
s.push_str("x");
|
||||||
|
assert_eq!(s.s, "x");
|
||||||
|
s.push_str("y");
|
||||||
|
assert_eq!(s.s, "xy");
|
||||||
|
s.push_str("z ");
|
||||||
|
assert_eq!(s.s, "xyz ");
|
||||||
|
s.push_str(" a ");
|
||||||
|
assert_eq!(s.s, "xyz a ");
|
||||||
|
s.push_str("\na");
|
||||||
|
assert_eq!(s.s, "xyz a \na");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn newline_remap() {
|
||||||
|
let mut s = Source::default();
|
||||||
|
s.push_str("function() {\n");
|
||||||
|
s.push_str("y\n");
|
||||||
|
s.push_str("}\n");
|
||||||
|
assert_eq!(s.s, "function() {\n y\n}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn if_else() {
|
||||||
|
let mut s = Source::default();
|
||||||
|
s.push_str("if() {\n");
|
||||||
|
s.push_str("y\n");
|
||||||
|
s.push_str("} else if () {\n");
|
||||||
|
s.push_str("z\n");
|
||||||
|
s.push_str("}\n");
|
||||||
|
assert_eq!(s.s, "if() {\n y\n} else if () {\n z\n}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn trim_ws() {
|
||||||
|
let mut s = Source::default();
|
||||||
|
s.push_str(
|
||||||
|
"function() {
|
||||||
|
x
|
||||||
|
}",
|
||||||
|
);
|
||||||
|
assert_eq!(s.s, "function() {\n x\n}");
|
||||||
|
}
|
||||||
|
}
|
||||||
207
crates/wit-bindgen/src/types.rs
Normal file
207
crates/wit-bindgen/src/types.rs
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
use wit_parser::*;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Types {
|
||||||
|
type_info: HashMap<TypeId, TypeInfo>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Clone, Copy, Debug, PartialEq)]
|
||||||
|
pub struct TypeInfo {
|
||||||
|
/// Whether or not this type is ever used (transitively) within the
|
||||||
|
/// parameter of a function.
|
||||||
|
pub param: bool,
|
||||||
|
|
||||||
|
/// Whether or not this type is ever used (transitively) within the
|
||||||
|
/// result of a function.
|
||||||
|
pub result: bool,
|
||||||
|
|
||||||
|
/// Whether or not this type is ever used (transitively) within the
|
||||||
|
/// error case in the result of a function.
|
||||||
|
pub error: bool,
|
||||||
|
|
||||||
|
/// Whether or not this type (transitively) has a list.
|
||||||
|
pub has_list: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::BitOrAssign for TypeInfo {
|
||||||
|
fn bitor_assign(&mut self, rhs: Self) {
|
||||||
|
self.param |= rhs.param;
|
||||||
|
self.result |= rhs.result;
|
||||||
|
self.error |= rhs.error;
|
||||||
|
self.has_list |= rhs.has_list;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Types {
|
||||||
|
pub fn analyze(&mut self, iface: &Interface) {
|
||||||
|
for (t, _) in iface.types.iter() {
|
||||||
|
self.type_id_info(iface, t);
|
||||||
|
}
|
||||||
|
for f in iface.functions.iter() {
|
||||||
|
for (_, ty) in f.params.iter() {
|
||||||
|
self.set_param_result_ty(
|
||||||
|
iface,
|
||||||
|
ty,
|
||||||
|
TypeInfo {
|
||||||
|
param: true,
|
||||||
|
..TypeInfo::default()
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
for ty in f.results.iter_types() {
|
||||||
|
self.set_param_result_ty(
|
||||||
|
iface,
|
||||||
|
ty,
|
||||||
|
TypeInfo {
|
||||||
|
result: true,
|
||||||
|
..TypeInfo::default()
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(&self, id: TypeId) -> TypeInfo {
|
||||||
|
self.type_info[&id]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn type_id_info(&mut self, iface: &Interface, ty: TypeId) -> TypeInfo {
|
||||||
|
if let Some(info) = self.type_info.get(&ty) {
|
||||||
|
return *info;
|
||||||
|
}
|
||||||
|
let mut info = TypeInfo::default();
|
||||||
|
match &iface.types[ty].kind {
|
||||||
|
TypeDefKind::Record(r) => {
|
||||||
|
for field in r.fields.iter() {
|
||||||
|
info |= self.type_info(iface, &field.ty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TypeDefKind::Tuple(t) => {
|
||||||
|
for ty in t.types.iter() {
|
||||||
|
info |= self.type_info(iface, ty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TypeDefKind::Flags(_) => {}
|
||||||
|
TypeDefKind::Enum(_) => {}
|
||||||
|
TypeDefKind::Variant(v) => {
|
||||||
|
for case in v.cases.iter() {
|
||||||
|
info |= self.optional_type_info(iface, case.ty.as_ref());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TypeDefKind::List(ty) => {
|
||||||
|
info = self.type_info(iface, ty);
|
||||||
|
info.has_list = true;
|
||||||
|
}
|
||||||
|
TypeDefKind::Type(ty) => {
|
||||||
|
info = self.type_info(iface, ty);
|
||||||
|
}
|
||||||
|
TypeDefKind::Option(ty) => {
|
||||||
|
info = self.type_info(iface, ty);
|
||||||
|
}
|
||||||
|
TypeDefKind::Result(r) => {
|
||||||
|
info = self.optional_type_info(iface, r.ok.as_ref());
|
||||||
|
info |= self.optional_type_info(iface, r.err.as_ref());
|
||||||
|
}
|
||||||
|
TypeDefKind::Union(u) => {
|
||||||
|
for case in u.cases.iter() {
|
||||||
|
info |= self.type_info(iface, &case.ty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TypeDefKind::Future(ty) => {
|
||||||
|
info = self.optional_type_info(iface, ty.as_ref());
|
||||||
|
}
|
||||||
|
TypeDefKind::Stream(stream) => {
|
||||||
|
info = self.optional_type_info(iface, stream.element.as_ref());
|
||||||
|
info |= self.optional_type_info(iface, stream.end.as_ref());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.type_info.insert(ty, info);
|
||||||
|
info
|
||||||
|
}
|
||||||
|
|
||||||
|
fn type_info(&mut self, iface: &Interface, ty: &Type) -> TypeInfo {
|
||||||
|
let mut info = TypeInfo::default();
|
||||||
|
match ty {
|
||||||
|
Type::String => info.has_list = true,
|
||||||
|
Type::Id(id) => return self.type_id_info(iface, *id),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
info
|
||||||
|
}
|
||||||
|
|
||||||
|
fn optional_type_info(&mut self, iface: &Interface, ty: Option<&Type>) -> TypeInfo {
|
||||||
|
match ty {
|
||||||
|
Some(ty) => self.type_info(iface, ty),
|
||||||
|
None => TypeInfo::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_param_result_id(&mut self, iface: &Interface, ty: TypeId, info: TypeInfo) {
|
||||||
|
match &iface.types[ty].kind {
|
||||||
|
TypeDefKind::Record(r) => {
|
||||||
|
for field in r.fields.iter() {
|
||||||
|
self.set_param_result_ty(iface, &field.ty, info)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TypeDefKind::Tuple(t) => {
|
||||||
|
for ty in t.types.iter() {
|
||||||
|
self.set_param_result_ty(iface, ty, info)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TypeDefKind::Flags(_) => {}
|
||||||
|
TypeDefKind::Enum(_) => {}
|
||||||
|
TypeDefKind::Variant(v) => {
|
||||||
|
for case in v.cases.iter() {
|
||||||
|
self.set_param_result_optional_ty(iface, case.ty.as_ref(), info)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TypeDefKind::List(ty) | TypeDefKind::Type(ty) | TypeDefKind::Option(ty) => {
|
||||||
|
self.set_param_result_ty(iface, ty, info)
|
||||||
|
}
|
||||||
|
TypeDefKind::Result(r) => {
|
||||||
|
self.set_param_result_optional_ty(iface, r.ok.as_ref(), info);
|
||||||
|
let mut info2 = info;
|
||||||
|
info2.error = info.result;
|
||||||
|
self.set_param_result_optional_ty(iface, r.err.as_ref(), info2);
|
||||||
|
}
|
||||||
|
TypeDefKind::Union(u) => {
|
||||||
|
for case in u.cases.iter() {
|
||||||
|
self.set_param_result_ty(iface, &case.ty, info)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TypeDefKind::Future(ty) => self.set_param_result_optional_ty(iface, ty.as_ref(), info),
|
||||||
|
TypeDefKind::Stream(stream) => {
|
||||||
|
self.set_param_result_optional_ty(iface, stream.element.as_ref(), info);
|
||||||
|
self.set_param_result_optional_ty(iface, stream.end.as_ref(), info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_param_result_ty(&mut self, iface: &Interface, ty: &Type, info: TypeInfo) {
|
||||||
|
match ty {
|
||||||
|
Type::Id(id) => {
|
||||||
|
self.type_id_info(iface, *id);
|
||||||
|
let cur = self.type_info.get_mut(id).unwrap();
|
||||||
|
let prev = *cur;
|
||||||
|
*cur |= info;
|
||||||
|
if prev != *cur {
|
||||||
|
self.set_param_result_id(iface, *id, info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_param_result_optional_ty(
|
||||||
|
&mut self,
|
||||||
|
iface: &Interface,
|
||||||
|
ty: Option<&Type>,
|
||||||
|
info: TypeInfo,
|
||||||
|
) {
|
||||||
|
match ty {
|
||||||
|
Some(ty) => self.set_param_result_ty(iface, ty, info),
|
||||||
|
None => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -47,6 +47,7 @@ const CRATES_TO_PUBLISH: &[&str] = &[
|
|||||||
// wasmtime
|
// wasmtime
|
||||||
"wasmtime-asm-macros",
|
"wasmtime-asm-macros",
|
||||||
"wasmtime-component-util",
|
"wasmtime-component-util",
|
||||||
|
"wasmtime-wit-bindgen",
|
||||||
"wasmtime-component-macro",
|
"wasmtime-component-macro",
|
||||||
"wasmtime-jit-debug",
|
"wasmtime-jit-debug",
|
||||||
"wasmtime-fiber",
|
"wasmtime-fiber",
|
||||||
|
|||||||
@@ -392,6 +392,16 @@ a few `unsafe` blocks related to utf-8 validation which are locally verifiable
|
|||||||
as correct and otherwise this crate is good to go.
|
as correct and otherwise this crate is good to go.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
[[audits.pulldown-cmark]]
|
||||||
|
who = "Alex Crichton <alex@alexcrichton.com>"
|
||||||
|
criteria = "safe-to-deploy"
|
||||||
|
version = "0.8.0"
|
||||||
|
notes = """
|
||||||
|
This crate has `unsafe` blocks and they're all related to SIMD-acceleration and
|
||||||
|
are otherwise not doing other `unsafe` operations. Additionally the crate does
|
||||||
|
not do anything other than markdown rendering as is expected.
|
||||||
|
"""
|
||||||
|
|
||||||
[[audits.regalloc2]]
|
[[audits.regalloc2]]
|
||||||
who = "Jamey Sharp <jsharp@fastly.com>"
|
who = "Jamey Sharp <jsharp@fastly.com>"
|
||||||
criteria = "safe-to-deploy"
|
criteria = "safe-to-deploy"
|
||||||
@@ -484,6 +494,15 @@ intended to multiplex across the internal representation of a tinyvec,
|
|||||||
presumably. This trivially doesn't contain anything bad.
|
presumably. This trivially doesn't contain anything bad.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
[[audits.unicase]]
|
||||||
|
who = "Alex Crichton <alex@alexcrichton.com>"
|
||||||
|
criteria = "safe-to-deploy"
|
||||||
|
version = "2.6.0"
|
||||||
|
notes = """
|
||||||
|
This crate contains no `unsafe` code and no unnecessary use of the standard
|
||||||
|
library.
|
||||||
|
"""
|
||||||
|
|
||||||
[[audits.unicode-bidi]]
|
[[audits.unicode-bidi]]
|
||||||
who = "Alex Crichton <alex@alexcrichton.com>"
|
who = "Alex Crichton <alex@alexcrichton.com>"
|
||||||
criteria = "safe-to-deploy"
|
criteria = "safe-to-deploy"
|
||||||
@@ -967,3 +986,9 @@ criteria = "safe-to-deploy"
|
|||||||
version = "0.34.0"
|
version = "0.34.0"
|
||||||
notes = "I am the author of this crate."
|
notes = "I am the author of this crate."
|
||||||
|
|
||||||
|
[[audits.wit-parser]]
|
||||||
|
who = "Alex Crichton <alex@alexcrichton.com>"
|
||||||
|
criteria = "safe-to-deploy"
|
||||||
|
version = "0.3.0"
|
||||||
|
notes = "The Bytecode Alliance is the author of this crate."
|
||||||
|
|
||||||
|
|||||||
@@ -338,10 +338,6 @@ criteria = "safe-to-deploy"
|
|||||||
version = "0.10.0"
|
version = "0.10.0"
|
||||||
criteria = "safe-to-deploy"
|
criteria = "safe-to-deploy"
|
||||||
|
|
||||||
[[exemptions.half]]
|
|
||||||
version = "1.8.2"
|
|
||||||
criteria = "safe-to-run"
|
|
||||||
|
|
||||||
[[exemptions.hermit-abi]]
|
[[exemptions.hermit-abi]]
|
||||||
version = "0.1.19"
|
version = "0.1.19"
|
||||||
criteria = "safe-to-deploy"
|
criteria = "safe-to-deploy"
|
||||||
@@ -738,10 +734,6 @@ criteria = "safe-to-deploy"
|
|||||||
version = "1.0.137"
|
version = "1.0.137"
|
||||||
criteria = "safe-to-deploy"
|
criteria = "safe-to-deploy"
|
||||||
|
|
||||||
[[exemptions.serde_cbor]]
|
|
||||||
version = "0.11.2"
|
|
||||||
criteria = "safe-to-run"
|
|
||||||
|
|
||||||
[[exemptions.serde_derive]]
|
[[exemptions.serde_derive]]
|
||||||
version = "1.0.137"
|
version = "1.0.137"
|
||||||
criteria = "safe-to-deploy"
|
criteria = "safe-to-deploy"
|
||||||
|
|||||||
@@ -169,6 +169,16 @@ who = "Mike Hommey <mh+mozilla@glandium.org>"
|
|||||||
criteria = "safe-to-deploy"
|
criteria = "safe-to-deploy"
|
||||||
delta = "0.2.6 -> 0.2.7"
|
delta = "0.2.6 -> 0.2.7"
|
||||||
|
|
||||||
|
[[audits.mozilla.audits.half]]
|
||||||
|
who = "John M. Schanck <jschanck@mozilla.com>"
|
||||||
|
criteria = "safe-to-deploy"
|
||||||
|
version = "1.8.2"
|
||||||
|
notes = """
|
||||||
|
This crate contains unsafe code for bitwise casts to/from binary16 floating-point
|
||||||
|
format. I've reviewed these and found no issues. There are no uses of ambient
|
||||||
|
capabilities.
|
||||||
|
"""
|
||||||
|
|
||||||
[[audits.mozilla.audits.hashbrown]]
|
[[audits.mozilla.audits.hashbrown]]
|
||||||
who = "Mike Hommey <mh+mozilla@glandium.org>"
|
who = "Mike Hommey <mh+mozilla@glandium.org>"
|
||||||
criteria = "safe-to-deploy"
|
criteria = "safe-to-deploy"
|
||||||
@@ -288,6 +298,16 @@ who = "Mike Hommey <mh+mozilla@glandium.org>"
|
|||||||
criteria = "safe-to-deploy"
|
criteria = "safe-to-deploy"
|
||||||
delta = "1.0.143 -> 1.0.144"
|
delta = "1.0.143 -> 1.0.144"
|
||||||
|
|
||||||
|
[[audits.mozilla.audits.serde_cbor]]
|
||||||
|
who = "R. Martinho Fernandes <bugs@rmf.io>"
|
||||||
|
criteria = "safe-to-deploy"
|
||||||
|
version = "0.11.1"
|
||||||
|
|
||||||
|
[[audits.mozilla.audits.serde_cbor]]
|
||||||
|
who = "John M. Schanck <jschanck@mozilla.com>"
|
||||||
|
criteria = "safe-to-deploy"
|
||||||
|
delta = "0.11.1 -> 0.11.2"
|
||||||
|
|
||||||
[[audits.mozilla.audits.serde_derive]]
|
[[audits.mozilla.audits.serde_derive]]
|
||||||
who = "Mike Hommey <mh+mozilla@glandium.org>"
|
who = "Mike Hommey <mh+mozilla@glandium.org>"
|
||||||
criteria = "safe-to-deploy"
|
criteria = "safe-to-deploy"
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use wasmtime_component_util::REALLOC_AND_FREE;
|
|||||||
|
|
||||||
mod aot;
|
mod aot;
|
||||||
mod r#async;
|
mod r#async;
|
||||||
|
mod bindgen;
|
||||||
mod dynamic;
|
mod dynamic;
|
||||||
mod func;
|
mod func;
|
||||||
mod import;
|
mod import;
|
||||||
|
|||||||
117
tests/all/component_model/bindgen.rs
Normal file
117
tests/all/component_model/bindgen.rs
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
use super::engine;
|
||||||
|
use anyhow::Result;
|
||||||
|
use wasmtime::{
|
||||||
|
component::{Component, Linker},
|
||||||
|
Store,
|
||||||
|
};
|
||||||
|
|
||||||
|
mod no_imports {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
wasmtime::component::bindgen!({
|
||||||
|
inline: "
|
||||||
|
world no-imports {
|
||||||
|
export foo: interface {
|
||||||
|
foo: func()
|
||||||
|
}
|
||||||
|
|
||||||
|
default export interface {
|
||||||
|
bar: func()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
",
|
||||||
|
});
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn run() -> Result<()> {
|
||||||
|
let engine = engine();
|
||||||
|
|
||||||
|
let component = Component::new(
|
||||||
|
&engine,
|
||||||
|
r#"
|
||||||
|
(component
|
||||||
|
(core module $m
|
||||||
|
(func (export ""))
|
||||||
|
)
|
||||||
|
(core instance $i (instantiate $m))
|
||||||
|
|
||||||
|
(func $f (export "bar") (canon lift (core func $i "")))
|
||||||
|
|
||||||
|
(instance $i (export "foo" (func $f)))
|
||||||
|
(export "foo" (instance $i))
|
||||||
|
)
|
||||||
|
"#,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let linker = Linker::new(&engine);
|
||||||
|
let mut store = Store::new(&engine, ());
|
||||||
|
let (no_imports, _) = NoImports::instantiate(&mut store, &component, &linker)?;
|
||||||
|
no_imports.bar(&mut store)?;
|
||||||
|
no_imports.foo().foo(&mut store)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod one_import {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
wasmtime::component::bindgen!({
|
||||||
|
inline: "
|
||||||
|
world one-import {
|
||||||
|
import foo: interface {
|
||||||
|
foo: func()
|
||||||
|
}
|
||||||
|
|
||||||
|
default export interface {
|
||||||
|
bar: func()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
",
|
||||||
|
});
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn run() -> Result<()> {
|
||||||
|
let engine = engine();
|
||||||
|
|
||||||
|
let component = Component::new(
|
||||||
|
&engine,
|
||||||
|
r#"
|
||||||
|
(component
|
||||||
|
(import "foo" (instance $i
|
||||||
|
(export "foo" (func))
|
||||||
|
))
|
||||||
|
(core module $m
|
||||||
|
(import "" "" (func))
|
||||||
|
(export "" (func 0))
|
||||||
|
)
|
||||||
|
(core func $f (canon lower (func $i "foo")))
|
||||||
|
(core instance $i (instantiate $m
|
||||||
|
(with "" (instance (export "" (func $f))))
|
||||||
|
))
|
||||||
|
|
||||||
|
(func $f (export "bar") (canon lift (core func $i "")))
|
||||||
|
)
|
||||||
|
"#,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct MyImports {
|
||||||
|
hit: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl foo::Foo for MyImports {
|
||||||
|
fn foo(&mut self) -> Result<()> {
|
||||||
|
self.hit = true;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut linker = Linker::new(&engine);
|
||||||
|
foo::add_to_linker(&mut linker, |f: &mut MyImports| f)?;
|
||||||
|
let mut store = Store::new(&engine, MyImports::default());
|
||||||
|
let (one_import, _) = OneImport::instantiate(&mut store, &component, &linker)?;
|
||||||
|
one_import.bar(&mut store)?;
|
||||||
|
assert!(store.data().hit);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user