Skip to content

Commit 5f90361

Browse files
authored
add Resource::take method to wit_bindgen::rt (#753)
* add `Resource::take` method to `wit_bindgen::rt` This allows the guest to take back ownership of an exported resource from the host; you can think of it as the reverse of `Resource::new`. It's a bit awkward to do this for the time being; WebAssembly/component-model#238 will improve the situation if accepted. Signed-off-by: Joel Dice <[email protected]> * address review feedback - add `type RawRep<T> = Option<T>` alias - rename `Resource::take` to `Resource::into_inner` - add `Resource::lift_borrow` and use it in code generator Signed-off-by: Joel Dice <[email protected]> --------- Signed-off-by: Joel Dice <[email protected]>
1 parent f30e6ac commit 5f90361

File tree

7 files changed

+99
-5
lines changed

7 files changed

+99
-5
lines changed

crates/guest-rust/src/lib.rs

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,8 @@ pub mod rt {
172172
}
173173
}
174174

175+
type RawRep<T> = Option<T>;
176+
175177
/// A type which represents a component model resource, either imported or
176178
/// exported into this component.
177179
///
@@ -238,7 +240,7 @@ impl<T: WasmResource> Resource<T> {
238240
where
239241
T: RustResource,
240242
{
241-
let rep = Box::into_raw(Box::new(val)) as usize;
243+
let rep = Box::into_raw(Box::new(Some(val))) as usize;
242244
unsafe {
243245
let handle = T::new(rep);
244246
Resource::from_handle(handle)
@@ -250,7 +252,26 @@ impl<T: WasmResource> Resource<T> {
250252
where
251253
T: RustResource,
252254
{
253-
let _ = Box::from_raw(rep as *mut T);
255+
let _ = Box::from_raw(rep as *mut RawRep<T>);
256+
}
257+
258+
/// Takes back ownership of the object, dropping the resource handle.
259+
pub fn into_inner(resource: Self) -> T
260+
where
261+
T: RustResource,
262+
{
263+
unsafe {
264+
let rep = T::rep(resource.handle);
265+
RawRep::take(&mut *(rep as *mut RawRep<T>)).unwrap()
266+
}
267+
}
268+
269+
#[doc(hidden)]
270+
pub unsafe fn lift_borrow<'a>(rep: usize) -> &'a T
271+
where
272+
T: RustResource,
273+
{
274+
RawRep::as_ref(&*(rep as *const RawRep<T>)).unwrap()
254275
}
255276
}
256277

@@ -260,7 +281,7 @@ impl<T: RustResource> Deref for Resource<T> {
260281
fn deref(&self) -> &T {
261282
unsafe {
262283
let rep = T::rep(self.handle);
263-
&*(rep as *const T)
284+
RawRep::as_ref(&*(rep as *const RawRep<T>)).unwrap()
264285
}
265286
}
266287
}
@@ -269,7 +290,7 @@ impl<T: RustResource> DerefMut for Resource<T> {
269290
fn deref_mut(&mut self) -> &mut T {
270291
unsafe {
271292
let rep = T::rep(self.handle);
272-
&mut *(rep as *mut T)
293+
RawRep::as_mut(&mut *(rep as *mut RawRep<T>)).unwrap()
273294
}
274295
}
275296
}

crates/rust/src/bindgen.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,10 @@ impl Bindgen for FunctionBindgen<'_, '_> {
443443
.as_deref()
444444
.unwrap()
445445
.to_upper_camel_case();
446-
format!("&*({op} as u32 as usize as *const {name})")
446+
let rt = self.gen.gen.runtime_path();
447+
format!(
448+
"{rt}::Resource::<{name}>::lift_borrow({op} as u32 as usize)"
449+
)
447450
}
448451
Handle::Own(_) => {
449452
let name = self.gen.type_path(resource, true);
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
include!("../../../../tests/runtime/resource_into_inner/wasm.rs");
2+
3+
fn main() {}

tests/runtime/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ mod resource_borrow_import;
2727
mod resource_borrow_in_record;
2828
mod resource_floats;
2929
mod resource_import_and_export;
30+
mod resource_into_inner;
3031
mod resource_with_lists;
3132
mod resources;
3233
mod smoke;

tests/runtime/resource_into_inner.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
use wasmtime::Store;
2+
3+
wasmtime::component::bindgen!(in "tests/runtime/resource_into_inner");
4+
5+
use exports::test::resource_into_inner::test::Test;
6+
7+
#[test]
8+
fn run() -> anyhow::Result<()> {
9+
crate::run_test(
10+
"resource_into_inner",
11+
|_| Ok(()),
12+
|store, component, linker| {
13+
let (u, e) = ResourceIntoInner::instantiate(store, component, linker)?;
14+
Ok((u.interface0, e))
15+
},
16+
run_test,
17+
)
18+
}
19+
20+
fn run_test(instance: Test, store: &mut Store<crate::Wasi<()>>) -> anyhow::Result<()> {
21+
instance.call_test(&mut *store)
22+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
wit_bindgen::generate!({
2+
path: "../../tests/runtime/resource_into_inner",
3+
exports: {
4+
world: Test,
5+
"test:resource-into-inner/test": Test,
6+
"test:resource-into-inner/test/thing": MyThing,
7+
},
8+
});
9+
10+
use exports::test::resource_into_inner::test::{Guest, GuestThing};
11+
use wit_bindgen::rt::Resource;
12+
13+
pub struct Test;
14+
15+
impl Guest for Test {
16+
fn test() {
17+
let text = "Jabberwocky";
18+
assert_eq!(
19+
text,
20+
&Resource::into_inner(Resource::new(MyThing(text.to_string()))).0
21+
);
22+
}
23+
}
24+
25+
pub struct MyThing(String);
26+
27+
impl GuestThing for MyThing {
28+
fn new(text: String) -> Self {
29+
Self(text)
30+
}
31+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package test:resource-into-inner;
2+
3+
interface test {
4+
resource thing {
5+
constructor(text: string);
6+
}
7+
8+
test: func();
9+
}
10+
11+
world resource-into-inner {
12+
export test;
13+
}

0 commit comments

Comments
 (0)