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 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)`] where `ty` is the value provided to the
56/// 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 ABI: CanonicalAbiInfo = HostResource::<Dynamic, u32>::ABI;
148 type Lower = crate::ValRaw;
149
150 fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> {
151 HostResource::<Dynamic, u32>::typecheck(ty, types)
152 }
153}
154
155unsafe impl Lower for ResourceDynamic {
156 fn linear_lower_to_flat<U>(
157 &self,
158 cx: &mut LowerContext<'_, U>,
159 ty: InterfaceType,
160 dst: &mut MaybeUninit<Self::Lower>,
161 ) -> Result<()> {
162 self.0.linear_lower_to_flat(cx, ty, dst)
163 }
164
165 fn linear_lower_to_memory<U>(
166 &self,
167 cx: &mut LowerContext<'_, U>,
168 ty: InterfaceType,
169 offset: usize,
170 ) -> Result<()> {
171 self.0.linear_lower_to_memory(cx, ty, offset)
172 }
173}
174
175unsafe impl Lift for ResourceDynamic {
176 fn linear_lift_from_flat(
177 cx: &mut LiftContext<'_>,
178 ty: InterfaceType,
179 src: &Self::Lower,
180 ) -> Result<Self> {
181 let host_resource = HostResource::linear_lift_from_flat(cx, ty, src)?;
182 Ok(ResourceDynamic(host_resource))
183 }
184
185 fn linear_lift_from_memory(
186 cx: &mut LiftContext<'_>,
187 ty: InterfaceType,
188 bytes: &[u8],
189 ) -> Result<Self> {
190 let host_resource = HostResource::linear_lift_from_memory(cx, ty, bytes)?;
191 Ok(ResourceDynamic(host_resource))
192 }
193}
194
195impl fmt::Debug for ResourceDynamic {
196 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
197 self.0.fmt(f)
198 }
199}