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 23 2024 at 12:05 UTC