Skip to main content

wasmtime/runtime/component/resources/
host_dynamic.rs

1use crate::AsContextMut;
2use crate::component::func::{LiftContext, LowerContext};
3use crate::component::matching::InstanceType;
4use crate::component::resources::host::{HostResource, HostResourceType};
5use crate::component::{ComponentType, Lift, Lower, ResourceAny, ResourceType};
6use crate::prelude::*;
7use core::fmt;
8use core::mem::MaybeUninit;
9use wasmtime_environ::component::{CanonicalAbiInfo, InterfaceType};
10
11/// A host-defined resource in the component model with a dynamic runtime value
12/// representing its type.
13///
14/// This type represents a host-owned resource in the same manner as
15/// [`Resource`], and almost all of the documentation on that type is applicable
16/// to usage of this type as well. Where the two differ is how embedders use
17/// these types in a particular embedding.
18///
19/// # Use cases for [`Resource`]
20///
21/// The [`Resource`] type is intended to be used by Rust embedders and provides
22/// a `T` type parameter to provide a layer of type safety when using the
23/// resource. The type parameter prevents mixing up resources of the same type
24/// by accident. The [`bindgen!`] macro, for example, uses [`Resource`] by
25/// default to represent all resources imported by a wasm guest.
26///
27/// As the documentation on [`Resource`] indicates the `T` type parameter on
28/// [`Resource<T>`] is a hint and `T` isn't stored inside. This means that the
29/// host can write a function which takes [`Resource<T>`], for example, and
30/// prevent mistakes of passing a wrong-typed-resource to that function.
31/// Typically the 32-bit value that [`Resource<T>`] wraps is an index into some
32/// sort of table the host manages and the index points to a value of type `T`.
33/// The `T` type parameter can assist in writing helper functions to access
34/// these types.
35///
36/// The downside of [`Resource`], however, is that all resource types must be
37/// statically assigned at compile time. It's not possible to manufacture more
38/// types at runtime in some more dynamic situations. That's where
39/// [`ResourceDynamic`] comes in.
40///
41/// # Use cases for [`ResourceDynamic`]
42///
43/// The general idea of [`ResourceDynamic`] is very similar to [`Resource`] --
44/// it represents a "trusted" 32-bit value that the host defines and assigns
45/// meaning to. There is no destructor on [`ResourceDynamic`] and the host has
46/// to know how to destroy the associated state, if any, that
47/// [`ResourceDynamic`] references. The difference with [`Resource`] is that is
48/// has runtime type information instead of static type information, meaning
49/// that it's possible to mix these up at compile by accident.
50///
51/// However a [`ResourceDynamic`] can be constructed dynamically at runtime with
52/// a runtime-defined type. For example an embedding that provides generic
53/// access to types in the host may want to take advantage of the dynamic nature
54/// of this type. Resources of type [`ResourceDynamic`] have a type of
55/// [`ResourceType::host_dynamic(ty)`](ResourceType::host_dynamic) where `ty` is
56/// the value provided to the constructors of [`ResourceDynamic`].
57///
58/// A [`ResourceDynamic`] implements [`Lift`] and [`Lower`] in the same manner
59/// as [`Resource`], but the implementations may fail after type-checking unlike
60/// with [`Resource`] (due to the dynamic nature of the type which can't be
61/// fully-checked during type-checking).
62///
63/// [`Resource`]: crate::component::Resource
64/// [`Resource<T>`]: crate::component::Resource
65/// [`bindgen!`]: crate::component::bindgen
66pub struct ResourceDynamic(HostResource<Dynamic, u32>);
67
68struct Dynamic;
69
70impl HostResourceType<u32> for Dynamic {
71    fn resource_type(ty: u32) -> ResourceType {
72        ResourceType::host_dynamic(ty)
73    }
74
75    fn typecheck(ty: ResourceType) -> Option<u32> {
76        ty.as_host_dynamic()
77    }
78}
79
80impl ResourceDynamic {
81    /// Creates a new owned resource with the `rep` specified.
82    ///
83    /// This is the same as [`Resource::new_own`] except that `ty` is an extra
84    /// parameter for the host-defined type information.
85    ///
86    /// [`Resource::new_own`]: crate::component::Resource::new_own
87    pub fn new_own(rep: u32, ty: u32) -> ResourceDynamic {
88        ResourceDynamic(HostResource::new_own(rep, ty))
89    }
90
91    /// Creates a new borrowed resource which isn't actually rooted in any
92    /// ownership.
93    ///
94    /// This is the same as [`Resource::new_borrow`] except that `ty` is an extra
95    /// parameter for the host-defined type information.
96    ///
97    /// [`Resource::new_borrow`]: crate::component::Resource::new_borrow
98    pub fn new_borrow(rep: u32, ty: u32) -> ResourceDynamic {
99        ResourceDynamic(HostResource::new_borrow(rep, ty))
100    }
101
102    /// Returns the underlying 32-bit representation used to originally create
103    /// this resource.
104    ///
105    /// This is the same as [`Resource::rep`].
106    ///
107    /// [`Resource::rep`]: crate::component::Resource::rep
108    pub fn rep(&self) -> u32 {
109        self.0.rep()
110    }
111
112    /// Returns the 32-bit integer indicating the type of this resource.
113    ///
114    /// This will return the same 32-bit integer provided to the
115    /// [`ResourceDynamic::new_own`] constructor. The meaning of this integer is
116    /// left to the host and this only serves as an accessor to provide the
117    /// value back to the host.
118    pub fn ty(&self) -> u32 {
119        self.0.ty()
120    }
121
122    /// Returns whether this is an owned resource or not.
123    ///
124    /// This is the same as [`Resource::owned`].
125    ///
126    /// [`Resource::owned`]: crate::component::Resource::owned
127    pub fn owned(&self) -> bool {
128        self.0.owned()
129    }
130
131    /// Attempts to convert a [`ResourceAny`] into [`ResourceDynamic`].
132    ///
133    /// This is the same as [`Resource::try_from_resource_any`].
134    ///
135    /// [`Resource::try_from_resource_any`]: crate::component::Resource::try_from_resource_any
136    pub fn try_from_resource_any(resource: ResourceAny, store: impl AsContextMut) -> Result<Self> {
137        Ok(ResourceDynamic(resource.try_into_host_resource(store)?))
138    }
139
140    /// See [`ResourceAny::try_from_resource`]
141    pub fn try_into_resource_any(self, store: impl AsContextMut) -> Result<ResourceAny> {
142        self.0.try_into_resource_any(store)
143    }
144}
145
146unsafe impl ComponentType for ResourceDynamic {
147    const MAY_REQUIRE_REALLOC: bool = false;
148    const ABI: CanonicalAbiInfo = HostResource::<Dynamic, u32>::ABI;
149    type Lower = crate::ValRaw;
150
151    fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> {
152        HostResource::<Dynamic, u32>::typecheck(ty, types)
153    }
154}
155
156unsafe impl Lower for ResourceDynamic {
157    fn linear_lower_to_flat<U>(
158        &self,
159        cx: &mut LowerContext<'_, U>,
160        ty: InterfaceType,
161        dst: &mut MaybeUninit<Self::Lower>,
162    ) -> Result<()> {
163        self.0.linear_lower_to_flat(cx, ty, dst)
164    }
165
166    fn linear_lower_to_memory<U>(
167        &self,
168        cx: &mut LowerContext<'_, U>,
169        ty: InterfaceType,
170        offset: usize,
171    ) -> Result<()> {
172        self.0.linear_lower_to_memory(cx, ty, offset)
173    }
174}
175
176unsafe impl Lift for ResourceDynamic {
177    fn linear_lift_from_flat(
178        cx: &mut LiftContext<'_>,
179        ty: InterfaceType,
180        src: &Self::Lower,
181    ) -> Result<Self> {
182        let host_resource = HostResource::linear_lift_from_flat(cx, ty, src)?;
183        Ok(ResourceDynamic(host_resource))
184    }
185
186    fn linear_lift_from_memory(
187        cx: &mut LiftContext<'_>,
188        ty: InterfaceType,
189        bytes: &[u8],
190    ) -> Result<Self> {
191        let host_resource = HostResource::linear_lift_from_memory(cx, ty, bytes)?;
192        Ok(ResourceDynamic(host_resource))
193    }
194}
195
196impl fmt::Debug for ResourceDynamic {
197    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
198        self.0.fmt(f)
199    }
200}