Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement ResourceAny -> Resource<T> conversion #7712

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions crates/wasmtime/src/component/resources.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Self> {
let store = store.as_context_mut();
let store_id = store.0.id();
let mut tables = host_resource_tables(store.0);
assert_eq!(ty, ResourceType::host::<T>(), "resource type mismatch");
let (state, rep) = if let Some(OwnState { store, dtor, flags }) = own_state {
assert_eq!(store_id, store, "wrong store used to convert resource");
assert!(dtor.is_some(), "destructor must be set");
assert!(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<U>(
self,
Expand Down Expand Up @@ -568,6 +594,11 @@ impl ResourceAny {
})
}

/// See [`Resource::try_from_resource_any`]
pub fn try_into_resource<T: 'static>(self, store: impl AsContextMut) -> Result<Resource<T>> {
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.
///
Expand Down
38 changes: 36 additions & 2 deletions tests/all/component_model/resources.rs
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,15 @@ fn dynamic_val() -> Result<()> {
match &results[0] {
Val::Resource(resource) => {
assert_eq!(resource.ty(), ResourceType::host::<MyType>());
assert!(resource.owned());

let resource = resource.try_into_resource::<MyType>(&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::<MyType>());
assert!(resource.owned());
}
_ => unreachable!(),
}
Expand All @@ -593,21 +602,46 @@ fn dynamic_val() -> Result<()> {
match &results[0] {
Val::Resource(resource) => {
assert_eq!(resource.ty(), ResourceType::host::<MyType>());
assert!(resource.owned());

let resource = resource.try_into_resource::<MyType>(&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::<MyType>());
assert!(resource.owned());
}
_ => unreachable!(),
}

let t1 = Resource::new_own(100);
let t1 = Resource::<MyType>::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::<MyType>(&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::<MyType>());
assert!(resource.owned());

let resource = resource.try_into_resource::<MyType>(&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::<MyType>());
assert!(resource.owned());
}
_ => unreachable!(),
}
Expand Down