Skip to content

Commit 7974198

Browse files
committed
Replace GetHost with a function pointer, add HasData
This commit is a refactoring to the fundamentals of the `bindgen!` macro and the functions that it generates. Prior to this change the fundamental entrypoint generated by `bindgen!` was a function `add_to_linker_get_host` which takes a value of type `G: GetHost`. This `GetHost` implementation is effectively an alias for a closure whose return value is able to close over the parameter given lfietime-wise. The `GetHost` abstraction was added to Wasmtime originally to enable using any type that implements `Host` traits, not just `&mut U` as was originally supported. The definition of `GetHost` was _just_ right to enable a type such as `MyThing<&mut T>` to implement `Host` and a closure could be provided that could return it. At the time that `GetHost` was added it was known to be problematic from an understandability point of view, namely: * It has a non-obvious definition. * It's pretty advanced Rust voodoo to understand what it's actually doing * Using `GetHost` required lots of `for<'a> ...` in places which is unfamiliar syntax for many. * `GetHost` values couldn't be type-erased (e.g. put in a trait object) as we couldn't figure out the lifetime syntax to do so. Despite these issues it was the only known solution at hand so we landed it and kept the previous `add_to_linker` style (`&mut T -> &mut U`) as a convenience. While this has worked reasonable well (most folks just try to not look at `GetHost`) it has reached a breaking point in the WASIp3 work. In the WASIp3 work it's effectively now going to be required that the `G: GetHost` value is packaged up and actually stored inside of accessors provided to host functions. This means that `GetHost` values now need to not only be taken in `add_to_linker` but additionally provided to the rest of the system through an "accessor". This was made possible in bytecodealliance#10746 by moving the `GetHost` type into Wasmtime itself (as opposed to generated code where it lived prior). While this worked with WASIp3 and it was possible to plumb `G: GetHost` safely around, this ended up surfacing more issues. Namely all "concurrent" host functions started getting significantly more complicated `where` clauses and type signatures. At the end of the day I felt that we had reached the end of the road to `GetHost` and wanted to search for alternatives, hence this change. The fundamental purpose of `GetHost` was to be able to express, in a generic fashion: * Give me a closure that takes `&mut T` and returns `D`. * The `D` type can close over the lifetime in `&mut T`. * The `D` type must implement `bindgen!`-generated traits. A realization I had was that we could model this with a generic associated type in Rust. Rust support for generic associated types is relatively new and not something I've used much before, but it ended up being a perfect model for this. The definition of the new `HasData` trait is deceptively simple: trait HasData { type Data<'a>; } What this enables us to do though is to generate `add_to_linker` functions that look like this: fn add_to_linker<T, D>( linker: &mut Linker<T>, getter: fn(&mut T) -> D::Data<'_>, ) -> Result<()> where D: HasData, for<'a> D::Data<'a>: Host; This definition here models `G: GetHost` as a literal function pointer, and the ability to close over the `&mut T` lifetime with type (not just `&mut U`) is expressed through the type constructor `type Data<'a>`). Ideally we could take a generic generic associated type (I'm not even sure what to call that), but that's not something Rust has today. Overall this felt like a much simpler way of modeling `GetHost` and its requirements. This plumbed well throughout the WASIp3 work and the signatures for concurrent functions felt much more appropriate in terms of complexity after this change. Taking this change to the limit means that `GetHost` in its entirety could be purged since all usages of it could be replaced with `fn(&mut T) -> D::Data<'a>`, a hopefully much more understandable type. This change is not all rainbows however, there are some gotchas that remain: * One is that all `add_to_linker` generated functions have a `D: HasData` type parameter. This type parameter cannot be inferred and must always be explicitly specified, and it's not easy to know what to supply here without reading documentation. Actually supplying the type parameter is quite easy once you know what to do (and what to fill in), but it may involve defining a small struct with a custom `HasData` implementation which can be non-obvious. * Another is that the `G: GetHost` value was previously a full Rust closure, but now it's transitioning to a function pointer. This is done in preparation for WASIp3 work where the function needs to be passed around, and doing that behind a generic parameter is more effort than it's worth. This means that embedders relying on the true closure-like nature here will have to update to using a function pointer instead. * The function pointer is stored in locations that require `'static`, and while `fn(T)` might be expected to be `'static` regardless of `T` is is, in fact, not. This means that practically `add_to_linker` requires `T: 'static`. Relative to just before this change this is a possible regression in functionality, but there orthogonal reasons beyond just this that we want to start requiring `T: 'static` anyway. That means that this isn't actually a regression relative to bytecodealliance#10760, a related change. The first point is partially ameliorated with WASIp3 work insofar that the `D` type parameter will start serving as a location to specify where concurrent implementations are found. These concurrent methods don't take `&mut self` but instead are implemented for `T: HasData` types. In that sense it's more justified to have this weird type parameter, but in the meantime without this support it'll feel a bit odd to have this little type parameter hanging off the side. This change has been integrated into the WASIp3 prototyping repository with success. This has additionally been integrated into the Spin embedding which has one of the more complicated reliances on `*_get_host` functions known. Given that it's expected that while this is not necessarily a trivial change to rebase over it should at least be possible. Finally the `HasData` trait here has been included with what I'm hoping is a sufficient amount of documentation to at least give folks a spring board to understand it. If folks have confusion about this `D` type parameter my hope is they'll make their way to `HasData` which showcases various patterns for "librarifying" host implementations of WIT interfaces. These patterns are all used throughout Wasmtime and WASI currently in crates and tests and such.
1 parent f81c0dc commit 7974198

File tree

21 files changed

+646
-583
lines changed

21 files changed

+646
-583
lines changed

Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/component-macro/tests/codegen.rs

+9-8
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,15 @@ macro_rules! gentest {
1212
async: true,
1313
});
1414
}
15-
mod concurrent {
16-
wasmtime::component::bindgen!({
17-
path: $path,
18-
async: true,
19-
concurrent_imports: true,
20-
concurrent_exports: true,
21-
});
22-
}
15+
// TODO: re-enable this when wasip3 is merged back into this repo
16+
// mod concurrent {
17+
// wasmtime::component::bindgen!({
18+
// path: $path,
19+
// async: true,
20+
// concurrent_imports: true,
21+
// concurrent_exports: true,
22+
// });
23+
// }
2324
mod tracing {
2425
wasmtime::component::bindgen!({
2526
path: $path,

crates/component-macro/tests/expanded.rs

+8-7
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,14 @@ macro_rules! genexpand {
1515
stringify: true,
1616
}))?;
1717

18-
process_expanded($path, "_concurrent", wasmtime::component::bindgen!({
19-
path: $path,
20-
async: true,
21-
concurrent_imports: true,
22-
concurrent_exports: true,
23-
stringify: true,
24-
}))?;
18+
// TODO: re-enable this when wasip3 is merged back into this repo
19+
// process_expanded($path, "_concurrent", wasmtime::component::bindgen!({
20+
// path: $path,
21+
// async: true,
22+
// concurrent_imports: true,
23+
// concurrent_exports: true,
24+
// stringify: true,
25+
// }))?;
2526

2627
process_expanded($path, "_tracing_async", wasmtime::component::bindgen!({
2728
path: $path,

crates/wasi-config/src/lib.rs

+10-3
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969

7070
use anyhow::Result;
7171
use std::collections::HashMap;
72+
use wasmtime::component::HasData;
7273

7374
mod gen_ {
7475
wasmtime::component::bindgen!({
@@ -140,10 +141,16 @@ impl generated::Host for WasiConfig<'_> {
140141
}
141142

142143
/// Add all the `wasi-config` world's interfaces to a [`wasmtime::component::Linker`].
143-
pub fn add_to_linker<T>(
144+
pub fn add_to_linker<T: 'static>(
144145
l: &mut wasmtime::component::Linker<T>,
145-
f: impl Fn(&mut T) -> WasiConfig<'_> + Send + Sync + Copy + 'static,
146+
f: fn(&mut T) -> WasiConfig<'_>,
146147
) -> Result<()> {
147-
generated::add_to_linker_get_host(l, f)?;
148+
generated::add_to_linker::<T, HasWasiConfig>(l, f)?;
148149
Ok(())
149150
}
151+
152+
struct HasWasiConfig;
153+
154+
impl HasData for HasWasiConfig {
155+
type Data<'a> = WasiConfig<'a>;
156+
}

crates/wasi-http/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ http-body = { workspace = true }
2727
http-body-util = { workspace = true }
2828
tracing = { workspace = true }
2929
wasmtime-wasi = { workspace = true }
30+
wasmtime-wasi-io = { workspace = true }
3031
wasmtime = { workspace = true, features = ['component-model'] }
3132
tokio-rustls = { workspace = true }
3233
rustls = { workspace = true }

crates/wasi-http/src/lib.rs

+27-69
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,9 @@ pub use crate::types::{
236236
WasiHttpCtx, WasiHttpImpl, WasiHttpView, DEFAULT_OUTGOING_BODY_BUFFER_CHUNKS,
237237
DEFAULT_OUTGOING_BODY_CHUNK_SIZE,
238238
};
239+
use wasmtime::component::{HasData, Linker};
239240
use wasmtime_wasi::p2::IoImpl;
241+
240242
/// Add all of the `wasi:http/proxy` world's interfaces to a [`wasmtime::component::Linker`].
241243
///
242244
/// This function will add the `async` variant of all interfaces into the
@@ -284,46 +286,12 @@ use wasmtime_wasi::p2::IoImpl;
284286
/// ```
285287
pub fn add_to_linker_async<T>(l: &mut wasmtime::component::Linker<T>) -> anyhow::Result<()>
286288
where
287-
T: WasiHttpView + wasmtime_wasi::p2::WasiView,
289+
T: WasiHttpView + wasmtime_wasi::p2::WasiView + 'static,
288290
{
289-
let io_closure = type_annotate_io::<T, _>(|t| wasmtime_wasi::p2::IoImpl(t));
290-
wasmtime_wasi::p2::bindings::io::poll::add_to_linker_get_host(l, io_closure)?;
291-
wasmtime_wasi::p2::bindings::io::error::add_to_linker_get_host(l, io_closure)?;
292-
wasmtime_wasi::p2::bindings::io::streams::add_to_linker_get_host(l, io_closure)?;
293-
294-
let closure =
295-
type_annotate_wasi::<T, _>(|t| wasmtime_wasi::p2::WasiImpl(wasmtime_wasi::p2::IoImpl(t)));
296-
wasmtime_wasi::p2::bindings::clocks::wall_clock::add_to_linker_get_host(l, closure)?;
297-
wasmtime_wasi::p2::bindings::clocks::monotonic_clock::add_to_linker_get_host(l, closure)?;
298-
wasmtime_wasi::p2::bindings::cli::stdin::add_to_linker_get_host(l, closure)?;
299-
wasmtime_wasi::p2::bindings::cli::stdout::add_to_linker_get_host(l, closure)?;
300-
wasmtime_wasi::p2::bindings::cli::stderr::add_to_linker_get_host(l, closure)?;
301-
wasmtime_wasi::p2::bindings::random::random::add_to_linker_get_host(l, closure)?;
302-
291+
wasmtime_wasi::p2::add_to_linker_proxy_interfaces_async(l)?;
303292
add_only_http_to_linker_async(l)
304293
}
305294

306-
// NB: workaround some rustc inference - a future refactoring may make this
307-
// obsolete.
308-
fn type_annotate_http<T, F>(val: F) -> F
309-
where
310-
F: Fn(&mut T) -> WasiHttpImpl<&mut T>,
311-
{
312-
val
313-
}
314-
fn type_annotate_wasi<T, F>(val: F) -> F
315-
where
316-
F: Fn(&mut T) -> wasmtime_wasi::p2::WasiImpl<&mut T>,
317-
{
318-
val
319-
}
320-
fn type_annotate_io<T, F>(val: F) -> F
321-
where
322-
F: Fn(&mut T) -> wasmtime_wasi::p2::IoImpl<&mut T>,
323-
{
324-
val
325-
}
326-
327295
/// A slimmed down version of [`add_to_linker_async`] which only adds
328296
/// `wasi:http` interfaces to the linker.
329297
///
@@ -333,15 +301,22 @@ pub fn add_only_http_to_linker_async<T>(
333301
l: &mut wasmtime::component::Linker<T>,
334302
) -> anyhow::Result<()>
335303
where
336-
T: WasiHttpView,
304+
T: WasiHttpView + 'static,
337305
{
338-
let closure = type_annotate_http::<T, _>(|t| WasiHttpImpl(IoImpl(t)));
339-
crate::bindings::http::outgoing_handler::add_to_linker_get_host(l, closure)?;
340-
crate::bindings::http::types::add_to_linker_get_host(l, closure)?;
306+
crate::bindings::http::outgoing_handler::add_to_linker::<_, WasiHttp<T>>(l, |x| {
307+
WasiHttpImpl(IoImpl(x))
308+
})?;
309+
crate::bindings::http::types::add_to_linker::<_, WasiHttp<T>>(l, |x| WasiHttpImpl(IoImpl(x)))?;
341310

342311
Ok(())
343312
}
344313

314+
struct WasiHttp<T>(T);
315+
316+
impl<T: 'static> HasData for WasiHttp<T> {
317+
type Data<'a> = WasiHttpImpl<&'a mut T>;
318+
}
319+
345320
/// Add all of the `wasi:http/proxy` world's interfaces to a [`wasmtime::component::Linker`].
346321
///
347322
/// This function will add the `sync` variant of all interfaces into the
@@ -382,46 +357,29 @@ where
382357
/// fn ctx(&mut self) -> &mut WasiCtx { &mut self.ctx }
383358
/// }
384359
/// ```
385-
pub fn add_to_linker_sync<T>(l: &mut wasmtime::component::Linker<T>) -> anyhow::Result<()>
360+
pub fn add_to_linker_sync<T>(l: &mut Linker<T>) -> anyhow::Result<()>
386361
where
387-
T: WasiHttpView + wasmtime_wasi::p2::WasiView,
362+
T: WasiHttpView + wasmtime_wasi::p2::WasiView + 'static,
388363
{
389-
let io_closure = type_annotate_io::<T, _>(|t| wasmtime_wasi::p2::IoImpl(t));
390-
// For the sync linker, use the definitions of poll and streams from the
391-
// wasmtime_wasi::p2::bindings::sync space because those are defined using in_tokio.
392-
wasmtime_wasi::p2::bindings::sync::io::poll::add_to_linker_get_host(l, io_closure)?;
393-
wasmtime_wasi::p2::bindings::sync::io::streams::add_to_linker_get_host(l, io_closure)?;
394-
// The error interface in the wasmtime_wasi is synchronous
395-
wasmtime_wasi::p2::bindings::io::error::add_to_linker_get_host(l, io_closure)?;
396-
397-
let closure =
398-
type_annotate_wasi::<T, _>(|t| wasmtime_wasi::p2::WasiImpl(wasmtime_wasi::p2::IoImpl(t)));
399-
400-
wasmtime_wasi::p2::bindings::clocks::wall_clock::add_to_linker_get_host(l, closure)?;
401-
wasmtime_wasi::p2::bindings::clocks::monotonic_clock::add_to_linker_get_host(l, closure)?;
402-
wasmtime_wasi::p2::bindings::cli::stdin::add_to_linker_get_host(l, closure)?;
403-
wasmtime_wasi::p2::bindings::cli::stdout::add_to_linker_get_host(l, closure)?;
404-
wasmtime_wasi::p2::bindings::cli::stderr::add_to_linker_get_host(l, closure)?;
405-
wasmtime_wasi::p2::bindings::random::random::add_to_linker_get_host(l, closure)?;
406-
407-
add_only_http_to_linker_sync(l)?;
408-
409-
Ok(())
364+
wasmtime_wasi::p2::add_to_linker_proxy_interfaces_sync(l)?;
365+
add_only_http_to_linker_sync(l)
410366
}
411367

412368
/// A slimmed down version of [`add_to_linker_sync`] which only adds
413369
/// `wasi:http` interfaces to the linker.
414370
///
415371
/// This is useful when using [`wasmtime_wasi::p2::add_to_linker_sync`] for
416372
/// example to avoid re-adding the same interfaces twice.
417-
pub fn add_only_http_to_linker_sync<T>(l: &mut wasmtime::component::Linker<T>) -> anyhow::Result<()>
373+
pub fn add_only_http_to_linker_sync<T>(l: &mut Linker<T>) -> anyhow::Result<()>
418374
where
419-
T: WasiHttpView,
375+
T: WasiHttpView + 'static,
420376
{
421-
let closure = type_annotate_http::<T, _>(|t| WasiHttpImpl(IoImpl(t)));
422-
423-
crate::bindings::http::outgoing_handler::add_to_linker_get_host(l, closure)?;
424-
crate::bindings::http::types::add_to_linker_get_host(l, closure)?;
377+
crate::bindings::sync::http::outgoing_handler::add_to_linker::<_, WasiHttp<T>>(l, |x| {
378+
WasiHttpImpl(IoImpl(x))
379+
})?;
380+
crate::bindings::sync::http::types::add_to_linker::<_, WasiHttp<T>>(l, |x| {
381+
WasiHttpImpl(IoImpl(x))
382+
})?;
425383

426384
Ok(())
427385
}

crates/wasi-io/src/lib.rs

+9-13
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ pub use async_trait::async_trait;
3636
pub use ::bytes;
3737

3838
use alloc::boxed::Box;
39-
use wasmtime::component::ResourceTable;
39+
use wasmtime::component::{HasData, ResourceTable};
4040

4141
/// A trait which provides access to the [`ResourceTable`] inside the
4242
/// embedder's `T` of [`Store<T>`][`Store`].
@@ -168,21 +168,17 @@ impl<T: IoView> IoView for IoImpl<T> {
168168
/// fn table(&mut self) -> &mut ResourceTable { &mut self.table }
169169
/// }
170170
/// ```
171-
pub fn add_to_linker_async<T: IoView>(
171+
pub fn add_to_linker_async<T: IoView + 'static>(
172172
l: &mut wasmtime::component::Linker<T>,
173173
) -> wasmtime::Result<()> {
174-
let closure = io_type_annotate::<T, _>(|t| IoImpl(t));
175-
crate::bindings::wasi::io::error::add_to_linker_get_host(l, closure)?;
176-
crate::bindings::wasi::io::poll::add_to_linker_get_host(l, closure)?;
177-
crate::bindings::wasi::io::streams::add_to_linker_get_host(l, closure)?;
174+
crate::bindings::wasi::io::error::add_to_linker::<T, HasIo<T>>(l, |x| IoImpl(x))?;
175+
crate::bindings::wasi::io::poll::add_to_linker::<T, HasIo<T>>(l, |x| IoImpl(x))?;
176+
crate::bindings::wasi::io::streams::add_to_linker::<T, HasIo<T>>(l, |x| IoImpl(x))?;
178177
Ok(())
179178
}
180179

181-
// NB: workaround some rustc inference - a future refactoring may make this
182-
// obsolete.
183-
fn io_type_annotate<T: IoView, F>(val: F) -> F
184-
where
185-
F: Fn(&mut T) -> IoImpl<&mut T>,
186-
{
187-
val
180+
struct HasIo<T>(T);
181+
182+
impl<T: 'static> HasData for HasIo<T> {
183+
type Data<'a> = IoImpl<&'a mut T>;
188184
}

crates/wasi-keyvalue/src/lib.rs

+12-6
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ mod generated {
8484
use self::generated::wasi::keyvalue;
8585
use anyhow::Result;
8686
use std::collections::HashMap;
87-
use wasmtime::component::{Resource, ResourceTable, ResourceTableError};
87+
use wasmtime::component::{HasData, Resource, ResourceTable, ResourceTableError};
8888

8989
#[doc(hidden)]
9090
pub enum Error {
@@ -288,12 +288,18 @@ impl keyvalue::batch::Host for WasiKeyValue<'_> {
288288
}
289289

290290
/// Add all the `wasi-keyvalue` world's interfaces to a [`wasmtime::component::Linker`].
291-
pub fn add_to_linker<T: Send>(
291+
pub fn add_to_linker<T: Send + 'static>(
292292
l: &mut wasmtime::component::Linker<T>,
293-
f: impl Fn(&mut T) -> WasiKeyValue<'_> + Send + Sync + Copy + 'static,
293+
f: fn(&mut T) -> WasiKeyValue<'_>,
294294
) -> Result<()> {
295-
keyvalue::store::add_to_linker_get_host(l, f)?;
296-
keyvalue::atomics::add_to_linker_get_host(l, f)?;
297-
keyvalue::batch::add_to_linker_get_host(l, f)?;
295+
keyvalue::store::add_to_linker::<_, HasWasiKeyValue>(l, f)?;
296+
keyvalue::atomics::add_to_linker::<_, HasWasiKeyValue>(l, f)?;
297+
keyvalue::batch::add_to_linker::<_, HasWasiKeyValue>(l, f)?;
298298
Ok(())
299299
}
300+
301+
struct HasWasiKeyValue;
302+
303+
impl HasData for HasWasiKeyValue {
304+
type Data<'a> = WasiKeyValue<'a>;
305+
}

crates/wasi-nn/src/wit.rs

+13-7
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use anyhow::anyhow;
2121
use std::collections::HashMap;
2222
use std::hash::Hash;
2323
use std::{fmt, str::FromStr};
24-
use wasmtime::component::{Resource, ResourceTable};
24+
use wasmtime::component::{HasData, Resource, ResourceTable};
2525

2626
/// Capture the state necessary for calling into the backend ML libraries.
2727
pub struct WasiNnCtx {
@@ -150,17 +150,23 @@ pub use generated_::Ml as ML;
150150

151151
/// Add the WIT-based version of the `wasi-nn` API to a
152152
/// [`wasmtime::component::Linker`].
153-
pub fn add_to_linker<T>(
153+
pub fn add_to_linker<T: 'static>(
154154
l: &mut wasmtime::component::Linker<T>,
155-
f: impl Fn(&mut T) -> WasiNnView<'_> + Send + Sync + Copy + 'static,
155+
f: fn(&mut T) -> WasiNnView<'_>,
156156
) -> anyhow::Result<()> {
157-
generated::graph::add_to_linker_get_host(l, f)?;
158-
generated::tensor::add_to_linker_get_host(l, f)?;
159-
generated::inference::add_to_linker_get_host(l, f)?;
160-
generated::errors::add_to_linker_get_host(l, f)?;
157+
generated::graph::add_to_linker::<_, HasWasiNnView>(l, f)?;
158+
generated::tensor::add_to_linker::<_, HasWasiNnView>(l, f)?;
159+
generated::inference::add_to_linker::<_, HasWasiNnView>(l, f)?;
160+
generated::errors::add_to_linker::<_, HasWasiNnView>(l, f)?;
161161
Ok(())
162162
}
163163

164+
struct HasWasiNnView;
165+
166+
impl HasData for HasWasiNnView {
167+
type Data<'a> = WasiNnView<'a>;
168+
}
169+
164170
impl generated::graph::Host for WasiNnView<'_> {
165171
fn load(
166172
&mut self,

crates/wasi-tls/src/lib.rs

+10-4
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ use std::{future::Future, mem, pin::Pin, sync::LazyLock};
8181
use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt};
8282
use tokio::sync::Mutex;
8383
use tokio_rustls::client::TlsStream;
84-
use wasmtime::component::{Resource, ResourceTable};
84+
use wasmtime::component::{HasData, Resource, ResourceTable};
8585
use wasmtime_wasi::async_trait;
8686
use wasmtime_wasi::p2::bindings::io::{
8787
error::Error as HostIoError,
@@ -139,15 +139,21 @@ impl<'a> WasiTlsCtx<'a> {
139139
impl<'a> generated::types::Host for WasiTlsCtx<'a> {}
140140

141141
/// Add the `wasi-tls` world's types to a [`wasmtime::component::Linker`].
142-
pub fn add_to_linker<T: Send>(
142+
pub fn add_to_linker<T: Send + 'static>(
143143
l: &mut wasmtime::component::Linker<T>,
144144
opts: &mut LinkOptions,
145-
f: impl Fn(&mut T) -> WasiTlsCtx + Send + Sync + Copy + 'static,
145+
f: fn(&mut T) -> WasiTlsCtx<'_>,
146146
) -> Result<()> {
147-
generated::types::add_to_linker_get_host(l, &opts, f)?;
147+
generated::types::add_to_linker::<_, WasiTls>(l, &opts, f)?;
148148
Ok(())
149149
}
150150

151+
struct WasiTls;
152+
153+
impl HasData for WasiTls {
154+
type Data<'a> = WasiTlsCtx<'a>;
155+
}
156+
151157
enum TlsError {
152158
/// The component should trap. Under normal circumstances, this only occurs
153159
/// when the underlying transport stream returns [`StreamError::Trap`].

0 commit comments

Comments
 (0)