Are there any examples of implementing a WIT Resource in the host other than at https://component-model.bytecodealliance.org/ ?
I'm trying to have a go but I have got stuck.
I have a Guest function like this:
before-add-note: func(note: borrow<note>);
and a function in my rust based Host application like this:
fn before_add_note(&mut self, note: &mut Note)
N.B. note
must be a ref in the rust function, I cannot change this to an Arc
etc.
Ideally I would like to be able to do something like this:
fn before_add_note(&mut self, note: &mut Note) {
self.wasm_component
.my_component_interface()
.call_before_add_note(&mut self.wasm_store, &mut note)
.unwrap();
}
I understand that this is not possible as shown because note
needs to be transformed into a handle for the wasm component to use.
Unfortunately I cannot see how I could put &mut note
into a ResourceTable
without causing issues with lifetimes.
I guess this leaves me with the less ideal solution of cloning note
so that I can put it into a ResourceTable
, then copying it back later.
Something like this:
fn before_add_note(&mut self, note: &mut Note) {
let note_resource = self.wasm_store.data_mut().resource_table.push(note.clone()).unwrap();
self.wasm_component
.my_component_interface()
.call_before_add_note(&mut self.wasm_store, note_resource)
.unwrap();
*note = self.wasm_store.data_mut().resource_table.delete(note_resource).unwrap();
}
But this does not work either.
Resource<T>
is not Copy
or Clone
and the generated call_before_add_note
wants note: Resource<Note>
.
This means resource
is moved when I call call_before_add_note
and I cannot use it with ResourceTable::delete
later.
I am not sure what I am meant to be doing at this point.
This sounds more specific than being solved by a simple example, but have you seen https://github.com/cpetig/resource-demo/blob/main/host-wasmtime/src/main.rs ?
I tested resources on both sides in this repo. Another option could be the runtime tests in wit-bindgen, https://github.com/bytecodealliance/wit-bindgen/blob/main/tests/runtime/resource_import_and_export.rs
Also we use resources in veloren plugins, https://gitlab.com/veloren/veloren/-/blob/master/common/state/src/plugin/module.rs?ref_type=heads but I think they are mostly guest side.
Perhaps these examples already help, otherwise I will need to take a thorough read of your problem statement above (after work).
I hope, ResourceTable as shown in the first link combined with Arc will solve your problem.
Thanks for the links, I'll have a look.
I assume I'm missing something pretty basic because I currently cannot see how the Host can maintain ownership of any Resources.
I've had a look at those links but I still cannot see the correct way of doing it.
If I wrapped the cloned Note
in an Arc
before pushing it into the ResourceTable
I would be able access to the Note
through the Arc
later, but it would still be stuck in the ResourceTable
forever.
I would not be able to call ResourceTable::delete
to clean up because note_resource
will have been moved.
I made a minimal example of what I am trying to do:
https://github.com/rbrownwsws/wit-host-resources
You can run it with:
cd <repo_root>/guest
cargo component build --release
cd <repo_root>/host
cargo run
I also realised wrapping Note
in Arc
would not work because the generated call_before_add_note
only accepts Resource<Note>
, not Resource<Arc<Note>>
.
Currently Wasmtime's documentation is a bit light on examples: this being the main one for host resources.
For this comment though I think the answer is you can use Resource::new_borrow
to pass to the function above. In general I think it's a mistake that Wasmtime doesn't have Clone for Resource<T>
. I originally thought that was a bad idea but I've come to think this is not the right conclusion any more.
In the wasmtime-wasi
crate we have an extension trait for doing this which you can copy to use locally as well if you'd like.
Thanks for the help @Alex Crichton, that works for me :smile:.
I found Resource::new_borrow
, but as I am not familiar with the internals of Wasmtime/ResourceTable
I was worried that manually creating one might break things in a non-obvious way.
In a future version of Wasmtime I think it would be nice to make it more obvious what the correct way is e.g.:
have a method like: Resource<T>::as_borrowed(&self) -> Resource<T>
similar to the native rust AsRef<T>::as_ref(&self) -> &T
.
alter bindgen!
so my_func: func(arg: borrow<my-type>)
generates fn call_my_func(&self, mut store: S, arg: &mut Resource<MyType>)
and calls Resource::new_borrow
for you under the hood.
have OwnedResource<T>
and BorrowedResource<T>
types with BorrowedResource
implementing Clone
/ Copy
Yeah threading the needle on these APIs has been really tricky. It's tough to capture all the nuance in Rust as it's not a 100% match to various Rust concepts despite being similar. Not to say the current API is the best by any means! At the very least I think adding .as_borrowed()
or similar is a great idea. The other ideas seem reasonable to me but would need some testing to see what it would be like to implement them.
Last updated: Dec 23 2024 at 13:07 UTC