I ran into an issue where implementing impl<T: WasiNnView> gen::tensor::HostTensor for T returned the following error:
error[E0119]: conflicting implementations of trait `HostTensor` for type `&mut _`
--> crates/wasi-nn/src/wit.rs:26:5
|
26 | / wasmtime::component::bindgen!({
27 | | world: "ml",
28 | | path: "wit/wasi-nn.wit",
29 | | trappable_imports: true,
30 | | });
| |______^ conflicting implementation for `&mut _`
...
265 | impl<T: WasiNnView> gen::tensor::HostTensor for T {
| ------------------------------------------------- first implementation here
|
= note: this error originates in the macro `wasmtime::component::bindgen` (in Nightly builds, run with -Z macro-backtrace for more info)
This is only a problem now that I started using resources in the WIT file. I noticed that wasmtime-wasi-http goes about this with a wrapper struct so I decided to add the following:
pub struct WasiNnImpl<T>(pub T);
impl<T: WasiNnView> gen::tensor::HostTensor for WasiNnImpl<T> { ... }
Is this the right approach? I don't seem to see the same kind of wrapping in wasmtime-wasi–how come?
cc: @Pat Hickey?
If you can avoid it I'd skip WasiNnView entirely
For resources, if you can get away with it, I might recommend:
pub struct WasiNnView<'a> {
pub table: &'a mut ResourceTable,
}
impl gen::tensor::HostTensor for WasiNnView<'_> { /* ... */ }
hm...
(sorry editing the message above)
and then add_to_linker would look like:
fn add_to_linker<T>(linker: &mut Linker<T>, f: fn(&mut T) -> WasiNnView<'_>) { /* ... */ }
for wasmtime-wasi we can in theory do this
Why do I see views in wasmtime-wasi and wasmtime-wasi-http?
but wasmtime-wasi-http we can't do this naively because it has customization hooks via a trait
so if you want customization hooks for wasi-nn eventually on the embedder size you can go the route of a WasiNnView trait
but if you don't know of any right now it's much easier to stick with concrete types/structures
what type of customization hooks does wasi-http need? where can I look at that?
oh, like each embedder of Wasmtime may want to "do special stuff" for each HTTP request so they provide their own implementation of WasiHttpView?
for wasi:http it's primarily send_request
it's basically which layer of abstraction you want to work at
so for example embedders can implement all the wasi traits themselves whenver they want
that's a bit of a big task though so ideally you want to use wasmtime-wasi
but then often embedders want to customize just a few things here and there
for some requests we can do that via WasiCtx and various configuration variables in there
but for other cases you want a full-blown host-defined callback
but for callbacks it's a question of how do you close over the interesting state, and threading &mut T from Store<T> isn't viable here
so the next best thing we've "figured out" is trait FooView
where the implementation of FooView has whatever state it needs and the callbacks are trait methods
overall it's not a great design but IMO it's the best we've got so far and it's a reflection of a tricky problem space
ok, I see what you mean; it seems like the approach should be "start with the concrete type" and eventually--and only if needed--"refactor with a view trait"
Yeah if that works it's the path I'd recommend, dealing with blanket impls and extra customization generally leads to headaches
Oh, I realized there might be another reason for creating a WasiNnView other than customizability. For wasmtime run and wasmtime serve, we end up creating a struct Host with a single ResourceTable to be shared between all the WASI proposals that are enabled at the time. In that case, we _do_ end up needing a bridge to the shared table and the current approach is via *View traits from each proposal. I think I do need to implement WasiNnView then, right?
Not necessarily, that's the 'a in WasiNnView<'a> above, you wouldn't actually store WasiNnView anywhere but it'd only be created as a temporary in a closure
but it'd borrow a ResourceTable from elsewhere
ah, ok!
Last updated: Dec 06 2025 at 06:05 UTC