diff --git a/Cargo.lock b/Cargo.lock index 48f540eac..e980539dc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1143,7 +1143,7 @@ name = "test-helpers" version = "0.0.0" dependencies = [ "codegen-macro", - "wasm-encoder 0.259.0", + "wasm-encoder 0.260.0", "wit-bindgen-core", "wit-component", "wit-parser", @@ -1360,9 +1360,9 @@ checksum = "d0094c9d281ca1ee9434e1287601ef8442cb23341b1cda917755619694814ba5" [[package]] name = "wasm-compose" -version = "0.259.0" +version = "0.260.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8aea3892e99cd163b7ac32984bbd434328928d63a9305ef1c55b1de3a42ae530" +checksum = "05106c4f0b304aee92d905c9b915d1042abb7245c1f53dbcd610f34b3c8d0ad2" dependencies = [ "anyhow", "indexmap", @@ -1372,8 +1372,8 @@ dependencies = [ "serde_derive", "serde_yaml2", "smallvec", - "wasm-encoder 0.259.0", - "wasmparser 0.259.0", + "wasm-encoder 0.260.0", + "wasmparser 0.260.0", "wat", ] @@ -1389,12 +1389,12 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.259.0" +version = "0.260.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1d0246511d901aacf25d2dc9111f0054947de5e093fe662099e709ff7530dc3" +checksum = "e1e9692da9ef627c5ee12b45378f68ac2689ce306f88078f5cf849b7c3444ed8" dependencies = [ "leb128fmt", - "wasmparser 0.259.0", + "wasmparser 0.260.0", ] [[package]] @@ -1418,14 +1418,14 @@ dependencies = [ [[package]] name = "wasm-metadata" -version = "0.259.0" +version = "0.260.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e7bf119eb01f4a246864c10bd87c8f26c566350abb25aa4d5273c415bbab338" +checksum = "8b777ac62b820a7e0fd6b1d6beb2712bfa15a89f611e6cd792ec60468f66d6fa" dependencies = [ "anyhow", "indexmap", - "wasm-encoder 0.259.0", - "wasmparser 0.259.0", + "wasm-encoder 0.260.0", + "wasmparser 0.260.0", ] [[package]] @@ -1443,9 +1443,9 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.259.0" +version = "0.260.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f7c12eac7bb587801590f6a67ff0bc84d0748513864b71108e4b311cc3df694" +checksum = "4c94519d78304dc4a4bb5925eda6ff153bf06167467cff9233dc9593bae28fdd" dependencies = [ "bitflags 2.13.1", "hashbrown 0.17.1", @@ -1456,22 +1456,22 @@ dependencies = [ [[package]] name = "wast" -version = "259.0.0" +version = "260.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c69beba8d9da07af9a0971b559149a2ac4729895b55144de4fddbf5a02660648" +checksum = "17573754cde137d26852892330414efb6d1d33480adcd10e8825d092b2132229" dependencies = [ "bumpalo", "leb128fmt", "memchr", "unicode-width 0.2.2", - "wasm-encoder 0.259.0", + "wasm-encoder 0.260.0", ] [[package]] name = "wat" -version = "1.259.0" +version = "1.260.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6eec44b0c80391b20fb7ad9ea440c72c5d382385bdf74444bb18321c425017e" +checksum = "5f56de9341c410d04121da51dd16c11d095cb6a914bd2b2850cd3c60558c0c15" dependencies = [ "wast", ] @@ -1516,8 +1516,8 @@ dependencies = [ "clap", "heck", "indexmap", - "wasm-encoder 0.259.0", - "wasm-metadata 0.259.0", + "wasm-encoder 0.260.0", + "wasm-metadata 0.260.0", "wit-bindgen-core", "wit-component", ] @@ -1529,7 +1529,7 @@ dependencies = [ "anyhow", "clap", "env_logger", - "wasm-encoder 0.259.0", + "wasm-encoder 0.260.0", "wit-bindgen-c", "wit-bindgen-core", "wit-bindgen-cpp", @@ -1563,8 +1563,8 @@ dependencies = [ "heck", "indexmap", "test-helpers", - "wasm-encoder 0.259.0", - "wasm-metadata 0.259.0", + "wasm-encoder 0.260.0", + "wasm-metadata 0.260.0", "wit-bindgen-c", "wit-bindgen-core", "wit-component", @@ -1580,7 +1580,7 @@ dependencies = [ "heck", "indexmap", "regex", - "wasm-metadata 0.259.0", + "wasm-metadata 0.260.0", "wit-bindgen-core", "wit-component", "wit-parser", @@ -1594,8 +1594,8 @@ dependencies = [ "clap", "heck", "indexmap", - "wasm-encoder 0.259.0", - "wasm-metadata 0.259.0", + "wasm-encoder 0.260.0", + "wasm-metadata 0.260.0", "wit-bindgen-core", "wit-component", ] @@ -1607,8 +1607,8 @@ dependencies = [ "anyhow", "clap", "heck", - "wasm-encoder 0.259.0", - "wasm-metadata 0.259.0", + "wasm-encoder 0.260.0", + "wasm-metadata 0.260.0", "wit-bindgen-core", "wit-component", ] @@ -1649,7 +1649,7 @@ dependencies = [ "serde_json", "syn 3.0.5", "test-helpers", - "wasm-metadata 0.259.0", + "wasm-metadata 0.260.0", "wit-bindgen", "wit-bindgen-core", "wit-component", @@ -1688,8 +1688,8 @@ dependencies = [ "wac-types", "wasi-preview1-component-adapter-provider", "wasm-compose", - "wasm-encoder 0.259.0", - "wasmparser 0.259.0", + "wasm-encoder 0.260.0", + "wasmparser 0.260.0", "wat", "wit-bindgen-csharp", "wit-component", @@ -1698,9 +1698,9 @@ dependencies = [ [[package]] name = "wit-component" -version = "0.259.0" +version = "0.260.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "092f783dee3253265fcde131475055f8c275ac0176a9c0396db1dc7b5544bfb4" +checksum = "389106e4fbac7c5bbece1496c442d2aceb1926c18884a3ad76f7559c160b8883" dependencies = [ "anyhow", "bitflags 2.13.1", @@ -1709,18 +1709,18 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "wasm-encoder 0.259.0", - "wasm-metadata 0.259.0", - "wasmparser 0.259.0", + "wasm-encoder 0.260.0", + "wasm-metadata 0.260.0", + "wasmparser 0.260.0", "wat", "wit-parser", ] [[package]] name = "wit-parser" -version = "0.259.0" +version = "0.260.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6390f4f02493ce678d509c859cf1698e38929fb75c8012a6ee2f7d6b6cb66cd7" +checksum = "3152a979bbe19638bb0655cc919d5a68ba1b7b2258f8f43f7c74430004ae7f5e" dependencies = [ "anyhow", "hashbrown 0.17.1", @@ -1732,7 +1732,7 @@ dependencies = [ "serde_derive", "serde_json", "unicode-ident", - "wasmparser 0.259.0", + "wasmparser 0.260.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 4a3e44c52..2247099a9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,13 +47,13 @@ syn = { version = "3.0.5", features = ["printing"] } futures = "0.3.31" macro-string = "0.3.0" -wat = "1.259.0" -wasmparser = "0.259.0" -wasm-encoder = "0.259.0" -wasm-metadata = { version = "0.259.0", default-features = false } -wit-parser = "0.259.0" -wit-component = "0.259.0" -wasm-compose = "0.259.0" +wat = "1.260.0" +wasmparser = "0.260.0" +wasm-encoder = "0.260.0" +wasm-metadata = { version = "0.260.0", default-features = false } +wit-parser = "0.260.0" +wit-component = "0.260.0" +wasm-compose = "0.260.0" wit-bindgen-core = { path = 'crates/core', version = '0.62.0' } wit-bindgen-c = { path = 'crates/c', version = '0.62.0' } diff --git a/crates/c/src/component_type_object.rs b/crates/c/src/component_type_object.rs index b38ce7ad8..5ff9fbac2 100644 --- a/crates/c/src/component_type_object.rs +++ b/crates/c/src/component_type_object.rs @@ -40,7 +40,8 @@ pub fn object( env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION"), ); - let data = wit_component::metadata::encode(resolve, world, encoding, Some(&producers)).unwrap(); + let data = + wit_component::metadata::encode(resolve, world, encoding, Some(&producers), false).unwrap(); // The custom section name here must start with "component-type" but // otherwise is attempted to be unique here to ensure that this doesn't get diff --git a/crates/core/src/async_.rs b/crates/core/src/async_.rs index e801e2ea3..7098eb210 100644 --- a/crates/core/src/async_.rs +++ b/crates/core/src/async_.rs @@ -105,7 +105,13 @@ impl AsyncFilterSet { FunctionKind::Freestanding | FunctionKind::Method(_) | FunctionKind::Static(_) - | FunctionKind::Constructor(_) => false, + | FunctionKind::Constructor(_) + | FunctionKind::Getter + | FunctionKind::MethodGetter(_) + | FunctionKind::StaticGetter(_) + | FunctionKind::Setter + | FunctionKind::MethodSetter(_) + | FunctionKind::StaticSetter(_) => false, FunctionKind::AsyncFreestanding | FunctionKind::AsyncMethod(_) | FunctionKind::AsyncStatic(_) => true, diff --git a/crates/cpp/src/lib.rs b/crates/cpp/src/lib.rs index 3490f8a4e..826428f0a 100644 --- a/crates/cpp/src/lib.rs +++ b/crates/cpp/src/lib.rs @@ -560,7 +560,10 @@ impl WorldGenerator for Cpp { r#gen.types(id); for (_name, func) in resolve.interfaces[id].functions.iter() { - if matches!(func.kind, FunctionKind::Freestanding) { + if matches!( + func.kind, + FunctionKind::Freestanding | FunctionKind::Getter | FunctionKind::Setter + ) { r#gen.r#gen.h_src.change_namespace(&namespace); r#gen.generate_function( func, @@ -616,7 +619,10 @@ impl WorldGenerator for Cpp { r#gen.types(id); for (_name, func) in resolve.interfaces[id].functions.iter() { - if matches!(func.kind, FunctionKind::Freestanding) { + if matches!( + func.kind, + FunctionKind::Freestanding | FunctionKind::Getter | FunctionKind::Setter + ) { r#gen.r#gen.h_src.change_namespace(&namespace); r#gen.generate_function(func, &TypeOwner::Interface(id), AbiVariant::GuestExport); } @@ -641,7 +647,10 @@ impl WorldGenerator for Cpp { let namespace = namespace(resolve, &TypeOwner::World(world), false, &*r#gen.r#gen); for (_name, func) in funcs.iter() { - if matches!(func.kind, FunctionKind::Freestanding) { + if matches!( + func.kind, + FunctionKind::Freestanding | FunctionKind::Getter | FunctionKind::Setter + ) { r#gen.r#gen.h_src.change_namespace(&namespace); r#gen.generate_function(func, &TypeOwner::World(world), AbiVariant::GuestImport); } @@ -662,7 +671,10 @@ impl WorldGenerator for Cpp { let namespace = namespace(resolve, &TypeOwner::World(world), true, &*r#gen.r#gen); for (_name, func) in funcs.iter() { - if matches!(func.kind, FunctionKind::Freestanding) { + if matches!( + func.kind, + FunctionKind::Freestanding | FunctionKind::Getter | FunctionKind::Setter + ) { r#gen.r#gen.h_src.change_namespace(&namespace); r#gen.generate_function(func, &TypeOwner::World(world), AbiVariant::GuestExport); } @@ -944,8 +956,14 @@ impl CppInterfaceGenerator<'_> { ) -> (Vec, String) { let (object, owner) = match &func.kind { FunctionKind::Freestanding => None, + FunctionKind::Getter => None, + FunctionKind::Setter => None, FunctionKind::Method(i) => Some(i), + FunctionKind::MethodGetter(i) => Some(i), + FunctionKind::MethodSetter(i) => Some(i), FunctionKind::Static(i) => Some(i), + FunctionKind::StaticGetter(i) => Some(i), + FunctionKind::StaticSetter(i) => Some(i), FunctionKind::Constructor(i) => Some(i), FunctionKind::AsyncFreestanding => todo!(), FunctionKind::AsyncMethod(_id) => todo!(), @@ -963,7 +981,10 @@ impl CppInterfaceGenerator<'_> { )); let mut namespace = namespace(self.resolve, &owner, guest_export, &*self.r#gen); let is_drop = is_special_method(func); - let func_name_h = if !matches!(&func.kind, FunctionKind::Freestanding) { + let func_name_h = if !matches!( + &func.kind, + FunctionKind::Freestanding | FunctionKind::Getter | FunctionKind::Setter + ) { namespace.push(object.clone()); if let FunctionKind::Constructor(_i) = &func.kind { // Fallible constructors return result and are static factory methods @@ -990,11 +1011,18 @@ impl CppInterfaceGenerator<'_> { SpecialMethod::ResourceNew => "ResourceNew".to_string(), SpecialMethod::ResourceRep => "ResourceRep".to_string(), SpecialMethod::Allocate => "New".to_string(), - SpecialMethod::None => func.item_name().to_pascal_case(), + SpecialMethod::None => match &func.kind { + FunctionKind::MethodSetter(_) | FunctionKind::StaticSetter(_) => { + format!("set-{}", func.item_name()).to_pascal_case() + } + _ => func.item_name().to_pascal_case(), + }, } } + } else if let FunctionKind::Setter = &func.kind { + format!("set-{}", func.item_name()).to_pascal_case() } else { - func.name.to_pascal_case() + func.item_name().to_pascal_case() }; (namespace, func_name_h) } @@ -1152,7 +1180,10 @@ impl CppInterfaceGenerator<'_> { res.post_return = true; } } - if (matches!(func.kind, FunctionKind::Static(_)) || is_fallible_constructor) + if (matches!( + func.kind, + FunctionKind::Static(_) | FunctionKind::StaticGetter(_) | FunctionKind::StaticSetter(_) + ) || is_fallible_constructor) && !(matches!(&is_drop, SpecialMethod::ResourceDrop) && matches!(abi_variant, AbiVariant::GuestImport)) { @@ -1167,9 +1198,13 @@ impl CppInterfaceGenerator<'_> { { if i == 0 && name == "self" - && (matches!(&func.kind, FunctionKind::Method(_)) - || (matches!(&is_drop, SpecialMethod::ResourceDrop) - && matches!(abi_variant, AbiVariant::GuestImport))) + && (matches!( + &func.kind, + FunctionKind::Method(_) + | FunctionKind::MethodGetter(_) + | FunctionKind::MethodSetter(_) + ) || (matches!(&is_drop, SpecialMethod::ResourceDrop) + && matches!(abi_variant, AbiVariant::GuestImport))) { res.implicit_self = true; continue; @@ -1190,7 +1225,11 @@ impl CppInterfaceGenerator<'_> { } // default to non-const when exporting a method let import = matches!(abi_variant, AbiVariant::GuestImport); - if matches!(func.kind, FunctionKind::Method(_)) && import { + if matches!( + func.kind, + FunctionKind::Method(_) | FunctionKind::MethodGetter(_) | FunctionKind::MethodSetter(_) + ) && import + { res.const_member = true; } res @@ -1418,7 +1457,10 @@ impl CppInterfaceGenerator<'_> { SpecialMethod::Allocate => unreachable!(), SpecialMethod::None => { // normal methods - let namespace = if matches!(func.kind, FunctionKind::Freestanding) { + let namespace = if matches!( + func.kind, + FunctionKind::Freestanding | FunctionKind::Getter | FunctionKind::Setter + ) { namespace( self.resolve, owner, @@ -1428,9 +1470,15 @@ impl CppInterfaceGenerator<'_> { } else { let owner = &self.resolve.types[match &func.kind { FunctionKind::Static(id) => *id, + FunctionKind::StaticGetter(id) => *id, + FunctionKind::StaticSetter(id) => *id, FunctionKind::Constructor(id) => *id, FunctionKind::Method(id) => *id, + FunctionKind::MethodGetter(id) => *id, + FunctionKind::MethodSetter(id) => *id, FunctionKind::Freestanding => unreachable!(), + FunctionKind::Getter => unreachable!(), + FunctionKind::Setter => unreachable!(), FunctionKind::AsyncFreestanding => todo!(), FunctionKind::AsyncMethod(_id) => todo!(), FunctionKind::AsyncStatic(_id) => todo!(), @@ -2004,8 +2052,14 @@ impl<'a> wit_bindgen_core::InterfaceGenerator<'a> for CppInterfaceGenerator<'a> for func in funcs { if match &func.kind { FunctionKind::Freestanding => false, + FunctionKind::Getter => false, + FunctionKind::Setter => false, FunctionKind::Method(mid) => *mid == id, + FunctionKind::MethodGetter(mid) => *mid == id, + FunctionKind::MethodSetter(mid) => *mid == id, FunctionKind::Static(mid) => *mid == id, + FunctionKind::StaticGetter(mid) => *mid == id, + FunctionKind::StaticSetter(mid) => *mid == id, FunctionKind::Constructor(mid) => *mid == id, FunctionKind::AsyncFreestanding => todo!(), FunctionKind::AsyncMethod(_id) => todo!(), @@ -3417,7 +3471,12 @@ impl<'a, 'b> Bindgen for FunctionBindgen<'a, 'b> { // dbg!(func); self.let_results(if func.result.is_some() { 1 } else { 0 }, results); let (namespace, func_name_h) = self.r#gen.func_namespace_name(func, true, true); - if matches!(func.kind, FunctionKind::Method(_)) { + if matches!( + func.kind, + FunctionKind::Method(_) + | FunctionKind::MethodGetter(_) + | FunctionKind::MethodSetter(_) + ) { let this = operands.remove(0); uwrite!(self.src, "({this}).get()."); } else { diff --git a/crates/csharp/src/interface.rs b/crates/csharp/src/interface.rs index 742b3d1ca..ef8ade04c 100644 --- a/crates/csharp/src/interface.rs +++ b/crates/csharp/src/interface.rs @@ -496,6 +496,12 @@ impl InterfaceGenerator<'_> { FunctionKind::Constructor(id) => { self.csharp_gen.all_resources[id].name.to_upper_camel_case() } + FunctionKind::Getter + | FunctionKind::Setter + | FunctionKind::MethodGetter(_) + | FunctionKind::MethodSetter(_) + | FunctionKind::StaticGetter(_) + | FunctionKind::StaticSetter(_) => todo!(), }; let access = self.csharp_gen.access_modifier(); @@ -851,6 +857,12 @@ var {async_status_var} = {raw_name}({wasm_params}); FunctionKind::Constructor(id) => { self.csharp_gen.all_resources[id].name.to_upper_camel_case() } + FunctionKind::Getter + | FunctionKind::Setter + | FunctionKind::MethodGetter(_) + | FunctionKind::MethodSetter(_) + | FunctionKind::StaticGetter(_) + | FunctionKind::StaticSetter(_) => todo!(), }; let modifiers = modifiers(func, &camel_name, Direction::Export); @@ -1579,6 +1591,12 @@ var {async_status_var} = {raw_name}({wasm_params}); self.csharp_gen.all_resources[id].name.to_upper_camel_case(), "", ), + FunctionKind::Getter + | FunctionKind::Setter + | FunctionKind::MethodGetter(_) + | FunctionKind::MethodSetter(_) + | FunctionKind::StaticGetter(_) + | FunctionKind::StaticSetter(_) => todo!(), }; let access = self.csharp_gen.access_modifier(); diff --git a/crates/csharp/src/world_generator.rs b/crates/csharp/src/world_generator.rs index c9b5780c9..1a8d9b39a 100644 --- a/crates/csharp/src/world_generator.rs +++ b/crates/csharp/src/world_generator.rs @@ -841,9 +841,14 @@ impl WorldGenerator for CSharp { // intended to be used non-interactively at link time, the // linker will have no additional information to resolve such // ambiguity. - let (resolve, world) = wit_parser::decoding::decode_world( - &wit_component::metadata::encode(resolve, id, self.opts.string_encoding, None)?, - )?; + let (resolve, world) = + wit_parser::decoding::decode_world(&wit_component::metadata::encode( + resolve, + id, + self.opts.string_encoding, + None, + false, + )?)?; let pkg = resolve.worlds[world].package.unwrap(); let mut printer = WitPrinter::default(); diff --git a/crates/d/src/lib.rs b/crates/d/src/lib.rs index 22ae744ad..71d18391b 100644 --- a/crates/d/src/lib.rs +++ b/crates/d/src/lib.rs @@ -675,6 +675,12 @@ impl WorldGenerator for D { r#gen.export_func(func); } } + FunctionKind::Getter + | FunctionKind::Setter + | FunctionKind::MethodGetter(_) + | FunctionKind::MethodSetter(_) + | FunctionKind::StaticGetter(_) + | FunctionKind::StaticSetter(_) => todo!(), } } @@ -904,6 +910,7 @@ impl WorldGenerator for D { world_id, wit_component::StringEncoding::UTF8, Some(&producers), + false, ) .unwrap(); @@ -1238,9 +1245,13 @@ impl<'a> DInterfaceGenerator<'a> { FunctionKind::AsyncFreestanding | FunctionKind::AsyncMethod(_) - | FunctionKind::AsyncStatic(_) => { - todo!() - } + | FunctionKind::AsyncStatic(_) + | FunctionKind::Getter + | FunctionKind::Setter + | FunctionKind::MethodGetter(_) + | FunctionKind::MethodSetter(_) + | FunctionKind::StaticGetter(_) + | FunctionKind::StaticSetter(_) => todo!(), } let mut res = DSig::default(); @@ -1252,6 +1263,12 @@ impl<'a> DInterfaceGenerator<'a> { | FunctionKind::Static(_) | FunctionKind::AsyncMethod(_) | FunctionKind::AsyncStatic(_) => func.name.split(".").skip(1).next().unwrap(), + FunctionKind::Getter + | FunctionKind::Setter + | FunctionKind::MethodGetter(_) + | FunctionKind::MethodSetter(_) + | FunctionKind::StaticGetter(_) + | FunctionKind::StaticSetter(_) => todo!(), }; let lower_name = split_name.to_lower_camel_case(); @@ -1832,7 +1849,13 @@ impl<'a> InterfaceGenerator<'a> for DInterfaceGenerator<'a> { FunctionKind::Constructor(mid) => *mid == id, FunctionKind::AsyncFreestanding => false, FunctionKind::AsyncMethod(_) => false, - FunctionKind::AsyncStatic(_) => todo!(), + FunctionKind::AsyncStatic(_) + | FunctionKind::Getter + | FunctionKind::Setter + | FunctionKind::MethodGetter(_) + | FunctionKind::MethodSetter(_) + | FunctionKind::StaticGetter(_) + | FunctionKind::StaticSetter(_) => todo!(), } { self.import_func(func); } @@ -1849,7 +1872,13 @@ impl<'a> InterfaceGenerator<'a> for DInterfaceGenerator<'a> { FunctionKind::Constructor(mid) => *mid == id, FunctionKind::AsyncFreestanding => false, FunctionKind::AsyncMethod(_) => false, - FunctionKind::AsyncStatic(_) => todo!(), + FunctionKind::AsyncStatic(_) + | FunctionKind::Getter + | FunctionKind::Setter + | FunctionKind::MethodGetter(_) + | FunctionKind::MethodSetter(_) + | FunctionKind::StaticGetter(_) + | FunctionKind::StaticSetter(_) => todo!(), } { self.import_func(func); } @@ -1920,8 +1949,14 @@ impl<'a> InterfaceGenerator<'a> for DInterfaceGenerator<'a> { FunctionKind::Static(_) => false, FunctionKind::Constructor(_) => false, FunctionKind::AsyncFreestanding => false, - FunctionKind::AsyncMethod(_) => todo!(), FunctionKind::AsyncStatic(_) => false, + FunctionKind::AsyncMethod(_) + | FunctionKind::Getter + | FunctionKind::Setter + | FunctionKind::MethodGetter(_) + | FunctionKind::MethodSetter(_) + | FunctionKind::StaticGetter(_) + | FunctionKind::StaticSetter(_) => todo!(), } { self.import_func(func); } @@ -1937,8 +1972,14 @@ impl<'a> InterfaceGenerator<'a> for DInterfaceGenerator<'a> { FunctionKind::Static(_) => false, FunctionKind::Constructor(_) => false, FunctionKind::AsyncFreestanding => false, - FunctionKind::AsyncMethod(_) => todo!(), FunctionKind::AsyncStatic(_) => false, + FunctionKind::AsyncMethod(_) + | FunctionKind::Getter + | FunctionKind::Setter + | FunctionKind::MethodGetter(_) + | FunctionKind::MethodSetter(_) + | FunctionKind::StaticGetter(_) + | FunctionKind::StaticSetter(_) => todo!(), } { self.import_func(func); } @@ -3398,6 +3439,12 @@ impl<'a, 'b> Bindgen for FunctionBindgen<'a, 'b> { | FunctionKind::Static(_) | FunctionKind::AsyncMethod(_) | FunctionKind::AsyncStatic(_) => func.name.split(".").skip(1).next().unwrap(), + FunctionKind::Getter + | FunctionKind::Setter + | FunctionKind::MethodGetter(_) + | FunctionKind::MethodSetter(_) + | FunctionKind::StaticGetter(_) + | FunctionKind::StaticSetter(_) => todo!(), }; let lower_name = split_name.to_lower_camel_case(); @@ -3422,6 +3469,12 @@ impl<'a, 'b> Bindgen for FunctionBindgen<'a, 'b> { )); true } + FunctionKind::Getter + | FunctionKind::Setter + | FunctionKind::MethodGetter(_) + | FunctionKind::MethodSetter(_) + | FunctionKind::StaticGetter(_) + | FunctionKind::StaticSetter(_) => todo!(), }; self.src.push_str( &operands diff --git a/crates/go/src/lib.rs b/crates/go/src/lib.rs index 1e21969de..be07f0d32 100644 --- a/crates/go/src/lib.rs +++ b/crates/go/src/lib.rs @@ -1720,6 +1720,12 @@ func wasm_export_{name}({params}) {results} {{ let camel = func.item_name().to_upper_camel_case(); (format!("{ty}{camel}"), false, "".to_string()) } + FunctionKind::Getter + | FunctionKind::Setter + | FunctionKind::MethodGetter(_) + | FunctionKind::MethodSetter(_) + | FunctionKind::StaticGetter(_) + | FunctionKind::StaticSetter(_) => todo!(), } } } @@ -2048,6 +2054,12 @@ for index := 0; index < int({length}); index++ {{ let ty = self.type_name(resolve, Type::Id(*ty)); format!("{ty}{name}({args})") } + FunctionKind::Getter + | FunctionKind::Setter + | FunctionKind::MethodGetter(_) + | FunctionKind::MethodSetter(_) + | FunctionKind::StaticGetter(_) + | FunctionKind::StaticSetter(_) => todo!(), }; if let Some(ty) = func.result { diff --git a/crates/moonbit/src/pkg.rs b/crates/moonbit/src/pkg.rs index b98343f23..2f01db0e8 100644 --- a/crates/moonbit/src/pkg.rs +++ b/crates/moonbit/src/pkg.rs @@ -112,6 +112,12 @@ impl PkgResolver { func.name.split(".").last().unwrap().to_moonbit_ident() ) } + FunctionKind::Getter + | FunctionKind::Setter + | FunctionKind::MethodGetter(_) + | FunctionKind::MethodSetter(_) + | FunctionKind::StaticGetter(_) + | FunctionKind::StaticSetter(_) => todo!(), } } diff --git a/crates/rust/src/bindgen.rs b/crates/rust/src/bindgen.rs index 70aeb67a5..3011f36b2 100644 --- a/crates/rust/src/bindgen.rs +++ b/crates/rust/src/bindgen.rs @@ -973,17 +973,27 @@ impl Bindgen for FunctionBindgen<'_, '_> { } self.push_str(&prev_src); let constructor_type = match &func.kind { - FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => { - self.push_str(&format!("T_::{}", to_rust_ident(func.item_name()))); - None - } - FunctionKind::Method(_) + FunctionKind::Freestanding + | FunctionKind::AsyncFreestanding + | FunctionKind::Getter + | FunctionKind::Method(_) + | FunctionKind::MethodGetter(_) | FunctionKind::Static(_) + | FunctionKind::StaticGetter(_) | FunctionKind::AsyncMethod(_) | FunctionKind::AsyncStatic(_) => { self.push_str(&format!("T_::{}", to_rust_ident(func.item_name()))); None } + FunctionKind::Setter + | FunctionKind::MethodSetter(_) + | FunctionKind::StaticSetter(_) => { + self.push_str(&format!( + "T_::{}", + to_rust_ident(&format!("set-{}", func.item_name())) + )); + None + } FunctionKind::Constructor(ty) => { let return_type = classify_constructor_return_type(resolve, *ty, &func.result); @@ -1017,8 +1027,13 @@ impl Bindgen for FunctionBindgen<'_, '_> { // `&Self` since traits have `&self` as their // first arguments. if i == 0 - && (matches!(func.kind, FunctionKind::Method(_)) - || matches!(func.kind, FunctionKind::AsyncMethod(_))) + && matches!( + func.kind, + FunctionKind::Method(_) + | FunctionKind::AsyncMethod(_) + | FunctionKind::MethodGetter(_) + | FunctionKind::MethodSetter(_) + ) { self.push_str(".get()") } diff --git a/crates/rust/src/interface.rs b/crates/rust/src/interface.rs index c79a22a55..778cd10b4 100644 --- a/crates/rust/src/interface.rs +++ b/crates/rust/src/interface.rs @@ -177,7 +177,6 @@ impl<'i> InterfaceGenerator<'i> { let prev = mem::take(&mut self.src); let mut sig = FnSig { async_, - use_item_name: true, private: true, ..Default::default() }; @@ -843,7 +842,6 @@ pub mod vtable{ordinal} {{ let name = self.resolve.types[id].name.as_ref().unwrap(); let name = to_upper_camel_case(name); uwriteln!(self.src, "impl {name} {{"); - sig.use_item_name = true; sig.update_for_func(&func, should_return_self); } self.src.push_str("#[allow(unused_unsafe, clippy::all)]\n"); @@ -1487,7 +1485,6 @@ unsafe fn call_import(&mut self, _params: Self::ParamsLower, _results: *mut u8) .is_async(self.resolve, interface.map(|p| p.1), func, false); let mut sig = FnSig { async_, - use_item_name: true, private: true, ..Default::default() }; @@ -1612,16 +1609,14 @@ unsafe fn call_import(&mut self, _params: Self::ParamsLower, _results: *mut u8) self.push_str("async "); } self.push_str("fn "); - let func_name = if sig.use_item_name { - if let FunctionKind::Constructor(_) = &func.kind { - "new" - } else { - func.item_name() - } - } else { - func.item_name() + let func_name = match &func.kind { + FunctionKind::Constructor(_) => "new".to_string(), + FunctionKind::Setter + | FunctionKind::MethodSetter(_) + | FunctionKind::StaticSetter(_) => format!("set-{}", func.item_name()), + _ => func.item_name().to_owned(), }; - self.push_str(&to_rust_ident(func_name)); + self.push_str(&to_rust_ident(&func_name)); if let Some(generics) = &sig.generics { self.push_str(generics); } diff --git a/crates/rust/src/lib.rs b/crates/rust/src/lib.rs index 94a2dacca..f56fdcb82 100644 --- a/crates/rust/src/lib.rs +++ b/crates/rust/src/lib.rs @@ -1034,6 +1034,7 @@ macro_rules! __export_{world_name}_impl {{ world_id, wit_component::StringEncoding::UTF8, Some(&producers), + false, ) .unwrap(); @@ -1778,7 +1779,6 @@ struct FnSig { async_: bool, unsafe_: bool, private: bool, - use_item_name: bool, generics: Option, self_arg: Option, self_is_first_param: bool, @@ -1786,7 +1786,11 @@ struct FnSig { impl FnSig { fn update_for_func(&mut self, func: &Function, return_self: Option) { - if let FunctionKind::Method(_) | FunctionKind::AsyncMethod(_) = &func.kind { + if let FunctionKind::Method(_) + | FunctionKind::AsyncMethod(_) + | FunctionKind::MethodGetter(_) + | FunctionKind::MethodSetter(_) = &func.kind + { self.self_arg = Some( match return_self { Some(ChainingMode::Owning) => "self", diff --git a/crates/rust/tests/codegen.rs b/crates/rust/tests/codegen.rs index 5cc96cf42..4ee716801 100644 --- a/crates/rust/tests/codegen.rs +++ b/crates/rust/tests/codegen.rs @@ -422,3 +422,142 @@ mod versioned_selectors { assert!(Alpha { x: 1 } < Alpha { x: 2 }); } } + +mod accessors { + wit_bindgen::generate!({ + inline: r#" + package test:accessors; + + interface i { + prop: get() -> u64; + prop: set(value: u64); + + read-only: get() -> string; + + fallible: get() -> u32; + fallible: set(value: u32) -> result<_, string>; + + %type: get() -> u32; + %type: set(value: u32); + + get: func(); + set: func(value: u32); + + resource blob { + constructor(); + position: get() -> u64; + position: set(value: u64); + label: get() -> string; + label: set(value: string) -> result<_, string>; + max-size: static get() -> u64; + max-size: static set(value: u64) -> result<_, string>; + } + } + + world test { + import i; + export i; + + import world-prop: get() -> u64; + import world-prop: set(value: u64); + export other-prop: get() -> string; + export other-prop: set(value: string) -> result<_, string>; + } + "#, + generate_all, + }); + + fn use_imports() { + use test::accessors::i::*; + + let _: u64 = prop(); + let _: () = set_prop(1); + let _: String = read_only(); + let _: u32 = fallible(); + let _: Result<(), String> = set_fallible(1); + let _: u32 = type_(); + let _: () = set_type(1); + let _: () = get(); + let _: () = set(1); + + let b = Blob::new(); + let _: u64 = b.position(); + let _: () = b.set_position(1); + let _: String = b.label(); + let _: Result<(), String> = b.set_label("x"); + let _: u64 = Blob::max_size(); + let _: Result<(), String> = Blob::set_max_size(1); + + let _: u64 = world_prop(); + let _: () = set_world_prop(1); + } + + struct Component; + + impl Guest for Component { + fn other_prop() -> String { + todo!() + } + fn set_other_prop(value: String) -> Result<(), String> { + todo!() + } + } + + impl exports::test::accessors::i::Guest for Component { + type Blob = MyBlob; + + fn prop() -> u64 { + todo!() + } + fn set_prop(value: u64) { + todo!() + } + fn read_only() -> String { + todo!() + } + fn fallible() -> u32 { + todo!() + } + fn set_fallible(value: u32) -> Result<(), String> { + todo!() + } + fn type_() -> u32 { + todo!() + } + fn set_type(value: u32) { + todo!() + } + fn get() { + todo!() + } + fn set(value: u32) { + todo!() + } + } + + struct MyBlob; + + impl exports::test::accessors::i::GuestBlob for MyBlob { + fn new() -> MyBlob { + todo!() + } + fn position(&self) -> u64 { + todo!() + } + fn set_position(&self, value: u64) { + todo!() + } + fn label(&self) -> String { + todo!() + } + fn set_label(&self, value: String) -> Result<(), String> { + todo!() + } + fn max_size() -> u64 { + todo!() + } + fn set_max_size(value: u64) -> Result<(), String> { + todo!() + } + } +} diff --git a/crates/test-helpers/src/lib.rs b/crates/test-helpers/src/lib.rs index f25088697..d764fdf52 100644 --- a/crates/test-helpers/src/lib.rs +++ b/crates/test-helpers/src/lib.rs @@ -99,7 +99,8 @@ pub fn run_component_codegen_test( let world_name = &resolve.worlds[world].name; let mut wasm = wit_component::dummy_module(&resolve, world, ManglingAndAbi::Standard32); let encoded = - wit_component::metadata::encode(&resolve, world, StringEncoding::UTF8, None).unwrap(); + wit_component::metadata::encode(&resolve, world, StringEncoding::UTF8, None, false) + .unwrap(); let section = wasm_encoder::CustomSection { name: std::borrow::Cow::Borrowed("component-type"), data: std::borrow::Cow::Borrowed(&encoded), diff --git a/crates/test/src/lib.rs b/crates/test/src/lib.rs index 2132a3cda..858631bb7 100644 --- a/crates/test/src/lib.rs +++ b/crates/test/src/lib.rs @@ -1123,8 +1123,13 @@ status: {}", let mut module = fs::read(&p1).context("failed to read wasm file")?; if !has_component_type_sections(&module) { - let encoded = - wit_component::metadata::encode(&resolve, world, StringEncoding::UTF8, None)?; + let encoded = wit_component::metadata::encode( + &resolve, + world, + StringEncoding::UTF8, + None, + false, + )?; let section = wasm_encoder::CustomSection { name: Cow::Borrowed("component-type"), data: Cow::Borrowed(&encoded), diff --git a/tests/runtime/accessors/cpp/exports-test-accessors-i-Blob.h b/tests/runtime/accessors/cpp/exports-test-accessors-i-Blob.h new file mode 100644 index 000000000..547ec26d8 --- /dev/null +++ b/tests/runtime/accessors/cpp/exports-test-accessors-i-Blob.h @@ -0,0 +1,61 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include "wit.h" +/* User class definition file, autogenerated once, then user modified +* Updated versions of this file are generated into Blob.template. +*/ +namespace exports { + namespace test { + namespace accessors { + namespace i { + class Blob : public wit::ResourceExportBase{ + + public: + + static void Dtor(i::Blob* self){delete self;} + Blob(wit::vector init) { + auto view = init.get_const_view(); + contents.assign(view.begin(), view.end()); + } + static Owned New(wit::vector init){return Owned(new Blob(std::move(init)));} + wit::vector Contents() { + return wit::vector::from_view(std::span(contents)); + } + uint64_t Position() { return position; } + void SetPosition(uint64_t value) { position = value; } + wit::string Label() { return wit::string::from_view(label); } + std::expected SetLabel(wit::string value) { + if (value.size() == 0) { + return std::unexpected(wit::string::from_view("label must not be empty")); + } + label = value.to_string(); + return std::expected(); + } + static uint64_t MaxSize() { return max_size; } + static std::expected SetMaxSize(uint64_t value) { + if (value == 0) { + return std::unexpected(wit::string::from_view("max size must be nonzero")); + } + max_size = value; + return std::expected(); + } + static int32_t ResourceNew(i::Blob* self); + static Blob* ResourceRep(int32_t id); + static void ResourceDrop(int32_t id); + + private: + std::vector contents; + uint64_t position = 0; + std::string label; + static inline uint64_t max_size = 1024; + }; + + } + } + } +} diff --git a/tests/runtime/accessors/runner.c b/tests/runtime/accessors/runner.c new file mode 100644 index 000000000..dddedd6c9 --- /dev/null +++ b/tests/runtime/accessors/runner.c @@ -0,0 +1,89 @@ +#include +#include +#include + +static void assert_str(runner_string_t *str, const char *expected) { + size_t expected_len = strlen(expected); + assert(str->len == expected_len); + assert(memcmp(str->ptr, expected, expected_len) == 0); +} + +void exports_runner_run(void) { + runner_string_t str; + runner_string_t err; + + assert(test_accessors_i_get_counter() == 0); + test_accessors_i_set_counter(5); + assert(test_accessors_i_get_counter() == 5); + test_accessors_i_set_counter(UINT32_MAX); + assert(test_accessors_i_get_counter() == UINT32_MAX); + + test_accessors_i_get_read_only(&str); + assert_str(&str, "read only"); + runner_string_free(&str); + + assert(test_accessors_i_get_bounded() == 0); + assert(test_accessors_i_set_bounded(10, &err)); + assert(test_accessors_i_get_bounded() == 10); + assert(!test_accessors_i_set_bounded(101, &err)); + assert_str(&err, "101 is out of bounds"); + runner_string_free(&err); + assert(test_accessors_i_get_bounded() == 10); + + uint8_t a_init[] = {1, 2, 3}; + uint8_t b_init[] = {4, 5}; + runner_list_u8_t a_list = {a_init, 3}; + runner_list_u8_t b_list = {b_init, 2}; + test_accessors_i_own_blob_t a_own = test_accessors_i_constructor_blob(&a_list); + test_accessors_i_own_blob_t b_own = test_accessors_i_constructor_blob(&b_list); + test_accessors_i_borrow_blob_t a = test_accessors_i_borrow_blob(a_own); + test_accessors_i_borrow_blob_t b = test_accessors_i_borrow_blob(b_own); + + runner_list_u8_t contents; + test_accessors_i_method_blob_contents(a, &contents); + assert(contents.len == 3); + assert(memcmp(contents.ptr, a_init, 3) == 0); + runner_list_u8_free(&contents); + + assert(test_accessors_i_method_get_blob_position(a) == 0); + assert(test_accessors_i_method_get_blob_position(b) == 0); + test_accessors_i_method_set_blob_position(a, 2); + assert(test_accessors_i_method_get_blob_position(a) == 2); + assert(test_accessors_i_method_get_blob_position(b) == 0); + test_accessors_i_method_set_blob_position(b, 1); + assert(test_accessors_i_method_get_blob_position(a) == 2); + assert(test_accessors_i_method_get_blob_position(b) == 1); + + test_accessors_i_method_get_blob_label(a, &str); + assert_str(&str, ""); + runner_string_free(&str); + + runner_string_t label; + runner_string_set(&label, "hello"); + assert(test_accessors_i_method_set_blob_label(a, &label, &err)); + test_accessors_i_method_get_blob_label(a, &str); + assert_str(&str, "hello"); + runner_string_free(&str); + test_accessors_i_method_get_blob_label(b, &str); + assert_str(&str, ""); + runner_string_free(&str); + + runner_string_set(&label, ""); + assert(!test_accessors_i_method_set_blob_label(a, &label, &err)); + assert_str(&err, "label must not be empty"); + runner_string_free(&err); + test_accessors_i_method_get_blob_label(a, &str); + assert_str(&str, "hello"); + runner_string_free(&str); + + assert(test_accessors_i_static_get_blob_max_size() == 1024); + assert(test_accessors_i_static_set_blob_max_size(2048, &err)); + assert(test_accessors_i_static_get_blob_max_size() == 2048); + assert(!test_accessors_i_static_set_blob_max_size(0, &err)); + assert_str(&err, "max size must be nonzero"); + runner_string_free(&err); + assert(test_accessors_i_static_get_blob_max_size() == 2048); + + test_accessors_i_blob_drop_own(a_own); + test_accessors_i_blob_drop_own(b_own); +} diff --git a/tests/runtime/accessors/runner.cpp b/tests/runtime/accessors/runner.cpp new file mode 100644 index 000000000..d3220a949 --- /dev/null +++ b/tests/runtime/accessors/runner.cpp @@ -0,0 +1,58 @@ +#include +#include +#include +#include + +namespace test_imports = ::test::accessors::i; + +static bool is_err(std::expected const& r, std::string_view msg) { + return !r.has_value() && r.error().get_view() == msg; +} + +static bool equal(wit::vector const& a, std::vector const& b) { + auto view = a.get_const_view(); + return std::vector(view.begin(), view.end()) == b; +} + +void exports::runner::Run() { + assert(test_imports::Counter() == 0); + test_imports::SetCounter(5); + assert(test_imports::Counter() == 5); + test_imports::SetCounter(UINT32_MAX); + assert(test_imports::Counter() == UINT32_MAX); + + assert(test_imports::ReadOnly().get_view() == "read only"); + + assert(test_imports::Bounded() == 0); + assert(test_imports::SetBounded(10).has_value()); + assert(test_imports::Bounded() == 10); + assert(is_err(test_imports::SetBounded(101), "101 is out of bounds")); + assert(test_imports::Bounded() == 10); + + std::vector a_init{1, 2, 3}; + std::vector b_init{4, 5}; + auto a = test_imports::Blob(std::span(a_init)); + auto b = test_imports::Blob(std::span(b_init)); + assert(equal(a.Contents(), a_init)); + assert(a.Position() == 0); + assert(b.Position() == 0); + a.SetPosition(2); + assert(a.Position() == 2); + assert(b.Position() == 0); + b.SetPosition(1); + assert(a.Position() == 2); + assert(b.Position() == 1); + + assert(a.Label().get_view() == ""); + assert(a.SetLabel("hello").has_value()); + assert(a.Label().get_view() == "hello"); + assert(b.Label().get_view() == ""); + assert(is_err(a.SetLabel(""), "label must not be empty")); + assert(a.Label().get_view() == "hello"); + + assert(test_imports::Blob::MaxSize() == 1024); + assert(test_imports::Blob::SetMaxSize(2048).has_value()); + assert(test_imports::Blob::MaxSize() == 2048); + assert(is_err(test_imports::Blob::SetMaxSize(0), "max size must be nonzero")); + assert(test_imports::Blob::MaxSize() == 2048); +} diff --git a/tests/runtime/accessors/runner.rs b/tests/runtime/accessors/runner.rs new file mode 100644 index 000000000..45794e80b --- /dev/null +++ b/tests/runtime/accessors/runner.rs @@ -0,0 +1,53 @@ +include!(env!("BINDINGS")); + +use crate::test::accessors::i::*; + +struct Component; + +export!(Component); + +impl Guest for Component { + fn run() { + assert_eq!(counter(), 0); + set_counter(5); + assert_eq!(counter(), 5); + set_counter(u32::MAX); + assert_eq!(counter(), u32::MAX); + + assert_eq!(read_only(), "read only"); + + assert_eq!(bounded(), 0); + assert_eq!(set_bounded(10), Ok(())); + assert_eq!(bounded(), 10); + assert_eq!(set_bounded(101), Err("101 is out of bounds".to_string())); + assert_eq!(bounded(), 10); + + let a = Blob::new(&[1, 2, 3]); + let b = Blob::new(&[4, 5]); + assert_eq!(a.contents(), [1, 2, 3]); + assert_eq!(a.position(), 0); + assert_eq!(b.position(), 0); + a.set_position(2); + assert_eq!(a.position(), 2); + assert_eq!(b.position(), 0); + b.set_position(1); + assert_eq!(a.position(), 2); + assert_eq!(b.position(), 1); + + assert_eq!(a.label(), ""); + assert_eq!(a.set_label("hello"), Ok(())); + assert_eq!(a.label(), "hello"); + assert_eq!(b.label(), ""); + assert_eq!(a.set_label(""), Err("label must not be empty".to_string())); + assert_eq!(a.label(), "hello"); + + assert_eq!(Blob::max_size(), 1024); + assert_eq!(Blob::set_max_size(2048), Ok(())); + assert_eq!(Blob::max_size(), 2048); + assert_eq!( + Blob::set_max_size(0), + Err("max size must be nonzero".to_string()) + ); + assert_eq!(Blob::max_size(), 2048); + } +} diff --git a/tests/runtime/accessors/test.c b/tests/runtime/accessors/test.c new file mode 100644 index 000000000..2af99684c --- /dev/null +++ b/tests/runtime/accessors/test.c @@ -0,0 +1,98 @@ +#include +#include +#include +#include +#include + +static uint32_t COUNTER = 0; +static uint32_t BOUNDED = 0; +static uint64_t MAX_SIZE = 1024; + +uint32_t exports_test_accessors_i_get_counter(void) { + return COUNTER; +} + +void exports_test_accessors_i_set_counter(uint32_t value) { + COUNTER = value; +} + +void exports_test_accessors_i_get_read_only(test_string_t *ret) { + test_string_dup(ret, "read only"); +} + +uint32_t exports_test_accessors_i_get_bounded(void) { + return BOUNDED; +} + +bool exports_test_accessors_i_set_bounded(uint32_t value, test_string_t *err) { + if (value > 100) { + char buf[64]; + snprintf(buf, sizeof(buf), "%" PRIu32 " is out of bounds", value); + test_string_dup(err, buf); + return false; + } + BOUNDED = value; + return true; +} + +struct exports_test_accessors_i_blob_t { + test_list_u8_t contents; + uint64_t position; + test_string_t label; +}; + +exports_test_accessors_i_own_blob_t exports_test_accessors_i_constructor_blob(test_list_u8_t *init) { + exports_test_accessors_i_blob_t *blob = (exports_test_accessors_i_blob_t *) malloc(sizeof(exports_test_accessors_i_blob_t)); + blob->contents = *init; + blob->position = 0; + test_string_dup(&blob->label, ""); + return exports_test_accessors_i_blob_new(blob); +} + +void exports_test_accessors_i_method_blob_contents(exports_test_accessors_i_borrow_blob_t self, test_list_u8_t *ret) { + ret->len = self->contents.len; + ret->ptr = (uint8_t *) malloc(ret->len); + memcpy(ret->ptr, self->contents.ptr, ret->len); +} + +uint64_t exports_test_accessors_i_method_get_blob_position(exports_test_accessors_i_borrow_blob_t self) { + return self->position; +} + +void exports_test_accessors_i_method_set_blob_position(exports_test_accessors_i_borrow_blob_t self, uint64_t value) { + self->position = value; +} + +void exports_test_accessors_i_method_get_blob_label(exports_test_accessors_i_borrow_blob_t self, test_string_t *ret) { + test_string_dup_n(ret, (const char *) self->label.ptr, self->label.len); +} + +bool exports_test_accessors_i_method_set_blob_label(exports_test_accessors_i_borrow_blob_t self, test_string_t *value, test_string_t *err) { + if (value->len == 0) { + test_string_free(value); + test_string_dup(err, "label must not be empty"); + return false; + } + test_string_free(&self->label); + self->label = *value; + return true; +} + +uint64_t exports_test_accessors_i_static_get_blob_max_size(void) { + return MAX_SIZE; +} + +bool exports_test_accessors_i_static_set_blob_max_size(uint64_t value, test_string_t *err) { + if (value == 0) { + test_string_dup(err, "max size must be nonzero"); + return false; + } + MAX_SIZE = value; + return true; +} + +void exports_test_accessors_i_blob_destructor(exports_test_accessors_i_blob_t *rep) { + test_list_u8_free(&rep->contents); + test_string_free(&rep->label); + free(rep); +} diff --git a/tests/runtime/accessors/test.cpp b/tests/runtime/accessors/test.cpp new file mode 100644 index 000000000..34f53d54f --- /dev/null +++ b/tests/runtime/accessors/test.cpp @@ -0,0 +1,31 @@ +#include +#include + +namespace test_exports = ::exports::test::accessors::i; + +static uint32_t counter = 0; +static uint32_t bounded = 0; + +uint32_t test_exports::Counter() { + return counter; +} + +void test_exports::SetCounter(uint32_t value) { + counter = value; +} + +wit::string test_exports::ReadOnly() { + return wit::string::from_view("read only"); +} + +uint32_t test_exports::Bounded() { + return bounded; +} + +std::expected test_exports::SetBounded(uint32_t value) { + if (value > 100) { + return std::unexpected(wit::string::from_view(std::to_string(value) + " is out of bounds")); + } + bounded = value; + return std::expected(); +} diff --git a/tests/runtime/accessors/test.rs b/tests/runtime/accessors/test.rs new file mode 100644 index 000000000..045a2c928 --- /dev/null +++ b/tests/runtime/accessors/test.rs @@ -0,0 +1,92 @@ +include!(env!("BINDINGS")); + +use crate::exports::test::accessors::i::{Guest, GuestBlob}; +use std::cell::{Cell, RefCell}; + +struct Component; + +export!(Component); + +static mut COUNTER: u32 = 0; +static mut BOUNDED: u32 = 0; +static mut MAX_SIZE: u64 = 1024; + +impl Guest for Component { + type Blob = MyBlob; + + fn counter() -> u32 { + unsafe { COUNTER } + } + + fn set_counter(value: u32) { + unsafe { COUNTER = value } + } + + fn read_only() -> String { + "read only".to_string() + } + + fn bounded() -> u32 { + unsafe { BOUNDED } + } + + fn set_bounded(value: u32) -> Result<(), String> { + if value > 100 { + return Err(format!("{value} is out of bounds")); + } + unsafe { BOUNDED = value } + Ok(()) + } +} + +struct MyBlob { + contents: Vec, + position: Cell, + label: RefCell, +} + +impl GuestBlob for MyBlob { + fn new(init: Vec) -> MyBlob { + MyBlob { + contents: init, + position: Cell::new(0), + label: RefCell::new(String::new()), + } + } + + fn contents(&self) -> Vec { + self.contents.clone() + } + + fn position(&self) -> u64 { + self.position.get() + } + + fn set_position(&self, value: u64) { + self.position.set(value); + } + + fn label(&self) -> String { + self.label.borrow().clone() + } + + fn set_label(&self, value: String) -> Result<(), String> { + if value.is_empty() { + return Err("label must not be empty".to_string()); + } + *self.label.borrow_mut() = value; + Ok(()) + } + + fn max_size() -> u64 { + unsafe { MAX_SIZE } + } + + fn set_max_size(value: u64) -> Result<(), String> { + if value == 0 { + return Err("max size must be nonzero".to_string()); + } + unsafe { MAX_SIZE = value } + Ok(()) + } +} diff --git a/tests/runtime/accessors/test.wit b/tests/runtime/accessors/test.wit new file mode 100644 index 000000000..7808ef65b --- /dev/null +++ b/tests/runtime/accessors/test.wit @@ -0,0 +1,35 @@ +package test:accessors; + +interface i { + counter: get() -> u32; + counter: set(value: u32); + + read-only: get() -> string; + + bounded: get() -> u32; + bounded: set(value: u32) -> result<_, string>; + + resource blob { + constructor(init: list); + contents: func() -> list; + + position: get() -> u64; + position: set(value: u64); + + label: get() -> string; + label: set(value: string) -> result<_, string>; + + max-size: static get() -> u64; + max-size: static set(value: u64) -> result<_, string>; + } +} + +world runner { + import i; + + export run: func(); +} + +world test { + export i; +}