diff --git a/Cargo.lock b/Cargo.lock index 084086534..676314ded 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -773,6 +773,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" dependencies = [ "ahash", + "serde", ] [[package]] @@ -1403,10 +1404,10 @@ name = "test-helpers" version = "0.0.0" dependencies = [ "codegen-macro", - "wasm-encoder 0.208.0", + "wasm-encoder 0.209.0", "wit-bindgen-core", "wit-component", - "wit-parser 0.208.0", + "wit-parser 0.209.0", ] [[package]] @@ -1681,18 +1682,18 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.208.0" +version = "0.209.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbc0fb39838056aeb096b2e7dd94bb2f0c2df3c9fb4d1055f2cb3c35c286ee71" +checksum = "821112ccd35a6e25790ba5f4ed72ac5321707cf18a379bf071b76f8d0336603d" dependencies = [ "leb128", ] [[package]] name = "wasm-metadata" -version = "0.208.0" +version = "0.209.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0477c12795d0de6243d03e0101e6a21b24a5f2f350f2e2bf9c80da274e68d243" +checksum = "6902f36840b21a4fb907f700125da1965a08478f8f1338d737f248edcf57c49b" dependencies = [ "anyhow", "indexmap", @@ -1700,8 +1701,8 @@ dependencies = [ "serde_derive", "serde_json", "spdx", - "wasm-encoder 0.208.0", - "wasmparser 0.208.0", + "wasm-encoder 0.209.0", + "wasmparser 0.209.0", ] [[package]] @@ -1717,15 +1718,16 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.208.0" +version = "0.209.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d20bf2b2d07ec86bab7a05ae4e3a290e5b333319cd73253bc79bfedb6c59c83" +checksum = "233c757e98c11d092b757fd3ada885a446fdc002432bf7bf12c93f81ba96c7c9" dependencies = [ "ahash", "bitflags 2.5.0", "hashbrown 0.14.3", "indexmap", "semver", + "serde", ] [[package]] @@ -2053,24 +2055,24 @@ dependencies = [ [[package]] name = "wast" -version = "208.0.0" +version = "209.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0450a853119b35441264ca99bd90be37d6f85f99decc4d993795ad396ed56b97" +checksum = "796916a29f4a8454655b7af3aa2d0e40532d07b4d3b8abdb78e4cb6b84c00586" dependencies = [ "bumpalo", "leb128", "memchr", "unicode-width", - "wasm-encoder 0.208.0", + "wasm-encoder 0.209.0", ] [[package]] name = "wat" -version = "1.208.0" +version = "1.209.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72fd5b4d1e1fb745f2eb6e8004563ffbf0858681c11a79f4ec663ee31907080d" +checksum = "0ecc135c1bdf98ef1c818b80996897ab23dff91391149e8c22d8278796b743e9" dependencies = [ - "wast 208.0.0", + "wast 209.0.0", ] [[package]] @@ -2330,11 +2332,11 @@ dependencies = [ "clap", "heck 0.5.0", "test-helpers", - "wasm-encoder 0.208.0", + "wasm-encoder 0.209.0", "wasm-metadata", "wit-bindgen-core", "wit-component", - "wit-parser 0.208.0", + "wit-parser 0.209.0", ] [[package]] @@ -2345,8 +2347,8 @@ dependencies = [ "clap", "heck 0.5.0", "test-artifacts", - "wasm-encoder 0.208.0", - "wasmparser 0.208.0", + "wasm-encoder 0.209.0", + "wasmparser 0.209.0", "wasmtime", "wasmtime-wasi", "wit-bindgen-c", @@ -2357,7 +2359,7 @@ dependencies = [ "wit-bindgen-rust", "wit-bindgen-teavm-java", "wit-component", - "wit-parser 0.208.0", + "wit-parser 0.209.0", ] [[package]] @@ -2366,7 +2368,7 @@ version = "0.25.0" dependencies = [ "anyhow", "heck 0.5.0", - "wit-parser 0.208.0", + "wit-parser 0.209.0", ] [[package]] @@ -2378,9 +2380,9 @@ dependencies = [ "heck 0.5.0", "indexmap", "test-helpers", - "wasm-encoder 0.208.0", + "wasm-encoder 0.209.0", "wasm-metadata", - "wasmparser 0.208.0", + "wasmparser 0.209.0", "wit-bindgen-core", "wit-component", ] @@ -2460,9 +2462,9 @@ dependencies = [ [[package]] name = "wit-component" -version = "0.208.0" +version = "0.209.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0397074e61e235635133f1301d1808545e4cb2701d117dc2aca128e65168ae" +checksum = "b996f57f396e6bd6bbb7b7322d35e9bf146a508885c910a800820a75febd2a05" dependencies = [ "anyhow", "bitflags 2.5.0", @@ -2471,11 +2473,11 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "wasm-encoder 0.208.0", + "wasm-encoder 0.209.0", "wasm-metadata", - "wasmparser 0.208.0", + "wasmparser 0.209.0", "wat", - "wit-parser 0.208.0", + "wit-parser 0.209.0", ] [[package]] @@ -2498,9 +2500,9 @@ dependencies = [ [[package]] name = "wit-parser" -version = "0.208.0" +version = "0.209.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27e6bf94e83a0633ae1790912fbe3a97c2fd1ea7956fc58be18aa03517b1b887" +checksum = "9455f94dfa4817ec1cdd7f53bba662dcbaf10cd41152d03bd39c6cabe90491fa" dependencies = [ "anyhow", "id-arena", @@ -2511,7 +2513,7 @@ dependencies = [ "serde_derive", "serde_json", "unicode-xid", - "wasmparser 0.208.0", + "wasmparser 0.209.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index e67db8d76..1786863e2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,11 +28,11 @@ pulldown-cmark = { version = "0.9", default-features = false } clap = { version = "4.3.19", features = ["derive"] } indexmap = "2.0.0" -wasmparser = "0.208.0" -wasm-encoder = "0.208.0" -wasm-metadata = "0.208.0" -wit-parser = "0.208.0" -wit-component = "0.208.0" +wasmparser = "0.209.0" +wasm-encoder = "0.209.0" +wasm-metadata = "0.209.0" +wit-parser = "0.209.0" +wit-component = "0.209.0" wit-bindgen-core = { path = 'crates/core', version = '0.25.0' } wit-bindgen-c = { path = 'crates/c', version = '0.25.0' } diff --git a/crates/c/src/lib.rs b/crates/c/src/lib.rs index f76a2520b..69c245e9c 100644 --- a/crates/c/src/lib.rs +++ b/crates/c/src/lib.rs @@ -656,9 +656,9 @@ pub fn imported_types_used_by_exported_interfaces( for (_, export) in resolve.worlds[world].exports.iter() { match export { WorldItem::Function(_) => {} - WorldItem::Interface(i) => { - exported_interfaces.insert(*i); - live_export_types.add_interface(resolve, *i) + WorldItem::Interface { id, .. } => { + exported_interfaces.insert(*id); + live_export_types.add_interface(resolve, *id) } WorldItem::Type(_) => unreachable!(), } @@ -1346,7 +1346,7 @@ impl<'a> wit_bindgen_core::AnonymousTypeGenerator<'a> for InterfaceGenerator<'a> self.resolve } - fn anonymous_type_handle(&mut self, id: TypeId, handle: &Handle, docs: &Docs) { + fn anonymous_type_handle(&mut self, id: TypeId, handle: &Handle, _docs: &Docs) { self.src.h_defs("\ntypedef "); let resource = match handle { Handle::Borrow(id) | Handle::Own(id) => id, @@ -1360,7 +1360,7 @@ impl<'a> wit_bindgen_core::AnonymousTypeGenerator<'a> for InterfaceGenerator<'a> self.print_typedef_target(id); } - fn anonymous_type_tuple(&mut self, id: TypeId, ty: &Tuple, docs: &Docs) { + fn anonymous_type_tuple(&mut self, id: TypeId, ty: &Tuple, _docs: &Docs) { self.src.h_defs("\ntypedef "); self.src.h_defs("struct {\n"); for (i, t) in ty.types.iter().enumerate() { @@ -1372,7 +1372,7 @@ impl<'a> wit_bindgen_core::AnonymousTypeGenerator<'a> for InterfaceGenerator<'a> self.print_typedef_target(id); } - fn anonymous_type_option(&mut self, id: TypeId, ty: &Type, docs: &Docs) { + fn anonymous_type_option(&mut self, id: TypeId, ty: &Type, _docs: &Docs) { self.src.h_defs("\ntypedef "); self.src.h_defs("struct {\n"); self.src.h_defs("bool is_some;\n"); @@ -1383,7 +1383,7 @@ impl<'a> wit_bindgen_core::AnonymousTypeGenerator<'a> for InterfaceGenerator<'a> self.print_typedef_target(id); } - fn anonymous_type_result(&mut self, id: TypeId, ty: &Result_, docs: &Docs) { + fn anonymous_type_result(&mut self, id: TypeId, ty: &Result_, _docs: &Docs) { self.src.h_defs("\ntypedef "); self.src.h_defs( "struct { @@ -1409,7 +1409,7 @@ impl<'a> wit_bindgen_core::AnonymousTypeGenerator<'a> for InterfaceGenerator<'a> self.print_typedef_target(id); } - fn anonymous_type_list(&mut self, id: TypeId, ty: &Type, docs: &Docs) { + fn anonymous_type_list(&mut self, id: TypeId, ty: &Type, _docs: &Docs) { self.src.h_defs("\ntypedef "); self.src.h_defs("struct {\n"); let ty = self.gen.type_name(ty); @@ -1420,15 +1420,15 @@ impl<'a> wit_bindgen_core::AnonymousTypeGenerator<'a> for InterfaceGenerator<'a> self.print_typedef_target(id); } - fn anonymous_type_future(&mut self, id: TypeId, ty: &Option, docs: &Docs) { + fn anonymous_type_future(&mut self, _id: TypeId, _ty: &Option, _docs: &Docs) { todo!("print_anonymous_type for future"); } - fn anonymous_type_stream(&mut self, id: TypeId, ty: &Stream, docs: &Docs) { + fn anonymous_type_stream(&mut self, _id: TypeId, _ty: &Stream, _docs: &Docs) { todo!("print_anonymous_type for stream"); } - fn anonymous_typ_type(&mut self, id: TypeId, ty: &Type, docs: &Docs) { + fn anonymous_typ_type(&mut self, _id: TypeId, _ty: &Type, _docs: &Docs) { todo!("print_anonymous_type for typ"); } } @@ -3098,16 +3098,6 @@ impl Source { } } -trait SourceExt { - fn as_source(&mut self) -> &mut wit_bindgen_core::Source; -} - -impl SourceExt for wit_bindgen_core::Source { - fn as_source(&mut self) -> &mut wit_bindgen_core::Source { - self - } -} - fn wasm_type(ty: WasmType) -> &'static str { match ty { WasmType::I32 => "int32_t", diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs index 773707d85..939a0c075 100644 --- a/crates/core/src/lib.rs +++ b/crates/core/src/lib.rs @@ -37,7 +37,7 @@ pub trait WorldGenerator { for (name, import) in world.imports.iter() { match import { WorldItem::Function(f) => funcs.push((unwrap_name(name), f)), - WorldItem::Interface(id) => self.import_interface(resolve, name, *id, files), + WorldItem::Interface { id, .. } => self.import_interface(resolve, name, *id, files), WorldItem::Type(id) => types.push((unwrap_name(name), *id)), } } @@ -61,7 +61,7 @@ pub trait WorldGenerator { for (name, export) in world.exports.iter() { match export { WorldItem::Function(f) => funcs.push((unwrap_name(name), f)), - WorldItem::Interface(id) => interfaces.push((name, id)), + WorldItem::Interface { id, .. } => interfaces.push((name, id)), WorldItem::Type(_) => unreachable!(), } } diff --git a/crates/core/src/types.rs b/crates/core/src/types.rs index d8bdec657..a0862f5e8 100644 --- a/crates/core/src/types.rs +++ b/crates/core/src/types.rs @@ -77,7 +77,7 @@ impl Types { WorldItem::Function(f) => { self.type_info_func(resolve, f, import); } - WorldItem::Interface(id) => { + WorldItem::Interface { id, stability: _ } => { for (_, f) in resolve.interfaces[*id].functions.iter() { self.type_info_func(resolve, f, import); } diff --git a/crates/go/src/lib.rs b/crates/go/src/lib.rs index 6abfbcec0..965b07e10 100644 --- a/crates/go/src/lib.rs +++ b/crates/go/src/lib.rs @@ -14,7 +14,6 @@ use wit_bindgen_core::{Direction, Files, Source, WorldGenerator}; mod bindgen; mod imports; mod interface; -mod path; #[derive(Debug, Clone)] #[cfg_attr(feature = "clap", derive(clap::Args))] diff --git a/crates/go/src/path.rs b/crates/go/src/path.rs deleted file mode 100644 index ae05651b0..000000000 --- a/crates/go/src/path.rs +++ /dev/null @@ -1,31 +0,0 @@ -use heck::ToSnakeCase; -use wit_bindgen_core::{ - name_package_module, - wit_parser::{Resolve, WorldKey}, - Direction, -}; - -pub(crate) trait GoPath { - fn to_path(&self, resolve: &Resolve, direction: Direction) -> Vec; -} - -impl GoPath for WorldKey { - fn to_path(&self, resolve: &Resolve, direction: Direction) -> Vec { - let mut path = Vec::new(); - if matches!(direction, Direction::Export) { - path.push("exports".to_string()); - } - match self { - WorldKey::Name(n) => path.push(n.to_snake_case()), - WorldKey::Interface(id) => { - let iface = &resolve.interfaces[*id]; - let pkg = iface.package.unwrap(); - let pkgname = resolve.packages[pkg].name.clone(); - path.push(pkgname.namespace.to_snake_case()); - path.push(name_package_module(resolve, pkg)); - path.push(iface.name.as_ref().unwrap().to_snake_case()); - } - } - path - } -} diff --git a/crates/guest-rust/macro/src/lib.rs b/crates/guest-rust/macro/src/lib.rs index d8c3b6465..1ab323f6e 100644 --- a/crates/guest-rust/macro/src/lib.rs +++ b/crates/guest-rust/macro/src/lib.rs @@ -46,6 +46,7 @@ impl Parse for Config { let mut opts = Opts::default(); let mut world = None; let mut source = None; + let mut features = Vec::new(); if input.peek(token::Brace) { let content; @@ -116,6 +117,9 @@ impl Parse for Config { Opt::GenerateUnusedTypes(enable) => { opts.generate_unused_types = enable.value(); } + Opt::Features(f) => { + features.extend(f.into_iter().map(|f| f.value())); + } } } } else { @@ -125,7 +129,7 @@ impl Parse for Config { } } let (resolve, pkg, files) = - parse_source(&source).map_err(|err| anyhow_to_syn(call_site, err))?; + parse_source(&source, &features).map_err(|err| anyhow_to_syn(call_site, err))?; let world = resolve .select_world(pkg, world.as_deref()) .map_err(|e| anyhow_to_syn(call_site, e))?; @@ -139,8 +143,12 @@ impl Parse for Config { } /// Parse the source -fn parse_source(source: &Option) -> anyhow::Result<(Resolve, PackageId, Vec)> { +fn parse_source( + source: &Option, + features: &[String], +) -> anyhow::Result<(Resolve, PackageId, Vec)> { let mut resolve = Resolve::default(); + resolve.features.extend(features.iter().cloned()); let mut files = Vec::new(); let root = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap()); let mut parse = |path: &Path| -> anyhow::Result<_> { @@ -235,6 +243,7 @@ mod kw { syn::custom_keyword!(export_macro_name); syn::custom_keyword!(pub_export_macro); syn::custom_keyword!(generate_unused_types); + syn::custom_keyword!(features); } #[derive(Clone)] @@ -285,6 +294,7 @@ enum Opt { ExportMacroName(syn::LitStr), PubExportMacro(syn::LitBool), GenerateUnusedTypes(syn::LitBool), + Features(Vec), } impl Parse for Opt { @@ -407,6 +417,13 @@ impl Parse for Opt { input.parse::()?; input.parse::()?; Ok(Opt::GenerateUnusedTypes(input.parse()?)) + } else if l.peek(kw::features) { + input.parse::()?; + input.parse::()?; + let contents; + syn::bracketed!(contents in input); + let list = Punctuated::<_, Token![,]>::parse_terminated(&contents)?; + Ok(Opt::Features(list.into_iter().collect())) } else { Err(l.error()) } diff --git a/crates/guest-rust/src/lib.rs b/crates/guest-rust/src/lib.rs index 8704223b0..d455193f4 100644 --- a/crates/guest-rust/src/lib.rs +++ b/crates/guest-rust/src/lib.rs @@ -790,6 +790,13 @@ /// // By default, they will not be generated unless they are used as input /// // or return value of a function. /// generate_unused_types: false, +/// +/// // A list of "features" which correspond to WIT features to activate +/// // when parsing WIT files. This enables `@unstable` annotations showing +/// // up and having bindings generated for them. +/// // +/// // By default this is an empty list. +/// features: ["foo", "bar", "baz"], /// }); /// ``` /// diff --git a/crates/markdown/src/lib.rs b/crates/markdown/src/lib.rs index b01eb02c8..ed325a892 100644 --- a/crates/markdown/src/lib.rs +++ b/crates/markdown/src/lib.rs @@ -66,7 +66,7 @@ impl WorldGenerator for Markdown { } let name = &resolve.name_world_key(name); match import { - WorldItem::Interface(_) => { + WorldItem::Interface { .. } => { gen.push_str(" - interface `"); gen.push_str(name); gen.push_str("`\n"); @@ -91,7 +91,7 @@ impl WorldGenerator for Markdown { } let name = &resolve.name_world_key(name); match export { - WorldItem::Interface(_) => { + WorldItem::Interface { .. } => { gen.push_str(" - interface `"); gen.push_str(name); gen.push_str("`\n"); diff --git a/crates/rust/src/interface.rs b/crates/rust/src/interface.rs index 73e7cdcc4..2eb5dc870 100644 --- a/crates/rust/src/interface.rs +++ b/crates/rust/src/interface.rs @@ -2188,11 +2188,11 @@ impl<'a, 'b> wit_bindgen_core::AnonymousTypeGenerator<'a> for AnonTypeGenerator< self.resolve } - fn anonymous_typ_type(&mut self, id: TypeId, ty: &Type, docs: &Docs) { + fn anonymous_typ_type(&mut self, _id: TypeId, ty: &Type, _docs: &Docs) { self.interface.print_ty(ty, self.mode); } - fn anonymous_type_handle(&mut self, id: TypeId, handle: &Handle, docs: &Docs) { + fn anonymous_type_handle(&mut self, _id: TypeId, handle: &Handle, _docs: &Docs) { match handle { Handle::Own(ty) => { self.interface.print_ty(&Type::Id(*ty), self.mode); @@ -2226,7 +2226,7 @@ impl<'a, 'b> wit_bindgen_core::AnonymousTypeGenerator<'a> for AnonTypeGenerator< } } - fn anonymous_type_tuple(&mut self, id: TypeId, ty: &Tuple, docs: &Docs) { + fn anonymous_type_tuple(&mut self, _id: TypeId, ty: &Tuple, _docs: &Docs) { self.interface.push_str("("); for ty in ty.types.iter() { let mode = self.interface.filter_mode_preserve_top(ty, self.mode); @@ -2236,14 +2236,14 @@ impl<'a, 'b> wit_bindgen_core::AnonymousTypeGenerator<'a> for AnonTypeGenerator< self.interface.push_str(")"); } - fn anonymous_type_option(&mut self, id: TypeId, t: &Type, docs: &Docs) { + fn anonymous_type_option(&mut self, _id: TypeId, t: &Type, _docs: &Docs) { self.interface.push_str("Option<"); let mode = self.interface.filter_mode_preserve_top(t, self.mode); self.interface.print_ty(t, mode); self.interface.push_str(">"); } - fn anonymous_type_result(&mut self, id: TypeId, r: &Result_, docs: &Docs) { + fn anonymous_type_result(&mut self, _id: TypeId, r: &Result_, _docs: &Docs) { self.interface.push_str("Result<"); self.interface.print_optional_ty(r.ok.as_ref(), self.mode); self.interface.push_str(","); @@ -2251,17 +2251,17 @@ impl<'a, 'b> wit_bindgen_core::AnonymousTypeGenerator<'a> for AnonTypeGenerator< self.interface.push_str(">"); } - fn anonymous_type_list(&mut self, id: TypeId, ty: &Type, docs: &Docs) { + fn anonymous_type_list(&mut self, _id: TypeId, ty: &Type, _docs: &Docs) { self.interface.print_list(ty, self.mode) } - fn anonymous_type_future(&mut self, id: TypeId, ty: &Option, docs: &Docs) { + fn anonymous_type_future(&mut self, _id: TypeId, ty: &Option, _docs: &Docs) { self.interface.push_str("Future<"); self.interface.print_optional_ty(ty.as_ref(), self.mode); self.interface.push_str(">"); } - fn anonymous_type_stream(&mut self, id: TypeId, stream: &Stream, docs: &Docs) { + fn anonymous_type_stream(&mut self, _id: TypeId, stream: &Stream, _docs: &Docs) { self.interface.push_str("Stream<"); self.interface .print_optional_ty(stream.element.as_ref(), self.mode); diff --git a/crates/rust/tests/codegen.rs b/crates/rust/tests/codegen.rs index 38815d0ce..a23fce99b 100644 --- a/crates/rust/tests/codegen.rs +++ b/crates/rust/tests/codegen.rs @@ -486,3 +486,27 @@ mod generate_unused_types { generate_unused_types: true, }); } + +#[allow(unused)] +mod gated_features { + wit_bindgen::generate!({ + inline: r#" + package foo:bar; + + world bindings { + @unstable(feature = x) + import x: func(); + @unstable(feature = y) + import y: func(); + @since(version = 1.2.3) + import z: func(); + } + "#, + features: ["y"], + }); + + fn _foo() { + y(); + z(); + } +} diff --git a/src/bin/wit-bindgen.rs b/src/bin/wit-bindgen.rs index 4e306ede3..9acb5d9e8 100644 --- a/src/bin/wit-bindgen.rs +++ b/src/bin/wit-bindgen.rs @@ -87,6 +87,13 @@ struct Common { /// they're up-to-date with the source files. #[clap(long)] check: bool, + + /// Comma-separated list of features that should be enabled when processing + /// WIT files. + /// + /// This enables using `@unstable` annotations in WIT files. + #[clap(long)] + features: Vec, } fn main() -> Result<()> { @@ -155,6 +162,15 @@ fn gen_world( files: &mut Files, ) -> Result<()> { let mut resolve = Resolve::default(); + for features in opts.features.iter() { + for feature in features + .split(',') + .flat_map(|s| s.split_whitespace()) + .filter(|f| !f.is_empty()) + { + resolve.features.insert(feature.to_string()); + } + } let (pkg, _files) = resolve.push_path(&opts.wit)?; let world = resolve.select_world(pkg, opts.world.as_deref())?; generator.generate(&resolve, world, files)?;