Skip to main content

wasm_link/
resource_wrapper.rs

1use std::sync::Arc ;
2use thiserror::Error ;
3use wasmtime::component::{ Resource, ResourceAny, Val };
4use wasmtime::StoreContextMut ;
5
6use crate::PluginContext ;
7
8
9
10#[derive( Debug )]
11pub(crate) struct ResourceWrapper<Id> {
12	pub plugin_id: Id,
13	pub resource_handle: ResourceAny,
14}
15
16/// Errors that occur when creating a resource handle for cross-plugin transfer.
17///
18/// Resources are wrapped before being passed between plugins to track ownership.
19/// These errors indicate failures in that wrapping process.
20#[derive( Debug, Error )]
21pub enum ResourceCreationError {
22	/// The resource table has reached capacity and cannot store more handles.
23	#[error( "Resource Table Full" )] ResourceTableFull,
24	/// Failed to convert a stored resource into a host handle.
25	#[error( "Resource Handle Conversion Failed" )] ResourceHandleConversionFailed,
26}
27impl From<ResourceCreationError> for Val {
28	fn from( error: ResourceCreationError ) -> Self { match error {
29		ResourceCreationError::ResourceTableFull => Val::Variant( "resource-table-full".to_string(), None ),
30		ResourceCreationError::ResourceHandleConversionFailed => Val::Variant( "resource-handle-conversion-failed".to_string(), None ),
31	}}
32}
33
34/// Errors that occur when unwrapping a resource handle received from another plugin.
35///
36/// When a plugin receives a resource from another plugin, the handle must be
37/// looked up in the resource table to retrieve the original resource.
38/// These errors indicate failures in that lookup process.
39#[derive( Debug, Error )]
40pub enum ResourceReceiveError {
41	/// The handle doesn't correspond to any known resource (possibly already dropped or invalid).
42	#[error( "Invalid Handle" )] InvalidHandle,
43}
44impl From<ResourceReceiveError> for Val {
45	fn from( error: ResourceReceiveError ) -> Self { match error {
46		ResourceReceiveError::InvalidHandle => Val::Variant( "invalid-resource-handle".to_string(), None ),
47	}}
48}
49
50impl<Id: 'static + Send + Sync> ResourceWrapper<Id> {
51
52	/// Wraps a resource handle with the owning plugin's id.
53	pub(crate) fn new( plugin_id: Id, resource_handle: ResourceAny ) -> Self {
54		Self { plugin_id, resource_handle }
55	}
56
57	/// Stores the wrapped resource in the host table and returns a handle.
58	pub(crate) fn attach<Ctx: PluginContext>(
59		self,
60		store: &mut StoreContextMut<Ctx>,
61	) -> Result<ResourceAny, ResourceCreationError> {
62		let table = store.data_mut().resource_table();
63		let resource = table.push( Arc::new( self )).map_err(|_| ResourceCreationError::ResourceTableFull )?;
64		ResourceAny::try_from_resource( resource, store )
65			.map_err(|_| ResourceCreationError::ResourceHandleConversionFailed )
66	}
67
68	/// Looks up a wrapped resource by handle in the host resource table.
69	pub(crate) fn from_handle<'a, Ctx: PluginContext>(
70		handle: ResourceAny,
71		store: &'a mut StoreContextMut<Ctx>,
72	) -> Result<&'a Self, ResourceReceiveError> {
73		let resource = Resource::<Arc<Self>>::try_from_resource_any( handle, &mut *store ).map_err(|_| ResourceReceiveError::InvalidHandle )?;
74		let table = store.data_mut().resource_table();
75		let wrapped = table.get( &resource ).map_err(|_| ResourceReceiveError::InvalidHandle )?;
76		Ok( wrapped )
77	}
78
79	/// Drops a wrapped resource by handle from the host resource table.
80	pub(crate) fn drop<Ctx: PluginContext>( mut ctx: StoreContextMut<Ctx>, handle: u32 ) -> Result<(), wasmtime::Error> {
81		let resource = Resource::<Arc<Self>>::new_own( handle );
82		let table = ctx.data_mut().resource_table();
83		table.delete( resource ).map_err(|_| wasmtime::Error::new( ResourceReceiveError::InvalidHandle ))?;
84		Ok(())
85	}
86
87}