1 use crate::AsContextMut; 2 use crate::component::func::{LiftContext, LowerContext}; 3 use crate::component::matching::InstanceType; 4 use crate::component::resources::host::{HostResource, HostResourceType}; 5 use crate::component::{ComponentType, Lift, Lower, ResourceAny, ResourceType}; 6 use crate::prelude::*; 7 use core::fmt; 8 use core::mem::MaybeUninit; 9 use 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 66 pub struct ResourceDynamic(HostResource<Dynamic, u32>); 67 68 struct Dynamic; 69 70 impl HostResourceType<u32> for Dynamic { resource_type(ty: u32) -> ResourceType71 fn resource_type(ty: u32) -> ResourceType { 72 ResourceType::host_dynamic(ty) 73 } 74 typecheck(ty: ResourceType) -> Option<u32>75 fn typecheck(ty: ResourceType) -> Option<u32> { 76 ty.as_host_dynamic() 77 } 78 } 79 80 impl 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 new_own(rep: u32, ty: u32) -> ResourceDynamic87 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 new_borrow(rep: u32, ty: u32) -> ResourceDynamic98 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 rep(&self) -> u32108 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. ty(&self) -> u32118 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 owned(&self) -> bool127 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 try_from_resource_any(resource: ResourceAny, store: impl AsContextMut) -> Result<Self>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`] try_into_resource_any(self, store: impl AsContextMut) -> Result<ResourceAny>141 pub fn try_into_resource_any(self, store: impl AsContextMut) -> Result<ResourceAny> { 142 self.0.try_into_resource_any(store) 143 } 144 } 145 146 unsafe impl ComponentType for ResourceDynamic { 147 const ABI: CanonicalAbiInfo = HostResource::<Dynamic, u32>::ABI; 148 type Lower = crate::ValRaw; 149 typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()>150 fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> { 151 HostResource::<Dynamic, u32>::typecheck(ty, types) 152 } 153 } 154 155 unsafe impl Lower for ResourceDynamic { linear_lower_to_flat<U>( &self, cx: &mut LowerContext<'_, U>, ty: InterfaceType, dst: &mut MaybeUninit<Self::Lower>, ) -> Result<()>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 linear_lower_to_memory<U>( &self, cx: &mut LowerContext<'_, U>, ty: InterfaceType, offset: usize, ) -> Result<()>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 175 unsafe impl Lift for ResourceDynamic { linear_lift_from_flat( cx: &mut LiftContext<'_>, ty: InterfaceType, src: &Self::Lower, ) -> Result<Self>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 linear_lift_from_memory( cx: &mut LiftContext<'_>, ty: InterfaceType, bytes: &[u8], ) -> Result<Self>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 195 impl fmt::Debug for ResourceDynamic { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result196 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 197 self.0.fmt(f) 198 } 199 } 200