diff --git a/Cargo.lock b/Cargo.lock index 0c756b8f9f1a..5f35e2e5eb3d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -259,7 +259,7 @@ checksum = "769f8cd02eb04d57f14e2e371ebb533f96817f9b2525d73a5c72b61ca7973747" dependencies = [ "cap-primitives", "cap-std", - "io-lifetimes", + "io-lifetimes 2.0.3", "windows-sys 0.52.0", ] @@ -271,7 +271,7 @@ checksum = "59ff6d3fb274292a9af283417e383afe6ded1fe66f6472d2c781216d3d80c218" dependencies = [ "cap-primitives", "cap-std", - "rustix", + "rustix 0.38.31", "smallvec", ] @@ -284,10 +284,10 @@ dependencies = [ "ambient-authority", "fs-set-times", "io-extras", - "io-lifetimes", + "io-lifetimes 2.0.3", "ipnet", "maybe-owned", - "rustix", + "rustix 0.38.31", "windows-sys 0.52.0", "winx", ] @@ -310,8 +310,8 @@ checksum = "266626ce180cf9709f317d0bf9754e3a5006359d87f4bf792f06c9c5f1b63c0f" dependencies = [ "cap-primitives", "io-extras", - "io-lifetimes", - "rustix", + "io-lifetimes 2.0.3", + "rustix 0.38.31", ] [[package]] @@ -324,7 +324,7 @@ dependencies = [ "cap-primitives", "iana-time-zone", "once_cell", - "rustix", + "rustix 0.38.31", "winx", ] @@ -441,6 +441,7 @@ dependencies = [ "anstyle", "clap_lex", "strsim", + "terminal_size 0.2.6", ] [[package]] @@ -531,7 +532,7 @@ dependencies = [ "libc", "once_cell", "regex", - "terminal_size", + "terminal_size 0.1.17", "unicode-width", "winapi", ] @@ -1152,7 +1153,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e5768da2206272c81ef0b5e951a41862938a6070da63bcea197899942d3b947" dependencies = [ "cfg-if", - "rustix", + "rustix 0.38.31", "windows-sys 0.52.0", ] @@ -1225,8 +1226,8 @@ version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "033b337d725b97690d86893f9de22b67b80dcc4e9ad815f348254c38119db8fb" dependencies = [ - "io-lifetimes", - "rustix", + "io-lifetimes 2.0.3", + "rustix 0.38.31", "windows-sys 0.52.0", ] @@ -1597,10 +1598,21 @@ version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c301e73fb90e8a29e600a9f402d095765f74310d582916a952f618836a1bd1ed" dependencies = [ - "io-lifetimes", + "io-lifetimes 2.0.3", "windows-sys 0.52.0", ] +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.48.0", +] + [[package]] name = "io-lifetimes" version = "2.0.3" @@ -1620,7 +1632,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bad00257d07be169d870ab665980b06cdb366d792ad690bf2e76876dc503455" dependencies = [ "hermit-abi", - "rustix", + "rustix 0.38.31", "windows-sys 0.52.0", ] @@ -1762,6 +1774,12 @@ dependencies = [ "threadpool", ] +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + [[package]] name = "linux-raw-sys" version = "0.4.12" @@ -1833,7 +1851,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2cffa4ad52c6f791f4f8b15f0c05f9824b2ced1160e88cc393d64fff9a8ac64" dependencies = [ - "rustix", + "rustix 0.38.31", ] [[package]] @@ -2368,6 +2386,20 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustix" +version = "0.37.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" +dependencies = [ + "bitflags 1.3.2", + "errno", + "io-lifetimes 1.0.11", + "libc", + "linux-raw-sys 0.3.8", + "windows-sys 0.48.0", +] + [[package]] name = "rustix" version = "0.38.31" @@ -2378,7 +2410,7 @@ dependencies = [ "errno", "itoa", "libc", - "linux-raw-sys", + "linux-raw-sys 0.4.12", "once_cell", "windows-sys 0.52.0", ] @@ -2699,8 +2731,8 @@ dependencies = [ "cap-fs-ext", "cap-std", "fd-lock", - "io-lifetimes", - "rustix", + "io-lifetimes 2.0.3", + "rustix 0.38.31", "windows-sys 0.52.0", "winx", ] @@ -2731,7 +2763,7 @@ dependencies = [ "cfg-if", "fastrand", "redox_syscall 0.3.5", - "rustix", + "rustix 0.38.31", "windows-sys 0.48.0", ] @@ -2754,6 +2786,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "terminal_size" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237" +dependencies = [ + "rustix 0.37.27", + "windows-sys 0.48.0", +] + [[package]] name = "test-log" version = "0.2.11" @@ -3173,11 +3215,11 @@ dependencies = [ "cap-time-ext", "fs-set-times", "io-extras", - "io-lifetimes", + "io-lifetimes 2.0.3", "libc", "log", "once_cell", - "rustix", + "rustix 0.38.31", "system-interface", "tempfile", "test-log", @@ -3456,7 +3498,7 @@ dependencies = [ "psm", "rand", "rayon", - "rustix", + "rustix 0.38.31", "semver", "serde", "serde_derive", @@ -3554,7 +3596,7 @@ dependencies = [ "once_cell", "postcard", "pretty_env_logger", - "rustix", + "rustix 0.38.31", "serde", "serde_derive", "sha2", @@ -3597,7 +3639,7 @@ dependencies = [ "object", "once_cell", "rayon", - "rustix", + "rustix 0.38.31", "serde", "serde_derive", "serde_json", @@ -3767,7 +3809,7 @@ dependencies = [ "backtrace", "cc", "cfg-if", - "rustix", + "rustix 0.38.31", "wasmtime-asm-macros", "wasmtime-versioned-export-macros", "windows-sys 0.52.0", @@ -3837,7 +3879,7 @@ version = "25.0.0" dependencies = [ "object", "once_cell", - "rustix", + "rustix 0.38.31", "wasmtime-versioned-export-macros", ] @@ -3902,9 +3944,9 @@ dependencies = [ "fs-set-times", "futures", "io-extras", - "io-lifetimes", + "io-lifetimes 2.0.3", "once_cell", - "rustix", + "rustix 0.38.31", "system-interface", "tempfile", "test-log", @@ -3996,6 +4038,7 @@ dependencies = [ "rand", "wasi-common", "wasmtime", + "wasmtime-wasi", ] [[package]] @@ -4094,7 +4137,7 @@ dependencies = [ "either", "home", "once_cell", - "rustix", + "rustix 0.38.31", "windows-sys 0.48.0", ] @@ -4537,8 +4580,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" dependencies = [ "libc", - "linux-raw-sys", - "rustix", + "linux-raw-sys 0.4.12", + "rustix 0.38.31", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index a3fa2e5d1717..f495286d1550 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,7 +50,7 @@ wasmtime-cranelift = { workspace = true, optional = true } wasmtime-environ = { workspace = true } wasmtime-explorer = { workspace = true, optional = true } wasmtime-wast = { workspace = true, optional = true } -wasi-common = { workspace = true, default-features = true, features = ["exit"], optional = true } +wasi-common = { workspace = true, default-features = true, features = ["exit", "tokio"], optional = true } wasmtime-wasi = { workspace = true, default-features = true, optional = true } wasmtime-wasi-nn = { workspace = true, optional = true } wasmtime-wasi-runtime-config = { workspace = true, optional = true } @@ -113,7 +113,7 @@ test-programs-artifacts = { workspace = true } bytesize = "1.3.0" wit-component = { workspace = true } cranelift-filetests = { workspace = true } -cranelift-codegen = { workspace = true } +cranelift-codegen = { workspace = true, features = ["disas", "trace-log", "timing"] } cranelift-reader = { workspace = true } toml = { workspace = true } similar = { workspace = true } @@ -391,6 +391,7 @@ default = [ # cost, so allow disabling this through disabling of our own `default` # feature. "clap/default", + "clap/wrap_help", ] # ======================================== @@ -473,7 +474,7 @@ explore = ["dep:wasmtime-explorer", "dep:tempfile"] wast = ["dep:wasmtime-wast"] config = ["cache"] compile = ["cranelift"] -run = ["dep:wasmtime-wasi", "wasmtime/runtime", "dep:listenfd", "dep:wasi-common"] +run = ["dep:wasmtime-wasi", "wasmtime/runtime", "dep:listenfd", "dep:wasi-common", "dep:tokio"] [[test]] name = "host_segfault" diff --git a/cranelift/codegen/src/opts/icmp.isle b/cranelift/codegen/src/opts/icmp.isle index 024e6668f02a..b838fd39720c 100644 --- a/cranelift/codegen/src/opts/icmp.isle +++ b/cranelift/codegen/src/opts/icmp.isle @@ -15,14 +15,14 @@ ;; Optimize icmp-of-icmp. ;; ne(icmp(ty, cc, x, y), 0) == icmp(ty, cc, x, y) -;; e.g. neq(ugt(x, y), 0) == ugt(x, y) +;; e.g. neq(ugt(x, y), 0) == ugt(x, y) (rule (simplify (ne ty (uextend_maybe _ inner @ (icmp ty _ _ _)) (iconst_u _ 0))) (subsume inner)) ;; eq(icmp(ty, cc, x, y), 0) == icmp(ty, cc_complement, x, y) -;; e.g. eq(ugt(x, y), 0) == ule(x, y) +;; e.g. eq(ugt(x, y), 0) == ule(x, y) (rule (simplify (eq ty (uextend_maybe _ (icmp ty cc x y)) (iconst_u _ 0))) @@ -213,3 +213,46 @@ (rule (intcc_class (IntCC.SignedGreaterThanOrEqual)) 2) (rule (intcc_class (IntCC.Equal)) 3) (rule (intcc_class (IntCC.NotEqual)) 3) + +;; Pattern-match what LLVM emits today for 128-bit comparisons into actual +;; 128-bit comparisons. Platforms like x64 and aarch64 have more optimal +;; lowerings for 128-bit arithmetic than the default structure. +(rule (simplify (select ty (eq _ a_hi @ (value_type $I64) b_hi @ (value_type $I64)) + (uge ty a_lo @ (value_type $I64) b_lo @ (value_type $I64)) + (uge ty a_hi b_hi))) + (uge ty (iconcat $I64 a_lo a_hi) (iconcat $I64 b_lo b_hi))) + +(rule (simplify (select ty (eq _ a_hi @ (value_type $I64) b_hi @ (value_type $I64)) + (uge ty a_lo @ (value_type $I64) b_lo @ (value_type $I64)) + (sge ty a_hi b_hi))) + (sge ty (iconcat $I64 a_lo a_hi) (iconcat $I64 b_lo b_hi))) + +(rule (simplify (select ty (eq _ a_hi @ (value_type $I64) b_hi @ (value_type $I64)) + (ugt ty a_lo @ (value_type $I64) b_lo @ (value_type $I64)) + (ugt ty a_hi b_hi))) + (ugt ty (iconcat $I64 a_lo a_hi) (iconcat $I64 b_lo b_hi))) + +(rule (simplify (select ty (eq _ a_hi @ (value_type $I64) b_hi @ (value_type $I64)) + (ugt ty a_lo @ (value_type $I64) b_lo @ (value_type $I64)) + (sgt ty a_hi b_hi))) + (sgt ty (iconcat $I64 a_lo a_hi) (iconcat $I64 b_lo b_hi))) + +(rule (simplify (select ty (eq _ a_hi @ (value_type $I64) b_hi @ (value_type $I64)) + (ule ty a_lo @ (value_type $I64) b_lo @ (value_type $I64)) + (ule ty a_hi b_hi))) + (ule ty (iconcat $I64 a_lo a_hi) (iconcat $I64 b_lo b_hi))) + +(rule (simplify (select ty (eq _ a_hi @ (value_type $I64) b_hi @ (value_type $I64)) + (ule ty a_lo @ (value_type $I64) b_lo @ (value_type $I64)) + (sle ty a_hi b_hi))) + (sle ty (iconcat $I64 a_lo a_hi) (iconcat $I64 b_lo b_hi))) + +(rule (simplify (select ty (eq _ a_hi @ (value_type $I64) b_hi @ (value_type $I64)) + (ult ty a_lo @ (value_type $I64) b_lo @ (value_type $I64)) + (ult ty a_hi b_hi))) + (ult ty (iconcat $I64 a_lo a_hi) (iconcat $I64 b_lo b_hi))) + +(rule (simplify (select ty (eq _ a_hi @ (value_type $I64) b_hi @ (value_type $I64)) + (ult ty a_lo @ (value_type $I64) b_lo @ (value_type $I64)) + (slt ty a_hi b_hi))) + (slt ty (iconcat $I64 a_lo a_hi) (iconcat $I64 b_lo b_hi))) diff --git a/cranelift/codegen/src/opts/selects.isle b/cranelift/codegen/src/opts/selects.isle index d0e06f855604..2968f05daba5 100644 --- a/cranelift/codegen/src/opts/selects.isle +++ b/cranelift/codegen/src/opts/selects.isle @@ -75,3 +75,14 @@ (rule (simplify (bor (ty_vec128 ty) (band ty (bnot ty c) y) (band ty x c))) (bitselect ty c x y)) (rule (simplify (bor (ty_vec128 ty) (band ty y (bnot ty c)) (band ty c x))) (bitselect ty c x y)) (rule (simplify (bor (ty_vec128 ty) (band ty y (bnot ty c)) (band ty x c))) (bitselect ty c x y)) + +;; Lift an extend operation outside of a `select` if the extend is happening +;; on both the consequent and the alternative. +(rule (simplify (select ty cond + (uextend ty a @ (value_type small)) + (uextend ty b @ (value_type small)))) + (uextend ty (select small cond a b))) +(rule (simplify (select ty cond + (sextend ty a @ (value_type small)) + (sextend ty b @ (value_type small)))) + (sextend ty (select small cond a b))) diff --git a/cranelift/filetests/filetests/egraph/select.clif b/cranelift/filetests/filetests/egraph/select.clif index 8b916e90d466..2cde44efaa56 100644 --- a/cranelift/filetests/filetests/egraph/select.clif +++ b/cranelift/filetests/filetests/egraph/select.clif @@ -208,3 +208,25 @@ block0(v0: i32, v1: i32): ; check: v6 = icmp sgt v0, v1 ; check: v8 = bmask.i64 v6 ; check: return v8 + +function %lift_uextend_out_of_select(i8, i32, i32) -> i64 { +block0(v0: i8, v1: i32, v2: i32): + v3 = uextend.i64 v1 + v4 = uextend.i64 v2 + v5 = select v0, v3, v4 + return v5 +} +; check: v6 = select v0, v1, v2 +; check: v7 = uextend.i64 v6 +; check: return v7 + +function %lift_sextend_out_of_select(i8, i32, i32) -> i64 { +block0(v0: i8, v1: i32, v2: i32): + v3 = sextend.i64 v1 + v4 = sextend.i64 v2 + v5 = select v0, v3, v4 + return v5 +} +; check: v6 = select v0, v1, v2 +; check: v7 = sextend.i64 v6 +; check: return v7 diff --git a/crates/component-macro/tests/expanded/char.rs b/crates/component-macro/tests/expanded/char.rs index a8b1a428dcc0..c8e1b9436487 100644 --- a/crates/component-macro/tests/expanded/char.rs +++ b/crates/component-macro/tests/expanded/char.rs @@ -4,69 +4,146 @@ /// This structure is created through [`TheWorldPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`TheWorld`] as well. pub struct TheWorldPre { instance_pre: wasmtime::component::InstancePre, - interface0: exports::foo::foo::chars::GuestPre, + indices: TheWorldIndices, } impl Clone for TheWorldPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), - interface0: self.interface0.clone(), + indices: self.indices.clone(), } } } +impl<_T> TheWorldPre<_T> { + /// Creates a new copy of `TheWorldPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`TheWorld`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub fn instantiate( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate(&mut store)?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `the-world`. +/// +/// This is an implementation detail of [`TheWorldPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`TheWorld`] as well. +#[derive(Clone)] +pub struct TheWorldIndices { + interface0: exports::foo::foo::chars::GuestIndices, +} /// Auto-generated bindings for an instance a component which /// implements the world `the-world`. /// -/// This structure is created through either -/// [`TheWorld::instantiate`] or by first creating -/// a [`TheWorldPre`] followed by using -/// [`TheWorldPre::instantiate`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`TheWorld::instantiate`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`TheWorldPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`TheWorldPre::instantiate`] to +/// create a [`TheWorld`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`TheWorld::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`TheWorldIndices::new_instance`] followed +/// by [`TheWorldIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct TheWorld { interface0: exports::foo::foo::chars::Guest, } const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> TheWorldPre<_T> { - /// Creates a new copy of `TheWorldPre` bindings which can then + impl TheWorldIndices { + /// Creates a new copy of `TheWorldIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, + ) -> wasmtime::Result { + let _component = component; + let interface0 = exports::foo::foo::chars::GuestIndices::new(_component)?; + Ok(TheWorldIndices { interface0 }) + } + /// Creates a new instance of [`TheWorldIndices`] from an + /// instantiated component. + /// + /// This method of creating a [`TheWorld`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`TheWorld`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let _component = instance_pre.component(); - let interface0 = exports::foo::foo::chars::GuestPre::new(_component)?; - Ok(TheWorldPre { - instance_pre, - interface0, - }) + let _instance = instance; + let interface0 = exports::foo::foo::chars::GuestIndices::new_instance( + &mut store, + _instance, + )?; + Ok(TheWorldIndices { interface0 }) } - /// Instantiates a new instance of [`TheWorld`] within the - /// `store` provided. + /// Uses the indices stored in `self` to load an instance + /// of [`TheWorld`] from the instance provided. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub fn instantiate( + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate(&mut store)?; + let _instance = instance; let interface0 = self.interface0.load(&mut store, &_instance)?; Ok(TheWorld { interface0 }) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl TheWorld { /// Convenience wrapper around [`TheWorldPre::new`] and @@ -79,6 +156,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate(store) } + /// Convenience wrapper around [`TheWorldIndices::new_instance`] and + /// [`TheWorldIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker( linker: &mut wasmtime::component::Linker, get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, @@ -178,15 +264,20 @@ pub mod exports { return_char: wasmtime::component::Func, } #[derive(Clone)] - pub struct GuestPre { + pub struct GuestIndices { take_char: wasmtime::component::ComponentExportIndex, return_char: wasmtime::component::ComponentExportIndex, } - impl GuestPre { + impl GuestIndices { + /// Constructor for [`GuestIndices`] which takes a + /// [`Component`](wasmtime::component::Component) as input and can be executed + /// before instantiation. + /// + /// This constructor can be used to front-load string lookups to find exports + /// within a component. pub fn new( component: &wasmtime::component::Component, - ) -> wasmtime::Result { - let _component = component; + ) -> wasmtime::Result { let (_, instance) = component .export_index(None, "foo:foo/chars") .ok_or_else(|| { @@ -194,10 +285,34 @@ pub mod exports { "no exported instance named `foo:foo/chars`" ) })?; - let _lookup = |name: &str| { - _component - .export_index(Some(&instance), name) - .map(|p| p.1) + Self::_new(|name| { + component.export_index(Some(&instance), name).map(|p| p.1) + }) + } + /// This constructor is similar to [`GuestIndices::new`] except that it + /// performs string lookups after instantiation time. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let instance_export = instance + .get_export(&mut store, None, "foo:foo/chars") + .ok_or_else(|| { + anyhow::anyhow!( + "no exported instance named `foo:foo/chars`" + ) + })?; + Self::_new(|name| { + instance.get_export(&mut store, Some(&instance_export), name) + }) + } + fn _new( + mut lookup: impl FnMut( + &str, + ) -> Option, + ) -> wasmtime::Result { + let mut lookup = move |name| { + lookup(name) .ok_or_else(|| { anyhow::anyhow!( "instance export `foo:foo/chars` does \ @@ -205,9 +320,13 @@ pub mod exports { ) }) }; - let take_char = _lookup("take-char")?; - let return_char = _lookup("return-char")?; - Ok(GuestPre { take_char, return_char }) + let _ = &mut lookup; + let take_char = lookup("take-char")?; + let return_char = lookup("return-char")?; + Ok(GuestIndices { + take_char, + return_char, + }) } pub fn load( &self, diff --git a/crates/component-macro/tests/expanded/char_async.rs b/crates/component-macro/tests/expanded/char_async.rs index e565be5dceeb..6fbcfca5517b 100644 --- a/crates/component-macro/tests/expanded/char_async.rs +++ b/crates/component-macro/tests/expanded/char_async.rs @@ -4,72 +4,149 @@ /// This structure is created through [`TheWorldPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`TheWorld`] as well. pub struct TheWorldPre { instance_pre: wasmtime::component::InstancePre, - interface0: exports::foo::foo::chars::GuestPre, + indices: TheWorldIndices, } impl Clone for TheWorldPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), - interface0: self.interface0.clone(), + indices: self.indices.clone(), } } } +impl<_T> TheWorldPre<_T> { + /// Creates a new copy of `TheWorldPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`TheWorld`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub async fn instantiate_async( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result + where + _T: Send, + { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate_async(&mut store).await?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `the-world`. +/// +/// This is an implementation detail of [`TheWorldPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`TheWorld`] as well. +#[derive(Clone)] +pub struct TheWorldIndices { + interface0: exports::foo::foo::chars::GuestIndices, +} /// Auto-generated bindings for an instance a component which /// implements the world `the-world`. /// -/// This structure is created through either -/// [`TheWorld::instantiate_async`] or by first creating -/// a [`TheWorldPre`] followed by using -/// [`TheWorldPre::instantiate_async`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`TheWorld::instantiate_async`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`TheWorldPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`TheWorldPre::instantiate_async`] to +/// create a [`TheWorld`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`TheWorld::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`TheWorldIndices::new_instance`] followed +/// by [`TheWorldIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct TheWorld { interface0: exports::foo::foo::chars::Guest, } const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> TheWorldPre<_T> { - /// Creates a new copy of `TheWorldPre` bindings which can then + impl TheWorldIndices { + /// Creates a new copy of `TheWorldIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, + ) -> wasmtime::Result { + let _component = component; + let interface0 = exports::foo::foo::chars::GuestIndices::new(_component)?; + Ok(TheWorldIndices { interface0 }) + } + /// Creates a new instance of [`TheWorldIndices`] from an + /// instantiated component. + /// + /// This method of creating a [`TheWorld`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`TheWorld`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let _component = instance_pre.component(); - let interface0 = exports::foo::foo::chars::GuestPre::new(_component)?; - Ok(TheWorldPre { - instance_pre, - interface0, - }) + let _instance = instance; + let interface0 = exports::foo::foo::chars::GuestIndices::new_instance( + &mut store, + _instance, + )?; + Ok(TheWorldIndices { interface0 }) } - /// Instantiates a new instance of [`TheWorld`] within the - /// `store` provided. + /// Uses the indices stored in `self` to load an instance + /// of [`TheWorld`] from the instance provided. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub async fn instantiate_async( + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate_async(&mut store).await?; + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; let interface0 = self.interface0.load(&mut store, &_instance)?; Ok(TheWorld { interface0 }) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl TheWorld { /// Convenience wrapper around [`TheWorldPre::new`] and @@ -85,6 +162,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate_async(store).await } + /// Convenience wrapper around [`TheWorldIndices::new_instance`] and + /// [`TheWorldIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker( linker: &mut wasmtime::component::Linker, get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, @@ -191,15 +277,20 @@ pub mod exports { return_char: wasmtime::component::Func, } #[derive(Clone)] - pub struct GuestPre { + pub struct GuestIndices { take_char: wasmtime::component::ComponentExportIndex, return_char: wasmtime::component::ComponentExportIndex, } - impl GuestPre { + impl GuestIndices { + /// Constructor for [`GuestIndices`] which takes a + /// [`Component`](wasmtime::component::Component) as input and can be executed + /// before instantiation. + /// + /// This constructor can be used to front-load string lookups to find exports + /// within a component. pub fn new( component: &wasmtime::component::Component, - ) -> wasmtime::Result { - let _component = component; + ) -> wasmtime::Result { let (_, instance) = component .export_index(None, "foo:foo/chars") .ok_or_else(|| { @@ -207,10 +298,34 @@ pub mod exports { "no exported instance named `foo:foo/chars`" ) })?; - let _lookup = |name: &str| { - _component - .export_index(Some(&instance), name) - .map(|p| p.1) + Self::_new(|name| { + component.export_index(Some(&instance), name).map(|p| p.1) + }) + } + /// This constructor is similar to [`GuestIndices::new`] except that it + /// performs string lookups after instantiation time. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let instance_export = instance + .get_export(&mut store, None, "foo:foo/chars") + .ok_or_else(|| { + anyhow::anyhow!( + "no exported instance named `foo:foo/chars`" + ) + })?; + Self::_new(|name| { + instance.get_export(&mut store, Some(&instance_export), name) + }) + } + fn _new( + mut lookup: impl FnMut( + &str, + ) -> Option, + ) -> wasmtime::Result { + let mut lookup = move |name| { + lookup(name) .ok_or_else(|| { anyhow::anyhow!( "instance export `foo:foo/chars` does \ @@ -218,9 +333,13 @@ pub mod exports { ) }) }; - let take_char = _lookup("take-char")?; - let return_char = _lookup("return-char")?; - Ok(GuestPre { take_char, return_char }) + let _ = &mut lookup; + let take_char = lookup("take-char")?; + let return_char = lookup("return-char")?; + Ok(GuestIndices { + take_char, + return_char, + }) } pub fn load( &self, diff --git a/crates/component-macro/tests/expanded/conventions.rs b/crates/component-macro/tests/expanded/conventions.rs index 1857ae385fa2..631be530d8b8 100644 --- a/crates/component-macro/tests/expanded/conventions.rs +++ b/crates/component-macro/tests/expanded/conventions.rs @@ -4,69 +4,148 @@ /// This structure is created through [`TheWorldPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`TheWorld`] as well. pub struct TheWorldPre { instance_pre: wasmtime::component::InstancePre, - interface0: exports::foo::foo::conventions::GuestPre, + indices: TheWorldIndices, } impl Clone for TheWorldPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), - interface0: self.interface0.clone(), + indices: self.indices.clone(), } } } +impl<_T> TheWorldPre<_T> { + /// Creates a new copy of `TheWorldPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`TheWorld`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub fn instantiate( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate(&mut store)?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `the-world`. +/// +/// This is an implementation detail of [`TheWorldPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`TheWorld`] as well. +#[derive(Clone)] +pub struct TheWorldIndices { + interface0: exports::foo::foo::conventions::GuestIndices, +} /// Auto-generated bindings for an instance a component which /// implements the world `the-world`. /// -/// This structure is created through either -/// [`TheWorld::instantiate`] or by first creating -/// a [`TheWorldPre`] followed by using -/// [`TheWorldPre::instantiate`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`TheWorld::instantiate`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`TheWorldPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`TheWorldPre::instantiate`] to +/// create a [`TheWorld`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`TheWorld::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`TheWorldIndices::new_instance`] followed +/// by [`TheWorldIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct TheWorld { interface0: exports::foo::foo::conventions::Guest, } const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> TheWorldPre<_T> { - /// Creates a new copy of `TheWorldPre` bindings which can then + impl TheWorldIndices { + /// Creates a new copy of `TheWorldIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, + ) -> wasmtime::Result { + let _component = component; + let interface0 = exports::foo::foo::conventions::GuestIndices::new( + _component, + )?; + Ok(TheWorldIndices { interface0 }) + } + /// Creates a new instance of [`TheWorldIndices`] from an + /// instantiated component. + /// + /// This method of creating a [`TheWorld`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`TheWorld`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let _component = instance_pre.component(); - let interface0 = exports::foo::foo::conventions::GuestPre::new(_component)?; - Ok(TheWorldPre { - instance_pre, - interface0, - }) + let _instance = instance; + let interface0 = exports::foo::foo::conventions::GuestIndices::new_instance( + &mut store, + _instance, + )?; + Ok(TheWorldIndices { interface0 }) } - /// Instantiates a new instance of [`TheWorld`] within the - /// `store` provided. + /// Uses the indices stored in `self` to load an instance + /// of [`TheWorld`] from the instance provided. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub fn instantiate( + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate(&mut store)?; + let _instance = instance; let interface0 = self.interface0.load(&mut store, &_instance)?; Ok(TheWorld { interface0 }) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl TheWorld { /// Convenience wrapper around [`TheWorldPre::new`] and @@ -79,6 +158,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate(store) } + /// Convenience wrapper around [`TheWorldIndices::new_instance`] and + /// [`TheWorldIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker( linker: &mut wasmtime::component::Linker, get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, @@ -386,7 +474,7 @@ pub mod exports { bool: wasmtime::component::Func, } #[derive(Clone)] - pub struct GuestPre { + pub struct GuestIndices { kebab_case: wasmtime::component::ComponentExportIndex, foo: wasmtime::component::ComponentExportIndex, function_with_dashes: wasmtime::component::ComponentExportIndex, @@ -400,11 +488,16 @@ pub mod exports { explicit_kebab: wasmtime::component::ComponentExportIndex, bool: wasmtime::component::ComponentExportIndex, } - impl GuestPre { + impl GuestIndices { + /// Constructor for [`GuestIndices`] which takes a + /// [`Component`](wasmtime::component::Component) as input and can be executed + /// before instantiation. + /// + /// This constructor can be used to front-load string lookups to find exports + /// within a component. pub fn new( component: &wasmtime::component::Component, - ) -> wasmtime::Result { - let _component = component; + ) -> wasmtime::Result { let (_, instance) = component .export_index(None, "foo:foo/conventions") .ok_or_else(|| { @@ -412,10 +505,34 @@ pub mod exports { "no exported instance named `foo:foo/conventions`" ) })?; - let _lookup = |name: &str| { - _component - .export_index(Some(&instance), name) - .map(|p| p.1) + Self::_new(|name| { + component.export_index(Some(&instance), name).map(|p| p.1) + }) + } + /// This constructor is similar to [`GuestIndices::new`] except that it + /// performs string lookups after instantiation time. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let instance_export = instance + .get_export(&mut store, None, "foo:foo/conventions") + .ok_or_else(|| { + anyhow::anyhow!( + "no exported instance named `foo:foo/conventions`" + ) + })?; + Self::_new(|name| { + instance.get_export(&mut store, Some(&instance_export), name) + }) + } + fn _new( + mut lookup: impl FnMut( + &str, + ) -> Option, + ) -> wasmtime::Result { + let mut lookup = move |name| { + lookup(name) .ok_or_else(|| { anyhow::anyhow!( "instance export `foo:foo/conventions` does \ @@ -423,21 +540,22 @@ pub mod exports { ) }) }; - let kebab_case = _lookup("kebab-case")?; - let foo = _lookup("foo")?; - let function_with_dashes = _lookup("function-with-dashes")?; - let function_with_no_weird_characters = _lookup( + let _ = &mut lookup; + let kebab_case = lookup("kebab-case")?; + let foo = lookup("foo")?; + let function_with_dashes = lookup("function-with-dashes")?; + let function_with_no_weird_characters = lookup( "function-with-no-weird-characters", )?; - let apple = _lookup("apple")?; - let apple_pear = _lookup("apple-pear")?; - let apple_pear_grape = _lookup("apple-pear-grape")?; - let a0 = _lookup("a0")?; - let is_xml = _lookup("is-XML")?; - let explicit = _lookup("explicit")?; - let explicit_kebab = _lookup("explicit-kebab")?; - let bool = _lookup("bool")?; - Ok(GuestPre { + let apple = lookup("apple")?; + let apple_pear = lookup("apple-pear")?; + let apple_pear_grape = lookup("apple-pear-grape")?; + let a0 = lookup("a0")?; + let is_xml = lookup("is-XML")?; + let explicit = lookup("explicit")?; + let explicit_kebab = lookup("explicit-kebab")?; + let bool = lookup("bool")?; + Ok(GuestIndices { kebab_case, foo, function_with_dashes, diff --git a/crates/component-macro/tests/expanded/conventions_async.rs b/crates/component-macro/tests/expanded/conventions_async.rs index 872695740c77..e03bae3f1012 100644 --- a/crates/component-macro/tests/expanded/conventions_async.rs +++ b/crates/component-macro/tests/expanded/conventions_async.rs @@ -4,72 +4,151 @@ /// This structure is created through [`TheWorldPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`TheWorld`] as well. pub struct TheWorldPre { instance_pre: wasmtime::component::InstancePre, - interface0: exports::foo::foo::conventions::GuestPre, + indices: TheWorldIndices, } impl Clone for TheWorldPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), - interface0: self.interface0.clone(), + indices: self.indices.clone(), } } } +impl<_T> TheWorldPre<_T> { + /// Creates a new copy of `TheWorldPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`TheWorld`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub async fn instantiate_async( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result + where + _T: Send, + { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate_async(&mut store).await?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `the-world`. +/// +/// This is an implementation detail of [`TheWorldPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`TheWorld`] as well. +#[derive(Clone)] +pub struct TheWorldIndices { + interface0: exports::foo::foo::conventions::GuestIndices, +} /// Auto-generated bindings for an instance a component which /// implements the world `the-world`. /// -/// This structure is created through either -/// [`TheWorld::instantiate_async`] or by first creating -/// a [`TheWorldPre`] followed by using -/// [`TheWorldPre::instantiate_async`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`TheWorld::instantiate_async`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`TheWorldPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`TheWorldPre::instantiate_async`] to +/// create a [`TheWorld`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`TheWorld::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`TheWorldIndices::new_instance`] followed +/// by [`TheWorldIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct TheWorld { interface0: exports::foo::foo::conventions::Guest, } const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> TheWorldPre<_T> { - /// Creates a new copy of `TheWorldPre` bindings which can then + impl TheWorldIndices { + /// Creates a new copy of `TheWorldIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, ) -> wasmtime::Result { - let _component = instance_pre.component(); - let interface0 = exports::foo::foo::conventions::GuestPre::new(_component)?; - Ok(TheWorldPre { - instance_pre, - interface0, - }) + let _component = component; + let interface0 = exports::foo::foo::conventions::GuestIndices::new( + _component, + )?; + Ok(TheWorldIndices { interface0 }) } - /// Instantiates a new instance of [`TheWorld`] within the - /// `store` provided. + /// Creates a new instance of [`TheWorldIndices`] from an + /// instantiated component. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub async fn instantiate_async( + /// This method of creating a [`TheWorld`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`TheWorld`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; + let interface0 = exports::foo::foo::conventions::GuestIndices::new_instance( + &mut store, + _instance, + )?; + Ok(TheWorldIndices { interface0 }) + } + /// Uses the indices stored in `self` to load an instance + /// of [`TheWorld`] from the instance provided. + /// + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate_async(&mut store).await?; + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; let interface0 = self.interface0.load(&mut store, &_instance)?; Ok(TheWorld { interface0 }) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl TheWorld { /// Convenience wrapper around [`TheWorldPre::new`] and @@ -85,6 +164,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate_async(store).await } + /// Convenience wrapper around [`TheWorldIndices::new_instance`] and + /// [`TheWorldIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker( linker: &mut wasmtime::component::Linker, get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, @@ -399,7 +487,7 @@ pub mod exports { bool: wasmtime::component::Func, } #[derive(Clone)] - pub struct GuestPre { + pub struct GuestIndices { kebab_case: wasmtime::component::ComponentExportIndex, foo: wasmtime::component::ComponentExportIndex, function_with_dashes: wasmtime::component::ComponentExportIndex, @@ -413,11 +501,16 @@ pub mod exports { explicit_kebab: wasmtime::component::ComponentExportIndex, bool: wasmtime::component::ComponentExportIndex, } - impl GuestPre { + impl GuestIndices { + /// Constructor for [`GuestIndices`] which takes a + /// [`Component`](wasmtime::component::Component) as input and can be executed + /// before instantiation. + /// + /// This constructor can be used to front-load string lookups to find exports + /// within a component. pub fn new( component: &wasmtime::component::Component, - ) -> wasmtime::Result { - let _component = component; + ) -> wasmtime::Result { let (_, instance) = component .export_index(None, "foo:foo/conventions") .ok_or_else(|| { @@ -425,10 +518,34 @@ pub mod exports { "no exported instance named `foo:foo/conventions`" ) })?; - let _lookup = |name: &str| { - _component - .export_index(Some(&instance), name) - .map(|p| p.1) + Self::_new(|name| { + component.export_index(Some(&instance), name).map(|p| p.1) + }) + } + /// This constructor is similar to [`GuestIndices::new`] except that it + /// performs string lookups after instantiation time. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let instance_export = instance + .get_export(&mut store, None, "foo:foo/conventions") + .ok_or_else(|| { + anyhow::anyhow!( + "no exported instance named `foo:foo/conventions`" + ) + })?; + Self::_new(|name| { + instance.get_export(&mut store, Some(&instance_export), name) + }) + } + fn _new( + mut lookup: impl FnMut( + &str, + ) -> Option, + ) -> wasmtime::Result { + let mut lookup = move |name| { + lookup(name) .ok_or_else(|| { anyhow::anyhow!( "instance export `foo:foo/conventions` does \ @@ -436,21 +553,22 @@ pub mod exports { ) }) }; - let kebab_case = _lookup("kebab-case")?; - let foo = _lookup("foo")?; - let function_with_dashes = _lookup("function-with-dashes")?; - let function_with_no_weird_characters = _lookup( + let _ = &mut lookup; + let kebab_case = lookup("kebab-case")?; + let foo = lookup("foo")?; + let function_with_dashes = lookup("function-with-dashes")?; + let function_with_no_weird_characters = lookup( "function-with-no-weird-characters", )?; - let apple = _lookup("apple")?; - let apple_pear = _lookup("apple-pear")?; - let apple_pear_grape = _lookup("apple-pear-grape")?; - let a0 = _lookup("a0")?; - let is_xml = _lookup("is-XML")?; - let explicit = _lookup("explicit")?; - let explicit_kebab = _lookup("explicit-kebab")?; - let bool = _lookup("bool")?; - Ok(GuestPre { + let apple = lookup("apple")?; + let apple_pear = lookup("apple-pear")?; + let apple_pear_grape = lookup("apple-pear-grape")?; + let a0 = lookup("a0")?; + let is_xml = lookup("is-XML")?; + let explicit = lookup("explicit")?; + let explicit_kebab = lookup("explicit-kebab")?; + let bool = lookup("bool")?; + Ok(GuestIndices { kebab_case, foo, function_with_dashes, diff --git a/crates/component-macro/tests/expanded/dead-code.rs b/crates/component-macro/tests/expanded/dead-code.rs index c0fb29841a1f..30781af56403 100644 --- a/crates/component-macro/tests/expanded/dead-code.rs +++ b/crates/component-macro/tests/expanded/dead-code.rs @@ -4,60 +4,136 @@ /// This structure is created through [`ImportsPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`Imports`] as well. pub struct ImportsPre { instance_pre: wasmtime::component::InstancePre, + indices: ImportsIndices, } impl Clone for ImportsPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), + indices: self.indices.clone(), } } } +impl<_T> ImportsPre<_T> { + /// Creates a new copy of `ImportsPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = ImportsIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`Imports`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub fn instantiate( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate(&mut store)?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `imports`. +/// +/// This is an implementation detail of [`ImportsPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`Imports`] as well. +#[derive(Clone)] +pub struct ImportsIndices {} /// Auto-generated bindings for an instance a component which /// implements the world `imports`. /// -/// This structure is created through either -/// [`Imports::instantiate`] or by first creating -/// a [`ImportsPre`] followed by using -/// [`ImportsPre::instantiate`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`Imports::instantiate`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`ImportsPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`ImportsPre::instantiate`] to +/// create a [`Imports`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`Imports::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`ImportsIndices::new_instance`] followed +/// by [`ImportsIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct Imports {} const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> ImportsPre<_T> { - /// Creates a new copy of `ImportsPre` bindings which can then + impl ImportsIndices { + /// Creates a new copy of `ImportsIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, + ) -> wasmtime::Result { + let _component = component; + Ok(ImportsIndices {}) + } + /// Creates a new instance of [`ImportsIndices`] from an + /// instantiated component. + /// + /// This method of creating a [`Imports`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`Imports`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let _component = instance_pre.component(); - Ok(ImportsPre { instance_pre }) + let _instance = instance; + Ok(ImportsIndices {}) } - /// Instantiates a new instance of [`Imports`] within the - /// `store` provided. + /// Uses the indices stored in `self` to load an instance + /// of [`Imports`] from the instance provided. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub fn instantiate( + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate(&mut store)?; + let _instance = instance; Ok(Imports {}) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl Imports { /// Convenience wrapper around [`ImportsPre::new`] and @@ -70,6 +146,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; ImportsPre::new(pre)?.instantiate(store) } + /// Convenience wrapper around [`ImportsIndices::new_instance`] and + /// [`ImportsIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = ImportsIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker( linker: &mut wasmtime::component::Linker, get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, diff --git a/crates/component-macro/tests/expanded/dead-code_async.rs b/crates/component-macro/tests/expanded/dead-code_async.rs index 46110f3cda57..ab2ce33833d4 100644 --- a/crates/component-macro/tests/expanded/dead-code_async.rs +++ b/crates/component-macro/tests/expanded/dead-code_async.rs @@ -4,63 +4,139 @@ /// This structure is created through [`ImportsPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`Imports`] as well. pub struct ImportsPre { instance_pre: wasmtime::component::InstancePre, + indices: ImportsIndices, } impl Clone for ImportsPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), + indices: self.indices.clone(), } } } +impl<_T> ImportsPre<_T> { + /// Creates a new copy of `ImportsPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = ImportsIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`Imports`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub async fn instantiate_async( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result + where + _T: Send, + { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate_async(&mut store).await?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `imports`. +/// +/// This is an implementation detail of [`ImportsPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`Imports`] as well. +#[derive(Clone)] +pub struct ImportsIndices {} /// Auto-generated bindings for an instance a component which /// implements the world `imports`. /// -/// This structure is created through either -/// [`Imports::instantiate_async`] or by first creating -/// a [`ImportsPre`] followed by using -/// [`ImportsPre::instantiate_async`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`Imports::instantiate_async`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`ImportsPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`ImportsPre::instantiate_async`] to +/// create a [`Imports`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`Imports::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`ImportsIndices::new_instance`] followed +/// by [`ImportsIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct Imports {} const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> ImportsPre<_T> { - /// Creates a new copy of `ImportsPre` bindings which can then + impl ImportsIndices { + /// Creates a new copy of `ImportsIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, + ) -> wasmtime::Result { + let _component = component; + Ok(ImportsIndices {}) + } + /// Creates a new instance of [`ImportsIndices`] from an + /// instantiated component. + /// + /// This method of creating a [`Imports`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`Imports`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let _component = instance_pre.component(); - Ok(ImportsPre { instance_pre }) + let _instance = instance; + Ok(ImportsIndices {}) } - /// Instantiates a new instance of [`Imports`] within the - /// `store` provided. + /// Uses the indices stored in `self` to load an instance + /// of [`Imports`] from the instance provided. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub async fn instantiate_async( + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate_async(&mut store).await?; + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; Ok(Imports {}) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl Imports { /// Convenience wrapper around [`ImportsPre::new`] and @@ -76,6 +152,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; ImportsPre::new(pre)?.instantiate_async(store).await } + /// Convenience wrapper around [`ImportsIndices::new_instance`] and + /// [`ImportsIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = ImportsIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker( linker: &mut wasmtime::component::Linker, get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, diff --git a/crates/component-macro/tests/expanded/direct-import.rs b/crates/component-macro/tests/expanded/direct-import.rs index baa6709a2d88..225fe6c9009f 100644 --- a/crates/component-macro/tests/expanded/direct-import.rs +++ b/crates/component-macro/tests/expanded/direct-import.rs @@ -4,23 +4,93 @@ /// This structure is created through [`FooPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`Foo`] as well. pub struct FooPre { instance_pre: wasmtime::component::InstancePre, + indices: FooIndices, } impl Clone for FooPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), + indices: self.indices.clone(), } } } +impl<_T> FooPre<_T> { + /// Creates a new copy of `FooPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = FooIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`Foo`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub fn instantiate( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate(&mut store)?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `foo`. +/// +/// This is an implementation detail of [`FooPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`Foo`] as well. +#[derive(Clone)] +pub struct FooIndices {} /// Auto-generated bindings for an instance a component which /// implements the world `foo`. /// -/// This structure is created through either -/// [`Foo::instantiate`] or by first creating -/// a [`FooPre`] followed by using -/// [`FooPre::instantiate`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`Foo::instantiate`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`FooPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`FooPre::instantiate`] to +/// create a [`Foo`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`Foo::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`FooIndices::new_instance`] followed +/// by [`FooIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct Foo {} pub trait FooImports { fn foo(&mut self) -> (); @@ -45,39 +115,45 @@ impl<_T: FooImports + ?Sized> FooImports for &mut _T { const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> FooPre<_T> { - /// Creates a new copy of `FooPre` bindings which can then + impl FooIndices { + /// Creates a new copy of `FooIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, + ) -> wasmtime::Result { + let _component = component; + Ok(FooIndices {}) + } + /// Creates a new instance of [`FooIndices`] from an + /// instantiated component. + /// + /// This method of creating a [`Foo`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`Foo`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let _component = instance_pre.component(); - Ok(FooPre { instance_pre }) + let _instance = instance; + Ok(FooIndices {}) } - /// Instantiates a new instance of [`Foo`] within the - /// `store` provided. + /// Uses the indices stored in `self` to load an instance + /// of [`Foo`] from the instance provided. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub fn instantiate( + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate(&mut store)?; + let _instance = instance; Ok(Foo {}) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl Foo { /// Convenience wrapper around [`FooPre::new`] and @@ -90,6 +166,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; FooPre::new(pre)?.instantiate(store) } + /// Convenience wrapper around [`FooIndices::new_instance`] and + /// [`FooIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = FooIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker_imports_get_host( linker: &mut wasmtime::component::Linker, host_getter: impl for<'a> FooImportsGetHost<&'a mut T>, diff --git a/crates/component-macro/tests/expanded/direct-import_async.rs b/crates/component-macro/tests/expanded/direct-import_async.rs index cae02be19e13..59ee3fc7c68a 100644 --- a/crates/component-macro/tests/expanded/direct-import_async.rs +++ b/crates/component-macro/tests/expanded/direct-import_async.rs @@ -4,23 +4,96 @@ /// This structure is created through [`FooPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`Foo`] as well. pub struct FooPre { instance_pre: wasmtime::component::InstancePre, + indices: FooIndices, } impl Clone for FooPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), + indices: self.indices.clone(), } } } +impl<_T> FooPre<_T> { + /// Creates a new copy of `FooPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = FooIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`Foo`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub async fn instantiate_async( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result + where + _T: Send, + { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate_async(&mut store).await?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `foo`. +/// +/// This is an implementation detail of [`FooPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`Foo`] as well. +#[derive(Clone)] +pub struct FooIndices {} /// Auto-generated bindings for an instance a component which /// implements the world `foo`. /// -/// This structure is created through either -/// [`Foo::instantiate_async`] or by first creating -/// a [`FooPre`] followed by using -/// [`FooPre::instantiate_async`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`Foo::instantiate_async`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`FooPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`FooPre::instantiate_async`] to +/// create a [`Foo`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`Foo::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`FooIndices::new_instance`] followed +/// by [`FooIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct Foo {} #[wasmtime::component::__internal::async_trait] pub trait FooImports: Send { @@ -47,42 +120,45 @@ impl<_T: FooImports + ?Sized + Send> FooImports for &mut _T { const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> FooPre<_T> { - /// Creates a new copy of `FooPre` bindings which can then + impl FooIndices { + /// Creates a new copy of `FooIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, + ) -> wasmtime::Result { + let _component = component; + Ok(FooIndices {}) + } + /// Creates a new instance of [`FooIndices`] from an + /// instantiated component. + /// + /// This method of creating a [`Foo`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`Foo`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let _component = instance_pre.component(); - Ok(FooPre { instance_pre }) + let _instance = instance; + Ok(FooIndices {}) } - /// Instantiates a new instance of [`Foo`] within the - /// `store` provided. + /// Uses the indices stored in `self` to load an instance + /// of [`Foo`] from the instance provided. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub async fn instantiate_async( + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate_async(&mut store).await?; + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; Ok(Foo {}) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl Foo { /// Convenience wrapper around [`FooPre::new`] and @@ -98,6 +174,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; FooPre::new(pre)?.instantiate_async(store).await } + /// Convenience wrapper around [`FooIndices::new_instance`] and + /// [`FooIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = FooIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker_imports_get_host( linker: &mut wasmtime::component::Linker, host_getter: impl for<'a> FooImportsGetHost<&'a mut T>, diff --git a/crates/component-macro/tests/expanded/empty.rs b/crates/component-macro/tests/expanded/empty.rs index 048156cd1998..573b02c84e74 100644 --- a/crates/component-macro/tests/expanded/empty.rs +++ b/crates/component-macro/tests/expanded/empty.rs @@ -4,60 +4,136 @@ /// This structure is created through [`EmptyPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`Empty`] as well. pub struct EmptyPre { instance_pre: wasmtime::component::InstancePre, + indices: EmptyIndices, } impl Clone for EmptyPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), + indices: self.indices.clone(), } } } +impl<_T> EmptyPre<_T> { + /// Creates a new copy of `EmptyPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = EmptyIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`Empty`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub fn instantiate( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate(&mut store)?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `empty`. +/// +/// This is an implementation detail of [`EmptyPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`Empty`] as well. +#[derive(Clone)] +pub struct EmptyIndices {} /// Auto-generated bindings for an instance a component which /// implements the world `empty`. /// -/// This structure is created through either -/// [`Empty::instantiate`] or by first creating -/// a [`EmptyPre`] followed by using -/// [`EmptyPre::instantiate`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`Empty::instantiate`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`EmptyPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`EmptyPre::instantiate`] to +/// create a [`Empty`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`Empty::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`EmptyIndices::new_instance`] followed +/// by [`EmptyIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct Empty {} const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> EmptyPre<_T> { - /// Creates a new copy of `EmptyPre` bindings which can then + impl EmptyIndices { + /// Creates a new copy of `EmptyIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, + ) -> wasmtime::Result { + let _component = component; + Ok(EmptyIndices {}) + } + /// Creates a new instance of [`EmptyIndices`] from an + /// instantiated component. + /// + /// This method of creating a [`Empty`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`Empty`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let _component = instance_pre.component(); - Ok(EmptyPre { instance_pre }) + let _instance = instance; + Ok(EmptyIndices {}) } - /// Instantiates a new instance of [`Empty`] within the - /// `store` provided. + /// Uses the indices stored in `self` to load an instance + /// of [`Empty`] from the instance provided. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub fn instantiate( + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate(&mut store)?; + let _instance = instance; Ok(Empty {}) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl Empty { /// Convenience wrapper around [`EmptyPre::new`] and @@ -70,5 +146,14 @@ const _: () = { let pre = linker.instantiate_pre(component)?; EmptyPre::new(pre)?.instantiate(store) } + /// Convenience wrapper around [`EmptyIndices::new_instance`] and + /// [`EmptyIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = EmptyIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } } }; diff --git a/crates/component-macro/tests/expanded/empty_async.rs b/crates/component-macro/tests/expanded/empty_async.rs index 1c4b3fc92669..d2eea87b72a0 100644 --- a/crates/component-macro/tests/expanded/empty_async.rs +++ b/crates/component-macro/tests/expanded/empty_async.rs @@ -4,63 +4,139 @@ /// This structure is created through [`EmptyPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`Empty`] as well. pub struct EmptyPre { instance_pre: wasmtime::component::InstancePre, + indices: EmptyIndices, } impl Clone for EmptyPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), + indices: self.indices.clone(), } } } +impl<_T> EmptyPre<_T> { + /// Creates a new copy of `EmptyPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = EmptyIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`Empty`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub async fn instantiate_async( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result + where + _T: Send, + { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate_async(&mut store).await?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `empty`. +/// +/// This is an implementation detail of [`EmptyPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`Empty`] as well. +#[derive(Clone)] +pub struct EmptyIndices {} /// Auto-generated bindings for an instance a component which /// implements the world `empty`. /// -/// This structure is created through either -/// [`Empty::instantiate_async`] or by first creating -/// a [`EmptyPre`] followed by using -/// [`EmptyPre::instantiate_async`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`Empty::instantiate_async`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`EmptyPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`EmptyPre::instantiate_async`] to +/// create a [`Empty`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`Empty::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`EmptyIndices::new_instance`] followed +/// by [`EmptyIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct Empty {} const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> EmptyPre<_T> { - /// Creates a new copy of `EmptyPre` bindings which can then + impl EmptyIndices { + /// Creates a new copy of `EmptyIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, + ) -> wasmtime::Result { + let _component = component; + Ok(EmptyIndices {}) + } + /// Creates a new instance of [`EmptyIndices`] from an + /// instantiated component. + /// + /// This method of creating a [`Empty`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`Empty`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let _component = instance_pre.component(); - Ok(EmptyPre { instance_pre }) + let _instance = instance; + Ok(EmptyIndices {}) } - /// Instantiates a new instance of [`Empty`] within the - /// `store` provided. + /// Uses the indices stored in `self` to load an instance + /// of [`Empty`] from the instance provided. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub async fn instantiate_async( + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate_async(&mut store).await?; + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; Ok(Empty {}) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl Empty { /// Convenience wrapper around [`EmptyPre::new`] and @@ -76,5 +152,14 @@ const _: () = { let pre = linker.instantiate_pre(component)?; EmptyPre::new(pre)?.instantiate_async(store).await } + /// Convenience wrapper around [`EmptyIndices::new_instance`] and + /// [`EmptyIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = EmptyIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } } }; diff --git a/crates/component-macro/tests/expanded/flags.rs b/crates/component-macro/tests/expanded/flags.rs index 75b842bdd2e1..c036a1a2d85b 100644 --- a/crates/component-macro/tests/expanded/flags.rs +++ b/crates/component-macro/tests/expanded/flags.rs @@ -4,69 +4,146 @@ /// This structure is created through [`TheFlagsPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`TheFlags`] as well. pub struct TheFlagsPre { instance_pre: wasmtime::component::InstancePre, - interface0: exports::foo::foo::flegs::GuestPre, + indices: TheFlagsIndices, } impl Clone for TheFlagsPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), - interface0: self.interface0.clone(), + indices: self.indices.clone(), } } } +impl<_T> TheFlagsPre<_T> { + /// Creates a new copy of `TheFlagsPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = TheFlagsIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`TheFlags`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub fn instantiate( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate(&mut store)?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `the-flags`. +/// +/// This is an implementation detail of [`TheFlagsPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`TheFlags`] as well. +#[derive(Clone)] +pub struct TheFlagsIndices { + interface0: exports::foo::foo::flegs::GuestIndices, +} /// Auto-generated bindings for an instance a component which /// implements the world `the-flags`. /// -/// This structure is created through either -/// [`TheFlags::instantiate`] or by first creating -/// a [`TheFlagsPre`] followed by using -/// [`TheFlagsPre::instantiate`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`TheFlags::instantiate`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`TheFlagsPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`TheFlagsPre::instantiate`] to +/// create a [`TheFlags`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`TheFlags::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`TheFlagsIndices::new_instance`] followed +/// by [`TheFlagsIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct TheFlags { interface0: exports::foo::foo::flegs::Guest, } const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> TheFlagsPre<_T> { - /// Creates a new copy of `TheFlagsPre` bindings which can then + impl TheFlagsIndices { + /// Creates a new copy of `TheFlagsIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, + ) -> wasmtime::Result { + let _component = component; + let interface0 = exports::foo::foo::flegs::GuestIndices::new(_component)?; + Ok(TheFlagsIndices { interface0 }) + } + /// Creates a new instance of [`TheFlagsIndices`] from an + /// instantiated component. + /// + /// This method of creating a [`TheFlags`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`TheFlags`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let _component = instance_pre.component(); - let interface0 = exports::foo::foo::flegs::GuestPre::new(_component)?; - Ok(TheFlagsPre { - instance_pre, - interface0, - }) + let _instance = instance; + let interface0 = exports::foo::foo::flegs::GuestIndices::new_instance( + &mut store, + _instance, + )?; + Ok(TheFlagsIndices { interface0 }) } - /// Instantiates a new instance of [`TheFlags`] within the - /// `store` provided. + /// Uses the indices stored in `self` to load an instance + /// of [`TheFlags`] from the instance provided. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub fn instantiate( + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate(&mut store)?; + let _instance = instance; let interface0 = self.interface0.load(&mut store, &_instance)?; Ok(TheFlags { interface0 }) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl TheFlags { /// Convenience wrapper around [`TheFlagsPre::new`] and @@ -79,6 +156,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; TheFlagsPre::new(pre)?.instantiate(store) } + /// Convenience wrapper around [`TheFlagsIndices::new_instance`] and + /// [`TheFlagsIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = TheFlagsIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker( linker: &mut wasmtime::component::Linker, get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, @@ -520,7 +606,7 @@ pub mod exports { roundtrip_flag64: wasmtime::component::Func, } #[derive(Clone)] - pub struct GuestPre { + pub struct GuestIndices { roundtrip_flag1: wasmtime::component::ComponentExportIndex, roundtrip_flag2: wasmtime::component::ComponentExportIndex, roundtrip_flag4: wasmtime::component::ComponentExportIndex, @@ -529,11 +615,16 @@ pub mod exports { roundtrip_flag32: wasmtime::component::ComponentExportIndex, roundtrip_flag64: wasmtime::component::ComponentExportIndex, } - impl GuestPre { + impl GuestIndices { + /// Constructor for [`GuestIndices`] which takes a + /// [`Component`](wasmtime::component::Component) as input and can be executed + /// before instantiation. + /// + /// This constructor can be used to front-load string lookups to find exports + /// within a component. pub fn new( component: &wasmtime::component::Component, - ) -> wasmtime::Result { - let _component = component; + ) -> wasmtime::Result { let (_, instance) = component .export_index(None, "foo:foo/flegs") .ok_or_else(|| { @@ -541,10 +632,34 @@ pub mod exports { "no exported instance named `foo:foo/flegs`" ) })?; - let _lookup = |name: &str| { - _component - .export_index(Some(&instance), name) - .map(|p| p.1) + Self::_new(|name| { + component.export_index(Some(&instance), name).map(|p| p.1) + }) + } + /// This constructor is similar to [`GuestIndices::new`] except that it + /// performs string lookups after instantiation time. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let instance_export = instance + .get_export(&mut store, None, "foo:foo/flegs") + .ok_or_else(|| { + anyhow::anyhow!( + "no exported instance named `foo:foo/flegs`" + ) + })?; + Self::_new(|name| { + instance.get_export(&mut store, Some(&instance_export), name) + }) + } + fn _new( + mut lookup: impl FnMut( + &str, + ) -> Option, + ) -> wasmtime::Result { + let mut lookup = move |name| { + lookup(name) .ok_or_else(|| { anyhow::anyhow!( "instance export `foo:foo/flegs` does \ @@ -552,14 +667,15 @@ pub mod exports { ) }) }; - let roundtrip_flag1 = _lookup("roundtrip-flag1")?; - let roundtrip_flag2 = _lookup("roundtrip-flag2")?; - let roundtrip_flag4 = _lookup("roundtrip-flag4")?; - let roundtrip_flag8 = _lookup("roundtrip-flag8")?; - let roundtrip_flag16 = _lookup("roundtrip-flag16")?; - let roundtrip_flag32 = _lookup("roundtrip-flag32")?; - let roundtrip_flag64 = _lookup("roundtrip-flag64")?; - Ok(GuestPre { + let _ = &mut lookup; + let roundtrip_flag1 = lookup("roundtrip-flag1")?; + let roundtrip_flag2 = lookup("roundtrip-flag2")?; + let roundtrip_flag4 = lookup("roundtrip-flag4")?; + let roundtrip_flag8 = lookup("roundtrip-flag8")?; + let roundtrip_flag16 = lookup("roundtrip-flag16")?; + let roundtrip_flag32 = lookup("roundtrip-flag32")?; + let roundtrip_flag64 = lookup("roundtrip-flag64")?; + Ok(GuestIndices { roundtrip_flag1, roundtrip_flag2, roundtrip_flag4, diff --git a/crates/component-macro/tests/expanded/flags_async.rs b/crates/component-macro/tests/expanded/flags_async.rs index 8a3ba252f8f3..4ac5814dab67 100644 --- a/crates/component-macro/tests/expanded/flags_async.rs +++ b/crates/component-macro/tests/expanded/flags_async.rs @@ -4,72 +4,149 @@ /// This structure is created through [`TheFlagsPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`TheFlags`] as well. pub struct TheFlagsPre { instance_pre: wasmtime::component::InstancePre, - interface0: exports::foo::foo::flegs::GuestPre, + indices: TheFlagsIndices, } impl Clone for TheFlagsPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), - interface0: self.interface0.clone(), + indices: self.indices.clone(), } } } +impl<_T> TheFlagsPre<_T> { + /// Creates a new copy of `TheFlagsPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = TheFlagsIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`TheFlags`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub async fn instantiate_async( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result + where + _T: Send, + { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate_async(&mut store).await?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `the-flags`. +/// +/// This is an implementation detail of [`TheFlagsPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`TheFlags`] as well. +#[derive(Clone)] +pub struct TheFlagsIndices { + interface0: exports::foo::foo::flegs::GuestIndices, +} /// Auto-generated bindings for an instance a component which /// implements the world `the-flags`. /// -/// This structure is created through either -/// [`TheFlags::instantiate_async`] or by first creating -/// a [`TheFlagsPre`] followed by using -/// [`TheFlagsPre::instantiate_async`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`TheFlags::instantiate_async`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`TheFlagsPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`TheFlagsPre::instantiate_async`] to +/// create a [`TheFlags`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`TheFlags::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`TheFlagsIndices::new_instance`] followed +/// by [`TheFlagsIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct TheFlags { interface0: exports::foo::foo::flegs::Guest, } const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> TheFlagsPre<_T> { - /// Creates a new copy of `TheFlagsPre` bindings which can then + impl TheFlagsIndices { + /// Creates a new copy of `TheFlagsIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, ) -> wasmtime::Result { - let _component = instance_pre.component(); - let interface0 = exports::foo::foo::flegs::GuestPre::new(_component)?; - Ok(TheFlagsPre { - instance_pre, - interface0, - }) + let _component = component; + let interface0 = exports::foo::foo::flegs::GuestIndices::new(_component)?; + Ok(TheFlagsIndices { interface0 }) } - /// Instantiates a new instance of [`TheFlags`] within the - /// `store` provided. + /// Creates a new instance of [`TheFlagsIndices`] from an + /// instantiated component. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub async fn instantiate_async( + /// This method of creating a [`TheFlags`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`TheFlags`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; + let interface0 = exports::foo::foo::flegs::GuestIndices::new_instance( + &mut store, + _instance, + )?; + Ok(TheFlagsIndices { interface0 }) + } + /// Uses the indices stored in `self` to load an instance + /// of [`TheFlags`] from the instance provided. + /// + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate_async(&mut store).await?; + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; let interface0 = self.interface0.load(&mut store, &_instance)?; Ok(TheFlags { interface0 }) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl TheFlags { /// Convenience wrapper around [`TheFlagsPre::new`] and @@ -85,6 +162,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; TheFlagsPre::new(pre)?.instantiate_async(store).await } + /// Convenience wrapper around [`TheFlagsIndices::new_instance`] and + /// [`TheFlagsIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = TheFlagsIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker( linker: &mut wasmtime::component::Linker, get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, @@ -533,7 +619,7 @@ pub mod exports { roundtrip_flag64: wasmtime::component::Func, } #[derive(Clone)] - pub struct GuestPre { + pub struct GuestIndices { roundtrip_flag1: wasmtime::component::ComponentExportIndex, roundtrip_flag2: wasmtime::component::ComponentExportIndex, roundtrip_flag4: wasmtime::component::ComponentExportIndex, @@ -542,11 +628,16 @@ pub mod exports { roundtrip_flag32: wasmtime::component::ComponentExportIndex, roundtrip_flag64: wasmtime::component::ComponentExportIndex, } - impl GuestPre { + impl GuestIndices { + /// Constructor for [`GuestIndices`] which takes a + /// [`Component`](wasmtime::component::Component) as input and can be executed + /// before instantiation. + /// + /// This constructor can be used to front-load string lookups to find exports + /// within a component. pub fn new( component: &wasmtime::component::Component, - ) -> wasmtime::Result { - let _component = component; + ) -> wasmtime::Result { let (_, instance) = component .export_index(None, "foo:foo/flegs") .ok_or_else(|| { @@ -554,10 +645,34 @@ pub mod exports { "no exported instance named `foo:foo/flegs`" ) })?; - let _lookup = |name: &str| { - _component - .export_index(Some(&instance), name) - .map(|p| p.1) + Self::_new(|name| { + component.export_index(Some(&instance), name).map(|p| p.1) + }) + } + /// This constructor is similar to [`GuestIndices::new`] except that it + /// performs string lookups after instantiation time. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let instance_export = instance + .get_export(&mut store, None, "foo:foo/flegs") + .ok_or_else(|| { + anyhow::anyhow!( + "no exported instance named `foo:foo/flegs`" + ) + })?; + Self::_new(|name| { + instance.get_export(&mut store, Some(&instance_export), name) + }) + } + fn _new( + mut lookup: impl FnMut( + &str, + ) -> Option, + ) -> wasmtime::Result { + let mut lookup = move |name| { + lookup(name) .ok_or_else(|| { anyhow::anyhow!( "instance export `foo:foo/flegs` does \ @@ -565,14 +680,15 @@ pub mod exports { ) }) }; - let roundtrip_flag1 = _lookup("roundtrip-flag1")?; - let roundtrip_flag2 = _lookup("roundtrip-flag2")?; - let roundtrip_flag4 = _lookup("roundtrip-flag4")?; - let roundtrip_flag8 = _lookup("roundtrip-flag8")?; - let roundtrip_flag16 = _lookup("roundtrip-flag16")?; - let roundtrip_flag32 = _lookup("roundtrip-flag32")?; - let roundtrip_flag64 = _lookup("roundtrip-flag64")?; - Ok(GuestPre { + let _ = &mut lookup; + let roundtrip_flag1 = lookup("roundtrip-flag1")?; + let roundtrip_flag2 = lookup("roundtrip-flag2")?; + let roundtrip_flag4 = lookup("roundtrip-flag4")?; + let roundtrip_flag8 = lookup("roundtrip-flag8")?; + let roundtrip_flag16 = lookup("roundtrip-flag16")?; + let roundtrip_flag32 = lookup("roundtrip-flag32")?; + let roundtrip_flag64 = lookup("roundtrip-flag64")?; + Ok(GuestIndices { roundtrip_flag1, roundtrip_flag2, roundtrip_flag4, diff --git a/crates/component-macro/tests/expanded/floats.rs b/crates/component-macro/tests/expanded/floats.rs index f3edd4174c51..a56863d0e78c 100644 --- a/crates/component-macro/tests/expanded/floats.rs +++ b/crates/component-macro/tests/expanded/floats.rs @@ -4,69 +4,146 @@ /// This structure is created through [`TheWorldPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`TheWorld`] as well. pub struct TheWorldPre { instance_pre: wasmtime::component::InstancePre, - interface0: exports::foo::foo::floats::GuestPre, + indices: TheWorldIndices, } impl Clone for TheWorldPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), - interface0: self.interface0.clone(), + indices: self.indices.clone(), } } } +impl<_T> TheWorldPre<_T> { + /// Creates a new copy of `TheWorldPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`TheWorld`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub fn instantiate( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate(&mut store)?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `the-world`. +/// +/// This is an implementation detail of [`TheWorldPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`TheWorld`] as well. +#[derive(Clone)] +pub struct TheWorldIndices { + interface0: exports::foo::foo::floats::GuestIndices, +} /// Auto-generated bindings for an instance a component which /// implements the world `the-world`. /// -/// This structure is created through either -/// [`TheWorld::instantiate`] or by first creating -/// a [`TheWorldPre`] followed by using -/// [`TheWorldPre::instantiate`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`TheWorld::instantiate`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`TheWorldPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`TheWorldPre::instantiate`] to +/// create a [`TheWorld`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`TheWorld::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`TheWorldIndices::new_instance`] followed +/// by [`TheWorldIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct TheWorld { interface0: exports::foo::foo::floats::Guest, } const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> TheWorldPre<_T> { - /// Creates a new copy of `TheWorldPre` bindings which can then + impl TheWorldIndices { + /// Creates a new copy of `TheWorldIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, + ) -> wasmtime::Result { + let _component = component; + let interface0 = exports::foo::foo::floats::GuestIndices::new(_component)?; + Ok(TheWorldIndices { interface0 }) + } + /// Creates a new instance of [`TheWorldIndices`] from an + /// instantiated component. + /// + /// This method of creating a [`TheWorld`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`TheWorld`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let _component = instance_pre.component(); - let interface0 = exports::foo::foo::floats::GuestPre::new(_component)?; - Ok(TheWorldPre { - instance_pre, - interface0, - }) + let _instance = instance; + let interface0 = exports::foo::foo::floats::GuestIndices::new_instance( + &mut store, + _instance, + )?; + Ok(TheWorldIndices { interface0 }) } - /// Instantiates a new instance of [`TheWorld`] within the - /// `store` provided. + /// Uses the indices stored in `self` to load an instance + /// of [`TheWorld`] from the instance provided. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub fn instantiate( + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate(&mut store)?; + let _instance = instance; let interface0 = self.interface0.load(&mut store, &_instance)?; Ok(TheWorld { interface0 }) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl TheWorld { /// Convenience wrapper around [`TheWorldPre::new`] and @@ -79,6 +156,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate(store) } + /// Convenience wrapper around [`TheWorldIndices::new_instance`] and + /// [`TheWorldIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker( linker: &mut wasmtime::component::Linker, get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, @@ -197,17 +283,22 @@ pub mod exports { float64_result: wasmtime::component::Func, } #[derive(Clone)] - pub struct GuestPre { + pub struct GuestIndices { float32_param: wasmtime::component::ComponentExportIndex, float64_param: wasmtime::component::ComponentExportIndex, float32_result: wasmtime::component::ComponentExportIndex, float64_result: wasmtime::component::ComponentExportIndex, } - impl GuestPre { + impl GuestIndices { + /// Constructor for [`GuestIndices`] which takes a + /// [`Component`](wasmtime::component::Component) as input and can be executed + /// before instantiation. + /// + /// This constructor can be used to front-load string lookups to find exports + /// within a component. pub fn new( component: &wasmtime::component::Component, - ) -> wasmtime::Result { - let _component = component; + ) -> wasmtime::Result { let (_, instance) = component .export_index(None, "foo:foo/floats") .ok_or_else(|| { @@ -215,10 +306,34 @@ pub mod exports { "no exported instance named `foo:foo/floats`" ) })?; - let _lookup = |name: &str| { - _component - .export_index(Some(&instance), name) - .map(|p| p.1) + Self::_new(|name| { + component.export_index(Some(&instance), name).map(|p| p.1) + }) + } + /// This constructor is similar to [`GuestIndices::new`] except that it + /// performs string lookups after instantiation time. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let instance_export = instance + .get_export(&mut store, None, "foo:foo/floats") + .ok_or_else(|| { + anyhow::anyhow!( + "no exported instance named `foo:foo/floats`" + ) + })?; + Self::_new(|name| { + instance.get_export(&mut store, Some(&instance_export), name) + }) + } + fn _new( + mut lookup: impl FnMut( + &str, + ) -> Option, + ) -> wasmtime::Result { + let mut lookup = move |name| { + lookup(name) .ok_or_else(|| { anyhow::anyhow!( "instance export `foo:foo/floats` does \ @@ -226,11 +341,12 @@ pub mod exports { ) }) }; - let float32_param = _lookup("float32-param")?; - let float64_param = _lookup("float64-param")?; - let float32_result = _lookup("float32-result")?; - let float64_result = _lookup("float64-result")?; - Ok(GuestPre { + let _ = &mut lookup; + let float32_param = lookup("float32-param")?; + let float64_param = lookup("float64-param")?; + let float32_result = lookup("float32-result")?; + let float64_result = lookup("float64-result")?; + Ok(GuestIndices { float32_param, float64_param, float32_result, diff --git a/crates/component-macro/tests/expanded/floats_async.rs b/crates/component-macro/tests/expanded/floats_async.rs index 84c9127d1ce9..9747e1cb6eab 100644 --- a/crates/component-macro/tests/expanded/floats_async.rs +++ b/crates/component-macro/tests/expanded/floats_async.rs @@ -4,72 +4,149 @@ /// This structure is created through [`TheWorldPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`TheWorld`] as well. pub struct TheWorldPre { instance_pre: wasmtime::component::InstancePre, - interface0: exports::foo::foo::floats::GuestPre, + indices: TheWorldIndices, } impl Clone for TheWorldPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), - interface0: self.interface0.clone(), + indices: self.indices.clone(), } } } +impl<_T> TheWorldPre<_T> { + /// Creates a new copy of `TheWorldPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`TheWorld`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub async fn instantiate_async( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result + where + _T: Send, + { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate_async(&mut store).await?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `the-world`. +/// +/// This is an implementation detail of [`TheWorldPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`TheWorld`] as well. +#[derive(Clone)] +pub struct TheWorldIndices { + interface0: exports::foo::foo::floats::GuestIndices, +} /// Auto-generated bindings for an instance a component which /// implements the world `the-world`. /// -/// This structure is created through either -/// [`TheWorld::instantiate_async`] or by first creating -/// a [`TheWorldPre`] followed by using -/// [`TheWorldPre::instantiate_async`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`TheWorld::instantiate_async`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`TheWorldPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`TheWorldPre::instantiate_async`] to +/// create a [`TheWorld`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`TheWorld::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`TheWorldIndices::new_instance`] followed +/// by [`TheWorldIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct TheWorld { interface0: exports::foo::foo::floats::Guest, } const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> TheWorldPre<_T> { - /// Creates a new copy of `TheWorldPre` bindings which can then + impl TheWorldIndices { + /// Creates a new copy of `TheWorldIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, ) -> wasmtime::Result { - let _component = instance_pre.component(); - let interface0 = exports::foo::foo::floats::GuestPre::new(_component)?; - Ok(TheWorldPre { - instance_pre, - interface0, - }) + let _component = component; + let interface0 = exports::foo::foo::floats::GuestIndices::new(_component)?; + Ok(TheWorldIndices { interface0 }) } - /// Instantiates a new instance of [`TheWorld`] within the - /// `store` provided. + /// Creates a new instance of [`TheWorldIndices`] from an + /// instantiated component. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub async fn instantiate_async( + /// This method of creating a [`TheWorld`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`TheWorld`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; + let interface0 = exports::foo::foo::floats::GuestIndices::new_instance( + &mut store, + _instance, + )?; + Ok(TheWorldIndices { interface0 }) + } + /// Uses the indices stored in `self` to load an instance + /// of [`TheWorld`] from the instance provided. + /// + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate_async(&mut store).await?; + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; let interface0 = self.interface0.load(&mut store, &_instance)?; Ok(TheWorld { interface0 }) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl TheWorld { /// Convenience wrapper around [`TheWorldPre::new`] and @@ -85,6 +162,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate_async(store).await } + /// Convenience wrapper around [`TheWorldIndices::new_instance`] and + /// [`TheWorldIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker( linker: &mut wasmtime::component::Linker, get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, @@ -210,17 +296,22 @@ pub mod exports { float64_result: wasmtime::component::Func, } #[derive(Clone)] - pub struct GuestPre { + pub struct GuestIndices { float32_param: wasmtime::component::ComponentExportIndex, float64_param: wasmtime::component::ComponentExportIndex, float32_result: wasmtime::component::ComponentExportIndex, float64_result: wasmtime::component::ComponentExportIndex, } - impl GuestPre { + impl GuestIndices { + /// Constructor for [`GuestIndices`] which takes a + /// [`Component`](wasmtime::component::Component) as input and can be executed + /// before instantiation. + /// + /// This constructor can be used to front-load string lookups to find exports + /// within a component. pub fn new( component: &wasmtime::component::Component, - ) -> wasmtime::Result { - let _component = component; + ) -> wasmtime::Result { let (_, instance) = component .export_index(None, "foo:foo/floats") .ok_or_else(|| { @@ -228,10 +319,34 @@ pub mod exports { "no exported instance named `foo:foo/floats`" ) })?; - let _lookup = |name: &str| { - _component - .export_index(Some(&instance), name) - .map(|p| p.1) + Self::_new(|name| { + component.export_index(Some(&instance), name).map(|p| p.1) + }) + } + /// This constructor is similar to [`GuestIndices::new`] except that it + /// performs string lookups after instantiation time. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let instance_export = instance + .get_export(&mut store, None, "foo:foo/floats") + .ok_or_else(|| { + anyhow::anyhow!( + "no exported instance named `foo:foo/floats`" + ) + })?; + Self::_new(|name| { + instance.get_export(&mut store, Some(&instance_export), name) + }) + } + fn _new( + mut lookup: impl FnMut( + &str, + ) -> Option, + ) -> wasmtime::Result { + let mut lookup = move |name| { + lookup(name) .ok_or_else(|| { anyhow::anyhow!( "instance export `foo:foo/floats` does \ @@ -239,11 +354,12 @@ pub mod exports { ) }) }; - let float32_param = _lookup("float32-param")?; - let float64_param = _lookup("float64-param")?; - let float32_result = _lookup("float32-result")?; - let float64_result = _lookup("float64-result")?; - Ok(GuestPre { + let _ = &mut lookup; + let float32_param = lookup("float32-param")?; + let float64_param = lookup("float64-param")?; + let float32_result = lookup("float32-result")?; + let float64_result = lookup("float64-result")?; + Ok(GuestIndices { float32_param, float64_param, float32_result, diff --git a/crates/component-macro/tests/expanded/function-new.rs b/crates/component-macro/tests/expanded/function-new.rs index a43b6bf26619..ca37b6668473 100644 --- a/crates/component-macro/tests/expanded/function-new.rs +++ b/crates/component-macro/tests/expanded/function-new.rs @@ -4,69 +4,148 @@ /// This structure is created through [`FooPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`Foo`] as well. pub struct FooPre { instance_pre: wasmtime::component::InstancePre, - new: wasmtime::component::ComponentExportIndex, + indices: FooIndices, } impl Clone for FooPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), - new: self.new.clone(), + indices: self.indices.clone(), } } } +impl<_T> FooPre<_T> { + /// Creates a new copy of `FooPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = FooIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`Foo`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub fn instantiate( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate(&mut store)?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `foo`. +/// +/// This is an implementation detail of [`FooPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`Foo`] as well. +#[derive(Clone)] +pub struct FooIndices { + new: wasmtime::component::ComponentExportIndex, +} /// Auto-generated bindings for an instance a component which /// implements the world `foo`. /// -/// This structure is created through either -/// [`Foo::instantiate`] or by first creating -/// a [`FooPre`] followed by using -/// [`FooPre::instantiate`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`Foo::instantiate`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`FooPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`FooPre::instantiate`] to +/// create a [`Foo`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`Foo::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`FooIndices::new_instance`] followed +/// by [`FooIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct Foo { new: wasmtime::component::Func, } const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> FooPre<_T> { - /// Creates a new copy of `FooPre` bindings which can then + impl FooIndices { + /// Creates a new copy of `FooIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, ) -> wasmtime::Result { - let _component = instance_pre.component(); + let _component = component; let new = _component .export_index(None, "new") .ok_or_else(|| anyhow::anyhow!("no function export `new` found"))? .1; - Ok(FooPre { instance_pre, new }) + Ok(FooIndices { new }) + } + /// Creates a new instance of [`FooIndices`] from an + /// instantiated component. + /// + /// This method of creating a [`Foo`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`Foo`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; + let new = _instance + .get_export(&mut store, None, "new") + .ok_or_else(|| anyhow::anyhow!("no function export `new` found"))?; + Ok(FooIndices { new }) } - /// Instantiates a new instance of [`Foo`] within the - /// `store` provided. + /// Uses the indices stored in `self` to load an instance + /// of [`Foo`] from the instance provided. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub fn instantiate( + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate(&mut store)?; + let _instance = instance; let new = *_instance.get_typed_func::<(), ()>(&mut store, &self.new)?.func(); Ok(Foo { new }) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl Foo { /// Convenience wrapper around [`FooPre::new`] and @@ -79,6 +158,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; FooPre::new(pre)?.instantiate(store) } + /// Convenience wrapper around [`FooIndices::new_instance`] and + /// [`FooIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = FooIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn call_new( &self, mut store: S, diff --git a/crates/component-macro/tests/expanded/function-new_async.rs b/crates/component-macro/tests/expanded/function-new_async.rs index a73d9e58b2ea..38a06794f9a6 100644 --- a/crates/component-macro/tests/expanded/function-new_async.rs +++ b/crates/component-macro/tests/expanded/function-new_async.rs @@ -4,72 +4,151 @@ /// This structure is created through [`FooPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`Foo`] as well. pub struct FooPre { instance_pre: wasmtime::component::InstancePre, - new: wasmtime::component::ComponentExportIndex, + indices: FooIndices, } impl Clone for FooPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), - new: self.new.clone(), + indices: self.indices.clone(), } } } +impl<_T> FooPre<_T> { + /// Creates a new copy of `FooPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = FooIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`Foo`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub async fn instantiate_async( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result + where + _T: Send, + { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate_async(&mut store).await?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `foo`. +/// +/// This is an implementation detail of [`FooPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`Foo`] as well. +#[derive(Clone)] +pub struct FooIndices { + new: wasmtime::component::ComponentExportIndex, +} /// Auto-generated bindings for an instance a component which /// implements the world `foo`. /// -/// This structure is created through either -/// [`Foo::instantiate_async`] or by first creating -/// a [`FooPre`] followed by using -/// [`FooPre::instantiate_async`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`Foo::instantiate_async`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`FooPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`FooPre::instantiate_async`] to +/// create a [`Foo`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`Foo::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`FooIndices::new_instance`] followed +/// by [`FooIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct Foo { new: wasmtime::component::Func, } const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> FooPre<_T> { - /// Creates a new copy of `FooPre` bindings which can then + impl FooIndices { + /// Creates a new copy of `FooIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, ) -> wasmtime::Result { - let _component = instance_pre.component(); + let _component = component; let new = _component .export_index(None, "new") .ok_or_else(|| anyhow::anyhow!("no function export `new` found"))? .1; - Ok(FooPre { instance_pre, new }) + Ok(FooIndices { new }) + } + /// Creates a new instance of [`FooIndices`] from an + /// instantiated component. + /// + /// This method of creating a [`Foo`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`Foo`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; + let new = _instance + .get_export(&mut store, None, "new") + .ok_or_else(|| anyhow::anyhow!("no function export `new` found"))?; + Ok(FooIndices { new }) } - /// Instantiates a new instance of [`Foo`] within the - /// `store` provided. + /// Uses the indices stored in `self` to load an instance + /// of [`Foo`] from the instance provided. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub async fn instantiate_async( + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate_async(&mut store).await?; + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; let new = *_instance.get_typed_func::<(), ()>(&mut store, &self.new)?.func(); Ok(Foo { new }) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl Foo { /// Convenience wrapper around [`FooPre::new`] and @@ -85,6 +164,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; FooPre::new(pre)?.instantiate_async(store).await } + /// Convenience wrapper around [`FooIndices::new_instance`] and + /// [`FooIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = FooIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub async fn call_new( &self, mut store: S, diff --git a/crates/component-macro/tests/expanded/integers.rs b/crates/component-macro/tests/expanded/integers.rs index 5c3f8b4c5771..a0ea4d42e45e 100644 --- a/crates/component-macro/tests/expanded/integers.rs +++ b/crates/component-macro/tests/expanded/integers.rs @@ -4,69 +4,146 @@ /// This structure is created through [`TheWorldPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`TheWorld`] as well. pub struct TheWorldPre { instance_pre: wasmtime::component::InstancePre, - interface0: exports::foo::foo::integers::GuestPre, + indices: TheWorldIndices, } impl Clone for TheWorldPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), - interface0: self.interface0.clone(), + indices: self.indices.clone(), } } } +impl<_T> TheWorldPre<_T> { + /// Creates a new copy of `TheWorldPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`TheWorld`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub fn instantiate( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate(&mut store)?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `the-world`. +/// +/// This is an implementation detail of [`TheWorldPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`TheWorld`] as well. +#[derive(Clone)] +pub struct TheWorldIndices { + interface0: exports::foo::foo::integers::GuestIndices, +} /// Auto-generated bindings for an instance a component which /// implements the world `the-world`. /// -/// This structure is created through either -/// [`TheWorld::instantiate`] or by first creating -/// a [`TheWorldPre`] followed by using -/// [`TheWorldPre::instantiate`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`TheWorld::instantiate`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`TheWorldPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`TheWorldPre::instantiate`] to +/// create a [`TheWorld`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`TheWorld::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`TheWorldIndices::new_instance`] followed +/// by [`TheWorldIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct TheWorld { interface0: exports::foo::foo::integers::Guest, } const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> TheWorldPre<_T> { - /// Creates a new copy of `TheWorldPre` bindings which can then + impl TheWorldIndices { + /// Creates a new copy of `TheWorldIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, + ) -> wasmtime::Result { + let _component = component; + let interface0 = exports::foo::foo::integers::GuestIndices::new(_component)?; + Ok(TheWorldIndices { interface0 }) + } + /// Creates a new instance of [`TheWorldIndices`] from an + /// instantiated component. + /// + /// This method of creating a [`TheWorld`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`TheWorld`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let _component = instance_pre.component(); - let interface0 = exports::foo::foo::integers::GuestPre::new(_component)?; - Ok(TheWorldPre { - instance_pre, - interface0, - }) + let _instance = instance; + let interface0 = exports::foo::foo::integers::GuestIndices::new_instance( + &mut store, + _instance, + )?; + Ok(TheWorldIndices { interface0 }) } - /// Instantiates a new instance of [`TheWorld`] within the - /// `store` provided. + /// Uses the indices stored in `self` to load an instance + /// of [`TheWorld`] from the instance provided. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub fn instantiate( + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate(&mut store)?; + let _instance = instance; let interface0 = self.interface0.load(&mut store, &_instance)?; Ok(TheWorld { interface0 }) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl TheWorld { /// Convenience wrapper around [`TheWorldPre::new`] and @@ -79,6 +156,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate(store) } + /// Convenience wrapper around [`TheWorldIndices::new_instance`] and + /// [`TheWorldIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker( linker: &mut wasmtime::component::Linker, get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, @@ -421,7 +507,7 @@ pub mod exports { pair_ret: wasmtime::component::Func, } #[derive(Clone)] - pub struct GuestPre { + pub struct GuestIndices { a1: wasmtime::component::ComponentExportIndex, a2: wasmtime::component::ComponentExportIndex, a3: wasmtime::component::ComponentExportIndex, @@ -441,11 +527,16 @@ pub mod exports { r8: wasmtime::component::ComponentExportIndex, pair_ret: wasmtime::component::ComponentExportIndex, } - impl GuestPre { + impl GuestIndices { + /// Constructor for [`GuestIndices`] which takes a + /// [`Component`](wasmtime::component::Component) as input and can be executed + /// before instantiation. + /// + /// This constructor can be used to front-load string lookups to find exports + /// within a component. pub fn new( component: &wasmtime::component::Component, - ) -> wasmtime::Result { - let _component = component; + ) -> wasmtime::Result { let (_, instance) = component .export_index(None, "foo:foo/integers") .ok_or_else(|| { @@ -453,10 +544,34 @@ pub mod exports { "no exported instance named `foo:foo/integers`" ) })?; - let _lookup = |name: &str| { - _component - .export_index(Some(&instance), name) - .map(|p| p.1) + Self::_new(|name| { + component.export_index(Some(&instance), name).map(|p| p.1) + }) + } + /// This constructor is similar to [`GuestIndices::new`] except that it + /// performs string lookups after instantiation time. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let instance_export = instance + .get_export(&mut store, None, "foo:foo/integers") + .ok_or_else(|| { + anyhow::anyhow!( + "no exported instance named `foo:foo/integers`" + ) + })?; + Self::_new(|name| { + instance.get_export(&mut store, Some(&instance_export), name) + }) + } + fn _new( + mut lookup: impl FnMut( + &str, + ) -> Option, + ) -> wasmtime::Result { + let mut lookup = move |name| { + lookup(name) .ok_or_else(|| { anyhow::anyhow!( "instance export `foo:foo/integers` does \ @@ -464,25 +579,26 @@ pub mod exports { ) }) }; - let a1 = _lookup("a1")?; - let a2 = _lookup("a2")?; - let a3 = _lookup("a3")?; - let a4 = _lookup("a4")?; - let a5 = _lookup("a5")?; - let a6 = _lookup("a6")?; - let a7 = _lookup("a7")?; - let a8 = _lookup("a8")?; - let a9 = _lookup("a9")?; - let r1 = _lookup("r1")?; - let r2 = _lookup("r2")?; - let r3 = _lookup("r3")?; - let r4 = _lookup("r4")?; - let r5 = _lookup("r5")?; - let r6 = _lookup("r6")?; - let r7 = _lookup("r7")?; - let r8 = _lookup("r8")?; - let pair_ret = _lookup("pair-ret")?; - Ok(GuestPre { + let _ = &mut lookup; + let a1 = lookup("a1")?; + let a2 = lookup("a2")?; + let a3 = lookup("a3")?; + let a4 = lookup("a4")?; + let a5 = lookup("a5")?; + let a6 = lookup("a6")?; + let a7 = lookup("a7")?; + let a8 = lookup("a8")?; + let a9 = lookup("a9")?; + let r1 = lookup("r1")?; + let r2 = lookup("r2")?; + let r3 = lookup("r3")?; + let r4 = lookup("r4")?; + let r5 = lookup("r5")?; + let r6 = lookup("r6")?; + let r7 = lookup("r7")?; + let r8 = lookup("r8")?; + let pair_ret = lookup("pair-ret")?; + Ok(GuestIndices { a1, a2, a3, diff --git a/crates/component-macro/tests/expanded/integers_async.rs b/crates/component-macro/tests/expanded/integers_async.rs index 3679c95b9d8c..3b6c21f7ce21 100644 --- a/crates/component-macro/tests/expanded/integers_async.rs +++ b/crates/component-macro/tests/expanded/integers_async.rs @@ -4,72 +4,149 @@ /// This structure is created through [`TheWorldPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`TheWorld`] as well. pub struct TheWorldPre { instance_pre: wasmtime::component::InstancePre, - interface0: exports::foo::foo::integers::GuestPre, + indices: TheWorldIndices, } impl Clone for TheWorldPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), - interface0: self.interface0.clone(), + indices: self.indices.clone(), } } } +impl<_T> TheWorldPre<_T> { + /// Creates a new copy of `TheWorldPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`TheWorld`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub async fn instantiate_async( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result + where + _T: Send, + { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate_async(&mut store).await?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `the-world`. +/// +/// This is an implementation detail of [`TheWorldPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`TheWorld`] as well. +#[derive(Clone)] +pub struct TheWorldIndices { + interface0: exports::foo::foo::integers::GuestIndices, +} /// Auto-generated bindings for an instance a component which /// implements the world `the-world`. /// -/// This structure is created through either -/// [`TheWorld::instantiate_async`] or by first creating -/// a [`TheWorldPre`] followed by using -/// [`TheWorldPre::instantiate_async`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`TheWorld::instantiate_async`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`TheWorldPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`TheWorldPre::instantiate_async`] to +/// create a [`TheWorld`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`TheWorld::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`TheWorldIndices::new_instance`] followed +/// by [`TheWorldIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct TheWorld { interface0: exports::foo::foo::integers::Guest, } const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> TheWorldPre<_T> { - /// Creates a new copy of `TheWorldPre` bindings which can then + impl TheWorldIndices { + /// Creates a new copy of `TheWorldIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, ) -> wasmtime::Result { - let _component = instance_pre.component(); - let interface0 = exports::foo::foo::integers::GuestPre::new(_component)?; - Ok(TheWorldPre { - instance_pre, - interface0, - }) + let _component = component; + let interface0 = exports::foo::foo::integers::GuestIndices::new(_component)?; + Ok(TheWorldIndices { interface0 }) } - /// Instantiates a new instance of [`TheWorld`] within the - /// `store` provided. + /// Creates a new instance of [`TheWorldIndices`] from an + /// instantiated component. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub async fn instantiate_async( + /// This method of creating a [`TheWorld`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`TheWorld`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; + let interface0 = exports::foo::foo::integers::GuestIndices::new_instance( + &mut store, + _instance, + )?; + Ok(TheWorldIndices { interface0 }) + } + /// Uses the indices stored in `self` to load an instance + /// of [`TheWorld`] from the instance provided. + /// + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate_async(&mut store).await?; + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; let interface0 = self.interface0.load(&mut store, &_instance)?; Ok(TheWorld { interface0 }) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl TheWorld { /// Convenience wrapper around [`TheWorldPre::new`] and @@ -85,6 +162,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate_async(store).await } + /// Convenience wrapper around [`TheWorldIndices::new_instance`] and + /// [`TheWorldIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker( linker: &mut wasmtime::component::Linker, get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, @@ -435,7 +521,7 @@ pub mod exports { pair_ret: wasmtime::component::Func, } #[derive(Clone)] - pub struct GuestPre { + pub struct GuestIndices { a1: wasmtime::component::ComponentExportIndex, a2: wasmtime::component::ComponentExportIndex, a3: wasmtime::component::ComponentExportIndex, @@ -455,11 +541,16 @@ pub mod exports { r8: wasmtime::component::ComponentExportIndex, pair_ret: wasmtime::component::ComponentExportIndex, } - impl GuestPre { + impl GuestIndices { + /// Constructor for [`GuestIndices`] which takes a + /// [`Component`](wasmtime::component::Component) as input and can be executed + /// before instantiation. + /// + /// This constructor can be used to front-load string lookups to find exports + /// within a component. pub fn new( component: &wasmtime::component::Component, - ) -> wasmtime::Result { - let _component = component; + ) -> wasmtime::Result { let (_, instance) = component .export_index(None, "foo:foo/integers") .ok_or_else(|| { @@ -467,10 +558,34 @@ pub mod exports { "no exported instance named `foo:foo/integers`" ) })?; - let _lookup = |name: &str| { - _component - .export_index(Some(&instance), name) - .map(|p| p.1) + Self::_new(|name| { + component.export_index(Some(&instance), name).map(|p| p.1) + }) + } + /// This constructor is similar to [`GuestIndices::new`] except that it + /// performs string lookups after instantiation time. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let instance_export = instance + .get_export(&mut store, None, "foo:foo/integers") + .ok_or_else(|| { + anyhow::anyhow!( + "no exported instance named `foo:foo/integers`" + ) + })?; + Self::_new(|name| { + instance.get_export(&mut store, Some(&instance_export), name) + }) + } + fn _new( + mut lookup: impl FnMut( + &str, + ) -> Option, + ) -> wasmtime::Result { + let mut lookup = move |name| { + lookup(name) .ok_or_else(|| { anyhow::anyhow!( "instance export `foo:foo/integers` does \ @@ -478,25 +593,26 @@ pub mod exports { ) }) }; - let a1 = _lookup("a1")?; - let a2 = _lookup("a2")?; - let a3 = _lookup("a3")?; - let a4 = _lookup("a4")?; - let a5 = _lookup("a5")?; - let a6 = _lookup("a6")?; - let a7 = _lookup("a7")?; - let a8 = _lookup("a8")?; - let a9 = _lookup("a9")?; - let r1 = _lookup("r1")?; - let r2 = _lookup("r2")?; - let r3 = _lookup("r3")?; - let r4 = _lookup("r4")?; - let r5 = _lookup("r5")?; - let r6 = _lookup("r6")?; - let r7 = _lookup("r7")?; - let r8 = _lookup("r8")?; - let pair_ret = _lookup("pair-ret")?; - Ok(GuestPre { + let _ = &mut lookup; + let a1 = lookup("a1")?; + let a2 = lookup("a2")?; + let a3 = lookup("a3")?; + let a4 = lookup("a4")?; + let a5 = lookup("a5")?; + let a6 = lookup("a6")?; + let a7 = lookup("a7")?; + let a8 = lookup("a8")?; + let a9 = lookup("a9")?; + let r1 = lookup("r1")?; + let r2 = lookup("r2")?; + let r3 = lookup("r3")?; + let r4 = lookup("r4")?; + let r5 = lookup("r5")?; + let r6 = lookup("r6")?; + let r7 = lookup("r7")?; + let r8 = lookup("r8")?; + let pair_ret = lookup("pair-ret")?; + Ok(GuestIndices { a1, a2, a3, diff --git a/crates/component-macro/tests/expanded/lists.rs b/crates/component-macro/tests/expanded/lists.rs index ae79038a46a4..acffcb2154d3 100644 --- a/crates/component-macro/tests/expanded/lists.rs +++ b/crates/component-macro/tests/expanded/lists.rs @@ -4,69 +4,146 @@ /// This structure is created through [`TheListsPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`TheLists`] as well. pub struct TheListsPre { instance_pre: wasmtime::component::InstancePre, - interface0: exports::foo::foo::lists::GuestPre, + indices: TheListsIndices, } impl Clone for TheListsPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), - interface0: self.interface0.clone(), + indices: self.indices.clone(), } } } +impl<_T> TheListsPre<_T> { + /// Creates a new copy of `TheListsPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = TheListsIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`TheLists`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub fn instantiate( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate(&mut store)?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `the-lists`. +/// +/// This is an implementation detail of [`TheListsPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`TheLists`] as well. +#[derive(Clone)] +pub struct TheListsIndices { + interface0: exports::foo::foo::lists::GuestIndices, +} /// Auto-generated bindings for an instance a component which /// implements the world `the-lists`. /// -/// This structure is created through either -/// [`TheLists::instantiate`] or by first creating -/// a [`TheListsPre`] followed by using -/// [`TheListsPre::instantiate`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`TheLists::instantiate`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`TheListsPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`TheListsPre::instantiate`] to +/// create a [`TheLists`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`TheLists::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`TheListsIndices::new_instance`] followed +/// by [`TheListsIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct TheLists { interface0: exports::foo::foo::lists::Guest, } const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> TheListsPre<_T> { - /// Creates a new copy of `TheListsPre` bindings which can then + impl TheListsIndices { + /// Creates a new copy of `TheListsIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, + ) -> wasmtime::Result { + let _component = component; + let interface0 = exports::foo::foo::lists::GuestIndices::new(_component)?; + Ok(TheListsIndices { interface0 }) + } + /// Creates a new instance of [`TheListsIndices`] from an + /// instantiated component. + /// + /// This method of creating a [`TheLists`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`TheLists`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let _component = instance_pre.component(); - let interface0 = exports::foo::foo::lists::GuestPre::new(_component)?; - Ok(TheListsPre { - instance_pre, - interface0, - }) + let _instance = instance; + let interface0 = exports::foo::foo::lists::GuestIndices::new_instance( + &mut store, + _instance, + )?; + Ok(TheListsIndices { interface0 }) } - /// Instantiates a new instance of [`TheLists`] within the - /// `store` provided. + /// Uses the indices stored in `self` to load an instance + /// of [`TheLists`] from the instance provided. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub fn instantiate( + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate(&mut store)?; + let _instance = instance; let interface0 = self.interface0.load(&mut store, &_instance)?; Ok(TheLists { interface0 }) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl TheLists { /// Convenience wrapper around [`TheListsPre::new`] and @@ -79,6 +156,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; TheListsPre::new(pre)?.instantiate(store) } + /// Convenience wrapper around [`TheListsIndices::new_instance`] and + /// [`TheListsIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = TheListsIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker( linker: &mut wasmtime::component::Linker, get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, @@ -1118,7 +1204,7 @@ pub mod exports { load_store_everything: wasmtime::component::Func, } #[derive(Clone)] - pub struct GuestPre { + pub struct GuestIndices { list_u8_param: wasmtime::component::ComponentExportIndex, list_u16_param: wasmtime::component::ComponentExportIndex, list_u32_param: wasmtime::component::ComponentExportIndex, @@ -1149,11 +1235,16 @@ pub mod exports { variant_list: wasmtime::component::ComponentExportIndex, load_store_everything: wasmtime::component::ComponentExportIndex, } - impl GuestPre { + impl GuestIndices { + /// Constructor for [`GuestIndices`] which takes a + /// [`Component`](wasmtime::component::Component) as input and can be executed + /// before instantiation. + /// + /// This constructor can be used to front-load string lookups to find exports + /// within a component. pub fn new( component: &wasmtime::component::Component, - ) -> wasmtime::Result { - let _component = component; + ) -> wasmtime::Result { let (_, instance) = component .export_index(None, "foo:foo/lists") .ok_or_else(|| { @@ -1161,10 +1252,34 @@ pub mod exports { "no exported instance named `foo:foo/lists`" ) })?; - let _lookup = |name: &str| { - _component - .export_index(Some(&instance), name) - .map(|p| p.1) + Self::_new(|name| { + component.export_index(Some(&instance), name).map(|p| p.1) + }) + } + /// This constructor is similar to [`GuestIndices::new`] except that it + /// performs string lookups after instantiation time. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let instance_export = instance + .get_export(&mut store, None, "foo:foo/lists") + .ok_or_else(|| { + anyhow::anyhow!( + "no exported instance named `foo:foo/lists`" + ) + })?; + Self::_new(|name| { + instance.get_export(&mut store, Some(&instance_export), name) + }) + } + fn _new( + mut lookup: impl FnMut( + &str, + ) -> Option, + ) -> wasmtime::Result { + let mut lookup = move |name| { + lookup(name) .ok_or_else(|| { anyhow::anyhow!( "instance export `foo:foo/lists` does \ @@ -1172,36 +1287,37 @@ pub mod exports { ) }) }; - let list_u8_param = _lookup("list-u8-param")?; - let list_u16_param = _lookup("list-u16-param")?; - let list_u32_param = _lookup("list-u32-param")?; - let list_u64_param = _lookup("list-u64-param")?; - let list_s8_param = _lookup("list-s8-param")?; - let list_s16_param = _lookup("list-s16-param")?; - let list_s32_param = _lookup("list-s32-param")?; - let list_s64_param = _lookup("list-s64-param")?; - let list_float32_param = _lookup("list-float32-param")?; - let list_float64_param = _lookup("list-float64-param")?; - let list_u8_ret = _lookup("list-u8-ret")?; - let list_u16_ret = _lookup("list-u16-ret")?; - let list_u32_ret = _lookup("list-u32-ret")?; - let list_u64_ret = _lookup("list-u64-ret")?; - let list_s8_ret = _lookup("list-s8-ret")?; - let list_s16_ret = _lookup("list-s16-ret")?; - let list_s32_ret = _lookup("list-s32-ret")?; - let list_s64_ret = _lookup("list-s64-ret")?; - let list_float32_ret = _lookup("list-float32-ret")?; - let list_float64_ret = _lookup("list-float64-ret")?; - let tuple_list = _lookup("tuple-list")?; - let string_list_arg = _lookup("string-list-arg")?; - let string_list_ret = _lookup("string-list-ret")?; - let tuple_string_list = _lookup("tuple-string-list")?; - let string_list = _lookup("string-list")?; - let record_list = _lookup("record-list")?; - let record_list_reverse = _lookup("record-list-reverse")?; - let variant_list = _lookup("variant-list")?; - let load_store_everything = _lookup("load-store-everything")?; - Ok(GuestPre { + let _ = &mut lookup; + let list_u8_param = lookup("list-u8-param")?; + let list_u16_param = lookup("list-u16-param")?; + let list_u32_param = lookup("list-u32-param")?; + let list_u64_param = lookup("list-u64-param")?; + let list_s8_param = lookup("list-s8-param")?; + let list_s16_param = lookup("list-s16-param")?; + let list_s32_param = lookup("list-s32-param")?; + let list_s64_param = lookup("list-s64-param")?; + let list_float32_param = lookup("list-float32-param")?; + let list_float64_param = lookup("list-float64-param")?; + let list_u8_ret = lookup("list-u8-ret")?; + let list_u16_ret = lookup("list-u16-ret")?; + let list_u32_ret = lookup("list-u32-ret")?; + let list_u64_ret = lookup("list-u64-ret")?; + let list_s8_ret = lookup("list-s8-ret")?; + let list_s16_ret = lookup("list-s16-ret")?; + let list_s32_ret = lookup("list-s32-ret")?; + let list_s64_ret = lookup("list-s64-ret")?; + let list_float32_ret = lookup("list-float32-ret")?; + let list_float64_ret = lookup("list-float64-ret")?; + let tuple_list = lookup("tuple-list")?; + let string_list_arg = lookup("string-list-arg")?; + let string_list_ret = lookup("string-list-ret")?; + let tuple_string_list = lookup("tuple-string-list")?; + let string_list = lookup("string-list")?; + let record_list = lookup("record-list")?; + let record_list_reverse = lookup("record-list-reverse")?; + let variant_list = lookup("variant-list")?; + let load_store_everything = lookup("load-store-everything")?; + Ok(GuestIndices { list_u8_param, list_u16_param, list_u32_param, diff --git a/crates/component-macro/tests/expanded/lists_async.rs b/crates/component-macro/tests/expanded/lists_async.rs index aa250df5f1b4..63d0fd7ff69f 100644 --- a/crates/component-macro/tests/expanded/lists_async.rs +++ b/crates/component-macro/tests/expanded/lists_async.rs @@ -4,72 +4,149 @@ /// This structure is created through [`TheListsPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`TheLists`] as well. pub struct TheListsPre { instance_pre: wasmtime::component::InstancePre, - interface0: exports::foo::foo::lists::GuestPre, + indices: TheListsIndices, } impl Clone for TheListsPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), - interface0: self.interface0.clone(), + indices: self.indices.clone(), } } } +impl<_T> TheListsPre<_T> { + /// Creates a new copy of `TheListsPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = TheListsIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`TheLists`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub async fn instantiate_async( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result + where + _T: Send, + { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate_async(&mut store).await?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `the-lists`. +/// +/// This is an implementation detail of [`TheListsPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`TheLists`] as well. +#[derive(Clone)] +pub struct TheListsIndices { + interface0: exports::foo::foo::lists::GuestIndices, +} /// Auto-generated bindings for an instance a component which /// implements the world `the-lists`. /// -/// This structure is created through either -/// [`TheLists::instantiate_async`] or by first creating -/// a [`TheListsPre`] followed by using -/// [`TheListsPre::instantiate_async`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`TheLists::instantiate_async`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`TheListsPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`TheListsPre::instantiate_async`] to +/// create a [`TheLists`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`TheLists::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`TheListsIndices::new_instance`] followed +/// by [`TheListsIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct TheLists { interface0: exports::foo::foo::lists::Guest, } const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> TheListsPre<_T> { - /// Creates a new copy of `TheListsPre` bindings which can then + impl TheListsIndices { + /// Creates a new copy of `TheListsIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, ) -> wasmtime::Result { - let _component = instance_pre.component(); - let interface0 = exports::foo::foo::lists::GuestPre::new(_component)?; - Ok(TheListsPre { - instance_pre, - interface0, - }) + let _component = component; + let interface0 = exports::foo::foo::lists::GuestIndices::new(_component)?; + Ok(TheListsIndices { interface0 }) } - /// Instantiates a new instance of [`TheLists`] within the - /// `store` provided. + /// Creates a new instance of [`TheListsIndices`] from an + /// instantiated component. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub async fn instantiate_async( + /// This method of creating a [`TheLists`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`TheLists`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; + let interface0 = exports::foo::foo::lists::GuestIndices::new_instance( + &mut store, + _instance, + )?; + Ok(TheListsIndices { interface0 }) + } + /// Uses the indices stored in `self` to load an instance + /// of [`TheLists`] from the instance provided. + /// + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate_async(&mut store).await?; + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; let interface0 = self.interface0.load(&mut store, &_instance)?; Ok(TheLists { interface0 }) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl TheLists { /// Convenience wrapper around [`TheListsPre::new`] and @@ -85,6 +162,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; TheListsPre::new(pre)?.instantiate_async(store).await } + /// Convenience wrapper around [`TheListsIndices::new_instance`] and + /// [`TheListsIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = TheListsIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker( linker: &mut wasmtime::component::Linker, get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, @@ -1163,7 +1249,7 @@ pub mod exports { load_store_everything: wasmtime::component::Func, } #[derive(Clone)] - pub struct GuestPre { + pub struct GuestIndices { list_u8_param: wasmtime::component::ComponentExportIndex, list_u16_param: wasmtime::component::ComponentExportIndex, list_u32_param: wasmtime::component::ComponentExportIndex, @@ -1194,11 +1280,16 @@ pub mod exports { variant_list: wasmtime::component::ComponentExportIndex, load_store_everything: wasmtime::component::ComponentExportIndex, } - impl GuestPre { + impl GuestIndices { + /// Constructor for [`GuestIndices`] which takes a + /// [`Component`](wasmtime::component::Component) as input and can be executed + /// before instantiation. + /// + /// This constructor can be used to front-load string lookups to find exports + /// within a component. pub fn new( component: &wasmtime::component::Component, - ) -> wasmtime::Result { - let _component = component; + ) -> wasmtime::Result { let (_, instance) = component .export_index(None, "foo:foo/lists") .ok_or_else(|| { @@ -1206,10 +1297,34 @@ pub mod exports { "no exported instance named `foo:foo/lists`" ) })?; - let _lookup = |name: &str| { - _component - .export_index(Some(&instance), name) - .map(|p| p.1) + Self::_new(|name| { + component.export_index(Some(&instance), name).map(|p| p.1) + }) + } + /// This constructor is similar to [`GuestIndices::new`] except that it + /// performs string lookups after instantiation time. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let instance_export = instance + .get_export(&mut store, None, "foo:foo/lists") + .ok_or_else(|| { + anyhow::anyhow!( + "no exported instance named `foo:foo/lists`" + ) + })?; + Self::_new(|name| { + instance.get_export(&mut store, Some(&instance_export), name) + }) + } + fn _new( + mut lookup: impl FnMut( + &str, + ) -> Option, + ) -> wasmtime::Result { + let mut lookup = move |name| { + lookup(name) .ok_or_else(|| { anyhow::anyhow!( "instance export `foo:foo/lists` does \ @@ -1217,36 +1332,37 @@ pub mod exports { ) }) }; - let list_u8_param = _lookup("list-u8-param")?; - let list_u16_param = _lookup("list-u16-param")?; - let list_u32_param = _lookup("list-u32-param")?; - let list_u64_param = _lookup("list-u64-param")?; - let list_s8_param = _lookup("list-s8-param")?; - let list_s16_param = _lookup("list-s16-param")?; - let list_s32_param = _lookup("list-s32-param")?; - let list_s64_param = _lookup("list-s64-param")?; - let list_float32_param = _lookup("list-float32-param")?; - let list_float64_param = _lookup("list-float64-param")?; - let list_u8_ret = _lookup("list-u8-ret")?; - let list_u16_ret = _lookup("list-u16-ret")?; - let list_u32_ret = _lookup("list-u32-ret")?; - let list_u64_ret = _lookup("list-u64-ret")?; - let list_s8_ret = _lookup("list-s8-ret")?; - let list_s16_ret = _lookup("list-s16-ret")?; - let list_s32_ret = _lookup("list-s32-ret")?; - let list_s64_ret = _lookup("list-s64-ret")?; - let list_float32_ret = _lookup("list-float32-ret")?; - let list_float64_ret = _lookup("list-float64-ret")?; - let tuple_list = _lookup("tuple-list")?; - let string_list_arg = _lookup("string-list-arg")?; - let string_list_ret = _lookup("string-list-ret")?; - let tuple_string_list = _lookup("tuple-string-list")?; - let string_list = _lookup("string-list")?; - let record_list = _lookup("record-list")?; - let record_list_reverse = _lookup("record-list-reverse")?; - let variant_list = _lookup("variant-list")?; - let load_store_everything = _lookup("load-store-everything")?; - Ok(GuestPre { + let _ = &mut lookup; + let list_u8_param = lookup("list-u8-param")?; + let list_u16_param = lookup("list-u16-param")?; + let list_u32_param = lookup("list-u32-param")?; + let list_u64_param = lookup("list-u64-param")?; + let list_s8_param = lookup("list-s8-param")?; + let list_s16_param = lookup("list-s16-param")?; + let list_s32_param = lookup("list-s32-param")?; + let list_s64_param = lookup("list-s64-param")?; + let list_float32_param = lookup("list-float32-param")?; + let list_float64_param = lookup("list-float64-param")?; + let list_u8_ret = lookup("list-u8-ret")?; + let list_u16_ret = lookup("list-u16-ret")?; + let list_u32_ret = lookup("list-u32-ret")?; + let list_u64_ret = lookup("list-u64-ret")?; + let list_s8_ret = lookup("list-s8-ret")?; + let list_s16_ret = lookup("list-s16-ret")?; + let list_s32_ret = lookup("list-s32-ret")?; + let list_s64_ret = lookup("list-s64-ret")?; + let list_float32_ret = lookup("list-float32-ret")?; + let list_float64_ret = lookup("list-float64-ret")?; + let tuple_list = lookup("tuple-list")?; + let string_list_arg = lookup("string-list-arg")?; + let string_list_ret = lookup("string-list-ret")?; + let tuple_string_list = lookup("tuple-string-list")?; + let string_list = lookup("string-list")?; + let record_list = lookup("record-list")?; + let record_list_reverse = lookup("record-list-reverse")?; + let variant_list = lookup("variant-list")?; + let load_store_everything = lookup("load-store-everything")?; + Ok(GuestIndices { list_u8_param, list_u16_param, list_u32_param, diff --git a/crates/component-macro/tests/expanded/many-arguments.rs b/crates/component-macro/tests/expanded/many-arguments.rs index ea02f665f101..86db694f8323 100644 --- a/crates/component-macro/tests/expanded/many-arguments.rs +++ b/crates/component-macro/tests/expanded/many-arguments.rs @@ -4,69 +4,146 @@ /// This structure is created through [`TheWorldPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`TheWorld`] as well. pub struct TheWorldPre { instance_pre: wasmtime::component::InstancePre, - interface0: exports::foo::foo::manyarg::GuestPre, + indices: TheWorldIndices, } impl Clone for TheWorldPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), - interface0: self.interface0.clone(), + indices: self.indices.clone(), } } } +impl<_T> TheWorldPre<_T> { + /// Creates a new copy of `TheWorldPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`TheWorld`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub fn instantiate( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate(&mut store)?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `the-world`. +/// +/// This is an implementation detail of [`TheWorldPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`TheWorld`] as well. +#[derive(Clone)] +pub struct TheWorldIndices { + interface0: exports::foo::foo::manyarg::GuestIndices, +} /// Auto-generated bindings for an instance a component which /// implements the world `the-world`. /// -/// This structure is created through either -/// [`TheWorld::instantiate`] or by first creating -/// a [`TheWorldPre`] followed by using -/// [`TheWorldPre::instantiate`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`TheWorld::instantiate`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`TheWorldPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`TheWorldPre::instantiate`] to +/// create a [`TheWorld`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`TheWorld::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`TheWorldIndices::new_instance`] followed +/// by [`TheWorldIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct TheWorld { interface0: exports::foo::foo::manyarg::Guest, } const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> TheWorldPre<_T> { - /// Creates a new copy of `TheWorldPre` bindings which can then + impl TheWorldIndices { + /// Creates a new copy of `TheWorldIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, + ) -> wasmtime::Result { + let _component = component; + let interface0 = exports::foo::foo::manyarg::GuestIndices::new(_component)?; + Ok(TheWorldIndices { interface0 }) + } + /// Creates a new instance of [`TheWorldIndices`] from an + /// instantiated component. + /// + /// This method of creating a [`TheWorld`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`TheWorld`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let _component = instance_pre.component(); - let interface0 = exports::foo::foo::manyarg::GuestPre::new(_component)?; - Ok(TheWorldPre { - instance_pre, - interface0, - }) + let _instance = instance; + let interface0 = exports::foo::foo::manyarg::GuestIndices::new_instance( + &mut store, + _instance, + )?; + Ok(TheWorldIndices { interface0 }) } - /// Instantiates a new instance of [`TheWorld`] within the - /// `store` provided. + /// Uses the indices stored in `self` to load an instance + /// of [`TheWorld`] from the instance provided. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub fn instantiate( + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate(&mut store)?; + let _instance = instance; let interface0 = self.interface0.load(&mut store, &_instance)?; Ok(TheWorld { interface0 }) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl TheWorld { /// Convenience wrapper around [`TheWorldPre::new`] and @@ -79,6 +156,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate(store) } + /// Convenience wrapper around [`TheWorldIndices::new_instance`] and + /// [`TheWorldIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker( linker: &mut wasmtime::component::Linker, get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, @@ -449,15 +535,20 @@ pub mod exports { big_argument: wasmtime::component::Func, } #[derive(Clone)] - pub struct GuestPre { + pub struct GuestIndices { many_args: wasmtime::component::ComponentExportIndex, big_argument: wasmtime::component::ComponentExportIndex, } - impl GuestPre { + impl GuestIndices { + /// Constructor for [`GuestIndices`] which takes a + /// [`Component`](wasmtime::component::Component) as input and can be executed + /// before instantiation. + /// + /// This constructor can be used to front-load string lookups to find exports + /// within a component. pub fn new( component: &wasmtime::component::Component, - ) -> wasmtime::Result { - let _component = component; + ) -> wasmtime::Result { let (_, instance) = component .export_index(None, "foo:foo/manyarg") .ok_or_else(|| { @@ -465,10 +556,34 @@ pub mod exports { "no exported instance named `foo:foo/manyarg`" ) })?; - let _lookup = |name: &str| { - _component - .export_index(Some(&instance), name) - .map(|p| p.1) + Self::_new(|name| { + component.export_index(Some(&instance), name).map(|p| p.1) + }) + } + /// This constructor is similar to [`GuestIndices::new`] except that it + /// performs string lookups after instantiation time. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let instance_export = instance + .get_export(&mut store, None, "foo:foo/manyarg") + .ok_or_else(|| { + anyhow::anyhow!( + "no exported instance named `foo:foo/manyarg`" + ) + })?; + Self::_new(|name| { + instance.get_export(&mut store, Some(&instance_export), name) + }) + } + fn _new( + mut lookup: impl FnMut( + &str, + ) -> Option, + ) -> wasmtime::Result { + let mut lookup = move |name| { + lookup(name) .ok_or_else(|| { anyhow::anyhow!( "instance export `foo:foo/manyarg` does \ @@ -476,9 +591,10 @@ pub mod exports { ) }) }; - let many_args = _lookup("many-args")?; - let big_argument = _lookup("big-argument")?; - Ok(GuestPre { + let _ = &mut lookup; + let many_args = lookup("many-args")?; + let big_argument = lookup("big-argument")?; + Ok(GuestIndices { many_args, big_argument, }) diff --git a/crates/component-macro/tests/expanded/many-arguments_async.rs b/crates/component-macro/tests/expanded/many-arguments_async.rs index a69503d28cb9..2411593f3fab 100644 --- a/crates/component-macro/tests/expanded/many-arguments_async.rs +++ b/crates/component-macro/tests/expanded/many-arguments_async.rs @@ -4,72 +4,149 @@ /// This structure is created through [`TheWorldPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`TheWorld`] as well. pub struct TheWorldPre { instance_pre: wasmtime::component::InstancePre, - interface0: exports::foo::foo::manyarg::GuestPre, + indices: TheWorldIndices, } impl Clone for TheWorldPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), - interface0: self.interface0.clone(), + indices: self.indices.clone(), } } } +impl<_T> TheWorldPre<_T> { + /// Creates a new copy of `TheWorldPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`TheWorld`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub async fn instantiate_async( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result + where + _T: Send, + { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate_async(&mut store).await?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `the-world`. +/// +/// This is an implementation detail of [`TheWorldPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`TheWorld`] as well. +#[derive(Clone)] +pub struct TheWorldIndices { + interface0: exports::foo::foo::manyarg::GuestIndices, +} /// Auto-generated bindings for an instance a component which /// implements the world `the-world`. /// -/// This structure is created through either -/// [`TheWorld::instantiate_async`] or by first creating -/// a [`TheWorldPre`] followed by using -/// [`TheWorldPre::instantiate_async`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`TheWorld::instantiate_async`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`TheWorldPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`TheWorldPre::instantiate_async`] to +/// create a [`TheWorld`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`TheWorld::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`TheWorldIndices::new_instance`] followed +/// by [`TheWorldIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct TheWorld { interface0: exports::foo::foo::manyarg::Guest, } const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> TheWorldPre<_T> { - /// Creates a new copy of `TheWorldPre` bindings which can then + impl TheWorldIndices { + /// Creates a new copy of `TheWorldIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, ) -> wasmtime::Result { - let _component = instance_pre.component(); - let interface0 = exports::foo::foo::manyarg::GuestPre::new(_component)?; - Ok(TheWorldPre { - instance_pre, - interface0, - }) + let _component = component; + let interface0 = exports::foo::foo::manyarg::GuestIndices::new(_component)?; + Ok(TheWorldIndices { interface0 }) } - /// Instantiates a new instance of [`TheWorld`] within the - /// `store` provided. + /// Creates a new instance of [`TheWorldIndices`] from an + /// instantiated component. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub async fn instantiate_async( + /// This method of creating a [`TheWorld`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`TheWorld`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; + let interface0 = exports::foo::foo::manyarg::GuestIndices::new_instance( + &mut store, + _instance, + )?; + Ok(TheWorldIndices { interface0 }) + } + /// Uses the indices stored in `self` to load an instance + /// of [`TheWorld`] from the instance provided. + /// + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate_async(&mut store).await?; + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; let interface0 = self.interface0.load(&mut store, &_instance)?; Ok(TheWorld { interface0 }) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl TheWorld { /// Convenience wrapper around [`TheWorldPre::new`] and @@ -85,6 +162,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate_async(store).await } + /// Convenience wrapper around [`TheWorldIndices::new_instance`] and + /// [`TheWorldIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker( linker: &mut wasmtime::component::Linker, get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, @@ -464,15 +550,20 @@ pub mod exports { big_argument: wasmtime::component::Func, } #[derive(Clone)] - pub struct GuestPre { + pub struct GuestIndices { many_args: wasmtime::component::ComponentExportIndex, big_argument: wasmtime::component::ComponentExportIndex, } - impl GuestPre { + impl GuestIndices { + /// Constructor for [`GuestIndices`] which takes a + /// [`Component`](wasmtime::component::Component) as input and can be executed + /// before instantiation. + /// + /// This constructor can be used to front-load string lookups to find exports + /// within a component. pub fn new( component: &wasmtime::component::Component, - ) -> wasmtime::Result { - let _component = component; + ) -> wasmtime::Result { let (_, instance) = component .export_index(None, "foo:foo/manyarg") .ok_or_else(|| { @@ -480,10 +571,34 @@ pub mod exports { "no exported instance named `foo:foo/manyarg`" ) })?; - let _lookup = |name: &str| { - _component - .export_index(Some(&instance), name) - .map(|p| p.1) + Self::_new(|name| { + component.export_index(Some(&instance), name).map(|p| p.1) + }) + } + /// This constructor is similar to [`GuestIndices::new`] except that it + /// performs string lookups after instantiation time. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let instance_export = instance + .get_export(&mut store, None, "foo:foo/manyarg") + .ok_or_else(|| { + anyhow::anyhow!( + "no exported instance named `foo:foo/manyarg`" + ) + })?; + Self::_new(|name| { + instance.get_export(&mut store, Some(&instance_export), name) + }) + } + fn _new( + mut lookup: impl FnMut( + &str, + ) -> Option, + ) -> wasmtime::Result { + let mut lookup = move |name| { + lookup(name) .ok_or_else(|| { anyhow::anyhow!( "instance export `foo:foo/manyarg` does \ @@ -491,9 +606,10 @@ pub mod exports { ) }) }; - let many_args = _lookup("many-args")?; - let big_argument = _lookup("big-argument")?; - Ok(GuestPre { + let _ = &mut lookup; + let many_args = lookup("many-args")?; + let big_argument = lookup("big-argument")?; + Ok(GuestIndices { many_args, big_argument, }) diff --git a/crates/component-macro/tests/expanded/multi-return.rs b/crates/component-macro/tests/expanded/multi-return.rs index b882e7404e8a..7b42ddcaeb3c 100644 --- a/crates/component-macro/tests/expanded/multi-return.rs +++ b/crates/component-macro/tests/expanded/multi-return.rs @@ -4,69 +4,148 @@ /// This structure is created through [`TheWorldPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`TheWorld`] as well. pub struct TheWorldPre { instance_pre: wasmtime::component::InstancePre, - interface0: exports::foo::foo::multi_return::GuestPre, + indices: TheWorldIndices, } impl Clone for TheWorldPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), - interface0: self.interface0.clone(), + indices: self.indices.clone(), } } } +impl<_T> TheWorldPre<_T> { + /// Creates a new copy of `TheWorldPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`TheWorld`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub fn instantiate( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate(&mut store)?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `the-world`. +/// +/// This is an implementation detail of [`TheWorldPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`TheWorld`] as well. +#[derive(Clone)] +pub struct TheWorldIndices { + interface0: exports::foo::foo::multi_return::GuestIndices, +} /// Auto-generated bindings for an instance a component which /// implements the world `the-world`. /// -/// This structure is created through either -/// [`TheWorld::instantiate`] or by first creating -/// a [`TheWorldPre`] followed by using -/// [`TheWorldPre::instantiate`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`TheWorld::instantiate`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`TheWorldPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`TheWorldPre::instantiate`] to +/// create a [`TheWorld`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`TheWorld::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`TheWorldIndices::new_instance`] followed +/// by [`TheWorldIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct TheWorld { interface0: exports::foo::foo::multi_return::Guest, } const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> TheWorldPre<_T> { - /// Creates a new copy of `TheWorldPre` bindings which can then + impl TheWorldIndices { + /// Creates a new copy of `TheWorldIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, + ) -> wasmtime::Result { + let _component = component; + let interface0 = exports::foo::foo::multi_return::GuestIndices::new( + _component, + )?; + Ok(TheWorldIndices { interface0 }) + } + /// Creates a new instance of [`TheWorldIndices`] from an + /// instantiated component. + /// + /// This method of creating a [`TheWorld`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`TheWorld`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let _component = instance_pre.component(); - let interface0 = exports::foo::foo::multi_return::GuestPre::new(_component)?; - Ok(TheWorldPre { - instance_pre, - interface0, - }) + let _instance = instance; + let interface0 = exports::foo::foo::multi_return::GuestIndices::new_instance( + &mut store, + _instance, + )?; + Ok(TheWorldIndices { interface0 }) } - /// Instantiates a new instance of [`TheWorld`] within the - /// `store` provided. + /// Uses the indices stored in `self` to load an instance + /// of [`TheWorld`] from the instance provided. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub fn instantiate( + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate(&mut store)?; + let _instance = instance; let interface0 = self.interface0.load(&mut store, &_instance)?; Ok(TheWorld { interface0 }) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl TheWorld { /// Convenience wrapper around [`TheWorldPre::new`] and @@ -79,6 +158,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate(store) } + /// Convenience wrapper around [`TheWorldIndices::new_instance`] and + /// [`TheWorldIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker( linker: &mut wasmtime::component::Linker, get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, @@ -210,18 +298,23 @@ pub mod exports { mre: wasmtime::component::Func, } #[derive(Clone)] - pub struct GuestPre { + pub struct GuestIndices { mra: wasmtime::component::ComponentExportIndex, mrb: wasmtime::component::ComponentExportIndex, mrc: wasmtime::component::ComponentExportIndex, mrd: wasmtime::component::ComponentExportIndex, mre: wasmtime::component::ComponentExportIndex, } - impl GuestPre { + impl GuestIndices { + /// Constructor for [`GuestIndices`] which takes a + /// [`Component`](wasmtime::component::Component) as input and can be executed + /// before instantiation. + /// + /// This constructor can be used to front-load string lookups to find exports + /// within a component. pub fn new( component: &wasmtime::component::Component, - ) -> wasmtime::Result { - let _component = component; + ) -> wasmtime::Result { let (_, instance) = component .export_index(None, "foo:foo/multi-return") .ok_or_else(|| { @@ -229,10 +322,34 @@ pub mod exports { "no exported instance named `foo:foo/multi-return`" ) })?; - let _lookup = |name: &str| { - _component - .export_index(Some(&instance), name) - .map(|p| p.1) + Self::_new(|name| { + component.export_index(Some(&instance), name).map(|p| p.1) + }) + } + /// This constructor is similar to [`GuestIndices::new`] except that it + /// performs string lookups after instantiation time. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let instance_export = instance + .get_export(&mut store, None, "foo:foo/multi-return") + .ok_or_else(|| { + anyhow::anyhow!( + "no exported instance named `foo:foo/multi-return`" + ) + })?; + Self::_new(|name| { + instance.get_export(&mut store, Some(&instance_export), name) + }) + } + fn _new( + mut lookup: impl FnMut( + &str, + ) -> Option, + ) -> wasmtime::Result { + let mut lookup = move |name| { + lookup(name) .ok_or_else(|| { anyhow::anyhow!( "instance export `foo:foo/multi-return` does \ @@ -240,12 +357,13 @@ pub mod exports { ) }) }; - let mra = _lookup("mra")?; - let mrb = _lookup("mrb")?; - let mrc = _lookup("mrc")?; - let mrd = _lookup("mrd")?; - let mre = _lookup("mre")?; - Ok(GuestPre { + let _ = &mut lookup; + let mra = lookup("mra")?; + let mrb = lookup("mrb")?; + let mrc = lookup("mrc")?; + let mrd = lookup("mrd")?; + let mre = lookup("mre")?; + Ok(GuestIndices { mra, mrb, mrc, diff --git a/crates/component-macro/tests/expanded/multi-return_async.rs b/crates/component-macro/tests/expanded/multi-return_async.rs index 83fd418ba805..77975ff6cb3d 100644 --- a/crates/component-macro/tests/expanded/multi-return_async.rs +++ b/crates/component-macro/tests/expanded/multi-return_async.rs @@ -4,72 +4,151 @@ /// This structure is created through [`TheWorldPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`TheWorld`] as well. pub struct TheWorldPre { instance_pre: wasmtime::component::InstancePre, - interface0: exports::foo::foo::multi_return::GuestPre, + indices: TheWorldIndices, } impl Clone for TheWorldPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), - interface0: self.interface0.clone(), + indices: self.indices.clone(), } } } +impl<_T> TheWorldPre<_T> { + /// Creates a new copy of `TheWorldPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`TheWorld`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub async fn instantiate_async( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result + where + _T: Send, + { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate_async(&mut store).await?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `the-world`. +/// +/// This is an implementation detail of [`TheWorldPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`TheWorld`] as well. +#[derive(Clone)] +pub struct TheWorldIndices { + interface0: exports::foo::foo::multi_return::GuestIndices, +} /// Auto-generated bindings for an instance a component which /// implements the world `the-world`. /// -/// This structure is created through either -/// [`TheWorld::instantiate_async`] or by first creating -/// a [`TheWorldPre`] followed by using -/// [`TheWorldPre::instantiate_async`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`TheWorld::instantiate_async`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`TheWorldPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`TheWorldPre::instantiate_async`] to +/// create a [`TheWorld`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`TheWorld::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`TheWorldIndices::new_instance`] followed +/// by [`TheWorldIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct TheWorld { interface0: exports::foo::foo::multi_return::Guest, } const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> TheWorldPre<_T> { - /// Creates a new copy of `TheWorldPre` bindings which can then + impl TheWorldIndices { + /// Creates a new copy of `TheWorldIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, ) -> wasmtime::Result { - let _component = instance_pre.component(); - let interface0 = exports::foo::foo::multi_return::GuestPre::new(_component)?; - Ok(TheWorldPre { - instance_pre, - interface0, - }) + let _component = component; + let interface0 = exports::foo::foo::multi_return::GuestIndices::new( + _component, + )?; + Ok(TheWorldIndices { interface0 }) } - /// Instantiates a new instance of [`TheWorld`] within the - /// `store` provided. + /// Creates a new instance of [`TheWorldIndices`] from an + /// instantiated component. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub async fn instantiate_async( + /// This method of creating a [`TheWorld`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`TheWorld`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; + let interface0 = exports::foo::foo::multi_return::GuestIndices::new_instance( + &mut store, + _instance, + )?; + Ok(TheWorldIndices { interface0 }) + } + /// Uses the indices stored in `self` to load an instance + /// of [`TheWorld`] from the instance provided. + /// + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate_async(&mut store).await?; + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; let interface0 = self.interface0.load(&mut store, &_instance)?; Ok(TheWorld { interface0 }) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl TheWorld { /// Convenience wrapper around [`TheWorldPre::new`] and @@ -85,6 +164,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate_async(store).await } + /// Convenience wrapper around [`TheWorldIndices::new_instance`] and + /// [`TheWorldIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker( linker: &mut wasmtime::component::Linker, get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, @@ -223,18 +311,23 @@ pub mod exports { mre: wasmtime::component::Func, } #[derive(Clone)] - pub struct GuestPre { + pub struct GuestIndices { mra: wasmtime::component::ComponentExportIndex, mrb: wasmtime::component::ComponentExportIndex, mrc: wasmtime::component::ComponentExportIndex, mrd: wasmtime::component::ComponentExportIndex, mre: wasmtime::component::ComponentExportIndex, } - impl GuestPre { + impl GuestIndices { + /// Constructor for [`GuestIndices`] which takes a + /// [`Component`](wasmtime::component::Component) as input and can be executed + /// before instantiation. + /// + /// This constructor can be used to front-load string lookups to find exports + /// within a component. pub fn new( component: &wasmtime::component::Component, - ) -> wasmtime::Result { - let _component = component; + ) -> wasmtime::Result { let (_, instance) = component .export_index(None, "foo:foo/multi-return") .ok_or_else(|| { @@ -242,10 +335,34 @@ pub mod exports { "no exported instance named `foo:foo/multi-return`" ) })?; - let _lookup = |name: &str| { - _component - .export_index(Some(&instance), name) - .map(|p| p.1) + Self::_new(|name| { + component.export_index(Some(&instance), name).map(|p| p.1) + }) + } + /// This constructor is similar to [`GuestIndices::new`] except that it + /// performs string lookups after instantiation time. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let instance_export = instance + .get_export(&mut store, None, "foo:foo/multi-return") + .ok_or_else(|| { + anyhow::anyhow!( + "no exported instance named `foo:foo/multi-return`" + ) + })?; + Self::_new(|name| { + instance.get_export(&mut store, Some(&instance_export), name) + }) + } + fn _new( + mut lookup: impl FnMut( + &str, + ) -> Option, + ) -> wasmtime::Result { + let mut lookup = move |name| { + lookup(name) .ok_or_else(|| { anyhow::anyhow!( "instance export `foo:foo/multi-return` does \ @@ -253,12 +370,13 @@ pub mod exports { ) }) }; - let mra = _lookup("mra")?; - let mrb = _lookup("mrb")?; - let mrc = _lookup("mrc")?; - let mrd = _lookup("mrd")?; - let mre = _lookup("mre")?; - Ok(GuestPre { + let _ = &mut lookup; + let mra = lookup("mra")?; + let mrb = lookup("mrb")?; + let mrc = lookup("mrc")?; + let mrd = lookup("mrd")?; + let mre = lookup("mre")?; + Ok(GuestIndices { mra, mrb, mrc, diff --git a/crates/component-macro/tests/expanded/multiversion.rs b/crates/component-macro/tests/expanded/multiversion.rs index 0bb9904483f2..44d9e429237e 100644 --- a/crates/component-macro/tests/expanded/multiversion.rs +++ b/crates/component-macro/tests/expanded/multiversion.rs @@ -4,27 +4,96 @@ /// This structure is created through [`FooPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`Foo`] as well. pub struct FooPre { instance_pre: wasmtime::component::InstancePre, - interface0: exports::my::dep0_1_0::a::GuestPre, - interface1: exports::my::dep0_2_0::a::GuestPre, + indices: FooIndices, } impl Clone for FooPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), - interface0: self.interface0.clone(), - interface1: self.interface1.clone(), + indices: self.indices.clone(), } } } +impl<_T> FooPre<_T> { + /// Creates a new copy of `FooPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = FooIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`Foo`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub fn instantiate( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate(&mut store)?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `foo`. +/// +/// This is an implementation detail of [`FooPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`Foo`] as well. +#[derive(Clone)] +pub struct FooIndices { + interface0: exports::my::dep0_1_0::a::GuestIndices, + interface1: exports::my::dep0_2_0::a::GuestIndices, +} /// Auto-generated bindings for an instance a component which /// implements the world `foo`. /// -/// This structure is created through either -/// [`Foo::instantiate`] or by first creating -/// a [`FooPre`] followed by using -/// [`FooPre::instantiate`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`Foo::instantiate`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`FooPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`FooPre::instantiate`] to +/// create a [`Foo`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`Foo::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`FooIndices::new_instance`] followed +/// by [`FooIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct Foo { interface0: exports::my::dep0_1_0::a::Guest, interface1: exports::my::dep0_2_0::a::Guest, @@ -32,47 +101,63 @@ pub struct Foo { const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> FooPre<_T> { - /// Creates a new copy of `FooPre` bindings which can then + impl FooIndices { + /// Creates a new copy of `FooIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, ) -> wasmtime::Result { - let _component = instance_pre.component(); - let interface0 = exports::my::dep0_1_0::a::GuestPre::new(_component)?; - let interface1 = exports::my::dep0_2_0::a::GuestPre::new(_component)?; - Ok(FooPre { - instance_pre, + let _component = component; + let interface0 = exports::my::dep0_1_0::a::GuestIndices::new(_component)?; + let interface1 = exports::my::dep0_2_0::a::GuestIndices::new(_component)?; + Ok(FooIndices { interface0, interface1, }) } - /// Instantiates a new instance of [`Foo`] within the - /// `store` provided. + /// Creates a new instance of [`FooIndices`] from an + /// instantiated component. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub fn instantiate( + /// This method of creating a [`Foo`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`Foo`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; + let interface0 = exports::my::dep0_1_0::a::GuestIndices::new_instance( + &mut store, + _instance, + )?; + let interface1 = exports::my::dep0_2_0::a::GuestIndices::new_instance( + &mut store, + _instance, + )?; + Ok(FooIndices { + interface0, + interface1, + }) + } + /// Uses the indices stored in `self` to load an instance + /// of [`Foo`] from the instance provided. + /// + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate(&mut store)?; + let _instance = instance; let interface0 = self.interface0.load(&mut store, &_instance)?; let interface1 = self.interface1.load(&mut store, &_instance)?; Ok(Foo { interface0, interface1 }) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl Foo { /// Convenience wrapper around [`FooPre::new`] and @@ -85,6 +170,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; FooPre::new(pre)?.instantiate(store) } + /// Convenience wrapper around [`FooIndices::new_instance`] and + /// [`FooIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = FooIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker( linker: &mut wasmtime::component::Linker, get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, @@ -219,14 +313,19 @@ pub mod exports { x: wasmtime::component::Func, } #[derive(Clone)] - pub struct GuestPre { + pub struct GuestIndices { x: wasmtime::component::ComponentExportIndex, } - impl GuestPre { + impl GuestIndices { + /// Constructor for [`GuestIndices`] which takes a + /// [`Component`](wasmtime::component::Component) as input and can be executed + /// before instantiation. + /// + /// This constructor can be used to front-load string lookups to find exports + /// within a component. pub fn new( component: &wasmtime::component::Component, - ) -> wasmtime::Result { - let _component = component; + ) -> wasmtime::Result { let (_, instance) = component .export_index(None, "my:dep/a@0.1.0") .ok_or_else(|| { @@ -234,10 +333,34 @@ pub mod exports { "no exported instance named `my:dep/a@0.1.0`" ) })?; - let _lookup = |name: &str| { - _component - .export_index(Some(&instance), name) - .map(|p| p.1) + Self::_new(|name| { + component.export_index(Some(&instance), name).map(|p| p.1) + }) + } + /// This constructor is similar to [`GuestIndices::new`] except that it + /// performs string lookups after instantiation time. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let instance_export = instance + .get_export(&mut store, None, "my:dep/a@0.1.0") + .ok_or_else(|| { + anyhow::anyhow!( + "no exported instance named `my:dep/a@0.1.0`" + ) + })?; + Self::_new(|name| { + instance.get_export(&mut store, Some(&instance_export), name) + }) + } + fn _new( + mut lookup: impl FnMut( + &str, + ) -> Option, + ) -> wasmtime::Result { + let mut lookup = move |name| { + lookup(name) .ok_or_else(|| { anyhow::anyhow!( "instance export `my:dep/a@0.1.0` does \ @@ -245,8 +368,9 @@ pub mod exports { ) }) }; - let x = _lookup("x")?; - Ok(GuestPre { x }) + let _ = &mut lookup; + let x = lookup("x")?; + Ok(GuestIndices { x }) } pub fn load( &self, @@ -289,14 +413,19 @@ pub mod exports { x: wasmtime::component::Func, } #[derive(Clone)] - pub struct GuestPre { + pub struct GuestIndices { x: wasmtime::component::ComponentExportIndex, } - impl GuestPre { + impl GuestIndices { + /// Constructor for [`GuestIndices`] which takes a + /// [`Component`](wasmtime::component::Component) as input and can be executed + /// before instantiation. + /// + /// This constructor can be used to front-load string lookups to find exports + /// within a component. pub fn new( component: &wasmtime::component::Component, - ) -> wasmtime::Result { - let _component = component; + ) -> wasmtime::Result { let (_, instance) = component .export_index(None, "my:dep/a@0.2.0") .ok_or_else(|| { @@ -304,10 +433,34 @@ pub mod exports { "no exported instance named `my:dep/a@0.2.0`" ) })?; - let _lookup = |name: &str| { - _component - .export_index(Some(&instance), name) - .map(|p| p.1) + Self::_new(|name| { + component.export_index(Some(&instance), name).map(|p| p.1) + }) + } + /// This constructor is similar to [`GuestIndices::new`] except that it + /// performs string lookups after instantiation time. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let instance_export = instance + .get_export(&mut store, None, "my:dep/a@0.2.0") + .ok_or_else(|| { + anyhow::anyhow!( + "no exported instance named `my:dep/a@0.2.0`" + ) + })?; + Self::_new(|name| { + instance.get_export(&mut store, Some(&instance_export), name) + }) + } + fn _new( + mut lookup: impl FnMut( + &str, + ) -> Option, + ) -> wasmtime::Result { + let mut lookup = move |name| { + lookup(name) .ok_or_else(|| { anyhow::anyhow!( "instance export `my:dep/a@0.2.0` does \ @@ -315,8 +468,9 @@ pub mod exports { ) }) }; - let x = _lookup("x")?; - Ok(GuestPre { x }) + let _ = &mut lookup; + let x = lookup("x")?; + Ok(GuestIndices { x }) } pub fn load( &self, diff --git a/crates/component-macro/tests/expanded/multiversion_async.rs b/crates/component-macro/tests/expanded/multiversion_async.rs index a35a919d8e20..08edeb34c3a7 100644 --- a/crates/component-macro/tests/expanded/multiversion_async.rs +++ b/crates/component-macro/tests/expanded/multiversion_async.rs @@ -4,27 +4,99 @@ /// This structure is created through [`FooPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`Foo`] as well. pub struct FooPre { instance_pre: wasmtime::component::InstancePre, - interface0: exports::my::dep0_1_0::a::GuestPre, - interface1: exports::my::dep0_2_0::a::GuestPre, + indices: FooIndices, } impl Clone for FooPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), - interface0: self.interface0.clone(), - interface1: self.interface1.clone(), + indices: self.indices.clone(), } } } +impl<_T> FooPre<_T> { + /// Creates a new copy of `FooPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = FooIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`Foo`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub async fn instantiate_async( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result + where + _T: Send, + { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate_async(&mut store).await?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `foo`. +/// +/// This is an implementation detail of [`FooPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`Foo`] as well. +#[derive(Clone)] +pub struct FooIndices { + interface0: exports::my::dep0_1_0::a::GuestIndices, + interface1: exports::my::dep0_2_0::a::GuestIndices, +} /// Auto-generated bindings for an instance a component which /// implements the world `foo`. /// -/// This structure is created through either -/// [`Foo::instantiate_async`] or by first creating -/// a [`FooPre`] followed by using -/// [`FooPre::instantiate_async`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`Foo::instantiate_async`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`FooPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`FooPre::instantiate_async`] to +/// create a [`Foo`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`Foo::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`FooIndices::new_instance`] followed +/// by [`FooIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct Foo { interface0: exports::my::dep0_1_0::a::Guest, interface1: exports::my::dep0_2_0::a::Guest, @@ -32,50 +104,63 @@ pub struct Foo { const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> FooPre<_T> { - /// Creates a new copy of `FooPre` bindings which can then + impl FooIndices { + /// Creates a new copy of `FooIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, + ) -> wasmtime::Result { + let _component = component; + let interface0 = exports::my::dep0_1_0::a::GuestIndices::new(_component)?; + let interface1 = exports::my::dep0_2_0::a::GuestIndices::new(_component)?; + Ok(FooIndices { + interface0, + interface1, + }) + } + /// Creates a new instance of [`FooIndices`] from an + /// instantiated component. + /// + /// This method of creating a [`Foo`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`Foo`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let _component = instance_pre.component(); - let interface0 = exports::my::dep0_1_0::a::GuestPre::new(_component)?; - let interface1 = exports::my::dep0_2_0::a::GuestPre::new(_component)?; - Ok(FooPre { - instance_pre, + let _instance = instance; + let interface0 = exports::my::dep0_1_0::a::GuestIndices::new_instance( + &mut store, + _instance, + )?; + let interface1 = exports::my::dep0_2_0::a::GuestIndices::new_instance( + &mut store, + _instance, + )?; + Ok(FooIndices { interface0, interface1, }) } - /// Instantiates a new instance of [`Foo`] within the - /// `store` provided. + /// Uses the indices stored in `self` to load an instance + /// of [`Foo`] from the instance provided. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub async fn instantiate_async( + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate_async(&mut store).await?; + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; let interface0 = self.interface0.load(&mut store, &_instance)?; let interface1 = self.interface1.load(&mut store, &_instance)?; Ok(Foo { interface0, interface1 }) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl Foo { /// Convenience wrapper around [`FooPre::new`] and @@ -91,6 +176,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; FooPre::new(pre)?.instantiate_async(store).await } + /// Convenience wrapper around [`FooIndices::new_instance`] and + /// [`FooIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = FooIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker( linker: &mut wasmtime::component::Linker, get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, @@ -238,14 +332,19 @@ pub mod exports { x: wasmtime::component::Func, } #[derive(Clone)] - pub struct GuestPre { + pub struct GuestIndices { x: wasmtime::component::ComponentExportIndex, } - impl GuestPre { + impl GuestIndices { + /// Constructor for [`GuestIndices`] which takes a + /// [`Component`](wasmtime::component::Component) as input and can be executed + /// before instantiation. + /// + /// This constructor can be used to front-load string lookups to find exports + /// within a component. pub fn new( component: &wasmtime::component::Component, - ) -> wasmtime::Result { - let _component = component; + ) -> wasmtime::Result { let (_, instance) = component .export_index(None, "my:dep/a@0.1.0") .ok_or_else(|| { @@ -253,10 +352,34 @@ pub mod exports { "no exported instance named `my:dep/a@0.1.0`" ) })?; - let _lookup = |name: &str| { - _component - .export_index(Some(&instance), name) - .map(|p| p.1) + Self::_new(|name| { + component.export_index(Some(&instance), name).map(|p| p.1) + }) + } + /// This constructor is similar to [`GuestIndices::new`] except that it + /// performs string lookups after instantiation time. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let instance_export = instance + .get_export(&mut store, None, "my:dep/a@0.1.0") + .ok_or_else(|| { + anyhow::anyhow!( + "no exported instance named `my:dep/a@0.1.0`" + ) + })?; + Self::_new(|name| { + instance.get_export(&mut store, Some(&instance_export), name) + }) + } + fn _new( + mut lookup: impl FnMut( + &str, + ) -> Option, + ) -> wasmtime::Result { + let mut lookup = move |name| { + lookup(name) .ok_or_else(|| { anyhow::anyhow!( "instance export `my:dep/a@0.1.0` does \ @@ -264,8 +387,9 @@ pub mod exports { ) }) }; - let x = _lookup("x")?; - Ok(GuestPre { x }) + let _ = &mut lookup; + let x = lookup("x")?; + Ok(GuestIndices { x }) } pub fn load( &self, @@ -311,14 +435,19 @@ pub mod exports { x: wasmtime::component::Func, } #[derive(Clone)] - pub struct GuestPre { + pub struct GuestIndices { x: wasmtime::component::ComponentExportIndex, } - impl GuestPre { + impl GuestIndices { + /// Constructor for [`GuestIndices`] which takes a + /// [`Component`](wasmtime::component::Component) as input and can be executed + /// before instantiation. + /// + /// This constructor can be used to front-load string lookups to find exports + /// within a component. pub fn new( component: &wasmtime::component::Component, - ) -> wasmtime::Result { - let _component = component; + ) -> wasmtime::Result { let (_, instance) = component .export_index(None, "my:dep/a@0.2.0") .ok_or_else(|| { @@ -326,10 +455,34 @@ pub mod exports { "no exported instance named `my:dep/a@0.2.0`" ) })?; - let _lookup = |name: &str| { - _component - .export_index(Some(&instance), name) - .map(|p| p.1) + Self::_new(|name| { + component.export_index(Some(&instance), name).map(|p| p.1) + }) + } + /// This constructor is similar to [`GuestIndices::new`] except that it + /// performs string lookups after instantiation time. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let instance_export = instance + .get_export(&mut store, None, "my:dep/a@0.2.0") + .ok_or_else(|| { + anyhow::anyhow!( + "no exported instance named `my:dep/a@0.2.0`" + ) + })?; + Self::_new(|name| { + instance.get_export(&mut store, Some(&instance_export), name) + }) + } + fn _new( + mut lookup: impl FnMut( + &str, + ) -> Option, + ) -> wasmtime::Result { + let mut lookup = move |name| { + lookup(name) .ok_or_else(|| { anyhow::anyhow!( "instance export `my:dep/a@0.2.0` does \ @@ -337,8 +490,9 @@ pub mod exports { ) }) }; - let x = _lookup("x")?; - Ok(GuestPre { x }) + let _ = &mut lookup; + let x = lookup("x")?; + Ok(GuestIndices { x }) } pub fn load( &self, diff --git a/crates/component-macro/tests/expanded/records.rs b/crates/component-macro/tests/expanded/records.rs index 428f92221416..5a6fed8dcbd3 100644 --- a/crates/component-macro/tests/expanded/records.rs +++ b/crates/component-macro/tests/expanded/records.rs @@ -4,69 +4,146 @@ /// This structure is created through [`TheWorldPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`TheWorld`] as well. pub struct TheWorldPre { instance_pre: wasmtime::component::InstancePre, - interface0: exports::foo::foo::records::GuestPre, + indices: TheWorldIndices, } impl Clone for TheWorldPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), - interface0: self.interface0.clone(), + indices: self.indices.clone(), } } } +impl<_T> TheWorldPre<_T> { + /// Creates a new copy of `TheWorldPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`TheWorld`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub fn instantiate( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate(&mut store)?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `the-world`. +/// +/// This is an implementation detail of [`TheWorldPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`TheWorld`] as well. +#[derive(Clone)] +pub struct TheWorldIndices { + interface0: exports::foo::foo::records::GuestIndices, +} /// Auto-generated bindings for an instance a component which /// implements the world `the-world`. /// -/// This structure is created through either -/// [`TheWorld::instantiate`] or by first creating -/// a [`TheWorldPre`] followed by using -/// [`TheWorldPre::instantiate`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`TheWorld::instantiate`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`TheWorldPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`TheWorldPre::instantiate`] to +/// create a [`TheWorld`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`TheWorld::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`TheWorldIndices::new_instance`] followed +/// by [`TheWorldIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct TheWorld { interface0: exports::foo::foo::records::Guest, } const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> TheWorldPre<_T> { - /// Creates a new copy of `TheWorldPre` bindings which can then + impl TheWorldIndices { + /// Creates a new copy of `TheWorldIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, + ) -> wasmtime::Result { + let _component = component; + let interface0 = exports::foo::foo::records::GuestIndices::new(_component)?; + Ok(TheWorldIndices { interface0 }) + } + /// Creates a new instance of [`TheWorldIndices`] from an + /// instantiated component. + /// + /// This method of creating a [`TheWorld`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`TheWorld`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let _component = instance_pre.component(); - let interface0 = exports::foo::foo::records::GuestPre::new(_component)?; - Ok(TheWorldPre { - instance_pre, - interface0, - }) + let _instance = instance; + let interface0 = exports::foo::foo::records::GuestIndices::new_instance( + &mut store, + _instance, + )?; + Ok(TheWorldIndices { interface0 }) } - /// Instantiates a new instance of [`TheWorld`] within the - /// `store` provided. + /// Uses the indices stored in `self` to load an instance + /// of [`TheWorld`] from the instance provided. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub fn instantiate( + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate(&mut store)?; + let _instance = instance; let interface0 = self.interface0.load(&mut store, &_instance)?; Ok(TheWorld { interface0 }) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl TheWorld { /// Convenience wrapper around [`TheWorldPre::new`] and @@ -79,6 +156,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate(store) } + /// Convenience wrapper around [`TheWorldIndices::new_instance`] and + /// [`TheWorldIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker( linker: &mut wasmtime::component::Linker, get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, @@ -625,7 +711,7 @@ pub mod exports { typedef_inout: wasmtime::component::Func, } #[derive(Clone)] - pub struct GuestPre { + pub struct GuestIndices { tuple_arg: wasmtime::component::ComponentExportIndex, tuple_result: wasmtime::component::ComponentExportIndex, empty_arg: wasmtime::component::ComponentExportIndex, @@ -638,11 +724,16 @@ pub mod exports { aggregate_result: wasmtime::component::ComponentExportIndex, typedef_inout: wasmtime::component::ComponentExportIndex, } - impl GuestPre { + impl GuestIndices { + /// Constructor for [`GuestIndices`] which takes a + /// [`Component`](wasmtime::component::Component) as input and can be executed + /// before instantiation. + /// + /// This constructor can be used to front-load string lookups to find exports + /// within a component. pub fn new( component: &wasmtime::component::Component, - ) -> wasmtime::Result { - let _component = component; + ) -> wasmtime::Result { let (_, instance) = component .export_index(None, "foo:foo/records") .ok_or_else(|| { @@ -650,10 +741,34 @@ pub mod exports { "no exported instance named `foo:foo/records`" ) })?; - let _lookup = |name: &str| { - _component - .export_index(Some(&instance), name) - .map(|p| p.1) + Self::_new(|name| { + component.export_index(Some(&instance), name).map(|p| p.1) + }) + } + /// This constructor is similar to [`GuestIndices::new`] except that it + /// performs string lookups after instantiation time. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let instance_export = instance + .get_export(&mut store, None, "foo:foo/records") + .ok_or_else(|| { + anyhow::anyhow!( + "no exported instance named `foo:foo/records`" + ) + })?; + Self::_new(|name| { + instance.get_export(&mut store, Some(&instance_export), name) + }) + } + fn _new( + mut lookup: impl FnMut( + &str, + ) -> Option, + ) -> wasmtime::Result { + let mut lookup = move |name| { + lookup(name) .ok_or_else(|| { anyhow::anyhow!( "instance export `foo:foo/records` does \ @@ -661,18 +776,19 @@ pub mod exports { ) }) }; - let tuple_arg = _lookup("tuple-arg")?; - let tuple_result = _lookup("tuple-result")?; - let empty_arg = _lookup("empty-arg")?; - let empty_result = _lookup("empty-result")?; - let scalar_arg = _lookup("scalar-arg")?; - let scalar_result = _lookup("scalar-result")?; - let flags_arg = _lookup("flags-arg")?; - let flags_result = _lookup("flags-result")?; - let aggregate_arg = _lookup("aggregate-arg")?; - let aggregate_result = _lookup("aggregate-result")?; - let typedef_inout = _lookup("typedef-inout")?; - Ok(GuestPre { + let _ = &mut lookup; + let tuple_arg = lookup("tuple-arg")?; + let tuple_result = lookup("tuple-result")?; + let empty_arg = lookup("empty-arg")?; + let empty_result = lookup("empty-result")?; + let scalar_arg = lookup("scalar-arg")?; + let scalar_result = lookup("scalar-result")?; + let flags_arg = lookup("flags-arg")?; + let flags_result = lookup("flags-result")?; + let aggregate_arg = lookup("aggregate-arg")?; + let aggregate_result = lookup("aggregate-result")?; + let typedef_inout = lookup("typedef-inout")?; + Ok(GuestIndices { tuple_arg, tuple_result, empty_arg, diff --git a/crates/component-macro/tests/expanded/records_async.rs b/crates/component-macro/tests/expanded/records_async.rs index f02a92c52571..287af7c19a78 100644 --- a/crates/component-macro/tests/expanded/records_async.rs +++ b/crates/component-macro/tests/expanded/records_async.rs @@ -4,72 +4,149 @@ /// This structure is created through [`TheWorldPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`TheWorld`] as well. pub struct TheWorldPre { instance_pre: wasmtime::component::InstancePre, - interface0: exports::foo::foo::records::GuestPre, + indices: TheWorldIndices, } impl Clone for TheWorldPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), - interface0: self.interface0.clone(), + indices: self.indices.clone(), } } } +impl<_T> TheWorldPre<_T> { + /// Creates a new copy of `TheWorldPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`TheWorld`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub async fn instantiate_async( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result + where + _T: Send, + { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate_async(&mut store).await?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `the-world`. +/// +/// This is an implementation detail of [`TheWorldPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`TheWorld`] as well. +#[derive(Clone)] +pub struct TheWorldIndices { + interface0: exports::foo::foo::records::GuestIndices, +} /// Auto-generated bindings for an instance a component which /// implements the world `the-world`. /// -/// This structure is created through either -/// [`TheWorld::instantiate_async`] or by first creating -/// a [`TheWorldPre`] followed by using -/// [`TheWorldPre::instantiate_async`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`TheWorld::instantiate_async`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`TheWorldPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`TheWorldPre::instantiate_async`] to +/// create a [`TheWorld`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`TheWorld::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`TheWorldIndices::new_instance`] followed +/// by [`TheWorldIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct TheWorld { interface0: exports::foo::foo::records::Guest, } const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> TheWorldPre<_T> { - /// Creates a new copy of `TheWorldPre` bindings which can then + impl TheWorldIndices { + /// Creates a new copy of `TheWorldIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, ) -> wasmtime::Result { - let _component = instance_pre.component(); - let interface0 = exports::foo::foo::records::GuestPre::new(_component)?; - Ok(TheWorldPre { - instance_pre, - interface0, - }) + let _component = component; + let interface0 = exports::foo::foo::records::GuestIndices::new(_component)?; + Ok(TheWorldIndices { interface0 }) } - /// Instantiates a new instance of [`TheWorld`] within the - /// `store` provided. + /// Creates a new instance of [`TheWorldIndices`] from an + /// instantiated component. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub async fn instantiate_async( + /// This method of creating a [`TheWorld`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`TheWorld`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; + let interface0 = exports::foo::foo::records::GuestIndices::new_instance( + &mut store, + _instance, + )?; + Ok(TheWorldIndices { interface0 }) + } + /// Uses the indices stored in `self` to load an instance + /// of [`TheWorld`] from the instance provided. + /// + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate_async(&mut store).await?; + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; let interface0 = self.interface0.load(&mut store, &_instance)?; Ok(TheWorld { interface0 }) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl TheWorld { /// Convenience wrapper around [`TheWorldPre::new`] and @@ -85,6 +162,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate_async(store).await } + /// Convenience wrapper around [`TheWorldIndices::new_instance`] and + /// [`TheWorldIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker( linker: &mut wasmtime::component::Linker, get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, @@ -638,7 +724,7 @@ pub mod exports { typedef_inout: wasmtime::component::Func, } #[derive(Clone)] - pub struct GuestPre { + pub struct GuestIndices { tuple_arg: wasmtime::component::ComponentExportIndex, tuple_result: wasmtime::component::ComponentExportIndex, empty_arg: wasmtime::component::ComponentExportIndex, @@ -651,11 +737,16 @@ pub mod exports { aggregate_result: wasmtime::component::ComponentExportIndex, typedef_inout: wasmtime::component::ComponentExportIndex, } - impl GuestPre { + impl GuestIndices { + /// Constructor for [`GuestIndices`] which takes a + /// [`Component`](wasmtime::component::Component) as input and can be executed + /// before instantiation. + /// + /// This constructor can be used to front-load string lookups to find exports + /// within a component. pub fn new( component: &wasmtime::component::Component, - ) -> wasmtime::Result { - let _component = component; + ) -> wasmtime::Result { let (_, instance) = component .export_index(None, "foo:foo/records") .ok_or_else(|| { @@ -663,10 +754,34 @@ pub mod exports { "no exported instance named `foo:foo/records`" ) })?; - let _lookup = |name: &str| { - _component - .export_index(Some(&instance), name) - .map(|p| p.1) + Self::_new(|name| { + component.export_index(Some(&instance), name).map(|p| p.1) + }) + } + /// This constructor is similar to [`GuestIndices::new`] except that it + /// performs string lookups after instantiation time. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let instance_export = instance + .get_export(&mut store, None, "foo:foo/records") + .ok_or_else(|| { + anyhow::anyhow!( + "no exported instance named `foo:foo/records`" + ) + })?; + Self::_new(|name| { + instance.get_export(&mut store, Some(&instance_export), name) + }) + } + fn _new( + mut lookup: impl FnMut( + &str, + ) -> Option, + ) -> wasmtime::Result { + let mut lookup = move |name| { + lookup(name) .ok_or_else(|| { anyhow::anyhow!( "instance export `foo:foo/records` does \ @@ -674,18 +789,19 @@ pub mod exports { ) }) }; - let tuple_arg = _lookup("tuple-arg")?; - let tuple_result = _lookup("tuple-result")?; - let empty_arg = _lookup("empty-arg")?; - let empty_result = _lookup("empty-result")?; - let scalar_arg = _lookup("scalar-arg")?; - let scalar_result = _lookup("scalar-result")?; - let flags_arg = _lookup("flags-arg")?; - let flags_result = _lookup("flags-result")?; - let aggregate_arg = _lookup("aggregate-arg")?; - let aggregate_result = _lookup("aggregate-result")?; - let typedef_inout = _lookup("typedef-inout")?; - Ok(GuestPre { + let _ = &mut lookup; + let tuple_arg = lookup("tuple-arg")?; + let tuple_result = lookup("tuple-result")?; + let empty_arg = lookup("empty-arg")?; + let empty_result = lookup("empty-result")?; + let scalar_arg = lookup("scalar-arg")?; + let scalar_result = lookup("scalar-result")?; + let flags_arg = lookup("flags-arg")?; + let flags_result = lookup("flags-result")?; + let aggregate_arg = lookup("aggregate-arg")?; + let aggregate_result = lookup("aggregate-result")?; + let typedef_inout = lookup("typedef-inout")?; + Ok(GuestIndices { tuple_arg, tuple_result, empty_arg, diff --git a/crates/component-macro/tests/expanded/rename.rs b/crates/component-macro/tests/expanded/rename.rs index def16f93453a..40ad51574259 100644 --- a/crates/component-macro/tests/expanded/rename.rs +++ b/crates/component-macro/tests/expanded/rename.rs @@ -4,60 +4,136 @@ /// This structure is created through [`NeptunePre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`Neptune`] as well. pub struct NeptunePre { instance_pre: wasmtime::component::InstancePre, + indices: NeptuneIndices, } impl Clone for NeptunePre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), + indices: self.indices.clone(), } } } +impl<_T> NeptunePre<_T> { + /// Creates a new copy of `NeptunePre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = NeptuneIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`Neptune`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub fn instantiate( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate(&mut store)?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `neptune`. +/// +/// This is an implementation detail of [`NeptunePre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`Neptune`] as well. +#[derive(Clone)] +pub struct NeptuneIndices {} /// Auto-generated bindings for an instance a component which /// implements the world `neptune`. /// -/// This structure is created through either -/// [`Neptune::instantiate`] or by first creating -/// a [`NeptunePre`] followed by using -/// [`NeptunePre::instantiate`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`Neptune::instantiate`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`NeptunePre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`NeptunePre::instantiate`] to +/// create a [`Neptune`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`Neptune::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`NeptuneIndices::new_instance`] followed +/// by [`NeptuneIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct Neptune {} const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> NeptunePre<_T> { - /// Creates a new copy of `NeptunePre` bindings which can then + impl NeptuneIndices { + /// Creates a new copy of `NeptuneIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, + ) -> wasmtime::Result { + let _component = component; + Ok(NeptuneIndices {}) + } + /// Creates a new instance of [`NeptuneIndices`] from an + /// instantiated component. + /// + /// This method of creating a [`Neptune`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`Neptune`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let _component = instance_pre.component(); - Ok(NeptunePre { instance_pre }) + let _instance = instance; + Ok(NeptuneIndices {}) } - /// Instantiates a new instance of [`Neptune`] within the - /// `store` provided. + /// Uses the indices stored in `self` to load an instance + /// of [`Neptune`] from the instance provided. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub fn instantiate( + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate(&mut store)?; + let _instance = instance; Ok(Neptune {}) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl Neptune { /// Convenience wrapper around [`NeptunePre::new`] and @@ -70,6 +146,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; NeptunePre::new(pre)?.instantiate(store) } + /// Convenience wrapper around [`NeptuneIndices::new_instance`] and + /// [`NeptuneIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = NeptuneIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker( linker: &mut wasmtime::component::Linker, get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, diff --git a/crates/component-macro/tests/expanded/rename_async.rs b/crates/component-macro/tests/expanded/rename_async.rs index 09a9efe5d5fd..6d8de01759a5 100644 --- a/crates/component-macro/tests/expanded/rename_async.rs +++ b/crates/component-macro/tests/expanded/rename_async.rs @@ -4,63 +4,139 @@ /// This structure is created through [`NeptunePre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`Neptune`] as well. pub struct NeptunePre { instance_pre: wasmtime::component::InstancePre, + indices: NeptuneIndices, } impl Clone for NeptunePre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), + indices: self.indices.clone(), } } } +impl<_T> NeptunePre<_T> { + /// Creates a new copy of `NeptunePre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = NeptuneIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`Neptune`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub async fn instantiate_async( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result + where + _T: Send, + { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate_async(&mut store).await?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `neptune`. +/// +/// This is an implementation detail of [`NeptunePre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`Neptune`] as well. +#[derive(Clone)] +pub struct NeptuneIndices {} /// Auto-generated bindings for an instance a component which /// implements the world `neptune`. /// -/// This structure is created through either -/// [`Neptune::instantiate_async`] or by first creating -/// a [`NeptunePre`] followed by using -/// [`NeptunePre::instantiate_async`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`Neptune::instantiate_async`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`NeptunePre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`NeptunePre::instantiate_async`] to +/// create a [`Neptune`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`Neptune::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`NeptuneIndices::new_instance`] followed +/// by [`NeptuneIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct Neptune {} const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> NeptunePre<_T> { - /// Creates a new copy of `NeptunePre` bindings which can then + impl NeptuneIndices { + /// Creates a new copy of `NeptuneIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, + ) -> wasmtime::Result { + let _component = component; + Ok(NeptuneIndices {}) + } + /// Creates a new instance of [`NeptuneIndices`] from an + /// instantiated component. + /// + /// This method of creating a [`Neptune`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`Neptune`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let _component = instance_pre.component(); - Ok(NeptunePre { instance_pre }) + let _instance = instance; + Ok(NeptuneIndices {}) } - /// Instantiates a new instance of [`Neptune`] within the - /// `store` provided. + /// Uses the indices stored in `self` to load an instance + /// of [`Neptune`] from the instance provided. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub async fn instantiate_async( + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate_async(&mut store).await?; + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; Ok(Neptune {}) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl Neptune { /// Convenience wrapper around [`NeptunePre::new`] and @@ -76,6 +152,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; NeptunePre::new(pre)?.instantiate_async(store).await } + /// Convenience wrapper around [`NeptuneIndices::new_instance`] and + /// [`NeptuneIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = NeptuneIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker( linker: &mut wasmtime::component::Linker, get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, diff --git a/crates/component-macro/tests/expanded/resources-export.rs b/crates/component-macro/tests/expanded/resources-export.rs index c83dc360c4d0..2df3c228fa37 100644 --- a/crates/component-macro/tests/expanded/resources-export.rs +++ b/crates/component-macro/tests/expanded/resources-export.rs @@ -4,31 +4,98 @@ /// This structure is created through [`WPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`W`] as well. pub struct WPre { instance_pre: wasmtime::component::InstancePre, - interface0: exports::foo::foo::simple_export::GuestPre, - interface1: exports::foo::foo::export_using_import::GuestPre, - interface2: exports::foo::foo::export_using_export1::GuestPre, - interface3: exports::foo::foo::export_using_export2::GuestPre, + indices: WIndices, } impl Clone for WPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), - interface0: self.interface0.clone(), - interface1: self.interface1.clone(), - interface2: self.interface2.clone(), - interface3: self.interface3.clone(), + indices: self.indices.clone(), } } } +impl<_T> WPre<_T> { + /// Creates a new copy of `WPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = WIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`W`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub fn instantiate( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate(&mut store)?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `w`. +/// +/// This is an implementation detail of [`WPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`W`] as well. +#[derive(Clone)] +pub struct WIndices { + interface0: exports::foo::foo::simple_export::GuestIndices, + interface1: exports::foo::foo::export_using_import::GuestIndices, + interface2: exports::foo::foo::export_using_export1::GuestIndices, + interface3: exports::foo::foo::export_using_export2::GuestIndices, +} /// Auto-generated bindings for an instance a component which /// implements the world `w`. /// -/// This structure is created through either -/// [`W::instantiate`] or by first creating -/// a [`WPre`] followed by using -/// [`WPre::instantiate`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`W::instantiate`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`WPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`WPre::instantiate`] to +/// create a [`W`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`W::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`WIndices::new_instance`] followed +/// by [`WIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct W { interface0: exports::foo::foo::simple_export::Guest, interface1: exports::foo::foo::export_using_import::Guest, @@ -38,49 +105,81 @@ pub struct W { const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> WPre<_T> { - /// Creates a new copy of `WPre` bindings which can then + impl WIndices { + /// Creates a new copy of `WIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, ) -> wasmtime::Result { - let _component = instance_pre.component(); - let interface0 = exports::foo::foo::simple_export::GuestPre::new( + let _component = component; + let interface0 = exports::foo::foo::simple_export::GuestIndices::new( _component, )?; - let interface1 = exports::foo::foo::export_using_import::GuestPre::new( + let interface1 = exports::foo::foo::export_using_import::GuestIndices::new( _component, )?; - let interface2 = exports::foo::foo::export_using_export1::GuestPre::new( + let interface2 = exports::foo::foo::export_using_export1::GuestIndices::new( _component, )?; - let interface3 = exports::foo::foo::export_using_export2::GuestPre::new( + let interface3 = exports::foo::foo::export_using_export2::GuestIndices::new( _component, )?; - Ok(WPre { - instance_pre, + Ok(WIndices { interface0, interface1, interface2, interface3, }) } - /// Instantiates a new instance of [`W`] within the - /// `store` provided. + /// Creates a new instance of [`WIndices`] from an + /// instantiated component. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub fn instantiate( + /// This method of creating a [`W`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`W`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; + let interface0 = exports::foo::foo::simple_export::GuestIndices::new_instance( + &mut store, + _instance, + )?; + let interface1 = exports::foo::foo::export_using_import::GuestIndices::new_instance( + &mut store, + _instance, + )?; + let interface2 = exports::foo::foo::export_using_export1::GuestIndices::new_instance( + &mut store, + _instance, + )?; + let interface3 = exports::foo::foo::export_using_export2::GuestIndices::new_instance( + &mut store, + _instance, + )?; + Ok(WIndices { + interface0, + interface1, + interface2, + interface3, + }) + } + /// Uses the indices stored in `self` to load an instance + /// of [`W`] from the instance provided. + /// + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate(&mut store)?; + let _instance = instance; let interface0 = self.interface0.load(&mut store, &_instance)?; let interface1 = self.interface1.load(&mut store, &_instance)?; let interface2 = self.interface2.load(&mut store, &_instance)?; @@ -92,12 +191,6 @@ const _: () = { interface3, }) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl W { /// Convenience wrapper around [`WPre::new`] and @@ -110,6 +203,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; WPre::new(pre)?.instantiate(store) } + /// Convenience wrapper around [`WIndices::new_instance`] and + /// [`WIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = WIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker( linker: &mut wasmtime::component::Linker, get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, @@ -221,16 +323,21 @@ pub mod exports { method_a_method_a: wasmtime::component::Func, } #[derive(Clone)] - pub struct GuestPre { + pub struct GuestIndices { constructor_a_constructor: wasmtime::component::ComponentExportIndex, static_a_static_a: wasmtime::component::ComponentExportIndex, method_a_method_a: wasmtime::component::ComponentExportIndex, } - impl GuestPre { + impl GuestIndices { + /// Constructor for [`GuestIndices`] which takes a + /// [`Component`](wasmtime::component::Component) as input and can be executed + /// before instantiation. + /// + /// This constructor can be used to front-load string lookups to find exports + /// within a component. pub fn new( component: &wasmtime::component::Component, - ) -> wasmtime::Result { - let _component = component; + ) -> wasmtime::Result { let (_, instance) = component .export_index(None, "foo:foo/simple-export") .ok_or_else(|| { @@ -238,10 +345,34 @@ pub mod exports { "no exported instance named `foo:foo/simple-export`" ) })?; - let _lookup = |name: &str| { - _component - .export_index(Some(&instance), name) - .map(|p| p.1) + Self::_new(|name| { + component.export_index(Some(&instance), name).map(|p| p.1) + }) + } + /// This constructor is similar to [`GuestIndices::new`] except that it + /// performs string lookups after instantiation time. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let instance_export = instance + .get_export(&mut store, None, "foo:foo/simple-export") + .ok_or_else(|| { + anyhow::anyhow!( + "no exported instance named `foo:foo/simple-export`" + ) + })?; + Self::_new(|name| { + instance.get_export(&mut store, Some(&instance_export), name) + }) + } + fn _new( + mut lookup: impl FnMut( + &str, + ) -> Option, + ) -> wasmtime::Result { + let mut lookup = move |name| { + lookup(name) .ok_or_else(|| { anyhow::anyhow!( "instance export `foo:foo/simple-export` does \ @@ -249,10 +380,11 @@ pub mod exports { ) }) }; - let constructor_a_constructor = _lookup("[constructor]a")?; - let static_a_static_a = _lookup("[static]a.static-a")?; - let method_a_method_a = _lookup("[method]a.method-a")?; - Ok(GuestPre { + let _ = &mut lookup; + let constructor_a_constructor = lookup("[constructor]a")?; + let static_a_static_a = lookup("[static]a.static-a")?; + let method_a_method_a = lookup("[method]a.method-a")?; + Ok(GuestIndices { constructor_a_constructor, static_a_static_a, method_a_method_a, @@ -357,16 +489,21 @@ pub mod exports { method_a_method_a: wasmtime::component::Func, } #[derive(Clone)] - pub struct GuestPre { + pub struct GuestIndices { constructor_a_constructor: wasmtime::component::ComponentExportIndex, static_a_static_a: wasmtime::component::ComponentExportIndex, method_a_method_a: wasmtime::component::ComponentExportIndex, } - impl GuestPre { + impl GuestIndices { + /// Constructor for [`GuestIndices`] which takes a + /// [`Component`](wasmtime::component::Component) as input and can be executed + /// before instantiation. + /// + /// This constructor can be used to front-load string lookups to find exports + /// within a component. pub fn new( component: &wasmtime::component::Component, - ) -> wasmtime::Result { - let _component = component; + ) -> wasmtime::Result { let (_, instance) = component .export_index(None, "foo:foo/export-using-import") .ok_or_else(|| { @@ -374,10 +511,34 @@ pub mod exports { "no exported instance named `foo:foo/export-using-import`" ) })?; - let _lookup = |name: &str| { - _component - .export_index(Some(&instance), name) - .map(|p| p.1) + Self::_new(|name| { + component.export_index(Some(&instance), name).map(|p| p.1) + }) + } + /// This constructor is similar to [`GuestIndices::new`] except that it + /// performs string lookups after instantiation time. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let instance_export = instance + .get_export(&mut store, None, "foo:foo/export-using-import") + .ok_or_else(|| { + anyhow::anyhow!( + "no exported instance named `foo:foo/export-using-import`" + ) + })?; + Self::_new(|name| { + instance.get_export(&mut store, Some(&instance_export), name) + }) + } + fn _new( + mut lookup: impl FnMut( + &str, + ) -> Option, + ) -> wasmtime::Result { + let mut lookup = move |name| { + lookup(name) .ok_or_else(|| { anyhow::anyhow!( "instance export `foo:foo/export-using-import` does \ @@ -385,10 +546,11 @@ pub mod exports { ) }) }; - let constructor_a_constructor = _lookup("[constructor]a")?; - let static_a_static_a = _lookup("[static]a.static-a")?; - let method_a_method_a = _lookup("[method]a.method-a")?; - Ok(GuestPre { + let _ = &mut lookup; + let constructor_a_constructor = lookup("[constructor]a")?; + let static_a_static_a = lookup("[static]a.static-a")?; + let method_a_method_a = lookup("[method]a.method-a")?; + Ok(GuestIndices { constructor_a_constructor, static_a_static_a, method_a_method_a, @@ -498,14 +660,19 @@ pub mod exports { constructor_a_constructor: wasmtime::component::Func, } #[derive(Clone)] - pub struct GuestPre { + pub struct GuestIndices { constructor_a_constructor: wasmtime::component::ComponentExportIndex, } - impl GuestPre { + impl GuestIndices { + /// Constructor for [`GuestIndices`] which takes a + /// [`Component`](wasmtime::component::Component) as input and can be executed + /// before instantiation. + /// + /// This constructor can be used to front-load string lookups to find exports + /// within a component. pub fn new( component: &wasmtime::component::Component, - ) -> wasmtime::Result { - let _component = component; + ) -> wasmtime::Result { let (_, instance) = component .export_index(None, "foo:foo/export-using-export1") .ok_or_else(|| { @@ -513,10 +680,34 @@ pub mod exports { "no exported instance named `foo:foo/export-using-export1`" ) })?; - let _lookup = |name: &str| { - _component - .export_index(Some(&instance), name) - .map(|p| p.1) + Self::_new(|name| { + component.export_index(Some(&instance), name).map(|p| p.1) + }) + } + /// This constructor is similar to [`GuestIndices::new`] except that it + /// performs string lookups after instantiation time. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let instance_export = instance + .get_export(&mut store, None, "foo:foo/export-using-export1") + .ok_or_else(|| { + anyhow::anyhow!( + "no exported instance named `foo:foo/export-using-export1`" + ) + })?; + Self::_new(|name| { + instance.get_export(&mut store, Some(&instance_export), name) + }) + } + fn _new( + mut lookup: impl FnMut( + &str, + ) -> Option, + ) -> wasmtime::Result { + let mut lookup = move |name| { + lookup(name) .ok_or_else(|| { anyhow::anyhow!( "instance export `foo:foo/export-using-export1` does \ @@ -524,8 +715,9 @@ pub mod exports { ) }) }; - let constructor_a_constructor = _lookup("[constructor]a")?; - Ok(GuestPre { + let _ = &mut lookup; + let constructor_a_constructor = lookup("[constructor]a")?; + Ok(GuestIndices { constructor_a_constructor, }) } @@ -581,14 +773,19 @@ pub mod exports { constructor_b_constructor: wasmtime::component::Func, } #[derive(Clone)] - pub struct GuestPre { + pub struct GuestIndices { constructor_b_constructor: wasmtime::component::ComponentExportIndex, } - impl GuestPre { + impl GuestIndices { + /// Constructor for [`GuestIndices`] which takes a + /// [`Component`](wasmtime::component::Component) as input and can be executed + /// before instantiation. + /// + /// This constructor can be used to front-load string lookups to find exports + /// within a component. pub fn new( component: &wasmtime::component::Component, - ) -> wasmtime::Result { - let _component = component; + ) -> wasmtime::Result { let (_, instance) = component .export_index(None, "foo:foo/export-using-export2") .ok_or_else(|| { @@ -596,10 +793,34 @@ pub mod exports { "no exported instance named `foo:foo/export-using-export2`" ) })?; - let _lookup = |name: &str| { - _component - .export_index(Some(&instance), name) - .map(|p| p.1) + Self::_new(|name| { + component.export_index(Some(&instance), name).map(|p| p.1) + }) + } + /// This constructor is similar to [`GuestIndices::new`] except that it + /// performs string lookups after instantiation time. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let instance_export = instance + .get_export(&mut store, None, "foo:foo/export-using-export2") + .ok_or_else(|| { + anyhow::anyhow!( + "no exported instance named `foo:foo/export-using-export2`" + ) + })?; + Self::_new(|name| { + instance.get_export(&mut store, Some(&instance_export), name) + }) + } + fn _new( + mut lookup: impl FnMut( + &str, + ) -> Option, + ) -> wasmtime::Result { + let mut lookup = move |name| { + lookup(name) .ok_or_else(|| { anyhow::anyhow!( "instance export `foo:foo/export-using-export2` does \ @@ -607,8 +828,9 @@ pub mod exports { ) }) }; - let constructor_b_constructor = _lookup("[constructor]b")?; - Ok(GuestPre { + let _ = &mut lookup; + let constructor_b_constructor = lookup("[constructor]b")?; + Ok(GuestIndices { constructor_b_constructor, }) } diff --git a/crates/component-macro/tests/expanded/resources-export_async.rs b/crates/component-macro/tests/expanded/resources-export_async.rs index 266c35ecdb06..09a3766b8731 100644 --- a/crates/component-macro/tests/expanded/resources-export_async.rs +++ b/crates/component-macro/tests/expanded/resources-export_async.rs @@ -4,31 +4,101 @@ /// This structure is created through [`WPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`W`] as well. pub struct WPre { instance_pre: wasmtime::component::InstancePre, - interface0: exports::foo::foo::simple_export::GuestPre, - interface1: exports::foo::foo::export_using_import::GuestPre, - interface2: exports::foo::foo::export_using_export1::GuestPre, - interface3: exports::foo::foo::export_using_export2::GuestPre, + indices: WIndices, } impl Clone for WPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), - interface0: self.interface0.clone(), - interface1: self.interface1.clone(), - interface2: self.interface2.clone(), - interface3: self.interface3.clone(), + indices: self.indices.clone(), } } } +impl<_T> WPre<_T> { + /// Creates a new copy of `WPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = WIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`W`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub async fn instantiate_async( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result + where + _T: Send, + { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate_async(&mut store).await?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `w`. +/// +/// This is an implementation detail of [`WPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`W`] as well. +#[derive(Clone)] +pub struct WIndices { + interface0: exports::foo::foo::simple_export::GuestIndices, + interface1: exports::foo::foo::export_using_import::GuestIndices, + interface2: exports::foo::foo::export_using_export1::GuestIndices, + interface3: exports::foo::foo::export_using_export2::GuestIndices, +} /// Auto-generated bindings for an instance a component which /// implements the world `w`. /// -/// This structure is created through either -/// [`W::instantiate_async`] or by first creating -/// a [`WPre`] followed by using -/// [`WPre::instantiate_async`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`W::instantiate_async`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`WPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`WPre::instantiate_async`] to +/// create a [`W`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`W::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`WIndices::new_instance`] followed +/// by [`WIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct W { interface0: exports::foo::foo::simple_export::Guest, interface1: exports::foo::foo::export_using_import::Guest, @@ -38,52 +108,81 @@ pub struct W { const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> WPre<_T> { - /// Creates a new copy of `WPre` bindings which can then + impl WIndices { + /// Creates a new copy of `WIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, ) -> wasmtime::Result { - let _component = instance_pre.component(); - let interface0 = exports::foo::foo::simple_export::GuestPre::new( + let _component = component; + let interface0 = exports::foo::foo::simple_export::GuestIndices::new( _component, )?; - let interface1 = exports::foo::foo::export_using_import::GuestPre::new( + let interface1 = exports::foo::foo::export_using_import::GuestIndices::new( _component, )?; - let interface2 = exports::foo::foo::export_using_export1::GuestPre::new( + let interface2 = exports::foo::foo::export_using_export1::GuestIndices::new( _component, )?; - let interface3 = exports::foo::foo::export_using_export2::GuestPre::new( + let interface3 = exports::foo::foo::export_using_export2::GuestIndices::new( _component, )?; - Ok(WPre { - instance_pre, + Ok(WIndices { interface0, interface1, interface2, interface3, }) } - /// Instantiates a new instance of [`W`] within the - /// `store` provided. + /// Creates a new instance of [`WIndices`] from an + /// instantiated component. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub async fn instantiate_async( + /// This method of creating a [`W`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`W`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; + let interface0 = exports::foo::foo::simple_export::GuestIndices::new_instance( + &mut store, + _instance, + )?; + let interface1 = exports::foo::foo::export_using_import::GuestIndices::new_instance( + &mut store, + _instance, + )?; + let interface2 = exports::foo::foo::export_using_export1::GuestIndices::new_instance( + &mut store, + _instance, + )?; + let interface3 = exports::foo::foo::export_using_export2::GuestIndices::new_instance( + &mut store, + _instance, + )?; + Ok(WIndices { + interface0, + interface1, + interface2, + interface3, + }) + } + /// Uses the indices stored in `self` to load an instance + /// of [`W`] from the instance provided. + /// + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate_async(&mut store).await?; + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; let interface0 = self.interface0.load(&mut store, &_instance)?; let interface1 = self.interface1.load(&mut store, &_instance)?; let interface2 = self.interface2.load(&mut store, &_instance)?; @@ -95,12 +194,6 @@ const _: () = { interface3, }) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl W { /// Convenience wrapper around [`WPre::new`] and @@ -116,6 +209,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; WPre::new(pre)?.instantiate_async(store).await } + /// Convenience wrapper around [`WIndices::new_instance`] and + /// [`WIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = WIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker( linker: &mut wasmtime::component::Linker, get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, @@ -239,16 +341,21 @@ pub mod exports { method_a_method_a: wasmtime::component::Func, } #[derive(Clone)] - pub struct GuestPre { + pub struct GuestIndices { constructor_a_constructor: wasmtime::component::ComponentExportIndex, static_a_static_a: wasmtime::component::ComponentExportIndex, method_a_method_a: wasmtime::component::ComponentExportIndex, } - impl GuestPre { + impl GuestIndices { + /// Constructor for [`GuestIndices`] which takes a + /// [`Component`](wasmtime::component::Component) as input and can be executed + /// before instantiation. + /// + /// This constructor can be used to front-load string lookups to find exports + /// within a component. pub fn new( component: &wasmtime::component::Component, - ) -> wasmtime::Result { - let _component = component; + ) -> wasmtime::Result { let (_, instance) = component .export_index(None, "foo:foo/simple-export") .ok_or_else(|| { @@ -256,10 +363,34 @@ pub mod exports { "no exported instance named `foo:foo/simple-export`" ) })?; - let _lookup = |name: &str| { - _component - .export_index(Some(&instance), name) - .map(|p| p.1) + Self::_new(|name| { + component.export_index(Some(&instance), name).map(|p| p.1) + }) + } + /// This constructor is similar to [`GuestIndices::new`] except that it + /// performs string lookups after instantiation time. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let instance_export = instance + .get_export(&mut store, None, "foo:foo/simple-export") + .ok_or_else(|| { + anyhow::anyhow!( + "no exported instance named `foo:foo/simple-export`" + ) + })?; + Self::_new(|name| { + instance.get_export(&mut store, Some(&instance_export), name) + }) + } + fn _new( + mut lookup: impl FnMut( + &str, + ) -> Option, + ) -> wasmtime::Result { + let mut lookup = move |name| { + lookup(name) .ok_or_else(|| { anyhow::anyhow!( "instance export `foo:foo/simple-export` does \ @@ -267,10 +398,11 @@ pub mod exports { ) }) }; - let constructor_a_constructor = _lookup("[constructor]a")?; - let static_a_static_a = _lookup("[static]a.static-a")?; - let method_a_method_a = _lookup("[method]a.method-a")?; - Ok(GuestPre { + let _ = &mut lookup; + let constructor_a_constructor = lookup("[constructor]a")?; + let static_a_static_a = lookup("[static]a.static-a")?; + let method_a_method_a = lookup("[method]a.method-a")?; + Ok(GuestIndices { constructor_a_constructor, static_a_static_a, method_a_method_a, @@ -390,16 +522,21 @@ pub mod exports { method_a_method_a: wasmtime::component::Func, } #[derive(Clone)] - pub struct GuestPre { + pub struct GuestIndices { constructor_a_constructor: wasmtime::component::ComponentExportIndex, static_a_static_a: wasmtime::component::ComponentExportIndex, method_a_method_a: wasmtime::component::ComponentExportIndex, } - impl GuestPre { + impl GuestIndices { + /// Constructor for [`GuestIndices`] which takes a + /// [`Component`](wasmtime::component::Component) as input and can be executed + /// before instantiation. + /// + /// This constructor can be used to front-load string lookups to find exports + /// within a component. pub fn new( component: &wasmtime::component::Component, - ) -> wasmtime::Result { - let _component = component; + ) -> wasmtime::Result { let (_, instance) = component .export_index(None, "foo:foo/export-using-import") .ok_or_else(|| { @@ -407,10 +544,34 @@ pub mod exports { "no exported instance named `foo:foo/export-using-import`" ) })?; - let _lookup = |name: &str| { - _component - .export_index(Some(&instance), name) - .map(|p| p.1) + Self::_new(|name| { + component.export_index(Some(&instance), name).map(|p| p.1) + }) + } + /// This constructor is similar to [`GuestIndices::new`] except that it + /// performs string lookups after instantiation time. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let instance_export = instance + .get_export(&mut store, None, "foo:foo/export-using-import") + .ok_or_else(|| { + anyhow::anyhow!( + "no exported instance named `foo:foo/export-using-import`" + ) + })?; + Self::_new(|name| { + instance.get_export(&mut store, Some(&instance_export), name) + }) + } + fn _new( + mut lookup: impl FnMut( + &str, + ) -> Option, + ) -> wasmtime::Result { + let mut lookup = move |name| { + lookup(name) .ok_or_else(|| { anyhow::anyhow!( "instance export `foo:foo/export-using-import` does \ @@ -418,10 +579,11 @@ pub mod exports { ) }) }; - let constructor_a_constructor = _lookup("[constructor]a")?; - let static_a_static_a = _lookup("[static]a.static-a")?; - let method_a_method_a = _lookup("[method]a.method-a")?; - Ok(GuestPre { + let _ = &mut lookup; + let constructor_a_constructor = lookup("[constructor]a")?; + let static_a_static_a = lookup("[static]a.static-a")?; + let method_a_method_a = lookup("[method]a.method-a")?; + Ok(GuestIndices { constructor_a_constructor, static_a_static_a, method_a_method_a, @@ -546,14 +708,19 @@ pub mod exports { constructor_a_constructor: wasmtime::component::Func, } #[derive(Clone)] - pub struct GuestPre { + pub struct GuestIndices { constructor_a_constructor: wasmtime::component::ComponentExportIndex, } - impl GuestPre { + impl GuestIndices { + /// Constructor for [`GuestIndices`] which takes a + /// [`Component`](wasmtime::component::Component) as input and can be executed + /// before instantiation. + /// + /// This constructor can be used to front-load string lookups to find exports + /// within a component. pub fn new( component: &wasmtime::component::Component, - ) -> wasmtime::Result { - let _component = component; + ) -> wasmtime::Result { let (_, instance) = component .export_index(None, "foo:foo/export-using-export1") .ok_or_else(|| { @@ -561,10 +728,34 @@ pub mod exports { "no exported instance named `foo:foo/export-using-export1`" ) })?; - let _lookup = |name: &str| { - _component - .export_index(Some(&instance), name) - .map(|p| p.1) + Self::_new(|name| { + component.export_index(Some(&instance), name).map(|p| p.1) + }) + } + /// This constructor is similar to [`GuestIndices::new`] except that it + /// performs string lookups after instantiation time. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let instance_export = instance + .get_export(&mut store, None, "foo:foo/export-using-export1") + .ok_or_else(|| { + anyhow::anyhow!( + "no exported instance named `foo:foo/export-using-export1`" + ) + })?; + Self::_new(|name| { + instance.get_export(&mut store, Some(&instance_export), name) + }) + } + fn _new( + mut lookup: impl FnMut( + &str, + ) -> Option, + ) -> wasmtime::Result { + let mut lookup = move |name| { + lookup(name) .ok_or_else(|| { anyhow::anyhow!( "instance export `foo:foo/export-using-export1` does \ @@ -572,8 +763,9 @@ pub mod exports { ) }) }; - let constructor_a_constructor = _lookup("[constructor]a")?; - Ok(GuestPre { + let _ = &mut lookup; + let constructor_a_constructor = lookup("[constructor]a")?; + Ok(GuestIndices { constructor_a_constructor, }) } @@ -634,14 +826,19 @@ pub mod exports { constructor_b_constructor: wasmtime::component::Func, } #[derive(Clone)] - pub struct GuestPre { + pub struct GuestIndices { constructor_b_constructor: wasmtime::component::ComponentExportIndex, } - impl GuestPre { + impl GuestIndices { + /// Constructor for [`GuestIndices`] which takes a + /// [`Component`](wasmtime::component::Component) as input and can be executed + /// before instantiation. + /// + /// This constructor can be used to front-load string lookups to find exports + /// within a component. pub fn new( component: &wasmtime::component::Component, - ) -> wasmtime::Result { - let _component = component; + ) -> wasmtime::Result { let (_, instance) = component .export_index(None, "foo:foo/export-using-export2") .ok_or_else(|| { @@ -649,10 +846,34 @@ pub mod exports { "no exported instance named `foo:foo/export-using-export2`" ) })?; - let _lookup = |name: &str| { - _component - .export_index(Some(&instance), name) - .map(|p| p.1) + Self::_new(|name| { + component.export_index(Some(&instance), name).map(|p| p.1) + }) + } + /// This constructor is similar to [`GuestIndices::new`] except that it + /// performs string lookups after instantiation time. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let instance_export = instance + .get_export(&mut store, None, "foo:foo/export-using-export2") + .ok_or_else(|| { + anyhow::anyhow!( + "no exported instance named `foo:foo/export-using-export2`" + ) + })?; + Self::_new(|name| { + instance.get_export(&mut store, Some(&instance_export), name) + }) + } + fn _new( + mut lookup: impl FnMut( + &str, + ) -> Option, + ) -> wasmtime::Result { + let mut lookup = move |name| { + lookup(name) .ok_or_else(|| { anyhow::anyhow!( "instance export `foo:foo/export-using-export2` does \ @@ -660,8 +881,9 @@ pub mod exports { ) }) }; - let constructor_b_constructor = _lookup("[constructor]b")?; - Ok(GuestPre { + let _ = &mut lookup; + let constructor_b_constructor = lookup("[constructor]b")?; + Ok(GuestIndices { constructor_b_constructor, }) } diff --git a/crates/component-macro/tests/expanded/resources-import.rs b/crates/component-macro/tests/expanded/resources-import.rs index 69e24379aa44..cbea8b03f851 100644 --- a/crates/component-macro/tests/expanded/resources-import.rs +++ b/crates/component-macro/tests/expanded/resources-import.rs @@ -31,27 +31,96 @@ impl<_T: HostWorldResource + ?Sized> HostWorldResource for &mut _T { /// This structure is created through [`TheWorldPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`TheWorld`] as well. pub struct TheWorldPre { instance_pre: wasmtime::component::InstancePre, - interface1: exports::foo::foo::uses_resource_transitively::GuestPre, - some_world_func2: wasmtime::component::ComponentExportIndex, + indices: TheWorldIndices, } impl Clone for TheWorldPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), - interface1: self.interface1.clone(), - some_world_func2: self.some_world_func2.clone(), + indices: self.indices.clone(), } } } +impl<_T> TheWorldPre<_T> { + /// Creates a new copy of `TheWorldPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`TheWorld`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub fn instantiate( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate(&mut store)?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `the-world`. +/// +/// This is an implementation detail of [`TheWorldPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`TheWorld`] as well. +#[derive(Clone)] +pub struct TheWorldIndices { + interface1: exports::foo::foo::uses_resource_transitively::GuestIndices, + some_world_func2: wasmtime::component::ComponentExportIndex, +} /// Auto-generated bindings for an instance a component which /// implements the world `the-world`. /// -/// This structure is created through either -/// [`TheWorld::instantiate`] or by first creating -/// a [`TheWorldPre`] followed by using -/// [`TheWorldPre::instantiate`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`TheWorld::instantiate`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`TheWorldPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`TheWorldPre::instantiate`] to +/// create a [`TheWorld`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`TheWorld::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`TheWorldIndices::new_instance`] followed +/// by [`TheWorldIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct TheWorld { interface1: exports::foo::foo::uses_resource_transitively::Guest, some_world_func2: wasmtime::component::Func, @@ -79,17 +148,17 @@ impl<_T: TheWorldImports + ?Sized> TheWorldImports for &mut _T { const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> TheWorldPre<_T> { - /// Creates a new copy of `TheWorldPre` bindings which can then + impl TheWorldIndices { + /// Creates a new copy of `TheWorldIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, ) -> wasmtime::Result { - let _component = instance_pre.component(); - let interface1 = exports::foo::foo::uses_resource_transitively::GuestPre::new( + let _component = component; + let interface1 = exports::foo::foo::uses_resource_transitively::GuestIndices::new( _component, )?; let some_world_func2 = _component @@ -98,25 +167,48 @@ const _: () = { anyhow::anyhow!("no function export `some-world-func2` found") })? .1; - Ok(TheWorldPre { - instance_pre, + Ok(TheWorldIndices { + interface1, + some_world_func2, + }) + } + /// Creates a new instance of [`TheWorldIndices`] from an + /// instantiated component. + /// + /// This method of creating a [`TheWorld`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`TheWorld`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; + let interface1 = exports::foo::foo::uses_resource_transitively::GuestIndices::new_instance( + &mut store, + _instance, + )?; + let some_world_func2 = _instance + .get_export(&mut store, None, "some-world-func2") + .ok_or_else(|| { + anyhow::anyhow!("no function export `some-world-func2` found") + })?; + Ok(TheWorldIndices { interface1, some_world_func2, }) } - /// Instantiates a new instance of [`TheWorld`] within the - /// `store` provided. + /// Uses the indices stored in `self` to load an instance + /// of [`TheWorld`] from the instance provided. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub fn instantiate( + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate(&mut store)?; + let _instance = instance; let interface1 = self.interface1.load(&mut store, &_instance)?; let some_world_func2 = *_instance .get_typed_func::< @@ -129,12 +221,6 @@ const _: () = { some_world_func2, }) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl TheWorld { /// Convenience wrapper around [`TheWorldPre::new`] and @@ -147,6 +233,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate(store) } + /// Convenience wrapper around [`TheWorldIndices::new_instance`] and + /// [`TheWorldIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker_imports_get_host( linker: &mut wasmtime::component::Linker, host_getter: impl for<'a> TheWorldImportsGetHost<&'a mut T>, @@ -1019,14 +1114,19 @@ pub mod exports { handle: wasmtime::component::Func, } #[derive(Clone)] - pub struct GuestPre { + pub struct GuestIndices { handle: wasmtime::component::ComponentExportIndex, } - impl GuestPre { + impl GuestIndices { + /// Constructor for [`GuestIndices`] which takes a + /// [`Component`](wasmtime::component::Component) as input and can be executed + /// before instantiation. + /// + /// This constructor can be used to front-load string lookups to find exports + /// within a component. pub fn new( component: &wasmtime::component::Component, - ) -> wasmtime::Result { - let _component = component; + ) -> wasmtime::Result { let (_, instance) = component .export_index(None, "foo:foo/uses-resource-transitively") .ok_or_else(|| { @@ -1034,19 +1134,48 @@ pub mod exports { "no exported instance named `foo:foo/uses-resource-transitively`" ) })?; - let _lookup = |name: &str| { - _component - .export_index(Some(&instance), name) - .map(|p| p.1) + Self::_new(|name| { + component.export_index(Some(&instance), name).map(|p| p.1) + }) + } + /// This constructor is similar to [`GuestIndices::new`] except that it + /// performs string lookups after instantiation time. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let instance_export = instance + .get_export( + &mut store, + None, + "foo:foo/uses-resource-transitively", + ) + .ok_or_else(|| { + anyhow::anyhow!( + "no exported instance named `foo:foo/uses-resource-transitively`" + ) + })?; + Self::_new(|name| { + instance.get_export(&mut store, Some(&instance_export), name) + }) + } + fn _new( + mut lookup: impl FnMut( + &str, + ) -> Option, + ) -> wasmtime::Result { + let mut lookup = move |name| { + lookup(name) .ok_or_else(|| { anyhow::anyhow!( "instance export `foo:foo/uses-resource-transitively` does \ - not have export `{name}`" + not have export `{name}`" ) }) }; - let handle = _lookup("handle")?; - Ok(GuestPre { handle }) + let _ = &mut lookup; + let handle = lookup("handle")?; + Ok(GuestIndices { handle }) } pub fn load( &self, diff --git a/crates/component-macro/tests/expanded/resources-import_async.rs b/crates/component-macro/tests/expanded/resources-import_async.rs index 55da75b2406d..1b8424df1eef 100644 --- a/crates/component-macro/tests/expanded/resources-import_async.rs +++ b/crates/component-macro/tests/expanded/resources-import_async.rs @@ -33,27 +33,99 @@ impl<_T: HostWorldResource + ?Sized + Send> HostWorldResource for &mut _T { /// This structure is created through [`TheWorldPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`TheWorld`] as well. pub struct TheWorldPre { instance_pre: wasmtime::component::InstancePre, - interface1: exports::foo::foo::uses_resource_transitively::GuestPre, - some_world_func2: wasmtime::component::ComponentExportIndex, + indices: TheWorldIndices, } impl Clone for TheWorldPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), - interface1: self.interface1.clone(), - some_world_func2: self.some_world_func2.clone(), + indices: self.indices.clone(), } } } +impl<_T> TheWorldPre<_T> { + /// Creates a new copy of `TheWorldPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`TheWorld`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub async fn instantiate_async( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result + where + _T: Send, + { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate_async(&mut store).await?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `the-world`. +/// +/// This is an implementation detail of [`TheWorldPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`TheWorld`] as well. +#[derive(Clone)] +pub struct TheWorldIndices { + interface1: exports::foo::foo::uses_resource_transitively::GuestIndices, + some_world_func2: wasmtime::component::ComponentExportIndex, +} /// Auto-generated bindings for an instance a component which /// implements the world `the-world`. /// -/// This structure is created through either -/// [`TheWorld::instantiate_async`] or by first creating -/// a [`TheWorldPre`] followed by using -/// [`TheWorldPre::instantiate_async`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`TheWorld::instantiate_async`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`TheWorldPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`TheWorldPre::instantiate_async`] to +/// create a [`TheWorld`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`TheWorld::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`TheWorldIndices::new_instance`] followed +/// by [`TheWorldIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct TheWorld { interface1: exports::foo::foo::uses_resource_transitively::Guest, some_world_func2: wasmtime::component::Func, @@ -83,17 +155,17 @@ impl<_T: TheWorldImports + ?Sized + Send> TheWorldImports for &mut _T { const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> TheWorldPre<_T> { - /// Creates a new copy of `TheWorldPre` bindings which can then + impl TheWorldIndices { + /// Creates a new copy of `TheWorldIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, ) -> wasmtime::Result { - let _component = instance_pre.component(); - let interface1 = exports::foo::foo::uses_resource_transitively::GuestPre::new( + let _component = component; + let interface1 = exports::foo::foo::uses_resource_transitively::GuestIndices::new( _component, )?; let some_world_func2 = _component @@ -102,28 +174,48 @@ const _: () = { anyhow::anyhow!("no function export `some-world-func2` found") })? .1; - Ok(TheWorldPre { - instance_pre, + Ok(TheWorldIndices { interface1, some_world_func2, }) } - /// Instantiates a new instance of [`TheWorld`] within the - /// `store` provided. + /// Creates a new instance of [`TheWorldIndices`] from an + /// instantiated component. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub async fn instantiate_async( + /// This method of creating a [`TheWorld`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`TheWorld`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; + let interface1 = exports::foo::foo::uses_resource_transitively::GuestIndices::new_instance( + &mut store, + _instance, + )?; + let some_world_func2 = _instance + .get_export(&mut store, None, "some-world-func2") + .ok_or_else(|| { + anyhow::anyhow!("no function export `some-world-func2` found") + })?; + Ok(TheWorldIndices { + interface1, + some_world_func2, + }) + } + /// Uses the indices stored in `self` to load an instance + /// of [`TheWorld`] from the instance provided. + /// + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate_async(&mut store).await?; + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; let interface1 = self.interface1.load(&mut store, &_instance)?; let some_world_func2 = *_instance .get_typed_func::< @@ -136,12 +228,6 @@ const _: () = { some_world_func2, }) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl TheWorld { /// Convenience wrapper around [`TheWorldPre::new`] and @@ -157,6 +243,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate_async(store).await } + /// Convenience wrapper around [`TheWorldIndices::new_instance`] and + /// [`TheWorldIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker_imports_get_host( linker: &mut wasmtime::component::Linker, host_getter: impl for<'a> TheWorldImportsGetHost<&'a mut T>, @@ -1104,14 +1199,19 @@ pub mod exports { handle: wasmtime::component::Func, } #[derive(Clone)] - pub struct GuestPre { + pub struct GuestIndices { handle: wasmtime::component::ComponentExportIndex, } - impl GuestPre { + impl GuestIndices { + /// Constructor for [`GuestIndices`] which takes a + /// [`Component`](wasmtime::component::Component) as input and can be executed + /// before instantiation. + /// + /// This constructor can be used to front-load string lookups to find exports + /// within a component. pub fn new( component: &wasmtime::component::Component, - ) -> wasmtime::Result { - let _component = component; + ) -> wasmtime::Result { let (_, instance) = component .export_index(None, "foo:foo/uses-resource-transitively") .ok_or_else(|| { @@ -1119,19 +1219,48 @@ pub mod exports { "no exported instance named `foo:foo/uses-resource-transitively`" ) })?; - let _lookup = |name: &str| { - _component - .export_index(Some(&instance), name) - .map(|p| p.1) + Self::_new(|name| { + component.export_index(Some(&instance), name).map(|p| p.1) + }) + } + /// This constructor is similar to [`GuestIndices::new`] except that it + /// performs string lookups after instantiation time. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let instance_export = instance + .get_export( + &mut store, + None, + "foo:foo/uses-resource-transitively", + ) + .ok_or_else(|| { + anyhow::anyhow!( + "no exported instance named `foo:foo/uses-resource-transitively`" + ) + })?; + Self::_new(|name| { + instance.get_export(&mut store, Some(&instance_export), name) + }) + } + fn _new( + mut lookup: impl FnMut( + &str, + ) -> Option, + ) -> wasmtime::Result { + let mut lookup = move |name| { + lookup(name) .ok_or_else(|| { anyhow::anyhow!( "instance export `foo:foo/uses-resource-transitively` does \ - not have export `{name}`" + not have export `{name}`" ) }) }; - let handle = _lookup("handle")?; - Ok(GuestPre { handle }) + let _ = &mut lookup; + let handle = lookup("handle")?; + Ok(GuestIndices { handle }) } pub fn load( &self, diff --git a/crates/component-macro/tests/expanded/share-types.rs b/crates/component-macro/tests/expanded/share-types.rs index 5818b3c48ce8..2e7bd33dfa35 100644 --- a/crates/component-macro/tests/expanded/share-types.rs +++ b/crates/component-macro/tests/expanded/share-types.rs @@ -4,69 +4,146 @@ /// This structure is created through [`HttpInterfacePre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`HttpInterface`] as well. pub struct HttpInterfacePre { instance_pre: wasmtime::component::InstancePre, - interface0: exports::http_handler::GuestPre, + indices: HttpInterfaceIndices, } impl Clone for HttpInterfacePre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), - interface0: self.interface0.clone(), + indices: self.indices.clone(), } } } +impl<_T> HttpInterfacePre<_T> { + /// Creates a new copy of `HttpInterfacePre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = HttpInterfaceIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`HttpInterface`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub fn instantiate( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate(&mut store)?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `http-interface`. +/// +/// This is an implementation detail of [`HttpInterfacePre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`HttpInterface`] as well. +#[derive(Clone)] +pub struct HttpInterfaceIndices { + interface0: exports::http_handler::GuestIndices, +} /// Auto-generated bindings for an instance a component which /// implements the world `http-interface`. /// -/// This structure is created through either -/// [`HttpInterface::instantiate`] or by first creating -/// a [`HttpInterfacePre`] followed by using -/// [`HttpInterfacePre::instantiate`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`HttpInterface::instantiate`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`HttpInterfacePre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`HttpInterfacePre::instantiate`] to +/// create a [`HttpInterface`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`HttpInterface::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`HttpInterfaceIndices::new_instance`] followed +/// by [`HttpInterfaceIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct HttpInterface { interface0: exports::http_handler::Guest, } const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> HttpInterfacePre<_T> { - /// Creates a new copy of `HttpInterfacePre` bindings which can then + impl HttpInterfaceIndices { + /// Creates a new copy of `HttpInterfaceIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, ) -> wasmtime::Result { - let _component = instance_pre.component(); - let interface0 = exports::http_handler::GuestPre::new(_component)?; - Ok(HttpInterfacePre { - instance_pre, - interface0, - }) + let _component = component; + let interface0 = exports::http_handler::GuestIndices::new(_component)?; + Ok(HttpInterfaceIndices { interface0 }) } - /// Instantiates a new instance of [`HttpInterface`] within the - /// `store` provided. + /// Creates a new instance of [`HttpInterfaceIndices`] from an + /// instantiated component. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub fn instantiate( + /// This method of creating a [`HttpInterface`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`HttpInterface`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; + let interface0 = exports::http_handler::GuestIndices::new_instance( + &mut store, + _instance, + )?; + Ok(HttpInterfaceIndices { interface0 }) + } + /// Uses the indices stored in `self` to load an instance + /// of [`HttpInterface`] from the instance provided. + /// + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate(&mut store)?; + let _instance = instance; let interface0 = self.interface0.load(&mut store, &_instance)?; Ok(HttpInterface { interface0 }) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl HttpInterface { /// Convenience wrapper around [`HttpInterfacePre::new`] and @@ -79,6 +156,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; HttpInterfacePre::new(pre)?.instantiate(store) } + /// Convenience wrapper around [`HttpInterfaceIndices::new_instance`] and + /// [`HttpInterfaceIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = HttpInterfaceIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker( linker: &mut wasmtime::component::Linker, get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, @@ -250,23 +336,50 @@ pub mod exports { handle_request: wasmtime::component::Func, } #[derive(Clone)] - pub struct GuestPre { + pub struct GuestIndices { handle_request: wasmtime::component::ComponentExportIndex, } - impl GuestPre { + impl GuestIndices { + /// Constructor for [`GuestIndices`] which takes a + /// [`Component`](wasmtime::component::Component) as input and can be executed + /// before instantiation. + /// + /// This constructor can be used to front-load string lookups to find exports + /// within a component. pub fn new( component: &wasmtime::component::Component, - ) -> wasmtime::Result { - let _component = component; + ) -> wasmtime::Result { let (_, instance) = component .export_index(None, "http-handler") .ok_or_else(|| { anyhow::anyhow!("no exported instance named `http-handler`") })?; - let _lookup = |name: &str| { - _component - .export_index(Some(&instance), name) - .map(|p| p.1) + Self::_new(|name| { + component.export_index(Some(&instance), name).map(|p| p.1) + }) + } + /// This constructor is similar to [`GuestIndices::new`] except that it + /// performs string lookups after instantiation time. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let instance_export = instance + .get_export(&mut store, None, "http-handler") + .ok_or_else(|| { + anyhow::anyhow!("no exported instance named `http-handler`") + })?; + Self::_new(|name| { + instance.get_export(&mut store, Some(&instance_export), name) + }) + } + fn _new( + mut lookup: impl FnMut( + &str, + ) -> Option, + ) -> wasmtime::Result { + let mut lookup = move |name| { + lookup(name) .ok_or_else(|| { anyhow::anyhow!( "instance export `http-handler` does \ @@ -274,8 +387,9 @@ pub mod exports { ) }) }; - let handle_request = _lookup("handle-request")?; - Ok(GuestPre { handle_request }) + let _ = &mut lookup; + let handle_request = lookup("handle-request")?; + Ok(GuestIndices { handle_request }) } pub fn load( &self, diff --git a/crates/component-macro/tests/expanded/share-types_async.rs b/crates/component-macro/tests/expanded/share-types_async.rs index b126ec59671e..09461c453bc2 100644 --- a/crates/component-macro/tests/expanded/share-types_async.rs +++ b/crates/component-macro/tests/expanded/share-types_async.rs @@ -4,72 +4,149 @@ /// This structure is created through [`HttpInterfacePre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`HttpInterface`] as well. pub struct HttpInterfacePre { instance_pre: wasmtime::component::InstancePre, - interface0: exports::http_handler::GuestPre, + indices: HttpInterfaceIndices, } impl Clone for HttpInterfacePre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), - interface0: self.interface0.clone(), + indices: self.indices.clone(), } } } +impl<_T> HttpInterfacePre<_T> { + /// Creates a new copy of `HttpInterfacePre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = HttpInterfaceIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`HttpInterface`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub async fn instantiate_async( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result + where + _T: Send, + { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate_async(&mut store).await?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `http-interface`. +/// +/// This is an implementation detail of [`HttpInterfacePre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`HttpInterface`] as well. +#[derive(Clone)] +pub struct HttpInterfaceIndices { + interface0: exports::http_handler::GuestIndices, +} /// Auto-generated bindings for an instance a component which /// implements the world `http-interface`. /// -/// This structure is created through either -/// [`HttpInterface::instantiate_async`] or by first creating -/// a [`HttpInterfacePre`] followed by using -/// [`HttpInterfacePre::instantiate_async`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`HttpInterface::instantiate_async`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`HttpInterfacePre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`HttpInterfacePre::instantiate_async`] to +/// create a [`HttpInterface`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`HttpInterface::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`HttpInterfaceIndices::new_instance`] followed +/// by [`HttpInterfaceIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct HttpInterface { interface0: exports::http_handler::Guest, } const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> HttpInterfacePre<_T> { - /// Creates a new copy of `HttpInterfacePre` bindings which can then + impl HttpInterfaceIndices { + /// Creates a new copy of `HttpInterfaceIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, ) -> wasmtime::Result { - let _component = instance_pre.component(); - let interface0 = exports::http_handler::GuestPre::new(_component)?; - Ok(HttpInterfacePre { - instance_pre, - interface0, - }) + let _component = component; + let interface0 = exports::http_handler::GuestIndices::new(_component)?; + Ok(HttpInterfaceIndices { interface0 }) } - /// Instantiates a new instance of [`HttpInterface`] within the - /// `store` provided. + /// Creates a new instance of [`HttpInterfaceIndices`] from an + /// instantiated component. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub async fn instantiate_async( + /// This method of creating a [`HttpInterface`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`HttpInterface`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; + let interface0 = exports::http_handler::GuestIndices::new_instance( + &mut store, + _instance, + )?; + Ok(HttpInterfaceIndices { interface0 }) + } + /// Uses the indices stored in `self` to load an instance + /// of [`HttpInterface`] from the instance provided. + /// + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate_async(&mut store).await?; + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; let interface0 = self.interface0.load(&mut store, &_instance)?; Ok(HttpInterface { interface0 }) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl HttpInterface { /// Convenience wrapper around [`HttpInterfacePre::new`] and @@ -85,6 +162,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; HttpInterfacePre::new(pre)?.instantiate_async(store).await } + /// Convenience wrapper around [`HttpInterfaceIndices::new_instance`] and + /// [`HttpInterfaceIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = HttpInterfaceIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker( linker: &mut wasmtime::component::Linker, get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, @@ -269,23 +355,50 @@ pub mod exports { handle_request: wasmtime::component::Func, } #[derive(Clone)] - pub struct GuestPre { + pub struct GuestIndices { handle_request: wasmtime::component::ComponentExportIndex, } - impl GuestPre { + impl GuestIndices { + /// Constructor for [`GuestIndices`] which takes a + /// [`Component`](wasmtime::component::Component) as input and can be executed + /// before instantiation. + /// + /// This constructor can be used to front-load string lookups to find exports + /// within a component. pub fn new( component: &wasmtime::component::Component, - ) -> wasmtime::Result { - let _component = component; + ) -> wasmtime::Result { let (_, instance) = component .export_index(None, "http-handler") .ok_or_else(|| { anyhow::anyhow!("no exported instance named `http-handler`") })?; - let _lookup = |name: &str| { - _component - .export_index(Some(&instance), name) - .map(|p| p.1) + Self::_new(|name| { + component.export_index(Some(&instance), name).map(|p| p.1) + }) + } + /// This constructor is similar to [`GuestIndices::new`] except that it + /// performs string lookups after instantiation time. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let instance_export = instance + .get_export(&mut store, None, "http-handler") + .ok_or_else(|| { + anyhow::anyhow!("no exported instance named `http-handler`") + })?; + Self::_new(|name| { + instance.get_export(&mut store, Some(&instance_export), name) + }) + } + fn _new( + mut lookup: impl FnMut( + &str, + ) -> Option, + ) -> wasmtime::Result { + let mut lookup = move |name| { + lookup(name) .ok_or_else(|| { anyhow::anyhow!( "instance export `http-handler` does \ @@ -293,8 +406,9 @@ pub mod exports { ) }) }; - let handle_request = _lookup("handle-request")?; - Ok(GuestPre { handle_request }) + let _ = &mut lookup; + let handle_request = lookup("handle-request")?; + Ok(GuestIndices { handle_request }) } pub fn load( &self, diff --git a/crates/component-macro/tests/expanded/simple-functions.rs b/crates/component-macro/tests/expanded/simple-functions.rs index a8ea93c6e148..16274afb8f98 100644 --- a/crates/component-macro/tests/expanded/simple-functions.rs +++ b/crates/component-macro/tests/expanded/simple-functions.rs @@ -4,69 +4,146 @@ /// This structure is created through [`TheWorldPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`TheWorld`] as well. pub struct TheWorldPre { instance_pre: wasmtime::component::InstancePre, - interface0: exports::foo::foo::simple::GuestPre, + indices: TheWorldIndices, } impl Clone for TheWorldPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), - interface0: self.interface0.clone(), + indices: self.indices.clone(), } } } +impl<_T> TheWorldPre<_T> { + /// Creates a new copy of `TheWorldPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`TheWorld`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub fn instantiate( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate(&mut store)?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `the-world`. +/// +/// This is an implementation detail of [`TheWorldPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`TheWorld`] as well. +#[derive(Clone)] +pub struct TheWorldIndices { + interface0: exports::foo::foo::simple::GuestIndices, +} /// Auto-generated bindings for an instance a component which /// implements the world `the-world`. /// -/// This structure is created through either -/// [`TheWorld::instantiate`] or by first creating -/// a [`TheWorldPre`] followed by using -/// [`TheWorldPre::instantiate`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`TheWorld::instantiate`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`TheWorldPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`TheWorldPre::instantiate`] to +/// create a [`TheWorld`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`TheWorld::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`TheWorldIndices::new_instance`] followed +/// by [`TheWorldIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct TheWorld { interface0: exports::foo::foo::simple::Guest, } const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> TheWorldPre<_T> { - /// Creates a new copy of `TheWorldPre` bindings which can then + impl TheWorldIndices { + /// Creates a new copy of `TheWorldIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, + ) -> wasmtime::Result { + let _component = component; + let interface0 = exports::foo::foo::simple::GuestIndices::new(_component)?; + Ok(TheWorldIndices { interface0 }) + } + /// Creates a new instance of [`TheWorldIndices`] from an + /// instantiated component. + /// + /// This method of creating a [`TheWorld`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`TheWorld`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let _component = instance_pre.component(); - let interface0 = exports::foo::foo::simple::GuestPre::new(_component)?; - Ok(TheWorldPre { - instance_pre, - interface0, - }) + let _instance = instance; + let interface0 = exports::foo::foo::simple::GuestIndices::new_instance( + &mut store, + _instance, + )?; + Ok(TheWorldIndices { interface0 }) } - /// Instantiates a new instance of [`TheWorld`] within the - /// `store` provided. + /// Uses the indices stored in `self` to load an instance + /// of [`TheWorld`] from the instance provided. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub fn instantiate( + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate(&mut store)?; + let _instance = instance; let interface0 = self.interface0.load(&mut store, &_instance)?; Ok(TheWorld { interface0 }) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl TheWorld { /// Convenience wrapper around [`TheWorldPre::new`] and @@ -79,6 +156,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate(store) } + /// Convenience wrapper around [`TheWorldIndices::new_instance`] and + /// [`TheWorldIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker( linker: &mut wasmtime::component::Linker, get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, @@ -229,7 +315,7 @@ pub mod exports { f6: wasmtime::component::Func, } #[derive(Clone)] - pub struct GuestPre { + pub struct GuestIndices { f1: wasmtime::component::ComponentExportIndex, f2: wasmtime::component::ComponentExportIndex, f3: wasmtime::component::ComponentExportIndex, @@ -237,11 +323,16 @@ pub mod exports { f5: wasmtime::component::ComponentExportIndex, f6: wasmtime::component::ComponentExportIndex, } - impl GuestPre { + impl GuestIndices { + /// Constructor for [`GuestIndices`] which takes a + /// [`Component`](wasmtime::component::Component) as input and can be executed + /// before instantiation. + /// + /// This constructor can be used to front-load string lookups to find exports + /// within a component. pub fn new( component: &wasmtime::component::Component, - ) -> wasmtime::Result { - let _component = component; + ) -> wasmtime::Result { let (_, instance) = component .export_index(None, "foo:foo/simple") .ok_or_else(|| { @@ -249,10 +340,34 @@ pub mod exports { "no exported instance named `foo:foo/simple`" ) })?; - let _lookup = |name: &str| { - _component - .export_index(Some(&instance), name) - .map(|p| p.1) + Self::_new(|name| { + component.export_index(Some(&instance), name).map(|p| p.1) + }) + } + /// This constructor is similar to [`GuestIndices::new`] except that it + /// performs string lookups after instantiation time. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let instance_export = instance + .get_export(&mut store, None, "foo:foo/simple") + .ok_or_else(|| { + anyhow::anyhow!( + "no exported instance named `foo:foo/simple`" + ) + })?; + Self::_new(|name| { + instance.get_export(&mut store, Some(&instance_export), name) + }) + } + fn _new( + mut lookup: impl FnMut( + &str, + ) -> Option, + ) -> wasmtime::Result { + let mut lookup = move |name| { + lookup(name) .ok_or_else(|| { anyhow::anyhow!( "instance export `foo:foo/simple` does \ @@ -260,13 +375,21 @@ pub mod exports { ) }) }; - let f1 = _lookup("f1")?; - let f2 = _lookup("f2")?; - let f3 = _lookup("f3")?; - let f4 = _lookup("f4")?; - let f5 = _lookup("f5")?; - let f6 = _lookup("f6")?; - Ok(GuestPre { f1, f2, f3, f4, f5, f6 }) + let _ = &mut lookup; + let f1 = lookup("f1")?; + let f2 = lookup("f2")?; + let f3 = lookup("f3")?; + let f4 = lookup("f4")?; + let f5 = lookup("f5")?; + let f6 = lookup("f6")?; + Ok(GuestIndices { + f1, + f2, + f3, + f4, + f5, + f6, + }) } pub fn load( &self, diff --git a/crates/component-macro/tests/expanded/simple-functions_async.rs b/crates/component-macro/tests/expanded/simple-functions_async.rs index ae674433e35f..5d3da65402a9 100644 --- a/crates/component-macro/tests/expanded/simple-functions_async.rs +++ b/crates/component-macro/tests/expanded/simple-functions_async.rs @@ -4,72 +4,149 @@ /// This structure is created through [`TheWorldPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`TheWorld`] as well. pub struct TheWorldPre { instance_pre: wasmtime::component::InstancePre, - interface0: exports::foo::foo::simple::GuestPre, + indices: TheWorldIndices, } impl Clone for TheWorldPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), - interface0: self.interface0.clone(), + indices: self.indices.clone(), } } } +impl<_T> TheWorldPre<_T> { + /// Creates a new copy of `TheWorldPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`TheWorld`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub async fn instantiate_async( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result + where + _T: Send, + { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate_async(&mut store).await?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `the-world`. +/// +/// This is an implementation detail of [`TheWorldPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`TheWorld`] as well. +#[derive(Clone)] +pub struct TheWorldIndices { + interface0: exports::foo::foo::simple::GuestIndices, +} /// Auto-generated bindings for an instance a component which /// implements the world `the-world`. /// -/// This structure is created through either -/// [`TheWorld::instantiate_async`] or by first creating -/// a [`TheWorldPre`] followed by using -/// [`TheWorldPre::instantiate_async`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`TheWorld::instantiate_async`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`TheWorldPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`TheWorldPre::instantiate_async`] to +/// create a [`TheWorld`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`TheWorld::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`TheWorldIndices::new_instance`] followed +/// by [`TheWorldIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct TheWorld { interface0: exports::foo::foo::simple::Guest, } const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> TheWorldPre<_T> { - /// Creates a new copy of `TheWorldPre` bindings which can then + impl TheWorldIndices { + /// Creates a new copy of `TheWorldIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, + ) -> wasmtime::Result { + let _component = component; + let interface0 = exports::foo::foo::simple::GuestIndices::new(_component)?; + Ok(TheWorldIndices { interface0 }) + } + /// Creates a new instance of [`TheWorldIndices`] from an + /// instantiated component. + /// + /// This method of creating a [`TheWorld`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`TheWorld`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let _component = instance_pre.component(); - let interface0 = exports::foo::foo::simple::GuestPre::new(_component)?; - Ok(TheWorldPre { - instance_pre, - interface0, - }) + let _instance = instance; + let interface0 = exports::foo::foo::simple::GuestIndices::new_instance( + &mut store, + _instance, + )?; + Ok(TheWorldIndices { interface0 }) } - /// Instantiates a new instance of [`TheWorld`] within the - /// `store` provided. + /// Uses the indices stored in `self` to load an instance + /// of [`TheWorld`] from the instance provided. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub async fn instantiate_async( + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate_async(&mut store).await?; + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; let interface0 = self.interface0.load(&mut store, &_instance)?; Ok(TheWorld { interface0 }) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl TheWorld { /// Convenience wrapper around [`TheWorldPre::new`] and @@ -85,6 +162,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate_async(store).await } + /// Convenience wrapper around [`TheWorldIndices::new_instance`] and + /// [`TheWorldIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker( linker: &mut wasmtime::component::Linker, get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, @@ -242,7 +328,7 @@ pub mod exports { f6: wasmtime::component::Func, } #[derive(Clone)] - pub struct GuestPre { + pub struct GuestIndices { f1: wasmtime::component::ComponentExportIndex, f2: wasmtime::component::ComponentExportIndex, f3: wasmtime::component::ComponentExportIndex, @@ -250,11 +336,16 @@ pub mod exports { f5: wasmtime::component::ComponentExportIndex, f6: wasmtime::component::ComponentExportIndex, } - impl GuestPre { + impl GuestIndices { + /// Constructor for [`GuestIndices`] which takes a + /// [`Component`](wasmtime::component::Component) as input and can be executed + /// before instantiation. + /// + /// This constructor can be used to front-load string lookups to find exports + /// within a component. pub fn new( component: &wasmtime::component::Component, - ) -> wasmtime::Result { - let _component = component; + ) -> wasmtime::Result { let (_, instance) = component .export_index(None, "foo:foo/simple") .ok_or_else(|| { @@ -262,10 +353,34 @@ pub mod exports { "no exported instance named `foo:foo/simple`" ) })?; - let _lookup = |name: &str| { - _component - .export_index(Some(&instance), name) - .map(|p| p.1) + Self::_new(|name| { + component.export_index(Some(&instance), name).map(|p| p.1) + }) + } + /// This constructor is similar to [`GuestIndices::new`] except that it + /// performs string lookups after instantiation time. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let instance_export = instance + .get_export(&mut store, None, "foo:foo/simple") + .ok_or_else(|| { + anyhow::anyhow!( + "no exported instance named `foo:foo/simple`" + ) + })?; + Self::_new(|name| { + instance.get_export(&mut store, Some(&instance_export), name) + }) + } + fn _new( + mut lookup: impl FnMut( + &str, + ) -> Option, + ) -> wasmtime::Result { + let mut lookup = move |name| { + lookup(name) .ok_or_else(|| { anyhow::anyhow!( "instance export `foo:foo/simple` does \ @@ -273,13 +388,21 @@ pub mod exports { ) }) }; - let f1 = _lookup("f1")?; - let f2 = _lookup("f2")?; - let f3 = _lookup("f3")?; - let f4 = _lookup("f4")?; - let f5 = _lookup("f5")?; - let f6 = _lookup("f6")?; - Ok(GuestPre { f1, f2, f3, f4, f5, f6 }) + let _ = &mut lookup; + let f1 = lookup("f1")?; + let f2 = lookup("f2")?; + let f3 = lookup("f3")?; + let f4 = lookup("f4")?; + let f5 = lookup("f5")?; + let f6 = lookup("f6")?; + Ok(GuestIndices { + f1, + f2, + f3, + f4, + f5, + f6, + }) } pub fn load( &self, diff --git a/crates/component-macro/tests/expanded/simple-lists.rs b/crates/component-macro/tests/expanded/simple-lists.rs index 26d93b44414e..0215d464ac38 100644 --- a/crates/component-macro/tests/expanded/simple-lists.rs +++ b/crates/component-macro/tests/expanded/simple-lists.rs @@ -4,69 +4,148 @@ /// This structure is created through [`MyWorldPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`MyWorld`] as well. pub struct MyWorldPre { instance_pre: wasmtime::component::InstancePre, - interface0: exports::foo::foo::simple_lists::GuestPre, + indices: MyWorldIndices, } impl Clone for MyWorldPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), - interface0: self.interface0.clone(), + indices: self.indices.clone(), } } } +impl<_T> MyWorldPre<_T> { + /// Creates a new copy of `MyWorldPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = MyWorldIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`MyWorld`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub fn instantiate( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate(&mut store)?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `my-world`. +/// +/// This is an implementation detail of [`MyWorldPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`MyWorld`] as well. +#[derive(Clone)] +pub struct MyWorldIndices { + interface0: exports::foo::foo::simple_lists::GuestIndices, +} /// Auto-generated bindings for an instance a component which /// implements the world `my-world`. /// -/// This structure is created through either -/// [`MyWorld::instantiate`] or by first creating -/// a [`MyWorldPre`] followed by using -/// [`MyWorldPre::instantiate`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`MyWorld::instantiate`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`MyWorldPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`MyWorldPre::instantiate`] to +/// create a [`MyWorld`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`MyWorld::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`MyWorldIndices::new_instance`] followed +/// by [`MyWorldIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct MyWorld { interface0: exports::foo::foo::simple_lists::Guest, } const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> MyWorldPre<_T> { - /// Creates a new copy of `MyWorldPre` bindings which can then + impl MyWorldIndices { + /// Creates a new copy of `MyWorldIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, + ) -> wasmtime::Result { + let _component = component; + let interface0 = exports::foo::foo::simple_lists::GuestIndices::new( + _component, + )?; + Ok(MyWorldIndices { interface0 }) + } + /// Creates a new instance of [`MyWorldIndices`] from an + /// instantiated component. + /// + /// This method of creating a [`MyWorld`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`MyWorld`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let _component = instance_pre.component(); - let interface0 = exports::foo::foo::simple_lists::GuestPre::new(_component)?; - Ok(MyWorldPre { - instance_pre, - interface0, - }) + let _instance = instance; + let interface0 = exports::foo::foo::simple_lists::GuestIndices::new_instance( + &mut store, + _instance, + )?; + Ok(MyWorldIndices { interface0 }) } - /// Instantiates a new instance of [`MyWorld`] within the - /// `store` provided. + /// Uses the indices stored in `self` to load an instance + /// of [`MyWorld`] from the instance provided. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub fn instantiate( + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate(&mut store)?; + let _instance = instance; let interface0 = self.interface0.load(&mut store, &_instance)?; Ok(MyWorld { interface0 }) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl MyWorld { /// Convenience wrapper around [`MyWorldPre::new`] and @@ -79,6 +158,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; MyWorldPre::new(pre)?.instantiate(store) } + /// Convenience wrapper around [`MyWorldIndices::new_instance`] and + /// [`MyWorldIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = MyWorldIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker( linker: &mut wasmtime::component::Linker, get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, @@ -252,17 +340,22 @@ pub mod exports { simple_list4: wasmtime::component::Func, } #[derive(Clone)] - pub struct GuestPre { + pub struct GuestIndices { simple_list1: wasmtime::component::ComponentExportIndex, simple_list2: wasmtime::component::ComponentExportIndex, simple_list3: wasmtime::component::ComponentExportIndex, simple_list4: wasmtime::component::ComponentExportIndex, } - impl GuestPre { + impl GuestIndices { + /// Constructor for [`GuestIndices`] which takes a + /// [`Component`](wasmtime::component::Component) as input and can be executed + /// before instantiation. + /// + /// This constructor can be used to front-load string lookups to find exports + /// within a component. pub fn new( component: &wasmtime::component::Component, - ) -> wasmtime::Result { - let _component = component; + ) -> wasmtime::Result { let (_, instance) = component .export_index(None, "foo:foo/simple-lists") .ok_or_else(|| { @@ -270,10 +363,34 @@ pub mod exports { "no exported instance named `foo:foo/simple-lists`" ) })?; - let _lookup = |name: &str| { - _component - .export_index(Some(&instance), name) - .map(|p| p.1) + Self::_new(|name| { + component.export_index(Some(&instance), name).map(|p| p.1) + }) + } + /// This constructor is similar to [`GuestIndices::new`] except that it + /// performs string lookups after instantiation time. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let instance_export = instance + .get_export(&mut store, None, "foo:foo/simple-lists") + .ok_or_else(|| { + anyhow::anyhow!( + "no exported instance named `foo:foo/simple-lists`" + ) + })?; + Self::_new(|name| { + instance.get_export(&mut store, Some(&instance_export), name) + }) + } + fn _new( + mut lookup: impl FnMut( + &str, + ) -> Option, + ) -> wasmtime::Result { + let mut lookup = move |name| { + lookup(name) .ok_or_else(|| { anyhow::anyhow!( "instance export `foo:foo/simple-lists` does \ @@ -281,11 +398,12 @@ pub mod exports { ) }) }; - let simple_list1 = _lookup("simple-list1")?; - let simple_list2 = _lookup("simple-list2")?; - let simple_list3 = _lookup("simple-list3")?; - let simple_list4 = _lookup("simple-list4")?; - Ok(GuestPre { + let _ = &mut lookup; + let simple_list1 = lookup("simple-list1")?; + let simple_list2 = lookup("simple-list2")?; + let simple_list3 = lookup("simple-list3")?; + let simple_list4 = lookup("simple-list4")?; + Ok(GuestIndices { simple_list1, simple_list2, simple_list3, diff --git a/crates/component-macro/tests/expanded/simple-lists_async.rs b/crates/component-macro/tests/expanded/simple-lists_async.rs index 7c44e359a264..ad713fdbd19f 100644 --- a/crates/component-macro/tests/expanded/simple-lists_async.rs +++ b/crates/component-macro/tests/expanded/simple-lists_async.rs @@ -4,72 +4,151 @@ /// This structure is created through [`MyWorldPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`MyWorld`] as well. pub struct MyWorldPre { instance_pre: wasmtime::component::InstancePre, - interface0: exports::foo::foo::simple_lists::GuestPre, + indices: MyWorldIndices, } impl Clone for MyWorldPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), - interface0: self.interface0.clone(), + indices: self.indices.clone(), } } } +impl<_T> MyWorldPre<_T> { + /// Creates a new copy of `MyWorldPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = MyWorldIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`MyWorld`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub async fn instantiate_async( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result + where + _T: Send, + { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate_async(&mut store).await?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `my-world`. +/// +/// This is an implementation detail of [`MyWorldPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`MyWorld`] as well. +#[derive(Clone)] +pub struct MyWorldIndices { + interface0: exports::foo::foo::simple_lists::GuestIndices, +} /// Auto-generated bindings for an instance a component which /// implements the world `my-world`. /// -/// This structure is created through either -/// [`MyWorld::instantiate_async`] or by first creating -/// a [`MyWorldPre`] followed by using -/// [`MyWorldPre::instantiate_async`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`MyWorld::instantiate_async`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`MyWorldPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`MyWorldPre::instantiate_async`] to +/// create a [`MyWorld`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`MyWorld::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`MyWorldIndices::new_instance`] followed +/// by [`MyWorldIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct MyWorld { interface0: exports::foo::foo::simple_lists::Guest, } const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> MyWorldPre<_T> { - /// Creates a new copy of `MyWorldPre` bindings which can then + impl MyWorldIndices { + /// Creates a new copy of `MyWorldIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, ) -> wasmtime::Result { - let _component = instance_pre.component(); - let interface0 = exports::foo::foo::simple_lists::GuestPre::new(_component)?; - Ok(MyWorldPre { - instance_pre, - interface0, - }) + let _component = component; + let interface0 = exports::foo::foo::simple_lists::GuestIndices::new( + _component, + )?; + Ok(MyWorldIndices { interface0 }) } - /// Instantiates a new instance of [`MyWorld`] within the - /// `store` provided. + /// Creates a new instance of [`MyWorldIndices`] from an + /// instantiated component. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub async fn instantiate_async( + /// This method of creating a [`MyWorld`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`MyWorld`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; + let interface0 = exports::foo::foo::simple_lists::GuestIndices::new_instance( + &mut store, + _instance, + )?; + Ok(MyWorldIndices { interface0 }) + } + /// Uses the indices stored in `self` to load an instance + /// of [`MyWorld`] from the instance provided. + /// + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate_async(&mut store).await?; + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; let interface0 = self.interface0.load(&mut store, &_instance)?; Ok(MyWorld { interface0 }) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl MyWorld { /// Convenience wrapper around [`MyWorldPre::new`] and @@ -85,6 +164,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; MyWorldPre::new(pre)?.instantiate_async(store).await } + /// Convenience wrapper around [`MyWorldIndices::new_instance`] and + /// [`MyWorldIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = MyWorldIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker( linker: &mut wasmtime::component::Linker, get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, @@ -269,17 +357,22 @@ pub mod exports { simple_list4: wasmtime::component::Func, } #[derive(Clone)] - pub struct GuestPre { + pub struct GuestIndices { simple_list1: wasmtime::component::ComponentExportIndex, simple_list2: wasmtime::component::ComponentExportIndex, simple_list3: wasmtime::component::ComponentExportIndex, simple_list4: wasmtime::component::ComponentExportIndex, } - impl GuestPre { + impl GuestIndices { + /// Constructor for [`GuestIndices`] which takes a + /// [`Component`](wasmtime::component::Component) as input and can be executed + /// before instantiation. + /// + /// This constructor can be used to front-load string lookups to find exports + /// within a component. pub fn new( component: &wasmtime::component::Component, - ) -> wasmtime::Result { - let _component = component; + ) -> wasmtime::Result { let (_, instance) = component .export_index(None, "foo:foo/simple-lists") .ok_or_else(|| { @@ -287,10 +380,34 @@ pub mod exports { "no exported instance named `foo:foo/simple-lists`" ) })?; - let _lookup = |name: &str| { - _component - .export_index(Some(&instance), name) - .map(|p| p.1) + Self::_new(|name| { + component.export_index(Some(&instance), name).map(|p| p.1) + }) + } + /// This constructor is similar to [`GuestIndices::new`] except that it + /// performs string lookups after instantiation time. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let instance_export = instance + .get_export(&mut store, None, "foo:foo/simple-lists") + .ok_or_else(|| { + anyhow::anyhow!( + "no exported instance named `foo:foo/simple-lists`" + ) + })?; + Self::_new(|name| { + instance.get_export(&mut store, Some(&instance_export), name) + }) + } + fn _new( + mut lookup: impl FnMut( + &str, + ) -> Option, + ) -> wasmtime::Result { + let mut lookup = move |name| { + lookup(name) .ok_or_else(|| { anyhow::anyhow!( "instance export `foo:foo/simple-lists` does \ @@ -298,11 +415,12 @@ pub mod exports { ) }) }; - let simple_list1 = _lookup("simple-list1")?; - let simple_list2 = _lookup("simple-list2")?; - let simple_list3 = _lookup("simple-list3")?; - let simple_list4 = _lookup("simple-list4")?; - Ok(GuestPre { + let _ = &mut lookup; + let simple_list1 = lookup("simple-list1")?; + let simple_list2 = lookup("simple-list2")?; + let simple_list3 = lookup("simple-list3")?; + let simple_list4 = lookup("simple-list4")?; + Ok(GuestIndices { simple_list1, simple_list2, simple_list3, diff --git a/crates/component-macro/tests/expanded/simple-wasi.rs b/crates/component-macro/tests/expanded/simple-wasi.rs index 247346794bea..96d4a0bc2a94 100644 --- a/crates/component-macro/tests/expanded/simple-wasi.rs +++ b/crates/component-macro/tests/expanded/simple-wasi.rs @@ -4,60 +4,136 @@ /// This structure is created through [`WasiPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`Wasi`] as well. pub struct WasiPre { instance_pre: wasmtime::component::InstancePre, + indices: WasiIndices, } impl Clone for WasiPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), + indices: self.indices.clone(), } } } +impl<_T> WasiPre<_T> { + /// Creates a new copy of `WasiPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = WasiIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`Wasi`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub fn instantiate( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate(&mut store)?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `wasi`. +/// +/// This is an implementation detail of [`WasiPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`Wasi`] as well. +#[derive(Clone)] +pub struct WasiIndices {} /// Auto-generated bindings for an instance a component which /// implements the world `wasi`. /// -/// This structure is created through either -/// [`Wasi::instantiate`] or by first creating -/// a [`WasiPre`] followed by using -/// [`WasiPre::instantiate`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`Wasi::instantiate`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`WasiPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`WasiPre::instantiate`] to +/// create a [`Wasi`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`Wasi::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`WasiIndices::new_instance`] followed +/// by [`WasiIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct Wasi {} const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> WasiPre<_T> { - /// Creates a new copy of `WasiPre` bindings which can then + impl WasiIndices { + /// Creates a new copy of `WasiIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, + ) -> wasmtime::Result { + let _component = component; + Ok(WasiIndices {}) + } + /// Creates a new instance of [`WasiIndices`] from an + /// instantiated component. + /// + /// This method of creating a [`Wasi`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`Wasi`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let _component = instance_pre.component(); - Ok(WasiPre { instance_pre }) + let _instance = instance; + Ok(WasiIndices {}) } - /// Instantiates a new instance of [`Wasi`] within the - /// `store` provided. + /// Uses the indices stored in `self` to load an instance + /// of [`Wasi`] from the instance provided. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub fn instantiate( + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate(&mut store)?; + let _instance = instance; Ok(Wasi {}) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl Wasi { /// Convenience wrapper around [`WasiPre::new`] and @@ -70,6 +146,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; WasiPre::new(pre)?.instantiate(store) } + /// Convenience wrapper around [`WasiIndices::new_instance`] and + /// [`WasiIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = WasiIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker( linker: &mut wasmtime::component::Linker, get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, diff --git a/crates/component-macro/tests/expanded/simple-wasi_async.rs b/crates/component-macro/tests/expanded/simple-wasi_async.rs index 21887ae6be21..3cb43fd26d6d 100644 --- a/crates/component-macro/tests/expanded/simple-wasi_async.rs +++ b/crates/component-macro/tests/expanded/simple-wasi_async.rs @@ -4,63 +4,139 @@ /// This structure is created through [`WasiPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`Wasi`] as well. pub struct WasiPre { instance_pre: wasmtime::component::InstancePre, + indices: WasiIndices, } impl Clone for WasiPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), + indices: self.indices.clone(), } } } +impl<_T> WasiPre<_T> { + /// Creates a new copy of `WasiPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = WasiIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`Wasi`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub async fn instantiate_async( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result + where + _T: Send, + { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate_async(&mut store).await?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `wasi`. +/// +/// This is an implementation detail of [`WasiPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`Wasi`] as well. +#[derive(Clone)] +pub struct WasiIndices {} /// Auto-generated bindings for an instance a component which /// implements the world `wasi`. /// -/// This structure is created through either -/// [`Wasi::instantiate_async`] or by first creating -/// a [`WasiPre`] followed by using -/// [`WasiPre::instantiate_async`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`Wasi::instantiate_async`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`WasiPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`WasiPre::instantiate_async`] to +/// create a [`Wasi`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`Wasi::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`WasiIndices::new_instance`] followed +/// by [`WasiIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct Wasi {} const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> WasiPre<_T> { - /// Creates a new copy of `WasiPre` bindings which can then + impl WasiIndices { + /// Creates a new copy of `WasiIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, + ) -> wasmtime::Result { + let _component = component; + Ok(WasiIndices {}) + } + /// Creates a new instance of [`WasiIndices`] from an + /// instantiated component. + /// + /// This method of creating a [`Wasi`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`Wasi`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let _component = instance_pre.component(); - Ok(WasiPre { instance_pre }) + let _instance = instance; + Ok(WasiIndices {}) } - /// Instantiates a new instance of [`Wasi`] within the - /// `store` provided. + /// Uses the indices stored in `self` to load an instance + /// of [`Wasi`] from the instance provided. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub async fn instantiate_async( + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate_async(&mut store).await?; + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; Ok(Wasi {}) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl Wasi { /// Convenience wrapper around [`WasiPre::new`] and @@ -76,6 +152,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; WasiPre::new(pre)?.instantiate_async(store).await } + /// Convenience wrapper around [`WasiIndices::new_instance`] and + /// [`WasiIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = WasiIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker( linker: &mut wasmtime::component::Linker, get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, diff --git a/crates/component-macro/tests/expanded/small-anonymous.rs b/crates/component-macro/tests/expanded/small-anonymous.rs index be5d84153b66..baa6463b58e8 100644 --- a/crates/component-macro/tests/expanded/small-anonymous.rs +++ b/crates/component-macro/tests/expanded/small-anonymous.rs @@ -4,69 +4,146 @@ /// This structure is created through [`TheWorldPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`TheWorld`] as well. pub struct TheWorldPre { instance_pre: wasmtime::component::InstancePre, - interface0: exports::foo::foo::anon::GuestPre, + indices: TheWorldIndices, } impl Clone for TheWorldPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), - interface0: self.interface0.clone(), + indices: self.indices.clone(), } } } +impl<_T> TheWorldPre<_T> { + /// Creates a new copy of `TheWorldPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`TheWorld`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub fn instantiate( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate(&mut store)?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `the-world`. +/// +/// This is an implementation detail of [`TheWorldPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`TheWorld`] as well. +#[derive(Clone)] +pub struct TheWorldIndices { + interface0: exports::foo::foo::anon::GuestIndices, +} /// Auto-generated bindings for an instance a component which /// implements the world `the-world`. /// -/// This structure is created through either -/// [`TheWorld::instantiate`] or by first creating -/// a [`TheWorldPre`] followed by using -/// [`TheWorldPre::instantiate`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`TheWorld::instantiate`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`TheWorldPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`TheWorldPre::instantiate`] to +/// create a [`TheWorld`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`TheWorld::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`TheWorldIndices::new_instance`] followed +/// by [`TheWorldIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct TheWorld { interface0: exports::foo::foo::anon::Guest, } const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> TheWorldPre<_T> { - /// Creates a new copy of `TheWorldPre` bindings which can then + impl TheWorldIndices { + /// Creates a new copy of `TheWorldIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, ) -> wasmtime::Result { - let _component = instance_pre.component(); - let interface0 = exports::foo::foo::anon::GuestPre::new(_component)?; - Ok(TheWorldPre { - instance_pre, - interface0, - }) + let _component = component; + let interface0 = exports::foo::foo::anon::GuestIndices::new(_component)?; + Ok(TheWorldIndices { interface0 }) } - /// Instantiates a new instance of [`TheWorld`] within the - /// `store` provided. + /// Creates a new instance of [`TheWorldIndices`] from an + /// instantiated component. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub fn instantiate( + /// This method of creating a [`TheWorld`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`TheWorld`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; + let interface0 = exports::foo::foo::anon::GuestIndices::new_instance( + &mut store, + _instance, + )?; + Ok(TheWorldIndices { interface0 }) + } + /// Uses the indices stored in `self` to load an instance + /// of [`TheWorld`] from the instance provided. + /// + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate(&mut store)?; + let _instance = instance; let interface0 = self.interface0.load(&mut store, &_instance)?; Ok(TheWorld { interface0 }) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl TheWorld { /// Convenience wrapper around [`TheWorldPre::new`] and @@ -79,6 +156,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate(store) } + /// Convenience wrapper around [`TheWorldIndices::new_instance`] and + /// [`TheWorldIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker( linker: &mut wasmtime::component::Linker, get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, @@ -262,23 +348,50 @@ pub mod exports { option_test: wasmtime::component::Func, } #[derive(Clone)] - pub struct GuestPre { + pub struct GuestIndices { option_test: wasmtime::component::ComponentExportIndex, } - impl GuestPre { + impl GuestIndices { + /// Constructor for [`GuestIndices`] which takes a + /// [`Component`](wasmtime::component::Component) as input and can be executed + /// before instantiation. + /// + /// This constructor can be used to front-load string lookups to find exports + /// within a component. pub fn new( component: &wasmtime::component::Component, - ) -> wasmtime::Result { - let _component = component; + ) -> wasmtime::Result { let (_, instance) = component .export_index(None, "foo:foo/anon") .ok_or_else(|| { anyhow::anyhow!("no exported instance named `foo:foo/anon`") })?; - let _lookup = |name: &str| { - _component - .export_index(Some(&instance), name) - .map(|p| p.1) + Self::_new(|name| { + component.export_index(Some(&instance), name).map(|p| p.1) + }) + } + /// This constructor is similar to [`GuestIndices::new`] except that it + /// performs string lookups after instantiation time. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let instance_export = instance + .get_export(&mut store, None, "foo:foo/anon") + .ok_or_else(|| { + anyhow::anyhow!("no exported instance named `foo:foo/anon`") + })?; + Self::_new(|name| { + instance.get_export(&mut store, Some(&instance_export), name) + }) + } + fn _new( + mut lookup: impl FnMut( + &str, + ) -> Option, + ) -> wasmtime::Result { + let mut lookup = move |name| { + lookup(name) .ok_or_else(|| { anyhow::anyhow!( "instance export `foo:foo/anon` does \ @@ -286,8 +399,9 @@ pub mod exports { ) }) }; - let option_test = _lookup("option-test")?; - Ok(GuestPre { option_test }) + let _ = &mut lookup; + let option_test = lookup("option-test")?; + Ok(GuestIndices { option_test }) } pub fn load( &self, diff --git a/crates/component-macro/tests/expanded/small-anonymous_async.rs b/crates/component-macro/tests/expanded/small-anonymous_async.rs index a53f57452821..6fdeda81a976 100644 --- a/crates/component-macro/tests/expanded/small-anonymous_async.rs +++ b/crates/component-macro/tests/expanded/small-anonymous_async.rs @@ -4,72 +4,149 @@ /// This structure is created through [`TheWorldPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`TheWorld`] as well. pub struct TheWorldPre { instance_pre: wasmtime::component::InstancePre, - interface0: exports::foo::foo::anon::GuestPre, + indices: TheWorldIndices, } impl Clone for TheWorldPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), - interface0: self.interface0.clone(), + indices: self.indices.clone(), } } } +impl<_T> TheWorldPre<_T> { + /// Creates a new copy of `TheWorldPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`TheWorld`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub async fn instantiate_async( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result + where + _T: Send, + { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate_async(&mut store).await?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `the-world`. +/// +/// This is an implementation detail of [`TheWorldPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`TheWorld`] as well. +#[derive(Clone)] +pub struct TheWorldIndices { + interface0: exports::foo::foo::anon::GuestIndices, +} /// Auto-generated bindings for an instance a component which /// implements the world `the-world`. /// -/// This structure is created through either -/// [`TheWorld::instantiate_async`] or by first creating -/// a [`TheWorldPre`] followed by using -/// [`TheWorldPre::instantiate_async`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`TheWorld::instantiate_async`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`TheWorldPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`TheWorldPre::instantiate_async`] to +/// create a [`TheWorld`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`TheWorld::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`TheWorldIndices::new_instance`] followed +/// by [`TheWorldIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct TheWorld { interface0: exports::foo::foo::anon::Guest, } const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> TheWorldPre<_T> { - /// Creates a new copy of `TheWorldPre` bindings which can then + impl TheWorldIndices { + /// Creates a new copy of `TheWorldIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, ) -> wasmtime::Result { - let _component = instance_pre.component(); - let interface0 = exports::foo::foo::anon::GuestPre::new(_component)?; - Ok(TheWorldPre { - instance_pre, - interface0, - }) + let _component = component; + let interface0 = exports::foo::foo::anon::GuestIndices::new(_component)?; + Ok(TheWorldIndices { interface0 }) } - /// Instantiates a new instance of [`TheWorld`] within the - /// `store` provided. + /// Creates a new instance of [`TheWorldIndices`] from an + /// instantiated component. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub async fn instantiate_async( + /// This method of creating a [`TheWorld`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`TheWorld`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; + let interface0 = exports::foo::foo::anon::GuestIndices::new_instance( + &mut store, + _instance, + )?; + Ok(TheWorldIndices { interface0 }) + } + /// Uses the indices stored in `self` to load an instance + /// of [`TheWorld`] from the instance provided. + /// + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate_async(&mut store).await?; + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; let interface0 = self.interface0.load(&mut store, &_instance)?; Ok(TheWorld { interface0 }) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl TheWorld { /// Convenience wrapper around [`TheWorldPre::new`] and @@ -85,6 +162,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate_async(store).await } + /// Convenience wrapper around [`TheWorldIndices::new_instance`] and + /// [`TheWorldIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker( linker: &mut wasmtime::component::Linker, get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, @@ -275,23 +361,50 @@ pub mod exports { option_test: wasmtime::component::Func, } #[derive(Clone)] - pub struct GuestPre { + pub struct GuestIndices { option_test: wasmtime::component::ComponentExportIndex, } - impl GuestPre { + impl GuestIndices { + /// Constructor for [`GuestIndices`] which takes a + /// [`Component`](wasmtime::component::Component) as input and can be executed + /// before instantiation. + /// + /// This constructor can be used to front-load string lookups to find exports + /// within a component. pub fn new( component: &wasmtime::component::Component, - ) -> wasmtime::Result { - let _component = component; + ) -> wasmtime::Result { let (_, instance) = component .export_index(None, "foo:foo/anon") .ok_or_else(|| { anyhow::anyhow!("no exported instance named `foo:foo/anon`") })?; - let _lookup = |name: &str| { - _component - .export_index(Some(&instance), name) - .map(|p| p.1) + Self::_new(|name| { + component.export_index(Some(&instance), name).map(|p| p.1) + }) + } + /// This constructor is similar to [`GuestIndices::new`] except that it + /// performs string lookups after instantiation time. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let instance_export = instance + .get_export(&mut store, None, "foo:foo/anon") + .ok_or_else(|| { + anyhow::anyhow!("no exported instance named `foo:foo/anon`") + })?; + Self::_new(|name| { + instance.get_export(&mut store, Some(&instance_export), name) + }) + } + fn _new( + mut lookup: impl FnMut( + &str, + ) -> Option, + ) -> wasmtime::Result { + let mut lookup = move |name| { + lookup(name) .ok_or_else(|| { anyhow::anyhow!( "instance export `foo:foo/anon` does \ @@ -299,8 +412,9 @@ pub mod exports { ) }) }; - let option_test = _lookup("option-test")?; - Ok(GuestPre { option_test }) + let _ = &mut lookup; + let option_test = lookup("option-test")?; + Ok(GuestIndices { option_test }) } pub fn load( &self, diff --git a/crates/component-macro/tests/expanded/smoke-default.rs b/crates/component-macro/tests/expanded/smoke-default.rs index 6d971d718426..e9ab3af1d8d4 100644 --- a/crates/component-macro/tests/expanded/smoke-default.rs +++ b/crates/component-macro/tests/expanded/smoke-default.rs @@ -4,69 +4,148 @@ /// This structure is created through [`TheWorldPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`TheWorld`] as well. pub struct TheWorldPre { instance_pre: wasmtime::component::InstancePre, - y: wasmtime::component::ComponentExportIndex, + indices: TheWorldIndices, } impl Clone for TheWorldPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), - y: self.y.clone(), + indices: self.indices.clone(), } } } +impl<_T> TheWorldPre<_T> { + /// Creates a new copy of `TheWorldPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`TheWorld`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub fn instantiate( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate(&mut store)?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `the-world`. +/// +/// This is an implementation detail of [`TheWorldPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`TheWorld`] as well. +#[derive(Clone)] +pub struct TheWorldIndices { + y: wasmtime::component::ComponentExportIndex, +} /// Auto-generated bindings for an instance a component which /// implements the world `the-world`. /// -/// This structure is created through either -/// [`TheWorld::instantiate`] or by first creating -/// a [`TheWorldPre`] followed by using -/// [`TheWorldPre::instantiate`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`TheWorld::instantiate`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`TheWorldPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`TheWorldPre::instantiate`] to +/// create a [`TheWorld`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`TheWorld::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`TheWorldIndices::new_instance`] followed +/// by [`TheWorldIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct TheWorld { y: wasmtime::component::Func, } const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> TheWorldPre<_T> { - /// Creates a new copy of `TheWorldPre` bindings which can then + impl TheWorldIndices { + /// Creates a new copy of `TheWorldIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, ) -> wasmtime::Result { - let _component = instance_pre.component(); + let _component = component; let y = _component .export_index(None, "y") .ok_or_else(|| anyhow::anyhow!("no function export `y` found"))? .1; - Ok(TheWorldPre { instance_pre, y }) + Ok(TheWorldIndices { y }) + } + /// Creates a new instance of [`TheWorldIndices`] from an + /// instantiated component. + /// + /// This method of creating a [`TheWorld`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`TheWorld`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; + let y = _instance + .get_export(&mut store, None, "y") + .ok_or_else(|| anyhow::anyhow!("no function export `y` found"))?; + Ok(TheWorldIndices { y }) } - /// Instantiates a new instance of [`TheWorld`] within the - /// `store` provided. + /// Uses the indices stored in `self` to load an instance + /// of [`TheWorld`] from the instance provided. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub fn instantiate( + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate(&mut store)?; + let _instance = instance; let y = *_instance.get_typed_func::<(), ()>(&mut store, &self.y)?.func(); Ok(TheWorld { y }) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl TheWorld { /// Convenience wrapper around [`TheWorldPre::new`] and @@ -79,6 +158,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate(store) } + /// Convenience wrapper around [`TheWorldIndices::new_instance`] and + /// [`TheWorldIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn call_y( &self, mut store: S, diff --git a/crates/component-macro/tests/expanded/smoke-default_async.rs b/crates/component-macro/tests/expanded/smoke-default_async.rs index d37c7f36db1a..30668f31d298 100644 --- a/crates/component-macro/tests/expanded/smoke-default_async.rs +++ b/crates/component-macro/tests/expanded/smoke-default_async.rs @@ -4,72 +4,151 @@ /// This structure is created through [`TheWorldPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`TheWorld`] as well. pub struct TheWorldPre { instance_pre: wasmtime::component::InstancePre, - y: wasmtime::component::ComponentExportIndex, + indices: TheWorldIndices, } impl Clone for TheWorldPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), - y: self.y.clone(), + indices: self.indices.clone(), } } } +impl<_T> TheWorldPre<_T> { + /// Creates a new copy of `TheWorldPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`TheWorld`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub async fn instantiate_async( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result + where + _T: Send, + { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate_async(&mut store).await?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `the-world`. +/// +/// This is an implementation detail of [`TheWorldPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`TheWorld`] as well. +#[derive(Clone)] +pub struct TheWorldIndices { + y: wasmtime::component::ComponentExportIndex, +} /// Auto-generated bindings for an instance a component which /// implements the world `the-world`. /// -/// This structure is created through either -/// [`TheWorld::instantiate_async`] or by first creating -/// a [`TheWorldPre`] followed by using -/// [`TheWorldPre::instantiate_async`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`TheWorld::instantiate_async`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`TheWorldPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`TheWorldPre::instantiate_async`] to +/// create a [`TheWorld`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`TheWorld::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`TheWorldIndices::new_instance`] followed +/// by [`TheWorldIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct TheWorld { y: wasmtime::component::Func, } const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> TheWorldPre<_T> { - /// Creates a new copy of `TheWorldPre` bindings which can then + impl TheWorldIndices { + /// Creates a new copy of `TheWorldIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, ) -> wasmtime::Result { - let _component = instance_pre.component(); + let _component = component; let y = _component .export_index(None, "y") .ok_or_else(|| anyhow::anyhow!("no function export `y` found"))? .1; - Ok(TheWorldPre { instance_pre, y }) + Ok(TheWorldIndices { y }) + } + /// Creates a new instance of [`TheWorldIndices`] from an + /// instantiated component. + /// + /// This method of creating a [`TheWorld`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`TheWorld`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; + let y = _instance + .get_export(&mut store, None, "y") + .ok_or_else(|| anyhow::anyhow!("no function export `y` found"))?; + Ok(TheWorldIndices { y }) } - /// Instantiates a new instance of [`TheWorld`] within the - /// `store` provided. + /// Uses the indices stored in `self` to load an instance + /// of [`TheWorld`] from the instance provided. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub async fn instantiate_async( + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate_async(&mut store).await?; + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; let y = *_instance.get_typed_func::<(), ()>(&mut store, &self.y)?.func(); Ok(TheWorld { y }) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl TheWorld { /// Convenience wrapper around [`TheWorldPre::new`] and @@ -85,6 +164,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate_async(store).await } + /// Convenience wrapper around [`TheWorldIndices::new_instance`] and + /// [`TheWorldIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub async fn call_y( &self, mut store: S, diff --git a/crates/component-macro/tests/expanded/smoke-export.rs b/crates/component-macro/tests/expanded/smoke-export.rs index a32cdef51e87..9a9f8a25b18e 100644 --- a/crates/component-macro/tests/expanded/smoke-export.rs +++ b/crates/component-macro/tests/expanded/smoke-export.rs @@ -4,69 +4,146 @@ /// This structure is created through [`TheWorldPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`TheWorld`] as well. pub struct TheWorldPre { instance_pre: wasmtime::component::InstancePre, - interface0: exports::the_name::GuestPre, + indices: TheWorldIndices, } impl Clone for TheWorldPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), - interface0: self.interface0.clone(), + indices: self.indices.clone(), } } } +impl<_T> TheWorldPre<_T> { + /// Creates a new copy of `TheWorldPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`TheWorld`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub fn instantiate( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate(&mut store)?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `the-world`. +/// +/// This is an implementation detail of [`TheWorldPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`TheWorld`] as well. +#[derive(Clone)] +pub struct TheWorldIndices { + interface0: exports::the_name::GuestIndices, +} /// Auto-generated bindings for an instance a component which /// implements the world `the-world`. /// -/// This structure is created through either -/// [`TheWorld::instantiate`] or by first creating -/// a [`TheWorldPre`] followed by using -/// [`TheWorldPre::instantiate`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`TheWorld::instantiate`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`TheWorldPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`TheWorldPre::instantiate`] to +/// create a [`TheWorld`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`TheWorld::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`TheWorldIndices::new_instance`] followed +/// by [`TheWorldIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct TheWorld { interface0: exports::the_name::Guest, } const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> TheWorldPre<_T> { - /// Creates a new copy of `TheWorldPre` bindings which can then + impl TheWorldIndices { + /// Creates a new copy of `TheWorldIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, ) -> wasmtime::Result { - let _component = instance_pre.component(); - let interface0 = exports::the_name::GuestPre::new(_component)?; - Ok(TheWorldPre { - instance_pre, - interface0, - }) + let _component = component; + let interface0 = exports::the_name::GuestIndices::new(_component)?; + Ok(TheWorldIndices { interface0 }) } - /// Instantiates a new instance of [`TheWorld`] within the - /// `store` provided. + /// Creates a new instance of [`TheWorldIndices`] from an + /// instantiated component. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub fn instantiate( + /// This method of creating a [`TheWorld`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`TheWorld`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; + let interface0 = exports::the_name::GuestIndices::new_instance( + &mut store, + _instance, + )?; + Ok(TheWorldIndices { interface0 }) + } + /// Uses the indices stored in `self` to load an instance + /// of [`TheWorld`] from the instance provided. + /// + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate(&mut store)?; + let _instance = instance; let interface0 = self.interface0.load(&mut store, &_instance)?; Ok(TheWorld { interface0 }) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl TheWorld { /// Convenience wrapper around [`TheWorldPre::new`] and @@ -79,6 +156,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate(store) } + /// Convenience wrapper around [`TheWorldIndices::new_instance`] and + /// [`TheWorldIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn the_name(&self) -> &exports::the_name::Guest { &self.interface0 } @@ -93,23 +179,50 @@ pub mod exports { y: wasmtime::component::Func, } #[derive(Clone)] - pub struct GuestPre { + pub struct GuestIndices { y: wasmtime::component::ComponentExportIndex, } - impl GuestPre { + impl GuestIndices { + /// Constructor for [`GuestIndices`] which takes a + /// [`Component`](wasmtime::component::Component) as input and can be executed + /// before instantiation. + /// + /// This constructor can be used to front-load string lookups to find exports + /// within a component. pub fn new( component: &wasmtime::component::Component, - ) -> wasmtime::Result { - let _component = component; + ) -> wasmtime::Result { let (_, instance) = component .export_index(None, "the-name") .ok_or_else(|| { anyhow::anyhow!("no exported instance named `the-name`") })?; - let _lookup = |name: &str| { - _component - .export_index(Some(&instance), name) - .map(|p| p.1) + Self::_new(|name| { + component.export_index(Some(&instance), name).map(|p| p.1) + }) + } + /// This constructor is similar to [`GuestIndices::new`] except that it + /// performs string lookups after instantiation time. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let instance_export = instance + .get_export(&mut store, None, "the-name") + .ok_or_else(|| { + anyhow::anyhow!("no exported instance named `the-name`") + })?; + Self::_new(|name| { + instance.get_export(&mut store, Some(&instance_export), name) + }) + } + fn _new( + mut lookup: impl FnMut( + &str, + ) -> Option, + ) -> wasmtime::Result { + let mut lookup = move |name| { + lookup(name) .ok_or_else(|| { anyhow::anyhow!( "instance export `the-name` does \ @@ -117,8 +230,9 @@ pub mod exports { ) }) }; - let y = _lookup("y")?; - Ok(GuestPre { y }) + let _ = &mut lookup; + let y = lookup("y")?; + Ok(GuestIndices { y }) } pub fn load( &self, diff --git a/crates/component-macro/tests/expanded/smoke-export_async.rs b/crates/component-macro/tests/expanded/smoke-export_async.rs index 381e8e72af0c..e21b8232c855 100644 --- a/crates/component-macro/tests/expanded/smoke-export_async.rs +++ b/crates/component-macro/tests/expanded/smoke-export_async.rs @@ -4,72 +4,149 @@ /// This structure is created through [`TheWorldPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`TheWorld`] as well. pub struct TheWorldPre { instance_pre: wasmtime::component::InstancePre, - interface0: exports::the_name::GuestPre, + indices: TheWorldIndices, } impl Clone for TheWorldPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), - interface0: self.interface0.clone(), + indices: self.indices.clone(), } } } +impl<_T> TheWorldPre<_T> { + /// Creates a new copy of `TheWorldPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`TheWorld`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub async fn instantiate_async( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result + where + _T: Send, + { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate_async(&mut store).await?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `the-world`. +/// +/// This is an implementation detail of [`TheWorldPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`TheWorld`] as well. +#[derive(Clone)] +pub struct TheWorldIndices { + interface0: exports::the_name::GuestIndices, +} /// Auto-generated bindings for an instance a component which /// implements the world `the-world`. /// -/// This structure is created through either -/// [`TheWorld::instantiate_async`] or by first creating -/// a [`TheWorldPre`] followed by using -/// [`TheWorldPre::instantiate_async`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`TheWorld::instantiate_async`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`TheWorldPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`TheWorldPre::instantiate_async`] to +/// create a [`TheWorld`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`TheWorld::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`TheWorldIndices::new_instance`] followed +/// by [`TheWorldIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct TheWorld { interface0: exports::the_name::Guest, } const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> TheWorldPre<_T> { - /// Creates a new copy of `TheWorldPre` bindings which can then + impl TheWorldIndices { + /// Creates a new copy of `TheWorldIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, ) -> wasmtime::Result { - let _component = instance_pre.component(); - let interface0 = exports::the_name::GuestPre::new(_component)?; - Ok(TheWorldPre { - instance_pre, - interface0, - }) + let _component = component; + let interface0 = exports::the_name::GuestIndices::new(_component)?; + Ok(TheWorldIndices { interface0 }) } - /// Instantiates a new instance of [`TheWorld`] within the - /// `store` provided. + /// Creates a new instance of [`TheWorldIndices`] from an + /// instantiated component. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub async fn instantiate_async( + /// This method of creating a [`TheWorld`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`TheWorld`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; + let interface0 = exports::the_name::GuestIndices::new_instance( + &mut store, + _instance, + )?; + Ok(TheWorldIndices { interface0 }) + } + /// Uses the indices stored in `self` to load an instance + /// of [`TheWorld`] from the instance provided. + /// + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate_async(&mut store).await?; + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; let interface0 = self.interface0.load(&mut store, &_instance)?; Ok(TheWorld { interface0 }) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl TheWorld { /// Convenience wrapper around [`TheWorldPre::new`] and @@ -85,6 +162,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate_async(store).await } + /// Convenience wrapper around [`TheWorldIndices::new_instance`] and + /// [`TheWorldIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn the_name(&self) -> &exports::the_name::Guest { &self.interface0 } @@ -99,23 +185,50 @@ pub mod exports { y: wasmtime::component::Func, } #[derive(Clone)] - pub struct GuestPre { + pub struct GuestIndices { y: wasmtime::component::ComponentExportIndex, } - impl GuestPre { + impl GuestIndices { + /// Constructor for [`GuestIndices`] which takes a + /// [`Component`](wasmtime::component::Component) as input and can be executed + /// before instantiation. + /// + /// This constructor can be used to front-load string lookups to find exports + /// within a component. pub fn new( component: &wasmtime::component::Component, - ) -> wasmtime::Result { - let _component = component; + ) -> wasmtime::Result { let (_, instance) = component .export_index(None, "the-name") .ok_or_else(|| { anyhow::anyhow!("no exported instance named `the-name`") })?; - let _lookup = |name: &str| { - _component - .export_index(Some(&instance), name) - .map(|p| p.1) + Self::_new(|name| { + component.export_index(Some(&instance), name).map(|p| p.1) + }) + } + /// This constructor is similar to [`GuestIndices::new`] except that it + /// performs string lookups after instantiation time. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let instance_export = instance + .get_export(&mut store, None, "the-name") + .ok_or_else(|| { + anyhow::anyhow!("no exported instance named `the-name`") + })?; + Self::_new(|name| { + instance.get_export(&mut store, Some(&instance_export), name) + }) + } + fn _new( + mut lookup: impl FnMut( + &str, + ) -> Option, + ) -> wasmtime::Result { + let mut lookup = move |name| { + lookup(name) .ok_or_else(|| { anyhow::anyhow!( "instance export `the-name` does \ @@ -123,8 +236,9 @@ pub mod exports { ) }) }; - let y = _lookup("y")?; - Ok(GuestPre { y }) + let _ = &mut lookup; + let y = lookup("y")?; + Ok(GuestIndices { y }) } pub fn load( &self, diff --git a/crates/component-macro/tests/expanded/smoke.rs b/crates/component-macro/tests/expanded/smoke.rs index 302cdfa0a634..f455ece5d3f7 100644 --- a/crates/component-macro/tests/expanded/smoke.rs +++ b/crates/component-macro/tests/expanded/smoke.rs @@ -4,60 +4,136 @@ /// This structure is created through [`TheWorldPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`TheWorld`] as well. pub struct TheWorldPre { instance_pre: wasmtime::component::InstancePre, + indices: TheWorldIndices, } impl Clone for TheWorldPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), + indices: self.indices.clone(), } } } +impl<_T> TheWorldPre<_T> { + /// Creates a new copy of `TheWorldPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`TheWorld`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub fn instantiate( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate(&mut store)?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `the-world`. +/// +/// This is an implementation detail of [`TheWorldPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`TheWorld`] as well. +#[derive(Clone)] +pub struct TheWorldIndices {} /// Auto-generated bindings for an instance a component which /// implements the world `the-world`. /// -/// This structure is created through either -/// [`TheWorld::instantiate`] or by first creating -/// a [`TheWorldPre`] followed by using -/// [`TheWorldPre::instantiate`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`TheWorld::instantiate`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`TheWorldPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`TheWorldPre::instantiate`] to +/// create a [`TheWorld`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`TheWorld::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`TheWorldIndices::new_instance`] followed +/// by [`TheWorldIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct TheWorld {} const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> TheWorldPre<_T> { - /// Creates a new copy of `TheWorldPre` bindings which can then + impl TheWorldIndices { + /// Creates a new copy of `TheWorldIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, + ) -> wasmtime::Result { + let _component = component; + Ok(TheWorldIndices {}) + } + /// Creates a new instance of [`TheWorldIndices`] from an + /// instantiated component. + /// + /// This method of creating a [`TheWorld`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`TheWorld`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let _component = instance_pre.component(); - Ok(TheWorldPre { instance_pre }) + let _instance = instance; + Ok(TheWorldIndices {}) } - /// Instantiates a new instance of [`TheWorld`] within the - /// `store` provided. + /// Uses the indices stored in `self` to load an instance + /// of [`TheWorld`] from the instance provided. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub fn instantiate( + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate(&mut store)?; + let _instance = instance; Ok(TheWorld {}) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl TheWorld { /// Convenience wrapper around [`TheWorldPre::new`] and @@ -70,6 +146,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate(store) } + /// Convenience wrapper around [`TheWorldIndices::new_instance`] and + /// [`TheWorldIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker( linker: &mut wasmtime::component::Linker, get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, diff --git a/crates/component-macro/tests/expanded/smoke_async.rs b/crates/component-macro/tests/expanded/smoke_async.rs index 38ea2a90c682..b826b5134ffd 100644 --- a/crates/component-macro/tests/expanded/smoke_async.rs +++ b/crates/component-macro/tests/expanded/smoke_async.rs @@ -4,63 +4,139 @@ /// This structure is created through [`TheWorldPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`TheWorld`] as well. pub struct TheWorldPre { instance_pre: wasmtime::component::InstancePre, + indices: TheWorldIndices, } impl Clone for TheWorldPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), + indices: self.indices.clone(), } } } +impl<_T> TheWorldPre<_T> { + /// Creates a new copy of `TheWorldPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`TheWorld`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub async fn instantiate_async( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result + where + _T: Send, + { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate_async(&mut store).await?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `the-world`. +/// +/// This is an implementation detail of [`TheWorldPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`TheWorld`] as well. +#[derive(Clone)] +pub struct TheWorldIndices {} /// Auto-generated bindings for an instance a component which /// implements the world `the-world`. /// -/// This structure is created through either -/// [`TheWorld::instantiate_async`] or by first creating -/// a [`TheWorldPre`] followed by using -/// [`TheWorldPre::instantiate_async`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`TheWorld::instantiate_async`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`TheWorldPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`TheWorldPre::instantiate_async`] to +/// create a [`TheWorld`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`TheWorld::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`TheWorldIndices::new_instance`] followed +/// by [`TheWorldIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct TheWorld {} const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> TheWorldPre<_T> { - /// Creates a new copy of `TheWorldPre` bindings which can then + impl TheWorldIndices { + /// Creates a new copy of `TheWorldIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, ) -> wasmtime::Result { - let _component = instance_pre.component(); - Ok(TheWorldPre { instance_pre }) + let _component = component; + Ok(TheWorldIndices {}) } - /// Instantiates a new instance of [`TheWorld`] within the - /// `store` provided. + /// Creates a new instance of [`TheWorldIndices`] from an + /// instantiated component. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub async fn instantiate_async( + /// This method of creating a [`TheWorld`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`TheWorld`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; + Ok(TheWorldIndices {}) + } + /// Uses the indices stored in `self` to load an instance + /// of [`TheWorld`] from the instance provided. + /// + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate_async(&mut store).await?; + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; Ok(TheWorld {}) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl TheWorld { /// Convenience wrapper around [`TheWorldPre::new`] and @@ -76,6 +152,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate_async(store).await } + /// Convenience wrapper around [`TheWorldIndices::new_instance`] and + /// [`TheWorldIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker( linker: &mut wasmtime::component::Linker, get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, diff --git a/crates/component-macro/tests/expanded/strings.rs b/crates/component-macro/tests/expanded/strings.rs index 858ecc1564ff..743d69f5044c 100644 --- a/crates/component-macro/tests/expanded/strings.rs +++ b/crates/component-macro/tests/expanded/strings.rs @@ -4,69 +4,146 @@ /// This structure is created through [`TheWorldPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`TheWorld`] as well. pub struct TheWorldPre { instance_pre: wasmtime::component::InstancePre, - interface0: exports::foo::foo::strings::GuestPre, + indices: TheWorldIndices, } impl Clone for TheWorldPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), - interface0: self.interface0.clone(), + indices: self.indices.clone(), } } } +impl<_T> TheWorldPre<_T> { + /// Creates a new copy of `TheWorldPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`TheWorld`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub fn instantiate( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate(&mut store)?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `the-world`. +/// +/// This is an implementation detail of [`TheWorldPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`TheWorld`] as well. +#[derive(Clone)] +pub struct TheWorldIndices { + interface0: exports::foo::foo::strings::GuestIndices, +} /// Auto-generated bindings for an instance a component which /// implements the world `the-world`. /// -/// This structure is created through either -/// [`TheWorld::instantiate`] or by first creating -/// a [`TheWorldPre`] followed by using -/// [`TheWorldPre::instantiate`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`TheWorld::instantiate`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`TheWorldPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`TheWorldPre::instantiate`] to +/// create a [`TheWorld`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`TheWorld::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`TheWorldIndices::new_instance`] followed +/// by [`TheWorldIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct TheWorld { interface0: exports::foo::foo::strings::Guest, } const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> TheWorldPre<_T> { - /// Creates a new copy of `TheWorldPre` bindings which can then + impl TheWorldIndices { + /// Creates a new copy of `TheWorldIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, + ) -> wasmtime::Result { + let _component = component; + let interface0 = exports::foo::foo::strings::GuestIndices::new(_component)?; + Ok(TheWorldIndices { interface0 }) + } + /// Creates a new instance of [`TheWorldIndices`] from an + /// instantiated component. + /// + /// This method of creating a [`TheWorld`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`TheWorld`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let _component = instance_pre.component(); - let interface0 = exports::foo::foo::strings::GuestPre::new(_component)?; - Ok(TheWorldPre { - instance_pre, - interface0, - }) + let _instance = instance; + let interface0 = exports::foo::foo::strings::GuestIndices::new_instance( + &mut store, + _instance, + )?; + Ok(TheWorldIndices { interface0 }) } - /// Instantiates a new instance of [`TheWorld`] within the - /// `store` provided. + /// Uses the indices stored in `self` to load an instance + /// of [`TheWorld`] from the instance provided. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub fn instantiate( + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate(&mut store)?; + let _instance = instance; let interface0 = self.interface0.load(&mut store, &_instance)?; Ok(TheWorld { interface0 }) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl TheWorld { /// Convenience wrapper around [`TheWorldPre::new`] and @@ -79,6 +156,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate(store) } + /// Convenience wrapper around [`TheWorldIndices::new_instance`] and + /// [`TheWorldIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker( linker: &mut wasmtime::component::Linker, get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, @@ -204,16 +290,21 @@ pub mod exports { c: wasmtime::component::Func, } #[derive(Clone)] - pub struct GuestPre { + pub struct GuestIndices { a: wasmtime::component::ComponentExportIndex, b: wasmtime::component::ComponentExportIndex, c: wasmtime::component::ComponentExportIndex, } - impl GuestPre { + impl GuestIndices { + /// Constructor for [`GuestIndices`] which takes a + /// [`Component`](wasmtime::component::Component) as input and can be executed + /// before instantiation. + /// + /// This constructor can be used to front-load string lookups to find exports + /// within a component. pub fn new( component: &wasmtime::component::Component, - ) -> wasmtime::Result { - let _component = component; + ) -> wasmtime::Result { let (_, instance) = component .export_index(None, "foo:foo/strings") .ok_or_else(|| { @@ -221,10 +312,34 @@ pub mod exports { "no exported instance named `foo:foo/strings`" ) })?; - let _lookup = |name: &str| { - _component - .export_index(Some(&instance), name) - .map(|p| p.1) + Self::_new(|name| { + component.export_index(Some(&instance), name).map(|p| p.1) + }) + } + /// This constructor is similar to [`GuestIndices::new`] except that it + /// performs string lookups after instantiation time. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let instance_export = instance + .get_export(&mut store, None, "foo:foo/strings") + .ok_or_else(|| { + anyhow::anyhow!( + "no exported instance named `foo:foo/strings`" + ) + })?; + Self::_new(|name| { + instance.get_export(&mut store, Some(&instance_export), name) + }) + } + fn _new( + mut lookup: impl FnMut( + &str, + ) -> Option, + ) -> wasmtime::Result { + let mut lookup = move |name| { + lookup(name) .ok_or_else(|| { anyhow::anyhow!( "instance export `foo:foo/strings` does \ @@ -232,10 +347,11 @@ pub mod exports { ) }) }; - let a = _lookup("a")?; - let b = _lookup("b")?; - let c = _lookup("c")?; - Ok(GuestPre { a, b, c }) + let _ = &mut lookup; + let a = lookup("a")?; + let b = lookup("b")?; + let c = lookup("c")?; + Ok(GuestIndices { a, b, c }) } pub fn load( &self, diff --git a/crates/component-macro/tests/expanded/strings_async.rs b/crates/component-macro/tests/expanded/strings_async.rs index 3450c3cf8583..63a20c32437d 100644 --- a/crates/component-macro/tests/expanded/strings_async.rs +++ b/crates/component-macro/tests/expanded/strings_async.rs @@ -4,72 +4,149 @@ /// This structure is created through [`TheWorldPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`TheWorld`] as well. pub struct TheWorldPre { instance_pre: wasmtime::component::InstancePre, - interface0: exports::foo::foo::strings::GuestPre, + indices: TheWorldIndices, } impl Clone for TheWorldPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), - interface0: self.interface0.clone(), + indices: self.indices.clone(), } } } +impl<_T> TheWorldPre<_T> { + /// Creates a new copy of `TheWorldPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`TheWorld`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub async fn instantiate_async( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result + where + _T: Send, + { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate_async(&mut store).await?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `the-world`. +/// +/// This is an implementation detail of [`TheWorldPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`TheWorld`] as well. +#[derive(Clone)] +pub struct TheWorldIndices { + interface0: exports::foo::foo::strings::GuestIndices, +} /// Auto-generated bindings for an instance a component which /// implements the world `the-world`. /// -/// This structure is created through either -/// [`TheWorld::instantiate_async`] or by first creating -/// a [`TheWorldPre`] followed by using -/// [`TheWorldPre::instantiate_async`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`TheWorld::instantiate_async`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`TheWorldPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`TheWorldPre::instantiate_async`] to +/// create a [`TheWorld`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`TheWorld::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`TheWorldIndices::new_instance`] followed +/// by [`TheWorldIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct TheWorld { interface0: exports::foo::foo::strings::Guest, } const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> TheWorldPre<_T> { - /// Creates a new copy of `TheWorldPre` bindings which can then + impl TheWorldIndices { + /// Creates a new copy of `TheWorldIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, + ) -> wasmtime::Result { + let _component = component; + let interface0 = exports::foo::foo::strings::GuestIndices::new(_component)?; + Ok(TheWorldIndices { interface0 }) + } + /// Creates a new instance of [`TheWorldIndices`] from an + /// instantiated component. + /// + /// This method of creating a [`TheWorld`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`TheWorld`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let _component = instance_pre.component(); - let interface0 = exports::foo::foo::strings::GuestPre::new(_component)?; - Ok(TheWorldPre { - instance_pre, - interface0, - }) + let _instance = instance; + let interface0 = exports::foo::foo::strings::GuestIndices::new_instance( + &mut store, + _instance, + )?; + Ok(TheWorldIndices { interface0 }) } - /// Instantiates a new instance of [`TheWorld`] within the - /// `store` provided. + /// Uses the indices stored in `self` to load an instance + /// of [`TheWorld`] from the instance provided. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub async fn instantiate_async( + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate_async(&mut store).await?; + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; let interface0 = self.interface0.load(&mut store, &_instance)?; Ok(TheWorld { interface0 }) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl TheWorld { /// Convenience wrapper around [`TheWorldPre::new`] and @@ -85,6 +162,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; TheWorldPre::new(pre)?.instantiate_async(store).await } + /// Convenience wrapper around [`TheWorldIndices::new_instance`] and + /// [`TheWorldIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = TheWorldIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker( linker: &mut wasmtime::component::Linker, get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, @@ -217,16 +303,21 @@ pub mod exports { c: wasmtime::component::Func, } #[derive(Clone)] - pub struct GuestPre { + pub struct GuestIndices { a: wasmtime::component::ComponentExportIndex, b: wasmtime::component::ComponentExportIndex, c: wasmtime::component::ComponentExportIndex, } - impl GuestPre { + impl GuestIndices { + /// Constructor for [`GuestIndices`] which takes a + /// [`Component`](wasmtime::component::Component) as input and can be executed + /// before instantiation. + /// + /// This constructor can be used to front-load string lookups to find exports + /// within a component. pub fn new( component: &wasmtime::component::Component, - ) -> wasmtime::Result { - let _component = component; + ) -> wasmtime::Result { let (_, instance) = component .export_index(None, "foo:foo/strings") .ok_or_else(|| { @@ -234,10 +325,34 @@ pub mod exports { "no exported instance named `foo:foo/strings`" ) })?; - let _lookup = |name: &str| { - _component - .export_index(Some(&instance), name) - .map(|p| p.1) + Self::_new(|name| { + component.export_index(Some(&instance), name).map(|p| p.1) + }) + } + /// This constructor is similar to [`GuestIndices::new`] except that it + /// performs string lookups after instantiation time. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let instance_export = instance + .get_export(&mut store, None, "foo:foo/strings") + .ok_or_else(|| { + anyhow::anyhow!( + "no exported instance named `foo:foo/strings`" + ) + })?; + Self::_new(|name| { + instance.get_export(&mut store, Some(&instance_export), name) + }) + } + fn _new( + mut lookup: impl FnMut( + &str, + ) -> Option, + ) -> wasmtime::Result { + let mut lookup = move |name| { + lookup(name) .ok_or_else(|| { anyhow::anyhow!( "instance export `foo:foo/strings` does \ @@ -245,10 +360,11 @@ pub mod exports { ) }) }; - let a = _lookup("a")?; - let b = _lookup("b")?; - let c = _lookup("c")?; - Ok(GuestPre { a, b, c }) + let _ = &mut lookup; + let a = lookup("a")?; + let b = lookup("b")?; + let c = lookup("c")?; + Ok(GuestIndices { a, b, c }) } pub fn load( &self, diff --git a/crates/component-macro/tests/expanded/unversioned-foo.rs b/crates/component-macro/tests/expanded/unversioned-foo.rs index 33bb74af8e07..20b394cf1bfb 100644 --- a/crates/component-macro/tests/expanded/unversioned-foo.rs +++ b/crates/component-macro/tests/expanded/unversioned-foo.rs @@ -4,60 +4,136 @@ /// This structure is created through [`NopePre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`Nope`] as well. pub struct NopePre { instance_pre: wasmtime::component::InstancePre, + indices: NopeIndices, } impl Clone for NopePre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), + indices: self.indices.clone(), } } } +impl<_T> NopePre<_T> { + /// Creates a new copy of `NopePre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = NopeIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`Nope`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub fn instantiate( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate(&mut store)?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `nope`. +/// +/// This is an implementation detail of [`NopePre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`Nope`] as well. +#[derive(Clone)] +pub struct NopeIndices {} /// Auto-generated bindings for an instance a component which /// implements the world `nope`. /// -/// This structure is created through either -/// [`Nope::instantiate`] or by first creating -/// a [`NopePre`] followed by using -/// [`NopePre::instantiate`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`Nope::instantiate`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`NopePre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`NopePre::instantiate`] to +/// create a [`Nope`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`Nope::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`NopeIndices::new_instance`] followed +/// by [`NopeIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct Nope {} const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> NopePre<_T> { - /// Creates a new copy of `NopePre` bindings which can then + impl NopeIndices { + /// Creates a new copy of `NopeIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, + ) -> wasmtime::Result { + let _component = component; + Ok(NopeIndices {}) + } + /// Creates a new instance of [`NopeIndices`] from an + /// instantiated component. + /// + /// This method of creating a [`Nope`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`Nope`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let _component = instance_pre.component(); - Ok(NopePre { instance_pre }) + let _instance = instance; + Ok(NopeIndices {}) } - /// Instantiates a new instance of [`Nope`] within the - /// `store` provided. + /// Uses the indices stored in `self` to load an instance + /// of [`Nope`] from the instance provided. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub fn instantiate( + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate(&mut store)?; + let _instance = instance; Ok(Nope {}) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl Nope { /// Convenience wrapper around [`NopePre::new`] and @@ -70,6 +146,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; NopePre::new(pre)?.instantiate(store) } + /// Convenience wrapper around [`NopeIndices::new_instance`] and + /// [`NopeIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = NopeIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker( linker: &mut wasmtime::component::Linker, get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, diff --git a/crates/component-macro/tests/expanded/unversioned-foo_async.rs b/crates/component-macro/tests/expanded/unversioned-foo_async.rs index 5e4bc7b9e1b2..05fe578c832a 100644 --- a/crates/component-macro/tests/expanded/unversioned-foo_async.rs +++ b/crates/component-macro/tests/expanded/unversioned-foo_async.rs @@ -4,63 +4,139 @@ /// This structure is created through [`NopePre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`Nope`] as well. pub struct NopePre { instance_pre: wasmtime::component::InstancePre, + indices: NopeIndices, } impl Clone for NopePre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), + indices: self.indices.clone(), } } } +impl<_T> NopePre<_T> { + /// Creates a new copy of `NopePre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = NopeIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`Nope`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub async fn instantiate_async( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result + where + _T: Send, + { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate_async(&mut store).await?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `nope`. +/// +/// This is an implementation detail of [`NopePre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`Nope`] as well. +#[derive(Clone)] +pub struct NopeIndices {} /// Auto-generated bindings for an instance a component which /// implements the world `nope`. /// -/// This structure is created through either -/// [`Nope::instantiate_async`] or by first creating -/// a [`NopePre`] followed by using -/// [`NopePre::instantiate_async`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`Nope::instantiate_async`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`NopePre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`NopePre::instantiate_async`] to +/// create a [`Nope`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`Nope::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`NopeIndices::new_instance`] followed +/// by [`NopeIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct Nope {} const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> NopePre<_T> { - /// Creates a new copy of `NopePre` bindings which can then + impl NopeIndices { + /// Creates a new copy of `NopeIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, + ) -> wasmtime::Result { + let _component = component; + Ok(NopeIndices {}) + } + /// Creates a new instance of [`NopeIndices`] from an + /// instantiated component. + /// + /// This method of creating a [`Nope`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`Nope`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let _component = instance_pre.component(); - Ok(NopePre { instance_pre }) + let _instance = instance; + Ok(NopeIndices {}) } - /// Instantiates a new instance of [`Nope`] within the - /// `store` provided. + /// Uses the indices stored in `self` to load an instance + /// of [`Nope`] from the instance provided. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub async fn instantiate_async( + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate_async(&mut store).await?; + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; Ok(Nope {}) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl Nope { /// Convenience wrapper around [`NopePre::new`] and @@ -76,6 +152,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; NopePre::new(pre)?.instantiate_async(store).await } + /// Convenience wrapper around [`NopeIndices::new_instance`] and + /// [`NopeIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = NopeIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker( linker: &mut wasmtime::component::Linker, get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, diff --git a/crates/component-macro/tests/expanded/use-paths.rs b/crates/component-macro/tests/expanded/use-paths.rs index cda46ef26d23..42e5e053aebc 100644 --- a/crates/component-macro/tests/expanded/use-paths.rs +++ b/crates/component-macro/tests/expanded/use-paths.rs @@ -4,60 +4,136 @@ /// This structure is created through [`DPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`D`] as well. pub struct DPre { instance_pre: wasmtime::component::InstancePre, + indices: DIndices, } impl Clone for DPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), + indices: self.indices.clone(), } } } +impl<_T> DPre<_T> { + /// Creates a new copy of `DPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = DIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`D`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub fn instantiate( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate(&mut store)?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `d`. +/// +/// This is an implementation detail of [`DPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`D`] as well. +#[derive(Clone)] +pub struct DIndices {} /// Auto-generated bindings for an instance a component which /// implements the world `d`. /// -/// This structure is created through either -/// [`D::instantiate`] or by first creating -/// a [`DPre`] followed by using -/// [`DPre::instantiate`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`D::instantiate`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`DPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`DPre::instantiate`] to +/// create a [`D`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`D::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`DIndices::new_instance`] followed +/// by [`DIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct D {} const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> DPre<_T> { - /// Creates a new copy of `DPre` bindings which can then + impl DIndices { + /// Creates a new copy of `DIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, + ) -> wasmtime::Result { + let _component = component; + Ok(DIndices {}) + } + /// Creates a new instance of [`DIndices`] from an + /// instantiated component. + /// + /// This method of creating a [`D`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`D`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let _component = instance_pre.component(); - Ok(DPre { instance_pre }) + let _instance = instance; + Ok(DIndices {}) } - /// Instantiates a new instance of [`D`] within the - /// `store` provided. + /// Uses the indices stored in `self` to load an instance + /// of [`D`] from the instance provided. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub fn instantiate( + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate(&mut store)?; + let _instance = instance; Ok(D {}) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl D { /// Convenience wrapper around [`DPre::new`] and @@ -70,6 +146,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; DPre::new(pre)?.instantiate(store) } + /// Convenience wrapper around [`DIndices::new_instance`] and + /// [`DIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = DIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker( linker: &mut wasmtime::component::Linker, get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, diff --git a/crates/component-macro/tests/expanded/use-paths_async.rs b/crates/component-macro/tests/expanded/use-paths_async.rs index 470bd5720dfd..71860e460cef 100644 --- a/crates/component-macro/tests/expanded/use-paths_async.rs +++ b/crates/component-macro/tests/expanded/use-paths_async.rs @@ -4,63 +4,139 @@ /// This structure is created through [`DPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`D`] as well. pub struct DPre { instance_pre: wasmtime::component::InstancePre, + indices: DIndices, } impl Clone for DPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), + indices: self.indices.clone(), } } } +impl<_T> DPre<_T> { + /// Creates a new copy of `DPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = DIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`D`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub async fn instantiate_async( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result + where + _T: Send, + { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate_async(&mut store).await?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `d`. +/// +/// This is an implementation detail of [`DPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`D`] as well. +#[derive(Clone)] +pub struct DIndices {} /// Auto-generated bindings for an instance a component which /// implements the world `d`. /// -/// This structure is created through either -/// [`D::instantiate_async`] or by first creating -/// a [`DPre`] followed by using -/// [`DPre::instantiate_async`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`D::instantiate_async`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`DPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`DPre::instantiate_async`] to +/// create a [`D`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`D::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`DIndices::new_instance`] followed +/// by [`DIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct D {} const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> DPre<_T> { - /// Creates a new copy of `DPre` bindings which can then + impl DIndices { + /// Creates a new copy of `DIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, ) -> wasmtime::Result { - let _component = instance_pre.component(); - Ok(DPre { instance_pre }) + let _component = component; + Ok(DIndices {}) } - /// Instantiates a new instance of [`D`] within the - /// `store` provided. + /// Creates a new instance of [`DIndices`] from an + /// instantiated component. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub async fn instantiate_async( + /// This method of creating a [`D`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`D`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; + Ok(DIndices {}) + } + /// Uses the indices stored in `self` to load an instance + /// of [`D`] from the instance provided. + /// + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate_async(&mut store).await?; + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; Ok(D {}) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl D { /// Convenience wrapper around [`DPre::new`] and @@ -76,6 +152,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; DPre::new(pre)?.instantiate_async(store).await } + /// Convenience wrapper around [`DIndices::new_instance`] and + /// [`DIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = DIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker( linker: &mut wasmtime::component::Linker, get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, diff --git a/crates/component-macro/tests/expanded/variants.rs b/crates/component-macro/tests/expanded/variants.rs index 0b5a684aeeda..3e67dc0d976d 100644 --- a/crates/component-macro/tests/expanded/variants.rs +++ b/crates/component-macro/tests/expanded/variants.rs @@ -4,69 +4,146 @@ /// This structure is created through [`MyWorldPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`MyWorld`] as well. pub struct MyWorldPre { instance_pre: wasmtime::component::InstancePre, - interface0: exports::foo::foo::variants::GuestPre, + indices: MyWorldIndices, } impl Clone for MyWorldPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), - interface0: self.interface0.clone(), + indices: self.indices.clone(), } } } +impl<_T> MyWorldPre<_T> { + /// Creates a new copy of `MyWorldPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = MyWorldIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`MyWorld`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub fn instantiate( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate(&mut store)?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `my-world`. +/// +/// This is an implementation detail of [`MyWorldPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`MyWorld`] as well. +#[derive(Clone)] +pub struct MyWorldIndices { + interface0: exports::foo::foo::variants::GuestIndices, +} /// Auto-generated bindings for an instance a component which /// implements the world `my-world`. /// -/// This structure is created through either -/// [`MyWorld::instantiate`] or by first creating -/// a [`MyWorldPre`] followed by using -/// [`MyWorldPre::instantiate`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`MyWorld::instantiate`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`MyWorldPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`MyWorldPre::instantiate`] to +/// create a [`MyWorld`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`MyWorld::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`MyWorldIndices::new_instance`] followed +/// by [`MyWorldIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct MyWorld { interface0: exports::foo::foo::variants::Guest, } const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> MyWorldPre<_T> { - /// Creates a new copy of `MyWorldPre` bindings which can then + impl MyWorldIndices { + /// Creates a new copy of `MyWorldIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, + ) -> wasmtime::Result { + let _component = component; + let interface0 = exports::foo::foo::variants::GuestIndices::new(_component)?; + Ok(MyWorldIndices { interface0 }) + } + /// Creates a new instance of [`MyWorldIndices`] from an + /// instantiated component. + /// + /// This method of creating a [`MyWorld`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`MyWorld`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let _component = instance_pre.component(); - let interface0 = exports::foo::foo::variants::GuestPre::new(_component)?; - Ok(MyWorldPre { - instance_pre, - interface0, - }) + let _instance = instance; + let interface0 = exports::foo::foo::variants::GuestIndices::new_instance( + &mut store, + _instance, + )?; + Ok(MyWorldIndices { interface0 }) } - /// Instantiates a new instance of [`MyWorld`] within the - /// `store` provided. + /// Uses the indices stored in `self` to load an instance + /// of [`MyWorld`] from the instance provided. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub fn instantiate( + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate(&mut store)?; + let _instance = instance; let interface0 = self.interface0.load(&mut store, &_instance)?; Ok(MyWorld { interface0 }) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl MyWorld { /// Convenience wrapper around [`MyWorldPre::new`] and @@ -79,6 +156,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; MyWorldPre::new(pre)?.instantiate(store) } + /// Convenience wrapper around [`MyWorldIndices::new_instance`] and + /// [`MyWorldIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = MyWorldIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker( linker: &mut wasmtime::component::Linker, get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, @@ -1212,7 +1298,7 @@ pub mod exports { return_named_result: wasmtime::component::Func, } #[derive(Clone)] - pub struct GuestPre { + pub struct GuestIndices { e1_arg: wasmtime::component::ComponentExportIndex, e1_result: wasmtime::component::ComponentExportIndex, v1_arg: wasmtime::component::ComponentExportIndex, @@ -1236,11 +1322,16 @@ pub mod exports { return_named_option: wasmtime::component::ComponentExportIndex, return_named_result: wasmtime::component::ComponentExportIndex, } - impl GuestPre { + impl GuestIndices { + /// Constructor for [`GuestIndices`] which takes a + /// [`Component`](wasmtime::component::Component) as input and can be executed + /// before instantiation. + /// + /// This constructor can be used to front-load string lookups to find exports + /// within a component. pub fn new( component: &wasmtime::component::Component, - ) -> wasmtime::Result { - let _component = component; + ) -> wasmtime::Result { let (_, instance) = component .export_index(None, "foo:foo/variants") .ok_or_else(|| { @@ -1248,10 +1339,34 @@ pub mod exports { "no exported instance named `foo:foo/variants`" ) })?; - let _lookup = |name: &str| { - _component - .export_index(Some(&instance), name) - .map(|p| p.1) + Self::_new(|name| { + component.export_index(Some(&instance), name).map(|p| p.1) + }) + } + /// This constructor is similar to [`GuestIndices::new`] except that it + /// performs string lookups after instantiation time. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let instance_export = instance + .get_export(&mut store, None, "foo:foo/variants") + .ok_or_else(|| { + anyhow::anyhow!( + "no exported instance named `foo:foo/variants`" + ) + })?; + Self::_new(|name| { + instance.get_export(&mut store, Some(&instance_export), name) + }) + } + fn _new( + mut lookup: impl FnMut( + &str, + ) -> Option, + ) -> wasmtime::Result { + let mut lookup = move |name| { + lookup(name) .ok_or_else(|| { anyhow::anyhow!( "instance export `foo:foo/variants` does \ @@ -1259,29 +1374,30 @@ pub mod exports { ) }) }; - let e1_arg = _lookup("e1-arg")?; - let e1_result = _lookup("e1-result")?; - let v1_arg = _lookup("v1-arg")?; - let v1_result = _lookup("v1-result")?; - let bool_arg = _lookup("bool-arg")?; - let bool_result = _lookup("bool-result")?; - let option_arg = _lookup("option-arg")?; - let option_result = _lookup("option-result")?; - let casts = _lookup("casts")?; - let result_arg = _lookup("result-arg")?; - let result_result = _lookup("result-result")?; - let return_result_sugar = _lookup("return-result-sugar")?; - let return_result_sugar2 = _lookup("return-result-sugar2")?; - let return_result_sugar3 = _lookup("return-result-sugar3")?; - let return_result_sugar4 = _lookup("return-result-sugar4")?; - let return_option_sugar = _lookup("return-option-sugar")?; - let return_option_sugar2 = _lookup("return-option-sugar2")?; - let result_simple = _lookup("result-simple")?; - let is_clone_arg = _lookup("is-clone-arg")?; - let is_clone_return = _lookup("is-clone-return")?; - let return_named_option = _lookup("return-named-option")?; - let return_named_result = _lookup("return-named-result")?; - Ok(GuestPre { + let _ = &mut lookup; + let e1_arg = lookup("e1-arg")?; + let e1_result = lookup("e1-result")?; + let v1_arg = lookup("v1-arg")?; + let v1_result = lookup("v1-result")?; + let bool_arg = lookup("bool-arg")?; + let bool_result = lookup("bool-result")?; + let option_arg = lookup("option-arg")?; + let option_result = lookup("option-result")?; + let casts = lookup("casts")?; + let result_arg = lookup("result-arg")?; + let result_result = lookup("result-result")?; + let return_result_sugar = lookup("return-result-sugar")?; + let return_result_sugar2 = lookup("return-result-sugar2")?; + let return_result_sugar3 = lookup("return-result-sugar3")?; + let return_result_sugar4 = lookup("return-result-sugar4")?; + let return_option_sugar = lookup("return-option-sugar")?; + let return_option_sugar2 = lookup("return-option-sugar2")?; + let result_simple = lookup("result-simple")?; + let is_clone_arg = lookup("is-clone-arg")?; + let is_clone_return = lookup("is-clone-return")?; + let return_named_option = lookup("return-named-option")?; + let return_named_result = lookup("return-named-result")?; + Ok(GuestIndices { e1_arg, e1_result, v1_arg, diff --git a/crates/component-macro/tests/expanded/variants_async.rs b/crates/component-macro/tests/expanded/variants_async.rs index eada61a58e23..e329d7d3b8ec 100644 --- a/crates/component-macro/tests/expanded/variants_async.rs +++ b/crates/component-macro/tests/expanded/variants_async.rs @@ -4,72 +4,149 @@ /// This structure is created through [`MyWorldPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`MyWorld`] as well. pub struct MyWorldPre { instance_pre: wasmtime::component::InstancePre, - interface0: exports::foo::foo::variants::GuestPre, + indices: MyWorldIndices, } impl Clone for MyWorldPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), - interface0: self.interface0.clone(), + indices: self.indices.clone(), } } } +impl<_T> MyWorldPre<_T> { + /// Creates a new copy of `MyWorldPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = MyWorldIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`MyWorld`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub async fn instantiate_async( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result + where + _T: Send, + { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate_async(&mut store).await?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `my-world`. +/// +/// This is an implementation detail of [`MyWorldPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`MyWorld`] as well. +#[derive(Clone)] +pub struct MyWorldIndices { + interface0: exports::foo::foo::variants::GuestIndices, +} /// Auto-generated bindings for an instance a component which /// implements the world `my-world`. /// -/// This structure is created through either -/// [`MyWorld::instantiate_async`] or by first creating -/// a [`MyWorldPre`] followed by using -/// [`MyWorldPre::instantiate_async`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`MyWorld::instantiate_async`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`MyWorldPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`MyWorldPre::instantiate_async`] to +/// create a [`MyWorld`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`MyWorld::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`MyWorldIndices::new_instance`] followed +/// by [`MyWorldIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct MyWorld { interface0: exports::foo::foo::variants::Guest, } const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> MyWorldPre<_T> { - /// Creates a new copy of `MyWorldPre` bindings which can then + impl MyWorldIndices { + /// Creates a new copy of `MyWorldIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, ) -> wasmtime::Result { - let _component = instance_pre.component(); - let interface0 = exports::foo::foo::variants::GuestPre::new(_component)?; - Ok(MyWorldPre { - instance_pre, - interface0, - }) + let _component = component; + let interface0 = exports::foo::foo::variants::GuestIndices::new(_component)?; + Ok(MyWorldIndices { interface0 }) } - /// Instantiates a new instance of [`MyWorld`] within the - /// `store` provided. + /// Creates a new instance of [`MyWorldIndices`] from an + /// instantiated component. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub async fn instantiate_async( + /// This method of creating a [`MyWorld`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`MyWorld`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; + let interface0 = exports::foo::foo::variants::GuestIndices::new_instance( + &mut store, + _instance, + )?; + Ok(MyWorldIndices { interface0 }) + } + /// Uses the indices stored in `self` to load an instance + /// of [`MyWorld`] from the instance provided. + /// + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate_async(&mut store).await?; + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; let interface0 = self.interface0.load(&mut store, &_instance)?; Ok(MyWorld { interface0 }) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl MyWorld { /// Convenience wrapper around [`MyWorldPre::new`] and @@ -85,6 +162,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; MyWorldPre::new(pre)?.instantiate_async(store).await } + /// Convenience wrapper around [`MyWorldIndices::new_instance`] and + /// [`MyWorldIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = MyWorldIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker( linker: &mut wasmtime::component::Linker, get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, @@ -1228,7 +1314,7 @@ pub mod exports { return_named_result: wasmtime::component::Func, } #[derive(Clone)] - pub struct GuestPre { + pub struct GuestIndices { e1_arg: wasmtime::component::ComponentExportIndex, e1_result: wasmtime::component::ComponentExportIndex, v1_arg: wasmtime::component::ComponentExportIndex, @@ -1252,11 +1338,16 @@ pub mod exports { return_named_option: wasmtime::component::ComponentExportIndex, return_named_result: wasmtime::component::ComponentExportIndex, } - impl GuestPre { + impl GuestIndices { + /// Constructor for [`GuestIndices`] which takes a + /// [`Component`](wasmtime::component::Component) as input and can be executed + /// before instantiation. + /// + /// This constructor can be used to front-load string lookups to find exports + /// within a component. pub fn new( component: &wasmtime::component::Component, - ) -> wasmtime::Result { - let _component = component; + ) -> wasmtime::Result { let (_, instance) = component .export_index(None, "foo:foo/variants") .ok_or_else(|| { @@ -1264,10 +1355,34 @@ pub mod exports { "no exported instance named `foo:foo/variants`" ) })?; - let _lookup = |name: &str| { - _component - .export_index(Some(&instance), name) - .map(|p| p.1) + Self::_new(|name| { + component.export_index(Some(&instance), name).map(|p| p.1) + }) + } + /// This constructor is similar to [`GuestIndices::new`] except that it + /// performs string lookups after instantiation time. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let instance_export = instance + .get_export(&mut store, None, "foo:foo/variants") + .ok_or_else(|| { + anyhow::anyhow!( + "no exported instance named `foo:foo/variants`" + ) + })?; + Self::_new(|name| { + instance.get_export(&mut store, Some(&instance_export), name) + }) + } + fn _new( + mut lookup: impl FnMut( + &str, + ) -> Option, + ) -> wasmtime::Result { + let mut lookup = move |name| { + lookup(name) .ok_or_else(|| { anyhow::anyhow!( "instance export `foo:foo/variants` does \ @@ -1275,29 +1390,30 @@ pub mod exports { ) }) }; - let e1_arg = _lookup("e1-arg")?; - let e1_result = _lookup("e1-result")?; - let v1_arg = _lookup("v1-arg")?; - let v1_result = _lookup("v1-result")?; - let bool_arg = _lookup("bool-arg")?; - let bool_result = _lookup("bool-result")?; - let option_arg = _lookup("option-arg")?; - let option_result = _lookup("option-result")?; - let casts = _lookup("casts")?; - let result_arg = _lookup("result-arg")?; - let result_result = _lookup("result-result")?; - let return_result_sugar = _lookup("return-result-sugar")?; - let return_result_sugar2 = _lookup("return-result-sugar2")?; - let return_result_sugar3 = _lookup("return-result-sugar3")?; - let return_result_sugar4 = _lookup("return-result-sugar4")?; - let return_option_sugar = _lookup("return-option-sugar")?; - let return_option_sugar2 = _lookup("return-option-sugar2")?; - let result_simple = _lookup("result-simple")?; - let is_clone_arg = _lookup("is-clone-arg")?; - let is_clone_return = _lookup("is-clone-return")?; - let return_named_option = _lookup("return-named-option")?; - let return_named_result = _lookup("return-named-result")?; - Ok(GuestPre { + let _ = &mut lookup; + let e1_arg = lookup("e1-arg")?; + let e1_result = lookup("e1-result")?; + let v1_arg = lookup("v1-arg")?; + let v1_result = lookup("v1-result")?; + let bool_arg = lookup("bool-arg")?; + let bool_result = lookup("bool-result")?; + let option_arg = lookup("option-arg")?; + let option_result = lookup("option-result")?; + let casts = lookup("casts")?; + let result_arg = lookup("result-arg")?; + let result_result = lookup("result-result")?; + let return_result_sugar = lookup("return-result-sugar")?; + let return_result_sugar2 = lookup("return-result-sugar2")?; + let return_result_sugar3 = lookup("return-result-sugar3")?; + let return_result_sugar4 = lookup("return-result-sugar4")?; + let return_option_sugar = lookup("return-option-sugar")?; + let return_option_sugar2 = lookup("return-option-sugar2")?; + let result_simple = lookup("result-simple")?; + let is_clone_arg = lookup("is-clone-arg")?; + let is_clone_return = lookup("is-clone-return")?; + let return_named_option = lookup("return-named-option")?; + let return_named_result = lookup("return-named-result")?; + Ok(GuestIndices { e1_arg, e1_result, v1_arg, diff --git a/crates/component-macro/tests/expanded/wat.rs b/crates/component-macro/tests/expanded/wat.rs index 767ed4972f01..14da6ff9efb6 100644 --- a/crates/component-macro/tests/expanded/wat.rs +++ b/crates/component-macro/tests/expanded/wat.rs @@ -4,71 +4,148 @@ /// This structure is created through [`ExamplePre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`Example`] as well. pub struct ExamplePre { instance_pre: wasmtime::component::InstancePre, - interface0: exports::same::name::this_name_is_duplicated::GuestPre, + indices: ExampleIndices, } impl Clone for ExamplePre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), - interface0: self.interface0.clone(), + indices: self.indices.clone(), } } } +impl<_T> ExamplePre<_T> { + /// Creates a new copy of `ExamplePre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = ExampleIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`Example`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub fn instantiate( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate(&mut store)?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `example`. +/// +/// This is an implementation detail of [`ExamplePre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`Example`] as well. +#[derive(Clone)] +pub struct ExampleIndices { + interface0: exports::same::name::this_name_is_duplicated::GuestIndices, +} /// Auto-generated bindings for an instance a component which /// implements the world `example`. /// -/// This structure is created through either -/// [`Example::instantiate`] or by first creating -/// a [`ExamplePre`] followed by using -/// [`ExamplePre::instantiate`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`Example::instantiate`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`ExamplePre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`ExamplePre::instantiate`] to +/// create a [`Example`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`Example::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`ExampleIndices::new_instance`] followed +/// by [`ExampleIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct Example { interface0: exports::same::name::this_name_is_duplicated::Guest, } const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> ExamplePre<_T> { - /// Creates a new copy of `ExamplePre` bindings which can then + impl ExampleIndices { + /// Creates a new copy of `ExampleIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, ) -> wasmtime::Result { - let _component = instance_pre.component(); - let interface0 = exports::same::name::this_name_is_duplicated::GuestPre::new( + let _component = component; + let interface0 = exports::same::name::this_name_is_duplicated::GuestIndices::new( _component, )?; - Ok(ExamplePre { - instance_pre, - interface0, - }) + Ok(ExampleIndices { interface0 }) } - /// Instantiates a new instance of [`Example`] within the - /// `store` provided. + /// Creates a new instance of [`ExampleIndices`] from an + /// instantiated component. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub fn instantiate( + /// This method of creating a [`Example`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`Example`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; + let interface0 = exports::same::name::this_name_is_duplicated::GuestIndices::new_instance( + &mut store, + _instance, + )?; + Ok(ExampleIndices { interface0 }) + } + /// Uses the indices stored in `self` to load an instance + /// of [`Example`] from the instance provided. + /// + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate(&mut store)?; + let _instance = instance; let interface0 = self.interface0.load(&mut store, &_instance)?; Ok(Example { interface0 }) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl Example { /// Convenience wrapper around [`ExamplePre::new`] and @@ -81,6 +158,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; ExamplePre::new(pre)?.instantiate(store) } + /// Convenience wrapper around [`ExampleIndices::new_instance`] and + /// [`ExampleIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = ExampleIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn same_name_this_name_is_duplicated( &self, ) -> &exports::same::name::this_name_is_duplicated::Guest { @@ -101,12 +187,17 @@ pub mod exports { } pub struct Guest {} #[derive(Clone)] - pub struct GuestPre {} - impl GuestPre { + pub struct GuestIndices {} + impl GuestIndices { + /// Constructor for [`GuestIndices`] which takes a + /// [`Component`](wasmtime::component::Component) as input and can be executed + /// before instantiation. + /// + /// This constructor can be used to front-load string lookups to find exports + /// within a component. pub fn new( component: &wasmtime::component::Component, - ) -> wasmtime::Result { - let _component = component; + ) -> wasmtime::Result { let (_, instance) = component .export_index(None, "same:name/this-name-is-duplicated") .ok_or_else(|| { @@ -114,10 +205,38 @@ pub mod exports { "no exported instance named `same:name/this-name-is-duplicated`" ) })?; - let _lookup = |name: &str| { - _component - .export_index(Some(&instance), name) - .map(|p| p.1) + Self::_new(|name| { + component.export_index(Some(&instance), name).map(|p| p.1) + }) + } + /// This constructor is similar to [`GuestIndices::new`] except that it + /// performs string lookups after instantiation time. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let instance_export = instance + .get_export( + &mut store, + None, + "same:name/this-name-is-duplicated", + ) + .ok_or_else(|| { + anyhow::anyhow!( + "no exported instance named `same:name/this-name-is-duplicated`" + ) + })?; + Self::_new(|name| { + instance.get_export(&mut store, Some(&instance_export), name) + }) + } + fn _new( + mut lookup: impl FnMut( + &str, + ) -> Option, + ) -> wasmtime::Result { + let mut lookup = move |name| { + lookup(name) .ok_or_else(|| { anyhow::anyhow!( "instance export `same:name/this-name-is-duplicated` does \ @@ -125,7 +244,8 @@ pub mod exports { ) }) }; - Ok(GuestPre {}) + let _ = &mut lookup; + Ok(GuestIndices {}) } pub fn load( &self, diff --git a/crates/component-macro/tests/expanded/wat_async.rs b/crates/component-macro/tests/expanded/wat_async.rs index 0fc5295cdb6a..cad73611fe21 100644 --- a/crates/component-macro/tests/expanded/wat_async.rs +++ b/crates/component-macro/tests/expanded/wat_async.rs @@ -4,74 +4,151 @@ /// This structure is created through [`ExamplePre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`Example`] as well. pub struct ExamplePre { instance_pre: wasmtime::component::InstancePre, - interface0: exports::same::name::this_name_is_duplicated::GuestPre, + indices: ExampleIndices, } impl Clone for ExamplePre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), - interface0: self.interface0.clone(), + indices: self.indices.clone(), } } } +impl<_T> ExamplePre<_T> { + /// Creates a new copy of `ExamplePre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = ExampleIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`Example`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub async fn instantiate_async( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result + where + _T: Send, + { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate_async(&mut store).await?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `example`. +/// +/// This is an implementation detail of [`ExamplePre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`Example`] as well. +#[derive(Clone)] +pub struct ExampleIndices { + interface0: exports::same::name::this_name_is_duplicated::GuestIndices, +} /// Auto-generated bindings for an instance a component which /// implements the world `example`. /// -/// This structure is created through either -/// [`Example::instantiate_async`] or by first creating -/// a [`ExamplePre`] followed by using -/// [`ExamplePre::instantiate_async`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`Example::instantiate_async`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`ExamplePre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`ExamplePre::instantiate_async`] to +/// create a [`Example`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`Example::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`ExampleIndices::new_instance`] followed +/// by [`ExampleIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct Example { interface0: exports::same::name::this_name_is_duplicated::Guest, } const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> ExamplePre<_T> { - /// Creates a new copy of `ExamplePre` bindings which can then + impl ExampleIndices { + /// Creates a new copy of `ExampleIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, ) -> wasmtime::Result { - let _component = instance_pre.component(); - let interface0 = exports::same::name::this_name_is_duplicated::GuestPre::new( + let _component = component; + let interface0 = exports::same::name::this_name_is_duplicated::GuestIndices::new( _component, )?; - Ok(ExamplePre { - instance_pre, - interface0, - }) + Ok(ExampleIndices { interface0 }) + } + /// Creates a new instance of [`ExampleIndices`] from an + /// instantiated component. + /// + /// This method of creating a [`Example`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`Example`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; + let interface0 = exports::same::name::this_name_is_duplicated::GuestIndices::new_instance( + &mut store, + _instance, + )?; + Ok(ExampleIndices { interface0 }) } - /// Instantiates a new instance of [`Example`] within the - /// `store` provided. + /// Uses the indices stored in `self` to load an instance + /// of [`Example`] from the instance provided. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub async fn instantiate_async( + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate_async(&mut store).await?; + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; let interface0 = self.interface0.load(&mut store, &_instance)?; Ok(Example { interface0 }) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl Example { /// Convenience wrapper around [`ExamplePre::new`] and @@ -87,6 +164,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; ExamplePre::new(pre)?.instantiate_async(store).await } + /// Convenience wrapper around [`ExampleIndices::new_instance`] and + /// [`ExampleIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = ExampleIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn same_name_this_name_is_duplicated( &self, ) -> &exports::same::name::this_name_is_duplicated::Guest { @@ -107,12 +193,17 @@ pub mod exports { } pub struct Guest {} #[derive(Clone)] - pub struct GuestPre {} - impl GuestPre { + pub struct GuestIndices {} + impl GuestIndices { + /// Constructor for [`GuestIndices`] which takes a + /// [`Component`](wasmtime::component::Component) as input and can be executed + /// before instantiation. + /// + /// This constructor can be used to front-load string lookups to find exports + /// within a component. pub fn new( component: &wasmtime::component::Component, - ) -> wasmtime::Result { - let _component = component; + ) -> wasmtime::Result { let (_, instance) = component .export_index(None, "same:name/this-name-is-duplicated") .ok_or_else(|| { @@ -120,10 +211,38 @@ pub mod exports { "no exported instance named `same:name/this-name-is-duplicated`" ) })?; - let _lookup = |name: &str| { - _component - .export_index(Some(&instance), name) - .map(|p| p.1) + Self::_new(|name| { + component.export_index(Some(&instance), name).map(|p| p.1) + }) + } + /// This constructor is similar to [`GuestIndices::new`] except that it + /// performs string lookups after instantiation time. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let instance_export = instance + .get_export( + &mut store, + None, + "same:name/this-name-is-duplicated", + ) + .ok_or_else(|| { + anyhow::anyhow!( + "no exported instance named `same:name/this-name-is-duplicated`" + ) + })?; + Self::_new(|name| { + instance.get_export(&mut store, Some(&instance_export), name) + }) + } + fn _new( + mut lookup: impl FnMut( + &str, + ) -> Option, + ) -> wasmtime::Result { + let mut lookup = move |name| { + lookup(name) .ok_or_else(|| { anyhow::anyhow!( "instance export `same:name/this-name-is-duplicated` does \ @@ -131,7 +250,8 @@ pub mod exports { ) }) }; - Ok(GuestPre {}) + let _ = &mut lookup; + Ok(GuestIndices {}) } pub fn load( &self, diff --git a/crates/component-macro/tests/expanded/worlds-with-types.rs b/crates/component-macro/tests/expanded/worlds-with-types.rs index 151154374e36..2fd790395a13 100644 --- a/crates/component-macro/tests/expanded/worlds-with-types.rs +++ b/crates/component-macro/tests/expanded/worlds-with-types.rs @@ -29,71 +29,150 @@ const _: () = { /// This structure is created through [`FooPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`Foo`] as well. pub struct FooPre { instance_pre: wasmtime::component::InstancePre, - f: wasmtime::component::ComponentExportIndex, + indices: FooIndices, } impl Clone for FooPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), - f: self.f.clone(), + indices: self.indices.clone(), } } } +impl<_T> FooPre<_T> { + /// Creates a new copy of `FooPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = FooIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`Foo`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub fn instantiate( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate(&mut store)?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `foo`. +/// +/// This is an implementation detail of [`FooPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`Foo`] as well. +#[derive(Clone)] +pub struct FooIndices { + f: wasmtime::component::ComponentExportIndex, +} /// Auto-generated bindings for an instance a component which /// implements the world `foo`. /// -/// This structure is created through either -/// [`Foo::instantiate`] or by first creating -/// a [`FooPre`] followed by using -/// [`FooPre::instantiate`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`Foo::instantiate`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`FooPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`FooPre::instantiate`] to +/// create a [`Foo`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`Foo::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`FooIndices::new_instance`] followed +/// by [`FooIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct Foo { f: wasmtime::component::Func, } const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> FooPre<_T> { - /// Creates a new copy of `FooPre` bindings which can then + impl FooIndices { + /// Creates a new copy of `FooIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, ) -> wasmtime::Result { - let _component = instance_pre.component(); + let _component = component; let f = _component .export_index(None, "f") .ok_or_else(|| anyhow::anyhow!("no function export `f` found"))? .1; - Ok(FooPre { instance_pre, f }) + Ok(FooIndices { f }) + } + /// Creates a new instance of [`FooIndices`] from an + /// instantiated component. + /// + /// This method of creating a [`Foo`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`Foo`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; + let f = _instance + .get_export(&mut store, None, "f") + .ok_or_else(|| anyhow::anyhow!("no function export `f` found"))?; + Ok(FooIndices { f }) } - /// Instantiates a new instance of [`Foo`] within the - /// `store` provided. + /// Uses the indices stored in `self` to load an instance + /// of [`Foo`] from the instance provided. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub fn instantiate( + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, ) -> wasmtime::Result { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate(&mut store)?; + let _instance = instance; let f = *_instance .get_typed_func::<(), ((T, U, R),)>(&mut store, &self.f)? .func(); Ok(Foo { f }) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl Foo { /// Convenience wrapper around [`FooPre::new`] and @@ -106,6 +185,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; FooPre::new(pre)?.instantiate(store) } + /// Convenience wrapper around [`FooIndices::new_instance`] and + /// [`FooIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = FooIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker( linker: &mut wasmtime::component::Linker, get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, diff --git a/crates/component-macro/tests/expanded/worlds-with-types_async.rs b/crates/component-macro/tests/expanded/worlds-with-types_async.rs index e771f3395066..48f42f3a99b6 100644 --- a/crates/component-macro/tests/expanded/worlds-with-types_async.rs +++ b/crates/component-macro/tests/expanded/worlds-with-types_async.rs @@ -29,74 +29,153 @@ const _: () = { /// This structure is created through [`FooPre::new`] which /// takes a [`InstancePre`](wasmtime::component::InstancePre) that /// has been created through a [`Linker`](wasmtime::component::Linker). +/// +/// For more information see [`Foo`] as well. pub struct FooPre { instance_pre: wasmtime::component::InstancePre, - f: wasmtime::component::ComponentExportIndex, + indices: FooIndices, } impl Clone for FooPre { fn clone(&self) -> Self { Self { instance_pre: self.instance_pre.clone(), - f: self.f.clone(), + indices: self.indices.clone(), } } } +impl<_T> FooPre<_T> { + /// Creates a new copy of `FooPre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new( + instance_pre: wasmtime::component::InstancePre<_T>, + ) -> wasmtime::Result { + let indices = FooIndices::new(instance_pre.component())?; + Ok(Self { instance_pre, indices }) + } + pub fn engine(&self) -> &wasmtime::Engine { + self.instance_pre.engine() + } + pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { + &self.instance_pre + } + /// Instantiates a new instance of [`Foo`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub async fn instantiate_async( + &self, + mut store: impl wasmtime::AsContextMut, + ) -> wasmtime::Result + where + _T: Send, + { + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate_async(&mut store).await?; + self.indices.load(&mut store, &instance) + } +} +/// Auto-generated bindings for index of the exports of +/// `foo`. +/// +/// This is an implementation detail of [`FooPre`] and can +/// be constructed if needed as well. +/// +/// For more information see [`Foo`] as well. +#[derive(Clone)] +pub struct FooIndices { + f: wasmtime::component::ComponentExportIndex, +} /// Auto-generated bindings for an instance a component which /// implements the world `foo`. /// -/// This structure is created through either -/// [`Foo::instantiate_async`] or by first creating -/// a [`FooPre`] followed by using -/// [`FooPre::instantiate_async`]. +/// This structure can be created through a number of means +/// depending on your requirements and what you have on hand: +/// +/// * The most convenient way is to use +/// [`Foo::instantiate_async`] which only needs a +/// [`Store`], [`Component`], and [`Linker`]. +/// +/// * Alternatively you can create a [`FooPre`] ahead of +/// time with a [`Component`] to front-load string lookups +/// of exports once instead of per-instantiation. This +/// method then uses [`FooPre::instantiate_async`] to +/// create a [`Foo`]. +/// +/// * If you've instantiated the instance yourself already +/// then you can use [`Foo::new`]. +/// +/// * You can also access the guts of instantiation through +/// [`FooIndices::new_instance`] followed +/// by [`FooIndices::load`] to crate an instance of this +/// type. +/// +/// These methods are all equivalent to one another and move +/// around the tradeoff of what work is performed when. +/// +/// [`Store`]: wasmtime::Store +/// [`Component`]: wasmtime::component::Component +/// [`Linker`]: wasmtime::component::Linker pub struct Foo { f: wasmtime::component::Func, } const _: () = { #[allow(unused_imports)] use wasmtime::component::__internal::anyhow; - impl<_T> FooPre<_T> { - /// Creates a new copy of `FooPre` bindings which can then + impl FooIndices { + /// Creates a new copy of `FooIndices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. + /// This method may fail if the component does not have the + /// required exports. pub fn new( - instance_pre: wasmtime::component::InstancePre<_T>, + component: &wasmtime::component::Component, ) -> wasmtime::Result { - let _component = instance_pre.component(); + let _component = component; let f = _component .export_index(None, "f") .ok_or_else(|| anyhow::anyhow!("no function export `f` found"))? .1; - Ok(FooPre { instance_pre, f }) + Ok(FooIndices { f }) + } + /// Creates a new instance of [`FooIndices`] from an + /// instantiated component. + /// + /// This method of creating a [`Foo`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`Foo`]. + pub fn new_instance( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; + let f = _instance + .get_export(&mut store, None, "f") + .ok_or_else(|| anyhow::anyhow!("no function export `f` found"))?; + Ok(FooIndices { f }) } - /// Instantiates a new instance of [`Foo`] within the - /// `store` provided. + /// Uses the indices stored in `self` to load an instance + /// of [`Foo`] from the instance provided. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub async fn instantiate_async( + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( &self, - mut store: impl wasmtime::AsContextMut, - ) -> wasmtime::Result - where - _T: Send, - { - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate_async(&mut store).await?; + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let _instance = instance; let f = *_instance .get_typed_func::<(), ((T, U, R),)>(&mut store, &self.f)? .func(); Ok(Foo { f }) } - pub fn engine(&self) -> &wasmtime::Engine { - self.instance_pre.engine() - } - pub fn instance_pre(&self) -> &wasmtime::component::InstancePre<_T> { - &self.instance_pre - } } impl Foo { /// Convenience wrapper around [`FooPre::new`] and @@ -112,6 +191,15 @@ const _: () = { let pre = linker.instantiate_pre(component)?; FooPre::new(pre)?.instantiate_async(store).await } + /// Convenience wrapper around [`FooIndices::new_instance`] and + /// [`FooIndices::load`]. + pub fn new( + mut store: impl wasmtime::AsContextMut, + instance: &wasmtime::component::Instance, + ) -> wasmtime::Result { + let indices = FooIndices::new_instance(&mut store, instance)?; + indices.load(store, instance) + } pub fn add_to_linker( linker: &mut wasmtime::component::Linker, get: impl Fn(&mut T) -> &mut U + Send + Sync + Copy + 'static, diff --git a/crates/test-programs/src/bin/cli_sleep_forever.rs b/crates/test-programs/src/bin/cli_sleep_forever.rs new file mode 100644 index 000000000000..f2be9622ceab --- /dev/null +++ b/crates/test-programs/src/bin/cli_sleep_forever.rs @@ -0,0 +1,5 @@ +use std::time::Duration; + +fn main() { + std::thread::sleep(Duration::from_nanos(u64::MAX)); +} diff --git a/crates/wasi-http/src/bindings.rs b/crates/wasi-http/src/bindings.rs index d48cbd6b52b5..00054e5a644b 100644 --- a/crates/wasi-http/src/bindings.rs +++ b/crates/wasi-http/src/bindings.rs @@ -47,7 +47,7 @@ pub use self::generated::wasi::*; pub use self::generated::exports; /// Bindings to the `wasi:http/proxy` world. -pub use self::generated::{Proxy, ProxyPre}; +pub use self::generated::{Proxy, ProxyIndices, ProxyPre}; /// Sync implementation of the `wasi:http/proxy` world. pub mod sync { @@ -73,5 +73,5 @@ pub mod sync { pub use self::generated::exports; /// Bindings to the `wasi:http/proxy` world. - pub use self::generated::{Proxy, ProxyPre}; + pub use self::generated::{Proxy, ProxyIndices, ProxyPre}; } diff --git a/crates/wasi-threads/Cargo.toml b/crates/wasi-threads/Cargo.toml index 0a5a681d7098..8ec1c9616465 100644 --- a/crates/wasi-threads/Cargo.toml +++ b/crates/wasi-threads/Cargo.toml @@ -21,3 +21,4 @@ log = { workspace = true } rand = "0.8" wasi-common = { workspace = true, features = ["exit"]} wasmtime = { workspace = true, features = ['threads'] } +wasmtime-wasi = { workspace = true } diff --git a/crates/wasi-threads/src/lib.rs b/crates/wasi-threads/src/lib.rs index 580be8c3e716..be775f5a4c13 100644 --- a/crates/wasi-threads/src/lib.rs +++ b/crates/wasi-threads/src/lib.rs @@ -61,7 +61,14 @@ impl WasiThreadsCtx { let result = catch_unwind(AssertUnwindSafe(|| { // Each new instance is created in its own store. let mut store = Store::new(&instance_pre.module().engine(), host); - let instance = instance_pre.instantiate(&mut store).unwrap(); + + let instance = if instance_pre.module().engine().is_async() { + wasmtime_wasi::runtime::in_tokio(instance_pre.instantiate_async(&mut store)) + } else { + instance_pre.instantiate(&mut store) + } + .unwrap(); + let thread_entry_point = instance .get_typed_func::<(i32, i32), ()>(&mut store, WASI_ENTRY_POINT) .unwrap(); @@ -77,7 +84,15 @@ impl WasiThreadsCtx { WASI_ENTRY_POINT, thread_start_arg ); - match thread_entry_point.call(&mut store, (wasi_thread_id, thread_start_arg)) { + let res = if instance_pre.module().engine().is_async() { + wasmtime_wasi::runtime::in_tokio( + thread_entry_point + .call_async(&mut store, (wasi_thread_id, thread_start_arg)), + ) + } else { + thread_entry_point.call(&mut store, (wasi_thread_id, thread_start_arg)) + }; + match res { Ok(_) => log::trace!("exiting thread id = {} normally", wasi_thread_id), Err(e) => { log::trace!("exiting thread id = {} due to error", wasi_thread_id); diff --git a/crates/wasi/src/bindings.rs b/crates/wasi/src/bindings.rs index 3bc96b5c6546..74392b1831b3 100644 --- a/crates/wasi/src/bindings.rs +++ b/crates/wasi/src/bindings.rs @@ -318,6 +318,8 @@ pub mod sync { /// /// --- pub use self::generated::CommandPre; + + pub use self::generated::CommandIndices; } mod async_io { @@ -557,3 +559,5 @@ pub use self::async_io::Command; /// /// --- pub use self::async_io::CommandPre; + +pub use self::async_io::CommandIndices; diff --git a/crates/wasmtime/src/engine.rs b/crates/wasmtime/src/engine.rs index 8fa1797706db..fbd6d8aac1c3 100644 --- a/crates/wasmtime/src/engine.rs +++ b/crates/wasmtime/src/engine.rs @@ -185,6 +185,13 @@ impl Engine { Arc::ptr_eq(&a.inner, &b.inner) } + /// Returns whether the engine is configured to support async functions. + #[cfg(feature = "async")] + #[inline] + pub fn is_async(&self) -> bool { + self.config().async_support + } + /// Detects whether the bytes provided are a precompiled object produced by /// Wasmtime. /// diff --git a/crates/wasmtime/src/runtime/store.rs b/crates/wasmtime/src/runtime/store.rs index 027531a5d12e..8b80c77529ac 100644 --- a/crates/wasmtime/src/runtime/store.rs +++ b/crates/wasmtime/src/runtime/store.rs @@ -1547,10 +1547,7 @@ impl StoreOpaque { #[cfg(feature = "gc")] fn allocate_gc_store(engine: &Engine) -> Result { - let (index, heap) = if engine - .features() - .contains(wasmparser::WasmFeatures::REFERENCE_TYPES) - { + let (index, heap) = if engine.features().gc_types() { engine .allocator() .allocate_gc_heap(&**engine.gc_runtime())? @@ -2766,7 +2763,14 @@ impl Drop for StoreOpaque { #[cfg(feature = "gc")] if let Some(gc_store) = self.gc_store.take() { - allocator.deallocate_gc_heap(gc_store.allocation_index, gc_store.gc_heap); + if self.engine.features().gc_types() { + allocator.deallocate_gc_heap(gc_store.allocation_index, gc_store.gc_heap); + } else { + // If GC types are not enabled, we are just dealing with a + // dummy GC heap. + debug_assert_eq!(gc_store.allocation_index, GcHeapAllocationIndex::default()); + debug_assert!(gc_store.gc_heap.as_any().is::()); + } } #[cfg(feature = "component-model")] diff --git a/crates/wasmtime/src/runtime/vm/gc.rs b/crates/wasmtime/src/runtime/vm/gc.rs index 9593ac260652..beafb0c71951 100644 --- a/crates/wasmtime/src/runtime/vm/gc.rs +++ b/crates/wasmtime/src/runtime/vm/gc.rs @@ -235,108 +235,105 @@ impl GcStore { /// time or dynamically due to it being turned off in the `wasmtime::Config`). pub fn disabled_gc_heap() -> Box { return Box::new(DisabledGcHeap); +} - struct DisabledGcHeap; +pub(crate) struct DisabledGcHeap; - unsafe impl GcHeap for DisabledGcHeap { - fn as_any(&self) -> &dyn Any { - self - } - fn as_any_mut(&mut self) -> &mut dyn Any { - self - } - fn enter_no_gc_scope(&mut self) {} - fn exit_no_gc_scope(&mut self) {} - fn header(&self, _gc_ref: &VMGcRef) -> &VMGcHeader { - unreachable!() - } - fn clone_gc_ref(&mut self, _gc_ref: &VMGcRef) -> VMGcRef { - unreachable!() - } - fn write_gc_ref( - &mut self, - _host_data_table: &mut ExternRefHostDataTable, - _destination: &mut Option, - _source: Option<&VMGcRef>, - ) { - unreachable!() - } - fn expose_gc_ref_to_wasm(&mut self, _gc_ref: VMGcRef) { - unreachable!() - } - fn need_gc_before_entering_wasm(&self, _num_gc_refs: NonZeroUsize) -> bool { - unreachable!() - } - fn alloc_externref( - &mut self, - _host_data: ExternRefHostDataId, - ) -> Result> { - bail!( - "GC support disabled either in the `Config` or at compile time \ +unsafe impl GcHeap for DisabledGcHeap { + fn as_any(&self) -> &dyn Any { + self + } + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } + fn enter_no_gc_scope(&mut self) {} + fn exit_no_gc_scope(&mut self) {} + fn header(&self, _gc_ref: &VMGcRef) -> &VMGcHeader { + unreachable!() + } + fn clone_gc_ref(&mut self, _gc_ref: &VMGcRef) -> VMGcRef { + unreachable!() + } + fn write_gc_ref( + &mut self, + _host_data_table: &mut ExternRefHostDataTable, + _destination: &mut Option, + _source: Option<&VMGcRef>, + ) { + unreachable!() + } + fn expose_gc_ref_to_wasm(&mut self, _gc_ref: VMGcRef) { + unreachable!() + } + fn need_gc_before_entering_wasm(&self, _num_gc_refs: NonZeroUsize) -> bool { + unreachable!() + } + fn alloc_externref(&mut self, _host_data: ExternRefHostDataId) -> Result> { + bail!( + "GC support disabled either in the `Config` or at compile time \ because the `gc` cargo feature was not enabled" - ) - } - fn externref_host_data(&self, _externref: &VMExternRef) -> ExternRefHostDataId { - unreachable!() - } - fn alloc_uninit_struct( - &mut self, - _ty: wasmtime_environ::VMSharedTypeIndex, - _layout: &GcStructLayout, - ) -> Result> { - bail!( - "GC support disabled either in the `Config` or at compile time \ + ) + } + fn externref_host_data(&self, _externref: &VMExternRef) -> ExternRefHostDataId { + unreachable!() + } + fn alloc_uninit_struct( + &mut self, + _ty: wasmtime_environ::VMSharedTypeIndex, + _layout: &GcStructLayout, + ) -> Result> { + bail!( + "GC support disabled either in the `Config` or at compile time \ because the `gc` cargo feature was not enabled" - ) - } - fn dealloc_uninit_struct(&mut self, _structref: VMStructRef) { - unreachable!() - } - fn gc_object_data(&mut self, _gc_ref: &VMGcRef) -> VMGcObjectDataMut<'_> { - unreachable!() - } - fn alloc_uninit_array( - &mut self, - _ty: VMSharedTypeIndex, - _len: u32, - _layout: &GcArrayLayout, - ) -> Result> { - bail!( - "GC support disabled either in the `Config` or at compile time \ + ) + } + fn dealloc_uninit_struct(&mut self, _structref: VMStructRef) { + unreachable!() + } + fn gc_object_data(&mut self, _gc_ref: &VMGcRef) -> VMGcObjectDataMut<'_> { + unreachable!() + } + fn alloc_uninit_array( + &mut self, + _ty: VMSharedTypeIndex, + _len: u32, + _layout: &GcArrayLayout, + ) -> Result> { + bail!( + "GC support disabled either in the `Config` or at compile time \ because the `gc` cargo feature was not enabled" - ) - } - fn dealloc_uninit_array(&mut self, _structref: VMArrayRef) { - unreachable!() - } - fn array_len(&self, _arrayref: &VMArrayRef) -> u32 { - unreachable!() - } - fn gc<'a>( - &'a mut self, - _roots: GcRootsIter<'a>, - _host_data_table: &'a mut ExternRefHostDataTable, - ) -> Box + 'a> { - return Box::new(NoGc); - - struct NoGc; - - impl<'a> GarbageCollection<'a> for NoGc { - fn collect_increment(&mut self) -> GcProgress { - GcProgress::Complete - } + ) + } + fn dealloc_uninit_array(&mut self, _structref: VMArrayRef) { + unreachable!() + } + fn array_len(&self, _arrayref: &VMArrayRef) -> u32 { + unreachable!() + } + fn gc<'a>( + &'a mut self, + _roots: GcRootsIter<'a>, + _host_data_table: &'a mut ExternRefHostDataTable, + ) -> Box + 'a> { + return Box::new(NoGc); + + struct NoGc; + + impl<'a> GarbageCollection<'a> for NoGc { + fn collect_increment(&mut self) -> GcProgress { + GcProgress::Complete } } - unsafe fn vmctx_gc_heap_base(&self) -> *mut u8 { - ptr::null_mut() - } - unsafe fn vmctx_gc_heap_bound(&self) -> usize { - 0 - } - unsafe fn vmctx_gc_heap_data(&self) -> *mut u8 { - ptr::null_mut() - } - #[cfg(feature = "pooling-allocator")] - fn reset(&mut self) {} } + unsafe fn vmctx_gc_heap_base(&self) -> *mut u8 { + ptr::null_mut() + } + unsafe fn vmctx_gc_heap_bound(&self) -> usize { + 0 + } + unsafe fn vmctx_gc_heap_data(&self) -> *mut u8 { + ptr::null_mut() + } + #[cfg(feature = "pooling-allocator")] + fn reset(&mut self) {} } diff --git a/crates/wasmtime/src/runtime/vm/instance/allocator/pooling/gc_heap_pool.rs b/crates/wasmtime/src/runtime/vm/instance/allocator/pooling/gc_heap_pool.rs index 6cd79330622c..8d471384bbc8 100644 --- a/crates/wasmtime/src/runtime/vm/instance/allocator/pooling/gc_heap_pool.rs +++ b/crates/wasmtime/src/runtime/vm/instance/allocator/pooling/gc_heap_pool.rs @@ -59,6 +59,7 @@ impl GcHeapPool { self.max_gc_heaps ) })?; + debug_assert_ne!(allocation_index, GcHeapAllocationIndex::default()); let heap = match { let mut heaps = self.heaps.lock().unwrap(); @@ -76,6 +77,7 @@ impl GcHeapPool { /// Deallocate a previously-allocated GC heap. pub fn deallocate(&self, allocation_index: GcHeapAllocationIndex, mut heap: Box) { + debug_assert_ne!(allocation_index, GcHeapAllocationIndex::default()); heap.reset(); // NB: Replace the heap before freeing the index. If we did it in the diff --git a/crates/wit-bindgen/src/lib.rs b/crates/wit-bindgen/src/lib.rs index eb73523f9375..e82e9e090a81 100644 --- a/crates/wit-bindgen/src/lib.rs +++ b/crates/wit-bindgen/src/lib.rs @@ -92,9 +92,10 @@ struct Exports { struct ExportField { ty: String, - ty_pre: String, - getter: String, - getter_pre: String, + ty_index: String, + load: String, + get_index_from_component: String, + get_index_from_instance: String, } #[derive(Default, Debug, Clone, Copy)] @@ -518,24 +519,30 @@ impl Wasmtime { let mut gen = InterfaceGenerator::new(self, resolve); let field; let ty; - let ty_pre; - let getter; - let getter_pre; + let ty_index; + let load; + let get_index_from_component; + let get_index_from_instance; match item { WorldItem::Function(func) => { gen.define_rust_guest_export(resolve, None, func); let body = mem::take(&mut gen.src).into(); - getter = gen.extract_typed_function(func).1; + load = gen.extract_typed_function(func).1; assert!(gen.src.is_empty()); self.exports.funcs.push(body); - ty_pre = format!("{wt}::component::ComponentExportIndex"); + ty_index = format!("{wt}::component::ComponentExportIndex"); field = func_field_name(resolve, func); ty = format!("{wt}::component::Func"); - getter_pre = format!( + get_index_from_component = format!( "_component.export_index(None, \"{}\") .ok_or_else(|| anyhow::anyhow!(\"no function export `{0}` found\"))?.1", func.name ); + get_index_from_instance = format!( + "_instance.get_export(&mut store, None, \"{}\") + .ok_or_else(|| anyhow::anyhow!(\"no function export `{0}` found\"))?", + func.name + ); } WorldItem::Type(_) => unreachable!(), WorldItem::Interface { id, .. } => { @@ -560,7 +567,7 @@ impl Wasmtime { uwriteln!(gen.src, "}}"); uwriteln!(gen.src, "#[derive(Clone)]"); - uwriteln!(gen.src, "pub struct {struct_name}Pre {{"); + uwriteln!(gen.src, "pub struct {struct_name}Indices {{"); for (_, func) in iface.functions.iter() { uwriteln!( gen.src, @@ -570,41 +577,67 @@ impl Wasmtime { } uwriteln!(gen.src, "}}"); - uwriteln!(gen.src, "impl {struct_name}Pre {{"); + uwriteln!(gen.src, "impl {struct_name}Indices {{"); let instance_name = resolve.name_world_key(name); uwrite!( gen.src, " +/// Constructor for [`{struct_name}Indices`] which takes a +/// [`Component`]({wt}::component::Component) as input and can be executed +/// before instantiation. +/// +/// This constructor can be used to front-load string lookups to find exports +/// within a component. pub fn new( component: &{wt}::component::Component, -) -> {wt}::Result<{struct_name}Pre> {{ - let _component = component; +) -> {wt}::Result<{struct_name}Indices> {{ let (_, instance) = component.export_index(None, \"{instance_name}\") .ok_or_else(|| anyhow::anyhow!(\"no exported instance named `{instance_name}`\"))?; - let _lookup = |name: &str| {{ - _component.export_index(Some(&instance), name) + Self::_new(|name| {{ + component.export_index(Some(&instance), name) .map(|p| p.1) - .ok_or_else(|| {{ - anyhow::anyhow!( - \"instance export `{instance_name}` does \\ - not have export `{{name}}`\" - ) - }}) + }}) +}} + +/// This constructor is similar to [`{struct_name}Indices::new`] except that it +/// performs string lookups after instantiation time. +pub fn new_instance( + mut store: impl {wt}::AsContextMut, + instance: &{wt}::component::Instance, +) -> {wt}::Result<{struct_name}Indices> {{ + let instance_export = instance.get_export(&mut store, None, \"{instance_name}\") + .ok_or_else(|| anyhow::anyhow!(\"no exported instance named `{instance_name}`\"))?; + Self::_new(|name| {{ + instance.get_export(&mut store, Some(&instance_export), name) + }}) +}} + +fn _new( + mut lookup: impl FnMut (&str) -> Option<{wt}::component::ComponentExportIndex>, +) -> {wt}::Result<{struct_name}Indices> {{ + let mut lookup = move |name| {{ + lookup(name).ok_or_else(|| {{ + anyhow::anyhow!( + \"instance export `{instance_name}` does \\ + not have export `{{name}}`\" + ) + }}) }}; + let _ = &mut lookup; " ); let mut fields = Vec::new(); for (_, func) in iface.functions.iter() { let name = func_field_name(resolve, func); - uwriteln!(gen.src, "let {name} = _lookup(\"{}\")?;", func.name); + uwriteln!(gen.src, "let {name} = lookup(\"{}\")?;", func.name); fields.push(name); } - uwriteln!(gen.src, "Ok({struct_name}Pre {{"); + uwriteln!(gen.src, "Ok({struct_name}Indices {{"); for name in fields { uwriteln!(gen.src, "{name},"); } uwriteln!(gen.src, "}})"); - uwriteln!(gen.src, "}}"); + uwriteln!(gen.src, "}}"); // end `fn _new` uwrite!( gen.src, @@ -631,7 +664,7 @@ pub fn new( } uwriteln!(gen.src, "}})"); uwriteln!(gen.src, "}}"); // end `fn new` - uwriteln!(gen.src, "}}"); // end `impl {struct_name}Pre` + uwriteln!(gen.src, "}}"); // end `impl {struct_name}Indices` uwriteln!(gen.src, "impl {struct_name} {{"); let mut resource_methods = IndexMap::new(); @@ -713,7 +746,7 @@ pub fn new( None => (format!("exports::{snake}::{struct_name}"), snake.clone()), }; field = format!("interface{}", self.exports.fields.len()); - getter = format!("self.{field}.load(&mut store, &_instance)?"); + load = format!("self.{field}.load(&mut store, &_instance)?"); self.exports.funcs.push(format!( " pub fn {method_name}(&self) -> &{path} {{ @@ -721,18 +754,21 @@ pub fn new( }} ", )); - ty_pre = format!("{path}Pre"); + ty_index = format!("{path}Indices"); ty = path; - getter_pre = format!("{ty_pre}::new(_component)?"); + get_index_from_component = format!("{ty_index}::new(_component)?"); + get_index_from_instance = + format!("{ty_index}::new_instance(&mut store, _instance)?"); } } let prev = self.exports.fields.insert( field, ExportField { ty, - ty_pre, - getter, - getter_pre, + ty_index, + load, + get_index_from_component, + get_index_from_instance, }, ); assert!(prev.is_none()); @@ -750,40 +786,119 @@ pub fn new( uwriteln!( self.src, " - /// Auto-generated bindings for a pre-instantiated version of a - /// component which implements the world `{world_name}`. +/// Auto-generated bindings for a pre-instantiated version of a +/// component which implements the world `{world_name}`. +/// +/// This structure is created through [`{camel}Pre::new`] which +/// takes a [`InstancePre`]({wt}::component::InstancePre) that +/// has been created through a [`Linker`]({wt}::component::Linker). +/// +/// For more information see [`{camel}`] as well. +pub struct {camel}Pre {{ + instance_pre: {wt}::component::InstancePre, + indices: {camel}Indices, +}} + +impl Clone for {camel}Pre {{ + fn clone(&self) -> Self {{ + Self {{ + instance_pre: self.instance_pre.clone(), + indices: self.indices.clone(), + }} + }} +}} + +impl<_T> {camel}Pre<_T> {{ + /// Creates a new copy of `{camel}Pre` bindings which can then + /// be used to instantiate into a particular store. + /// + /// This method may fail if the component behind `instance_pre` + /// does not have the required exports. + pub fn new(instance_pre: {wt}::component::InstancePre<_T>) -> {wt}::Result {{ + let indices = {camel}Indices::new(instance_pre.component())?; + Ok(Self {{ instance_pre, indices }}) + }} + + pub fn engine(&self) -> &{wt}::Engine {{ + self.instance_pre.engine() + }} + + pub fn instance_pre(&self) -> &{wt}::component::InstancePre<_T> {{ + &self.instance_pre + }} + + /// Instantiates a new instance of [`{camel}`] within the + /// `store` provided. + /// + /// This function will use `self` as the pre-instantiated + /// instance to perform instantiation. Afterwards the preloaded + /// indices in `self` are used to lookup all exports on the + /// resulting instance. + pub {async_} fn instantiate{async__}( + &self, + mut store: impl {wt}::AsContextMut, + ) -> {wt}::Result<{camel}> + {where_clause} + {{ + let mut store = store.as_context_mut(); + let instance = self.instance_pre.instantiate{async__}(&mut store){await_}?; + self.indices.load(&mut store, &instance) + }} +}} +" + ); + + uwriteln!( + self.src, + " + /// Auto-generated bindings for index of the exports of + /// `{world_name}`. /// - /// This structure is created through [`{camel}Pre::new`] which - /// takes a [`InstancePre`]({wt}::component::InstancePre) that - /// has been created through a [`Linker`]({wt}::component::Linker). - pub struct {camel}Pre {{" + /// This is an implementation detail of [`{camel}Pre`] and can + /// be constructed if needed as well. + /// + /// For more information see [`{camel}`] as well. + #[derive(Clone)] + pub struct {camel}Indices {{" ); - uwriteln!(self.src, "instance_pre: {wt}::component::InstancePre,"); for (name, field) in self.exports.fields.iter() { - uwriteln!(self.src, "{name}: {},", field.ty_pre); + uwriteln!(self.src, "{name}: {},", field.ty_index); } self.src.push_str("}\n"); - uwriteln!(self.src, "impl Clone for {camel}Pre {{"); - uwriteln!(self.src, "fn clone(&self) -> Self {{"); - uwriteln!(self.src, "Self {{ instance_pre: self.instance_pre.clone(),"); - for (name, _field) in self.exports.fields.iter() { - uwriteln!(self.src, "{name}: self.{name}.clone(),"); - } - uwriteln!(self.src, "}}"); // `Self ... - uwriteln!(self.src, "}}"); // `fn clone` - uwriteln!(self.src, "}}"); // `impl Clone` - uwriteln!( self.src, " /// Auto-generated bindings for an instance a component which /// implements the world `{world_name}`. /// - /// This structure is created through either - /// [`{camel}::instantiate{async__}`] or by first creating - /// a [`{camel}Pre`] followed by using - /// [`{camel}Pre::instantiate{async__}`]. + /// This structure can be created through a number of means + /// depending on your requirements and what you have on hand: + /// + /// * The most convenient way is to use + /// [`{camel}::instantiate{async__}`] which only needs a + /// [`Store`], [`Component`], and [`Linker`]. + /// + /// * Alternatively you can create a [`{camel}Pre`] ahead of + /// time with a [`Component`] to front-load string lookups + /// of exports once instead of per-instantiation. This + /// method then uses [`{camel}Pre::instantiate{async__}`] to + /// create a [`{camel}`]. + /// + /// * If you've instantiated the instance yourself already + /// then you can use [`{camel}::new`]. + /// + /// * You can also access the guts of instantiation through + /// [`{camel}Indices::new_instance`] followed + /// by [`{camel}Indices::load`] to crate an instance of this + /// type. + /// + /// These methods are all equivalent to one another and move + /// around the tradeoff of what work is performed when. + /// + /// [`Store`]: {wt}::Store + /// [`Component`]: {wt}::component::Component + /// [`Linker`]: {wt}::component::Linker pub struct {camel} {{" ); for (name, field) in self.exports.fields.iter() { @@ -804,23 +919,20 @@ pub fn new( uwriteln!( self.src, - "impl<_T> {camel}Pre<_T> {{ - /// Creates a new copy of `{camel}Pre` bindings which can then + "impl {camel}Indices {{ + /// Creates a new copy of `{camel}Indices` bindings which can then /// be used to instantiate into a particular store. /// - /// This method may fail if the component behind `instance_pre` - /// does not have the required exports. - pub fn new( - instance_pre: {wt}::component::InstancePre<_T>, - ) -> {wt}::Result {{ - let _component = instance_pre.component(); + /// This method may fail if the component does not have the + /// required exports. + pub fn new(component: &{wt}::component::Component) -> {wt}::Result {{ + let _component = component; ", ); for (name, field) in self.exports.fields.iter() { - uwriteln!(self.src, "let {name} = {};", field.getter_pre); + uwriteln!(self.src, "let {name} = {};", field.get_index_from_component); } - uwriteln!(self.src, "Ok({camel}Pre {{"); - uwriteln!(self.src, "instance_pre,"); + uwriteln!(self.src, "Ok({camel}Indices {{"); for (name, _) in self.exports.fields.iter() { uwriteln!(self.src, "{name},"); } @@ -830,46 +942,56 @@ pub fn new( uwriteln!( self.src, " - /// Instantiates a new instance of [`{camel}`] within the - /// `store` provided. + /// Creates a new instance of [`{camel}Indices`] from an + /// instantiated component. /// - /// This function will use `self` as the pre-instantiated - /// instance to perform instantiation. Afterwards the preloaded - /// indices in `self` are used to lookup all exports on the - /// resulting instance. - pub {async_} fn instantiate{async__}( - &self, - mut store: impl {wt}::AsContextMut, - ) -> {wt}::Result<{camel}> - {where_clause} - {{ - let mut store = store.as_context_mut(); - let _instance = self.instance_pre.instantiate{async__}(&mut store){await_}?; + /// This method of creating a [`{camel}`] will perform string + /// lookups for all exports when this method is called. This + /// will only succeed if the provided instance matches the + /// requirements of [`{camel}`]. + pub fn new_instance( + mut store: impl {wt}::AsContextMut, + instance: &{wt}::component::Instance, + ) -> {wt}::Result {{ + let _instance = instance; ", ); for (name, field) in self.exports.fields.iter() { - uwriteln!(self.src, "let {name} = {};", field.getter); + uwriteln!(self.src, "let {name} = {};", field.get_index_from_instance); } - uwriteln!(self.src, "Ok({camel} {{"); + uwriteln!(self.src, "Ok({camel}Indices {{"); for (name, _) in self.exports.fields.iter() { uwriteln!(self.src, "{name},"); } uwriteln!(self.src, "}})"); - uwriteln!(self.src, "}}"); // close `fn new` + uwriteln!(self.src, "}}"); // close `fn new_instance` + uwriteln!( self.src, " - pub fn engine(&self) -> &{wt}::Engine {{ - self.instance_pre.engine() - }} - - pub fn instance_pre(&self) -> &{wt}::component::InstancePre<_T> {{ - &self.instance_pre - }} + /// Uses the indices stored in `self` to load an instance + /// of [`{camel}`] from the instance provided. + /// + /// Note that at this time this method will additionally + /// perform type-checks of all exports. + pub fn load( + &self, + mut store: impl {wt}::AsContextMut, + instance: &{wt}::component::Instance, + ) -> {wt}::Result<{camel}> {{ + let _instance = instance; ", ); - - uwriteln!(self.src, "}}"); + for (name, field) in self.exports.fields.iter() { + uwriteln!(self.src, "let {name} = {};", field.load); + } + uwriteln!(self.src, "Ok({camel} {{"); + for (name, _) in self.exports.fields.iter() { + uwriteln!(self.src, "{name},"); + } + uwriteln!(self.src, "}})"); + uwriteln!(self.src, "}}"); // close `fn load` + uwriteln!(self.src, "}}"); // close `impl {camel}Indices` uwriteln!( self.src, @@ -886,6 +1008,16 @@ pub fn new( let pre = linker.instantiate_pre(component)?; {camel}Pre::new(pre)?.instantiate{async__}(store){await_} }} + + /// Convenience wrapper around [`{camel}Indices::new_instance`] and + /// [`{camel}Indices::load`]. + pub fn new( + mut store: impl {wt}::AsContextMut, + instance: &{wt}::component::Instance, + ) -> {wt}::Result<{camel}> {{ + let indices = {camel}Indices::new_instance(&mut store, instance)?; + indices.load(store, instance) + }} ", ); self.world_add_to_linker(resolve, world); diff --git a/deny.toml b/deny.toml index e9f09df26c43..1ecdf0cbea06 100644 --- a/deny.toml +++ b/deny.toml @@ -62,4 +62,7 @@ skip-tree = [ # criterion is on old version, will update on next release. { name = "itertools" }, + + # right now terminal_size pulls in an older version of io-lifetimes + { name = "io-lifetimes" }, ] diff --git a/docs/wmemcheck.md b/docs/wmemcheck.md index 76d731f2cce7..6869fa04a94f 100644 --- a/docs/wmemcheck.md +++ b/docs/wmemcheck.md @@ -10,8 +10,8 @@ How to use: 1. When building Wasmtime, add the CLI flag "--features wmemcheck" to compile with wmemcheck configured. > cargo build --features wmemcheck -2. When running your wasm module, add the CLI flag "--wmemcheck". - > wasmtime run --wmemcheck test.wasm +2. When running your wasm module, add the CLI flag "-W wmemcheck". + > wasmtime run -W wmemcheck test.wasm If your program executes an invalid operation (load or store to non-allocated address, double-free, or an internal error in malloc that allocates the same @@ -37,7 +37,7 @@ $ /opt/wasi-sdk/bin/clang -o test.wasm test.c you can observe the memory checker working like so: ```plain -$ wasmtime run --wmemcheck ./test.wasm +$ wasmtime run -W wmemcheck ./test.wasm Error: failed to run main module `./test.wasm` Caused by: diff --git a/src/commands/run.rs b/src/commands/run.rs index 4aa504aed2fd..d06108576367 100644 --- a/src/commands/run.rs +++ b/src/commands/run.rs @@ -88,6 +88,7 @@ impl RunCommand { self.run.common.init_logging()?; let mut config = self.run.common.config(None, None)?; + config.async_support(true); if self.run.common.wasm.timeout.is_some() { config.epoch_interruption(true); @@ -149,61 +150,78 @@ impl RunCommand { store.set_fuel(fuel)?; } - // Load the preload wasm modules. - let mut modules = Vec::new(); - if let RunTarget::Core(m) = &main { - modules.push((String::new(), m.clone())); - } - for (name, path) in self.preloads.iter() { - // Read the wasm module binary either as `*.wat` or a raw binary - let module = match self.run.load_module(&engine, path)? { - RunTarget::Core(m) => m, - #[cfg(feature = "component-model")] - RunTarget::Component(_) => bail!("components cannot be loaded with `--preload`"), - }; - modules.push((name.clone(), module.clone())); + // Always run the module asynchronously to ensure that the module can be + // interrupted, even if it is blocking on I/O or a timeout or something. + let runtime = tokio::runtime::Builder::new_multi_thread() + .enable_time() + .enable_io() + .build()?; - // Add the module's functions to the linker. - match &mut linker { - #[cfg(feature = "cranelift")] - CliLinker::Core(linker) => { - linker.module(&mut store, name, &module).context(format!( - "failed to process preload `{}` at `{}`", - name, - path.display() - ))?; - } - #[cfg(not(feature = "cranelift"))] - CliLinker::Core(_) => { - bail!("support for --preload disabled at compile time"); + let dur = self + .run + .common + .wasm + .timeout + .unwrap_or(std::time::Duration::MAX); + let result = runtime.block_on(async { + tokio::time::timeout(dur, async { + // Load the preload wasm modules. + let mut modules = Vec::new(); + if let RunTarget::Core(m) = &main { + modules.push((String::new(), m.clone())); } - #[cfg(feature = "component-model")] - CliLinker::Component(_) => { - bail!("--preload cannot be used with components"); + for (name, path) in self.preloads.iter() { + // Read the wasm module binary either as `*.wat` or a raw binary + let module = match self.run.load_module(&engine, path)? { + RunTarget::Core(m) => m, + #[cfg(feature = "component-model")] + RunTarget::Component(_) => { + bail!("components cannot be loaded with `--preload`") + } + }; + modules.push((name.clone(), module.clone())); + + // Add the module's functions to the linker. + match &mut linker { + #[cfg(feature = "cranelift")] + CliLinker::Core(linker) => { + linker + .module_async(&mut store, name, &module) + .await + .context(format!( + "failed to process preload `{}` at `{}`", + name, + path.display() + ))?; + } + #[cfg(not(feature = "cranelift"))] + CliLinker::Core(_) => { + bail!("support for --preload disabled at compile time"); + } + #[cfg(feature = "component-model")] + CliLinker::Component(_) => { + bail!("--preload cannot be used with components"); + } + } } - } - } - // Pre-emptively initialize and install a Tokio runtime ambiently in the - // environment when executing the module. Without this whenever a WASI - // call is made that needs to block on a future a Tokio runtime is - // configured and entered, and this appears to be slower than simply - // picking an existing runtime out of the environment and using that. - // The goal of this is to improve the performance of WASI-related - // operations that block in the CLI since the CLI doesn't use async to - // invoke WebAssembly. - let result = wasmtime_wasi::runtime::with_ambient_tokio_runtime(|| { - self.load_main_module(&mut store, &mut linker, &main, modules) - .with_context(|| { - format!( - "failed to run main module `{}`", - self.module_and_args[0].to_string_lossy() - ) - }) + self.load_main_module(&mut store, &mut linker, &main, modules) + .await + .with_context(|| { + format!( + "failed to run main module `{}`", + self.module_and_args[0].to_string_lossy() + ) + }) + }) + .await }); // Load the main wasm module. - match result { + match result.unwrap_or_else(|elapsed| { + Err(anyhow::Error::from(wasmtime::Trap::Interrupt)) + .with_context(|| format!("timed out after {elapsed}")) + }) { Ok(()) => (), Err(e) => { // Exit the process if Wasmtime understands the error; @@ -367,7 +385,7 @@ impl RunCommand { }); } - fn load_main_module( + async fn load_main_module( &self, store: &mut Store, linker: &mut CliLinker, @@ -403,15 +421,20 @@ impl RunCommand { let result = match linker { CliLinker::Core(linker) => { let module = module.unwrap_core(); - let instance = linker.instantiate(&mut *store, &module).context(format!( - "failed to instantiate {:?}", - self.module_and_args[0] - ))?; + let instance = linker + .instantiate_async(&mut *store, &module) + .await + .context(format!( + "failed to instantiate {:?}", + self.module_and_args[0] + ))?; // If `_initialize` is present, meaning a reactor, then invoke // the function. if let Some(func) = instance.get_func(&mut *store, "_initialize") { - func.typed::<(), ()>(&store)?.call(&mut *store, ())?; + func.typed::<(), ()>(&store)? + .call_async(&mut *store, ()) + .await?; } // Look for the specific function provided or otherwise look for @@ -429,7 +452,7 @@ impl RunCommand { }; match func { - Some(func) => self.invoke_func(store, func), + Some(func) => self.invoke_func(store, func).await, None => Ok(()), } } @@ -441,14 +464,16 @@ impl RunCommand { let component = module.unwrap_component(); - let command = wasmtime_wasi::bindings::sync::Command::instantiate( + let command = wasmtime_wasi::bindings::Command::instantiate_async( &mut *store, component, linker, - )?; + ) + .await?; let result = command .wasi_cli_run() .call_run(&mut *store) + .await .context("failed to invoke `run` function") .map_err(|e| self.handle_core_dump(&mut *store, e)); @@ -465,7 +490,7 @@ impl RunCommand { result } - fn invoke_func(&self, store: &mut Store, func: Func) -> Result<()> { + async fn invoke_func(&self, store: &mut Store, func: Func) -> Result<()> { let ty = func.ty(&store); if ty.params().len() > 0 { eprintln!( @@ -505,7 +530,8 @@ impl RunCommand { // out, if there are any. let mut results = vec![Val::null_func_ref(); ty.results().len()]; let invoke_res = func - .call(&mut *store, &values, &mut results) + .call_async(&mut *store, &values, &mut results) + .await .with_context(|| { if let Some(name) = &self.invoke { format!("failed to invoke `{name}`") @@ -600,7 +626,7 @@ impl RunCommand { // are enabled, then use the historical preview1 // implementation. (Some(false), _) | (None, Some(true)) => { - wasi_common::sync::add_to_linker(linker, |host| { + wasi_common::tokio::add_to_linker(linker, |host| { host.preview1_ctx.as_mut().unwrap() })?; self.set_preview1_ctx(store)?; @@ -613,11 +639,11 @@ impl RunCommand { // default-disabled in the future. (Some(true), _) | (None, Some(false) | None) => { if self.run.common.wasi.preview0 != Some(false) { - wasmtime_wasi::preview0::add_to_linker_sync(linker, |t| { + wasmtime_wasi::preview0::add_to_linker_async(linker, |t| { t.preview2_ctx() })?; } - wasmtime_wasi::preview1::add_to_linker_sync(linker, |t| { + wasmtime_wasi::preview1::add_to_linker_async(linker, |t| { t.preview2_ctx() })?; self.set_preview2_ctx(store)?; @@ -626,7 +652,7 @@ impl RunCommand { } #[cfg(feature = "component-model")] CliLinker::Component(linker) => { - wasmtime_wasi::add_to_linker_sync(linker)?; + wasmtime_wasi::add_to_linker_async(linker)?; self.set_preview2_ctx(store)?; } } diff --git a/src/common.rs b/src/common.rs index 79837d79071c..a0599b3329a5 100644 --- a/src/common.rs +++ b/src/common.rs @@ -260,7 +260,11 @@ impl RunCommon { // the program as the CLI. This helps improve the performance of some // blocking operations in WASI, for example, by skipping the // back-and-forth between sync and async. - builder.allow_blocking_current_thread(true); + // + // However, do not set this if a timeout is configured, as that would + // cause the timeout to be ignored if the guest does, for example, + // something like `sleep(FOREVER)`. + builder.allow_blocking_current_thread(self.common.wasm.timeout.is_none()); if self.common.wasi.inherit_env == Some(true) { for (k, v) in std::env::vars() { diff --git a/supply-chain/audits.toml b/supply-chain/audits.toml index c5008b5d59da..312abdbb9d57 100644 --- a/supply-chain/audits.toml +++ b/supply-chain/audits.toml @@ -2593,6 +2593,12 @@ criteria = "safe-to-deploy" delta = "3.5.0 -> 3.6.0" notes = "Dependency updates and new optimized trait implementations, but otherwise everything looks normal." +[[audits.terminal_size]] +who = "Alex Crichton " +criteria = "safe-to-deploy" +delta = "0.1.17 -> 0.2.6" +notes = "Minor updates around using some utilities from the standard library, nothing major." + [[audits.test-log]] who = "Pat Hickey " criteria = "safe-to-deploy" diff --git a/supply-chain/imports.lock b/supply-chain/imports.lock index 77e71d88b255..e1f81c500991 100644 --- a/supply-chain/imports.lock +++ b/supply-chain/imports.lock @@ -752,6 +752,13 @@ user-id = 6825 user-login = "sunfishcode" user-name = "Dan Gohman" +[[publisher.io-lifetimes]] +version = "1.0.11" +when = "2023-05-24" +user-id = 6825 +user-login = "sunfishcode" +user-name = "Dan Gohman" + [[publisher.io-lifetimes]] version = "2.0.3" when = "2023-12-01" @@ -787,6 +794,13 @@ user-id = 2915 user-login = "Amanieu" user-name = "Amanieu d'Antras" +[[publisher.linux-raw-sys]] +version = "0.3.8" +when = "2023-05-19" +user-id = 6825 +user-login = "sunfishcode" +user-name = "Dan Gohman" + [[publisher.linux-raw-sys]] version = "0.4.12" when = "2023-11-30" @@ -878,6 +892,13 @@ user-id = 189 user-login = "BurntSushi" user-name = "Andrew Gallant" +[[publisher.rustix]] +version = "0.37.27" +when = "2023-10-26" +user-id = 6825 +user-login = "sunfishcode" +user-name = "Dan Gohman" + [[publisher.rustix]] version = "0.38.31" when = "2024-02-01" diff --git a/tests/all/cli_tests.rs b/tests/all/cli_tests.rs index fce63cb0aa98..dfb31842a91b 100644 --- a/tests/all/cli_tests.rs +++ b/tests/all/cli_tests.rs @@ -1443,6 +1443,28 @@ mod test_programs { Ok(()) } + #[test] + fn cli_sleep_forever() -> Result<()> { + for timeout in [ + // Tests still pass when we race with going to sleep. + "-Wtimeout=1ns", + // Tests pass when we wait till the Wasm has (likely) gone to sleep. + "-Wtimeout=250ms", + ] { + let e = run_wasmtime(&["run", timeout, CLI_SLEEP_FOREVER]).unwrap_err(); + let e = e.to_string(); + println!("Got error: {e}"); + assert!(e.contains("interrupt")); + + let e = run_wasmtime(&["run", timeout, CLI_SLEEP_FOREVER_COMPONENT]).unwrap_err(); + let e = e.to_string(); + println!("Got error: {e}"); + assert!(e.contains("interrupt")); + } + + Ok(()) + } + /// Helper structure to manage an invocation of `wasmtime serve` struct WasmtimeServe { child: Option, diff --git a/tests/disas/i128-cmp.wat b/tests/disas/i128-cmp.wat new file mode 100644 index 000000000000..4bfafc56e3a3 --- /dev/null +++ b/tests/disas/i128-cmp.wat @@ -0,0 +1,236 @@ +;;! target = "x86_64" +;;! test = "optimize" + +(module + (func $lt_s (param i64 i64 i64 i64) (result i32) + local.get 0 + local.get 2 + i64.lt_u + local.get 1 + local.get 3 + i64.lt_s + local.get 1 + local.get 3 + i64.eq + select + ) + (func $lt_u (param i64 i64 i64 i64) (result i32) + local.get 0 + local.get 2 + i64.lt_u + local.get 1 + local.get 3 + i64.lt_u + local.get 1 + local.get 3 + i64.eq + select + ) + (func $le_s (param i64 i64 i64 i64) (result i32) + local.get 0 + local.get 2 + i64.le_u + local.get 1 + local.get 3 + i64.le_s + local.get 1 + local.get 3 + i64.eq + select + ) + (func $le_u (param i64 i64 i64 i64) (result i32) + local.get 0 + local.get 2 + i64.le_u + local.get 1 + local.get 3 + i64.le_u + local.get 1 + local.get 3 + i64.eq + select + ) + (func $gt_s (param i64 i64 i64 i64) (result i32) + local.get 0 + local.get 2 + i64.gt_u + local.get 1 + local.get 3 + i64.gt_s + local.get 1 + local.get 3 + i64.eq + select + ) + (func $gt_u (param i64 i64 i64 i64) (result i32) + local.get 0 + local.get 2 + i64.gt_u + local.get 1 + local.get 3 + i64.gt_u + local.get 1 + local.get 3 + i64.eq + select + ) + (func $ge_s (param i64 i64 i64 i64) (result i32) + local.get 0 + local.get 2 + i64.ge_u + local.get 1 + local.get 3 + i64.ge_s + local.get 1 + local.get 3 + i64.eq + select + ) + (func $ge_u (param i64 i64 i64 i64) (result i32) + local.get 0 + local.get 2 + i64.ge_u + local.get 1 + local.get 3 + i64.ge_u + local.get 1 + local.get 3 + i64.eq + select + ) +) +;; function u0:0(i64 vmctx, i64, i64, i64, i64, i64) -> i32 tail { +;; gv0 = vmctx +;; gv1 = load.i64 notrap aligned readonly gv0+8 +;; gv2 = load.i64 notrap aligned gv1 +;; stack_limit = gv2 +;; +;; block0(v0: i64, v1: i64, v2: i64, v3: i64, v4: i64, v5: i64): +;; @0034 jump block1 +;; +;; block1: +;; v16 = iconcat.i64 v2, v3 +;; v17 = iconcat.i64 v4, v5 +;; v18 = icmp slt v16, v17 +;; v20 = uextend.i32 v18 +;; @0034 return v20 +;; } +;; +;; function u0:1(i64 vmctx, i64, i64, i64, i64, i64) -> i32 tail { +;; gv0 = vmctx +;; gv1 = load.i64 notrap aligned readonly gv0+8 +;; gv2 = load.i64 notrap aligned gv1 +;; stack_limit = gv2 +;; +;; block0(v0: i64, v1: i64, v2: i64, v3: i64, v4: i64, v5: i64): +;; @0047 jump block1 +;; +;; block1: +;; v16 = iconcat.i64 v2, v3 +;; v17 = iconcat.i64 v4, v5 +;; v18 = icmp ult v16, v17 +;; v20 = uextend.i32 v18 +;; @0047 return v20 +;; } +;; +;; function u0:2(i64 vmctx, i64, i64, i64, i64, i64) -> i32 tail { +;; gv0 = vmctx +;; gv1 = load.i64 notrap aligned readonly gv0+8 +;; gv2 = load.i64 notrap aligned gv1 +;; stack_limit = gv2 +;; +;; block0(v0: i64, v1: i64, v2: i64, v3: i64, v4: i64, v5: i64): +;; @005a jump block1 +;; +;; block1: +;; v16 = iconcat.i64 v2, v3 +;; v17 = iconcat.i64 v4, v5 +;; v18 = icmp sle v16, v17 +;; v20 = uextend.i32 v18 +;; @005a return v20 +;; } +;; +;; function u0:3(i64 vmctx, i64, i64, i64, i64, i64) -> i32 tail { +;; gv0 = vmctx +;; gv1 = load.i64 notrap aligned readonly gv0+8 +;; gv2 = load.i64 notrap aligned gv1 +;; stack_limit = gv2 +;; +;; block0(v0: i64, v1: i64, v2: i64, v3: i64, v4: i64, v5: i64): +;; @006d jump block1 +;; +;; block1: +;; v16 = iconcat.i64 v2, v3 +;; v17 = iconcat.i64 v4, v5 +;; v18 = icmp ule v16, v17 +;; v20 = uextend.i32 v18 +;; @006d return v20 +;; } +;; +;; function u0:4(i64 vmctx, i64, i64, i64, i64, i64) -> i32 tail { +;; gv0 = vmctx +;; gv1 = load.i64 notrap aligned readonly gv0+8 +;; gv2 = load.i64 notrap aligned gv1 +;; stack_limit = gv2 +;; +;; block0(v0: i64, v1: i64, v2: i64, v3: i64, v4: i64, v5: i64): +;; @0080 jump block1 +;; +;; block1: +;; v16 = iconcat.i64 v2, v3 +;; v17 = iconcat.i64 v4, v5 +;; v18 = icmp sgt v16, v17 +;; v20 = uextend.i32 v18 +;; @0080 return v20 +;; } +;; +;; function u0:5(i64 vmctx, i64, i64, i64, i64, i64) -> i32 tail { +;; gv0 = vmctx +;; gv1 = load.i64 notrap aligned readonly gv0+8 +;; gv2 = load.i64 notrap aligned gv1 +;; stack_limit = gv2 +;; +;; block0(v0: i64, v1: i64, v2: i64, v3: i64, v4: i64, v5: i64): +;; @0093 jump block1 +;; +;; block1: +;; v16 = iconcat.i64 v2, v3 +;; v17 = iconcat.i64 v4, v5 +;; v18 = icmp ugt v16, v17 +;; v20 = uextend.i32 v18 +;; @0093 return v20 +;; } +;; +;; function u0:6(i64 vmctx, i64, i64, i64, i64, i64) -> i32 tail { +;; gv0 = vmctx +;; gv1 = load.i64 notrap aligned readonly gv0+8 +;; gv2 = load.i64 notrap aligned gv1 +;; stack_limit = gv2 +;; +;; block0(v0: i64, v1: i64, v2: i64, v3: i64, v4: i64, v5: i64): +;; @00a6 jump block1 +;; +;; block1: +;; v16 = iconcat.i64 v2, v3 +;; v17 = iconcat.i64 v4, v5 +;; v18 = icmp sge v16, v17 +;; v20 = uextend.i32 v18 +;; @00a6 return v20 +;; } +;; +;; function u0:7(i64 vmctx, i64, i64, i64, i64, i64) -> i32 tail { +;; gv0 = vmctx +;; gv1 = load.i64 notrap aligned readonly gv0+8 +;; gv2 = load.i64 notrap aligned gv1 +;; stack_limit = gv2 +;; +;; block0(v0: i64, v1: i64, v2: i64, v3: i64, v4: i64, v5: i64): +;; @00b9 jump block1 +;; +;; block1: +;; v16 = iconcat.i64 v2, v3 +;; v17 = iconcat.i64 v4, v5 +;; v18 = icmp uge v16, v17 +;; v20 = uextend.i32 v18 +;; @00b9 return v20 +;; } diff --git a/tests/spec_testsuite b/tests/spec_testsuite index 7570678ade12..ae5a66933070 160000 --- a/tests/spec_testsuite +++ b/tests/spec_testsuite @@ -1 +1 @@ -Subproject commit 7570678ade1244ae69c9fefc990f4534c63ffaec +Subproject commit ae5a66933070b705dde56c2a71bf3fbc33282864