diff --git a/crates/wasmtime/src/component/resources.rs b/crates/wasmtime/src/component/resources.rs index 400583d3525d..a8cad7a8308b 100644 --- a/crates/wasmtime/src/component/resources.rs +++ b/crates/wasmtime/src/component/resources.rs @@ -397,6 +397,32 @@ where }) } + /// Attempts to convert a [`ResourceAny`] into [`Resource`]. + pub fn try_from_resource_any( + ResourceAny { idx, ty, own_state }: ResourceAny, + mut store: impl AsContextMut, + ) -> Result { + let store = store.as_context_mut(); + let store_id = store.0.id(); + let mut tables = host_resource_tables(store.0); + ensure!(ty == ResourceType::host::(), "resource type mismatch"); + let (state, rep) = if let Some(OwnState { store, dtor, flags }) = own_state { + ensure!(store_id == store, "wrong store used to convert resource"); + ensure!(dtor.is_some(), "destructor must be set"); + ensure!(flags.is_none(), "flags must not be set"); + let rep = tables.resource_lift_own(None, idx)?; + (AtomicU32::new(NOT_IN_TABLE), rep) + } else { + let rep = tables.resource_lift_borrow(None, idx)?; + (AtomicU32::new(BORROW), rep) + }; + Ok(Resource { + state, + rep, + _marker: marker::PhantomData, + }) + } + /// See [`ResourceAny::try_from_resource`] pub fn try_into_resource_any( self, @@ -566,6 +592,11 @@ impl ResourceAny { }) } + /// See [`Resource::try_from_resource_any`] + pub fn try_into_resource(self, store: impl AsContextMut) -> Result> { + Resource::try_from_resource_any(self, store) + } + /// Returns the corresponding type associated with this resource, either a /// host-defined type or a guest-defined type. /// diff --git a/tests/all/component_model/resources.rs b/tests/all/component_model/resources.rs index 2787d4cedd53..448eceecf7ad 100644 --- a/tests/all/component_model/resources.rs +++ b/tests/all/component_model/resources.rs @@ -582,6 +582,15 @@ fn dynamic_val() -> Result<()> { match &results[0] { Val::Resource(resource) => { assert_eq!(resource.ty(), ResourceType::host::()); + assert!(resource.owned()); + + let resource = resource.try_into_resource::(&mut store)?; + assert_eq!(resource.rep(), 100); + assert!(resource.owned()); + + let resource = resource.try_into_resource_any(&mut store, &i_pre, idx)?; + assert_eq!(resource.ty(), ResourceType::host::()); + assert!(resource.owned()); } _ => unreachable!(), } @@ -593,21 +602,46 @@ fn dynamic_val() -> Result<()> { match &results[0] { Val::Resource(resource) => { assert_eq!(resource.ty(), ResourceType::host::()); + assert!(resource.owned()); + + let resource = resource.try_into_resource::(&mut store)?; + assert_eq!(resource.rep(), 100); + assert!(resource.owned()); + + let resource = resource.try_into_resource_any(&mut store, &i_pre, idx)?; + assert_eq!(resource.ty(), ResourceType::host::()); + assert!(resource.owned()); } _ => unreachable!(), } - let t1 = Resource::new_own(100); + let t1 = Resource::::new_own(100) + .try_into_resource_any(&mut store, &i_pre, idx)? + .try_into_resource(&mut store)?; let (t1,) = a_typed_result.call(&mut store, (t1,))?; a_typed_result.post_return(&mut store)?; + assert_eq!(t1.rep(), 100); + assert!(t1.owned()); - let t1_any = t1.try_into_resource_any(&mut store, &i_pre, idx)?; + let t1_any = t1 + .try_into_resource_any(&mut store, &i_pre, idx)? + .try_into_resource::(&mut store)? + .try_into_resource_any(&mut store, &i_pre, idx)?; let mut results = [Val::Bool(false)]; a.call(&mut store, &[Val::Resource(t1_any)], &mut results)?; a.post_return(&mut store)?; match &results[0] { Val::Resource(resource) => { assert_eq!(resource.ty(), ResourceType::host::()); + assert!(resource.owned()); + + let resource = resource.try_into_resource::(&mut store)?; + assert_eq!(resource.rep(), 100); + assert!(resource.owned()); + + let resource = resource.try_into_resource_any(&mut store, &i_pre, idx)?; + assert_eq!(resource.ty(), ResourceType::host::()); + assert!(resource.owned()); } _ => unreachable!(), }