wasmtime/runtime/component/
resources.rs

1use crate::component::func::{bad_type_info, desc, LiftContext, LowerContext};
2use crate::component::matching::InstanceType;
3use crate::component::{ComponentType, Lift, Lower};
4use crate::prelude::*;
5use crate::runtime::vm::component::{
6    ComponentInstance, InstanceFlags, ResourceTables, TypedResource, TypedResourceIndex,
7};
8use crate::runtime::vm::{SendSyncPtr, VMFuncRef, ValRaw};
9use crate::store::{StoreId, StoreOpaque};
10use crate::{AsContextMut, StoreContextMut, Trap};
11use core::any::TypeId;
12use core::fmt;
13use core::marker;
14use core::mem::MaybeUninit;
15use core::ptr::NonNull;
16use core::sync::atomic::{AtomicU32, Ordering::Relaxed};
17use wasmtime_environ::component::{
18    CanonicalAbiInfo, ComponentTypes, DefinedResourceIndex, InterfaceType, ResourceIndex,
19    TypeResourceTableIndex,
20};
21
22/// Representation of a resource type in the component model.
23///
24/// Resources are currently always represented as 32-bit integers but they have
25/// unique types across instantiations and the host. For example instantiating
26/// the same component twice means that defined resource types in the component
27/// will all be different. Values of this type can be compared to see if
28/// resources have the same type.
29///
30/// Resource types can also be defined on the host in addition to guests. On the
31/// host resource types are tied to a `T`, an arbitrary Rust type. Two host
32/// resource types are the same if they point to the same `T`.
33#[derive(Debug, Copy, Clone, PartialEq, Eq)]
34pub struct ResourceType {
35    kind: ResourceTypeKind,
36}
37
38impl ResourceType {
39    /// Creates a new host resource type corresponding to `T`.
40    ///
41    /// Note that `T` is a mostly a phantom type parameter here. It does not
42    /// need to reflect the actual storage of the resource `T`. For example this
43    /// is valid:
44    ///
45    /// ```rust
46    /// use wasmtime::component::ResourceType;
47    ///
48    /// struct Foo;
49    ///
50    /// let ty = ResourceType::host::<Foo>();
51    /// ```
52    ///
53    /// A resource type of type `ResourceType::host::<T>()` will match the type
54    /// of the value produced by `Resource::<T>::new_{own,borrow}`.
55    pub fn host<T: 'static>() -> ResourceType {
56        ResourceType {
57            kind: ResourceTypeKind::Host(TypeId::of::<T>()),
58        }
59    }
60
61    pub(crate) fn guest(
62        store: StoreId,
63        instance: &ComponentInstance,
64        id: DefinedResourceIndex,
65    ) -> ResourceType {
66        ResourceType {
67            kind: ResourceTypeKind::Guest {
68                store,
69                instance: instance as *const _ as usize,
70                id,
71            },
72        }
73    }
74
75    pub(crate) fn uninstantiated(types: &ComponentTypes, index: ResourceIndex) -> ResourceType {
76        ResourceType {
77            kind: ResourceTypeKind::Uninstantiated {
78                component: types as *const _ as usize,
79                index,
80            },
81        }
82    }
83}
84
85#[derive(Debug, Copy, Clone, PartialEq, Eq)]
86enum ResourceTypeKind {
87    Host(TypeId),
88    Guest {
89        store: StoreId,
90        // For now this is the `*mut ComponentInstance` pointer within the store
91        // that this guest corresponds to. It's used to distinguish different
92        // instantiations of the same component within the store.
93        instance: usize,
94        id: DefinedResourceIndex,
95    },
96    Uninstantiated {
97        // Like `instance` in `Guest` above this is a pointer and is used to
98        // distinguish between two components. Technically susceptible to ABA
99        // issues but the consequence is a nonexistent resource would be equal
100        // to a new resource so there's not really any issue with that.
101        component: usize,
102        index: ResourceIndex,
103    },
104}
105
106/// A host-defined resource in the component model.
107///
108/// This type can be thought of as roughly a newtype wrapper around `u32` for
109/// use as a resource with the component model. The main guarantee that the
110/// component model provides is that the `u32` is not forgeable by guests and
111/// there are guaranteed semantics about when a `u32` may be in use by the guest
112/// and when it's guaranteed no longer needed. This means that it is safe for
113/// embedders to consider the internal `u32` representation "trusted" and use it
114/// for things like table indices with infallible accessors that panic on
115/// out-of-bounds. This should only panic for embedder bugs, not because of any
116/// possible behavior in the guest.
117///
118/// A `Resource<T>` value dynamically represents both an `(own $t)` in the
119/// component model as well as a `(borrow $t)`. It can be inspected via
120/// [`Resource::owned`] to test whether it is an owned handle. An owned handle
121/// which is not actively borrowed can be destroyed at any time as it's
122/// guaranteed that the guest does not have access to it. A borrowed handle, on
123/// the other hand, may be accessed by the guest so it's not necessarily
124/// guaranteed to be able to be destroyed.
125///
126/// Note that the "own" and "borrow" here refer to the component model, not
127/// Rust. The semantics of Rust ownership and borrowing are slightly different
128/// than the component model's (but spiritually the same) in that more dynamic
129/// tracking is employed as part of the component model. This means that it's
130/// possible to get runtime errors when using a `Resource<T>`. For example it is
131/// an error to call [`Resource::new_borrow`] and pass that to a component
132/// function expecting `(own $t)` and this is not statically disallowed.
133///
134/// The [`Resource`] type implements both the [`Lift`] and [`Lower`] trait to be
135/// used with typed functions in the component model or as part of aggregate
136/// structures and datatypes.
137///
138/// # Destruction of a resource
139///
140/// Resources in the component model are optionally defined with a destructor,
141/// but this host resource type does not specify a destructor. It is left up to
142/// the embedder to be able to determine how best to a destroy a resource when
143/// it is owned.
144///
145/// Note, though, that while [`Resource`] itself does not specify destructors
146/// it's still possible to do so via the [`Linker::resource`] definition. When a
147/// resource type is defined for a guest component a destructor can be specified
148/// which can be used to hook into resource destruction triggered by the guest.
149///
150/// This means that there are two ways that resource destruction is handled:
151///
152/// * Host resources destroyed by the guest can hook into the
153///   [`Linker::resource`] destructor closure to handle resource destruction.
154///   This could, for example, remove table entries.
155///
156/// * Host resources owned by the host itself have no automatic means of
157///   destruction. The host can make its own determination that its own resource
158///   is not lent out to the guest and at that time choose to destroy or
159///   deallocate it.
160///
161/// # Dynamic behavior of a resource
162///
163/// A host-defined [`Resource`] does not necessarily represent a static value.
164/// Its internals may change throughout its usage to track the state associated
165/// with the resource. The internal 32-bit host-defined representation never
166/// changes, however.
167///
168/// For example if there's a component model function of the form:
169///
170/// ```wasm
171/// (func (param "a" (borrow $t)) (param "b" (own $t)))
172/// ```
173///
174/// Then that can be extracted in Rust with:
175///
176/// ```rust,ignore
177/// let func = instance.get_typed_func::<(&Resource<T>, &Resource<T>), ()>(&mut store, "name")?;
178/// ```
179///
180/// Here the exact same resource can be provided as both arguments but that is
181/// not valid to do so because the same resource cannot be actively borrowed and
182/// passed by-value as the second parameter at the same time. The internal state
183/// in `Resource<T>` will track this information and provide a dynamic runtime
184/// error in this situation.
185///
186/// Mostly it's important to be aware that there is dynamic state associated
187/// with a [`Resource<T>`] to provide errors in situations that cannot be
188/// statically ruled out.
189///
190/// # Borrows and host responsibilities
191///
192/// Borrows to resources in the component model are guaranteed to be transient
193/// such that if a borrow is passed as part of a function call then when the
194/// function returns it's guaranteed that the guest no longer has access to the
195/// resource. This guarantee, however, must be manually upheld by the host when
196/// it receives its own borrow.
197///
198/// As mentioned above the [`Resource<T>`] type can represent a borrowed value
199/// in addition to an owned value. This means a guest can provide the host with
200/// a borrow, such as an argument to an imported function:
201///
202/// ```rust,ignore
203/// linker.root().func_wrap("name", |_cx, (r,): (Resource<MyType>,)| {
204///     assert!(!r.owned());
205///     // .. here `r` is a borrowed value provided by the guest and the host
206///     // shouldn't continue to access it beyond the scope of this call
207/// })?;
208/// ```
209///
210/// In this situation the host should take care to not attempt to persist the
211/// resource beyond the scope of the call. It's the host's resource so it
212/// technically can do what it wants with it but nothing is statically
213/// preventing `r` to stay pinned to the lifetime of the closure invocation.
214/// It's considered a mistake that the host performed if `r` is persisted too
215/// long and accessed at the wrong time.
216///
217/// [`Linker::resource`]: crate::component::LinkerInstance::resource
218pub struct Resource<T> {
219    /// The host-defined 32-bit representation of this resource.
220    rep: u32,
221
222    /// Dear rust please consider `T` used even though it's not actually used.
223    _marker: marker::PhantomData<fn() -> T>,
224
225    state: AtomicResourceState,
226}
227
228/// Internal dynamic state tracking for this resource. This can be one of
229/// four different states:
230///
231/// * `BORROW` / `u64::MAX` - this indicates that this is a borrowed
232///   resource. The `rep` doesn't live in the host table and this `Resource`
233///   instance is transiently available. It's the host's responsibility to
234///   discard this resource when the borrow duration has finished.
235///
236/// * `NOT_IN_TABLE` / `u64::MAX - 1` - this indicates that this is an owned
237///   resource not present in any store's table. This resource is not lent
238///   out. It can be passed as an `(own $t)` directly into a guest's table
239///   or it can be passed as a borrow to a guest which will insert it into
240///   a host store's table for dynamic borrow tracking.
241///
242/// * `TAKEN` / `u64::MAX - 2` - while the `rep` is available the resource
243///   has been dynamically moved into a guest and cannot be moved in again.
244///   This is used for example to prevent the same resource from being
245///   passed twice to a guest.
246///
247/// * All other values - any other value indicates that the value is an
248///   index into a store's table of host resources. It's guaranteed that the
249///   table entry represents a host resource and the resource may have
250///   borrow tracking associated with it. The low 32-bits of the value are
251///   the table index and the upper 32-bits are the generation.
252///
253/// Note that this is two `AtomicU32` fields but it's not intended to actually
254/// be used in conjunction with threads as generally a `Store<T>` lives on one
255/// thread at a time. The pair of `AtomicU32` here is used to ensure that this
256/// type is `Send + Sync` when captured as a reference to make async
257/// programming more ergonomic.
258///
259/// Also note that two `AtomicU32` here are used instead of `AtomicU64` to be
260/// more portable to platforms without 64-bit atomics.
261struct AtomicResourceState {
262    index: AtomicU32,
263    generation: AtomicU32,
264}
265
266#[derive(Debug, PartialEq, Eq, Copy, Clone)]
267enum ResourceState {
268    Borrow,
269    NotInTable,
270    Taken,
271    Index(HostResourceIndex),
272}
273
274impl AtomicResourceState {
275    const BORROW: Self = AtomicResourceState::new(ResourceState::Borrow);
276    const NOT_IN_TABLE: Self = AtomicResourceState::new(ResourceState::NotInTable);
277
278    const fn new(state: ResourceState) -> AtomicResourceState {
279        let (index, generation) = state.encode();
280        Self {
281            index: AtomicU32::new(index),
282            generation: AtomicU32::new(generation),
283        }
284    }
285
286    fn get(&self) -> ResourceState {
287        ResourceState::decode(self.index.load(Relaxed), self.generation.load(Relaxed))
288    }
289
290    fn swap(&self, state: ResourceState) -> ResourceState {
291        let (index, generation) = state.encode();
292        let index_prev = self.index.load(Relaxed);
293        self.index.store(index, Relaxed);
294        let generation_prev = self.generation.load(Relaxed);
295        self.generation.store(generation, Relaxed);
296        ResourceState::decode(index_prev, generation_prev)
297    }
298}
299
300impl ResourceState {
301    // See comments on `state` above for info about these values.
302    const BORROW: u32 = u32::MAX;
303    const NOT_IN_TABLE: u32 = u32::MAX - 1;
304    const TAKEN: u32 = u32::MAX - 2;
305
306    fn decode(idx: u32, generation: u32) -> ResourceState {
307        match generation {
308            Self::BORROW => Self::Borrow,
309            Self::NOT_IN_TABLE => Self::NotInTable,
310            Self::TAKEN => Self::Taken,
311            _ => Self::Index(HostResourceIndex::new(idx, generation)),
312        }
313    }
314
315    const fn encode(&self) -> (u32, u32) {
316        match self {
317            Self::Borrow => (0, Self::BORROW),
318            Self::NotInTable => (0, Self::NOT_IN_TABLE),
319            Self::Taken => (0, Self::TAKEN),
320            Self::Index(index) => (index.index(), index.generation()),
321        }
322    }
323}
324
325/// Metadata tracking the state of resources within a `Store`.
326///
327/// This is a borrowed structure created from a `Store` piecemeal from below.
328/// The `ResourceTables` type holds most of the raw information and this
329/// structure tacks on a reference to `HostResourceData` to track generation
330/// numbers of host indices.
331pub struct HostResourceTables<'a> {
332    tables: ResourceTables<'a>,
333    host_resource_data: &'a mut HostResourceData,
334}
335
336/// Metadata for host-owned resources owned within a `Store`.
337///
338/// This metadata is used to prevent the ABA problem with indices handed out as
339/// part of `Resource` and `ResourceAny`. Those structures are `Copy` meaning
340/// that it's easy to reuse them, possibly accidentally. To prevent issues in
341/// the host Wasmtime attaches both an index (within `ResourceTables`) as well
342/// as a 32-bit generation counter onto each `HostResourceIndex` which the host
343/// actually holds in `Resource` and `ResourceAny`.
344///
345/// This structure holds a list which is a parallel list to the "list of reps"
346/// that's stored within `ResourceTables` elsewhere in the `Store`. This
347/// parallel list holds the last known generation of each element in the table.
348/// The generation is then compared on access to make sure it's the same.
349///
350/// Whenever a slot in the table is allocated the `cur_generation` field is
351/// pushed at the corresponding index of `generation_of_table_slot`. Whenever
352/// a field is accessed the current value of `generation_of_table_slot` is
353/// checked against the generation of the index. Whenever a slot is deallocated
354/// the generation is incremented. Put together this means that any access of a
355/// deallocated slot should deterministically provide an error.
356#[derive(Default)]
357pub struct HostResourceData {
358    cur_generation: u32,
359    table_slot_metadata: Vec<TableSlot>,
360}
361
362#[derive(Copy, Clone)]
363struct TableSlot {
364    generation: u32,
365    flags: Option<InstanceFlags>,
366    dtor: Option<SendSyncPtr<VMFuncRef>>,
367}
368
369/// Host representation of an index into a table slot.
370///
371/// This is morally (u32, u32) but is encoded as a 64-bit integer. The low
372/// 32-bits are the table index and the upper 32-bits are the generation
373/// counter.
374#[derive(PartialEq, Eq, Debug, Copy, Clone)]
375#[repr(transparent)]
376pub struct HostResourceIndex(u64);
377
378impl HostResourceIndex {
379    fn new(idx: u32, generation: u32) -> HostResourceIndex {
380        HostResourceIndex(u64::from(idx) | (u64::from(generation) << 32))
381    }
382
383    const fn index(&self) -> u32 {
384        (self.0 & 0xffffffff) as u32
385    }
386
387    const fn generation(&self) -> u32 {
388        (self.0 >> 32) as u32
389    }
390}
391
392impl<'a> HostResourceTables<'a> {
393    pub fn new_host(store: &'a mut StoreOpaque) -> HostResourceTables<'a> {
394        let (calls, host_table, host_resource_data) = store.component_resource_state();
395        HostResourceTables::from_parts(
396            ResourceTables {
397                host_table: Some(host_table),
398                calls,
399                guest: None,
400            },
401            host_resource_data,
402        )
403    }
404
405    pub fn from_parts(
406        tables: ResourceTables<'a>,
407        host_resource_data: &'a mut HostResourceData,
408    ) -> Self {
409        HostResourceTables {
410            tables,
411            host_resource_data,
412        }
413    }
414
415    /// Lifts an `own` resource that resides in the host's tables at the `idx`
416    /// specified into its `rep`.
417    ///
418    /// # Errors
419    ///
420    /// Returns an error if `idx` doesn't point to a valid owned resource, or
421    /// if `idx` can't be lifted as an `own` (e.g. it has active borrows).
422    pub fn host_resource_lift_own(&mut self, idx: HostResourceIndex) -> Result<u32> {
423        let (idx, _) = self.validate_host_index(idx, true)?;
424        self.tables.resource_lift_own(TypedResourceIndex::Host(idx))
425    }
426
427    /// See [`HostResourceTables::host_resource_lift_own`].
428    pub fn host_resource_lift_borrow(&mut self, idx: HostResourceIndex) -> Result<u32> {
429        let (idx, _) = self.validate_host_index(idx, false)?;
430        self.tables
431            .resource_lift_borrow(TypedResourceIndex::Host(idx))
432    }
433
434    /// Lowers an `own` resource to be owned by the host.
435    ///
436    /// This returns a new index into the host's set of resource tables which
437    /// will point to the `rep` specified. The returned index is suitable for
438    /// conversion into either [`Resource`] or [`ResourceAny`].
439    ///
440    /// The `dtor` and instance `flags` are specified as well to know what
441    /// destructor to run when this resource is destroyed.
442    pub fn host_resource_lower_own(
443        &mut self,
444        rep: u32,
445        dtor: Option<NonNull<VMFuncRef>>,
446        flags: Option<InstanceFlags>,
447    ) -> Result<HostResourceIndex> {
448        let idx = self.tables.resource_lower_own(TypedResource::Host(rep))?;
449        Ok(self.new_host_index(idx, dtor, flags))
450    }
451
452    /// See [`HostResourceTables::host_resource_lower_own`].
453    pub fn host_resource_lower_borrow(&mut self, rep: u32) -> Result<HostResourceIndex> {
454        let idx = self
455            .tables
456            .resource_lower_borrow(TypedResource::Host(rep))?;
457        Ok(self.new_host_index(idx, None, None))
458    }
459
460    /// Validates that `idx` is still valid for the host tables, notably
461    /// ensuring that the generation listed in `idx` is the same as the
462    /// last recorded generation of the slot itself.
463    ///
464    /// The `is_removal` option indicates whether or not this table access will
465    /// end up removing the element from the host table. In such a situation the
466    /// current generation number is incremented.
467    fn validate_host_index(
468        &mut self,
469        idx: HostResourceIndex,
470        is_removal: bool,
471    ) -> Result<(u32, Option<TableSlot>)> {
472        let actual = usize::try_from(idx.index())
473            .ok()
474            .and_then(|i| self.host_resource_data.table_slot_metadata.get(i).copied());
475
476        // If `idx` is out-of-bounds then skip returning an error. In such a
477        // situation the operation that this is guarding will return a more
478        // precise error, such as a lift operation.
479        if let Some(actual) = actual {
480            if actual.generation != idx.generation() {
481                bail!("host-owned resource is being used with the wrong type");
482            }
483        }
484
485        // Bump the current generation of this is a removal to ensure any
486        // future item placed in this slot can't be pointed to by the `idx`
487        // provided above.
488        if is_removal {
489            self.host_resource_data.cur_generation += 1;
490        }
491
492        Ok((idx.index(), actual))
493    }
494
495    /// Creates a new `HostResourceIndex` which will point to the raw table
496    /// slot provided by `idx`.
497    ///
498    /// This will register metadata necessary to track the current generation
499    /// in the returned `HostResourceIndex` as well.
500    fn new_host_index(
501        &mut self,
502        idx: u32,
503        dtor: Option<NonNull<VMFuncRef>>,
504        flags: Option<InstanceFlags>,
505    ) -> HostResourceIndex {
506        let list = &mut self.host_resource_data.table_slot_metadata;
507        let info = TableSlot {
508            generation: self.host_resource_data.cur_generation,
509            flags,
510            dtor: dtor.map(SendSyncPtr::new),
511        };
512        match list.get_mut(idx as usize) {
513            Some(slot) => *slot = info,
514            None => {
515                // Resource handles start at 1, not zero, so push two elements
516                // for the first resource handle.
517                if list.is_empty() {
518                    assert_eq!(idx, 1);
519                    list.push(TableSlot {
520                        generation: 0,
521                        flags: None,
522                        dtor: None,
523                    });
524                }
525                assert_eq!(idx as usize, list.len());
526                list.push(info);
527            }
528        }
529
530        HostResourceIndex::new(idx, info.generation)
531    }
532
533    /// Drops a host-owned resource from host tables.
534    ///
535    /// This method will attempt to interpret `idx` as pointing to either a
536    /// `borrow` or `own` resource with the `expected` type specified. This
537    /// method will then return the underlying `rep` if it points to an `own`
538    /// resource which can then be further processed for destruction.
539    ///
540    /// # Errors
541    ///
542    /// Returns an error if `idx` doesn't point to a valid resource, points to
543    /// an `own` with active borrows, or if it doesn't have the type `expected`
544    /// in the host tables.
545    fn host_resource_drop(&mut self, idx: HostResourceIndex) -> Result<Option<(u32, TableSlot)>> {
546        let (idx, slot) = self.validate_host_index(idx, true)?;
547        match self.tables.resource_drop(TypedResourceIndex::Host(idx))? {
548            Some(rep) => Ok(Some((rep, slot.unwrap()))),
549            None => Ok(None),
550        }
551    }
552
553    /// Lowers an `own` resource into the guest, converting the `rep` specified
554    /// into a guest-local index.
555    ///
556    /// The `ty` provided is which table to put this into.
557    pub fn guest_resource_lower_own(
558        &mut self,
559        rep: u32,
560        ty: TypeResourceTableIndex,
561    ) -> Result<u32> {
562        self.tables
563            .resource_lower_own(TypedResource::Component { ty, rep })
564    }
565
566    /// Lowers a `borrow` resource into the guest, converting the `rep`
567    /// specified into a guest-local index.
568    ///
569    /// The `ty` provided is which table to put this into.
570    ///
571    /// Note that this cannot be used in isolation because lowering a borrow
572    /// into a guest has a special case where `rep` is returned directly if `ty`
573    /// belongs to the component being lowered into. That property must be
574    /// handled by the caller of this function.
575    pub fn guest_resource_lower_borrow(
576        &mut self,
577        rep: u32,
578        ty: TypeResourceTableIndex,
579    ) -> Result<u32> {
580        self.tables
581            .resource_lower_borrow(TypedResource::Component { ty, rep })
582    }
583
584    /// Lifts an `own` resource from the `idx` specified from the table `ty`.
585    ///
586    /// This will lookup the appropriate table in the guest and return the `rep`
587    /// corresponding to `idx` if it's valid.
588    pub fn guest_resource_lift_own(
589        &mut self,
590        index: u32,
591        ty: TypeResourceTableIndex,
592    ) -> Result<u32> {
593        self.tables
594            .resource_lift_own(TypedResourceIndex::Component { ty, index })
595    }
596
597    /// Lifts a `borrow` resource from the `idx` specified from the table `ty`.
598    ///
599    /// This will lookup the appropriate table in the guest and return the `rep`
600    /// corresponding to `idx` if it's valid.
601    pub fn guest_resource_lift_borrow(
602        &mut self,
603        index: u32,
604        ty: TypeResourceTableIndex,
605    ) -> Result<u32> {
606        self.tables
607            .resource_lift_borrow(TypedResourceIndex::Component { ty, index })
608    }
609
610    /// Begins a call into the component instance, starting recording of
611    /// metadata related to resource borrowing.
612    #[inline]
613    pub fn enter_call(&mut self) {
614        self.tables.enter_call()
615    }
616
617    /// Completes a call into the component instance, validating that it's ok to
618    /// complete by ensuring the are no remaining active borrows.
619    #[inline]
620    pub fn exit_call(&mut self) -> Result<()> {
621        self.tables.exit_call()
622    }
623}
624
625impl<T> Resource<T>
626where
627    T: 'static,
628{
629    /// Creates a new owned resource with the `rep` specified.
630    ///
631    /// The returned value is suitable for passing to a guest as either a
632    /// `(borrow $t)` or `(own $t)`.
633    pub fn new_own(rep: u32) -> Resource<T> {
634        Resource {
635            state: AtomicResourceState::NOT_IN_TABLE,
636            rep,
637            _marker: marker::PhantomData,
638        }
639    }
640
641    /// Creates a new borrowed resource which isn't actually rooted in any
642    /// ownership.
643    ///
644    /// This can be used to pass to a guest as a borrowed resource and the
645    /// embedder will know that the `rep` won't be in use by the guest
646    /// afterwards. Exactly how the lifetime of `rep` works is up to the
647    /// embedder.
648    pub fn new_borrow(rep: u32) -> Resource<T> {
649        Resource {
650            state: AtomicResourceState::BORROW,
651            rep,
652            _marker: marker::PhantomData,
653        }
654    }
655
656    /// Returns the underlying 32-bit representation used to originally create
657    /// this resource.
658    pub fn rep(&self) -> u32 {
659        self.rep
660    }
661
662    /// Returns whether this is an owned resource or not.
663    ///
664    /// Owned resources can be safely destroyed by the embedder at any time, and
665    /// borrowed resources have an owner somewhere else on the stack so can only
666    /// be accessed, not destroyed.
667    pub fn owned(&self) -> bool {
668        match self.state.get() {
669            ResourceState::Borrow => false,
670            ResourceState::Taken | ResourceState::NotInTable | ResourceState::Index(_) => true,
671        }
672    }
673
674    fn lower_to_index<U>(&self, cx: &mut LowerContext<'_, U>, ty: InterfaceType) -> Result<u32> {
675        match ty {
676            InterfaceType::Own(t) => {
677                let rep = match self.state.get() {
678                    // If this is a borrow resource then this is a dynamic
679                    // error on behalf of the embedder.
680                    ResourceState::Borrow => {
681                        bail!("cannot lower a `borrow` resource into an `own`")
682                    }
683
684                    // If this resource does not yet live in a table then we're
685                    // dynamically transferring ownership to wasm. Record that
686                    // it's no longer present and then pass through the
687                    // representation.
688                    ResourceState::NotInTable => {
689                        let prev = self.state.swap(ResourceState::Taken);
690                        assert_eq!(prev, ResourceState::NotInTable);
691                        self.rep
692                    }
693
694                    // This resource has already been moved into wasm so this is
695                    // a dynamic error on behalf of the embedder.
696                    ResourceState::Taken => bail!("host resource already consumed"),
697
698                    // If this resource lives in a host table then try to take
699                    // it out of the table, which may fail, and on success we
700                    // can move the rep into the guest table.
701                    ResourceState::Index(idx) => cx.host_resource_lift_own(idx)?,
702                };
703                cx.guest_resource_lower_own(t, rep)
704            }
705            InterfaceType::Borrow(t) => {
706                let rep = match self.state.get() {
707                    // If this is already a borrowed resource, nothing else to
708                    // do and the rep is passed through.
709                    ResourceState::Borrow => self.rep,
710
711                    // If this resource is already gone, that's a dynamic error
712                    // for the embedder.
713                    ResourceState::Taken => bail!("host resource already consumed"),
714
715                    // If this resource is not currently in a table then it
716                    // needs to move into a table to participate in state
717                    // related to borrow tracking. Execute the
718                    // `host_resource_lower_own` operation here and update our
719                    // state.
720                    //
721                    // Afterwards this is the same as the `idx` case below.
722                    //
723                    // Note that flags/dtor are passed as `None` here since
724                    // `Resource<T>` doesn't offer destruction support.
725                    ResourceState::NotInTable => {
726                        let idx = cx.host_resource_lower_own(self.rep, None, None)?;
727                        let prev = self.state.swap(ResourceState::Index(idx));
728                        assert_eq!(prev, ResourceState::NotInTable);
729                        cx.host_resource_lift_borrow(idx)?
730                    }
731
732                    // If this resource lives in a table then it needs to come
733                    // out of the table with borrow-tracking employed.
734                    ResourceState::Index(idx) => cx.host_resource_lift_borrow(idx)?,
735                };
736                cx.guest_resource_lower_borrow(t, rep)
737            }
738            _ => bad_type_info(),
739        }
740    }
741
742    fn lift_from_index(cx: &mut LiftContext<'_>, ty: InterfaceType, index: u32) -> Result<Self> {
743        let (state, rep) = match ty {
744            // Ownership is being transferred from a guest to the host, so move
745            // it from the guest table into a new `Resource`. Note that this
746            // isn't immediately inserted into the host table and that's left
747            // for the future if it's necessary to take a borrow from this owned
748            // resource.
749            InterfaceType::Own(t) => {
750                debug_assert!(cx.resource_type(t) == ResourceType::host::<T>());
751                let (rep, dtor, flags) = cx.guest_resource_lift_own(t, index)?;
752                assert!(dtor.is_some());
753                assert!(flags.is_none());
754                (AtomicResourceState::NOT_IN_TABLE, rep)
755            }
756
757            // The borrow here is lifted from the guest, but note the lack of
758            // `host_resource_lower_borrow` as it's intentional. Lowering
759            // a borrow has a special case in the canonical ABI where if the
760            // receiving module is the owner of the resource then it directly
761            // receives the `rep` and no other dynamic tracking is employed.
762            // This effectively mirrors that even though the canonical ABI
763            // isn't really all that applicable in host context here.
764            InterfaceType::Borrow(t) => {
765                debug_assert!(cx.resource_type(t) == ResourceType::host::<T>());
766                let rep = cx.guest_resource_lift_borrow(t, index)?;
767                (AtomicResourceState::BORROW, rep)
768            }
769            _ => bad_type_info(),
770        };
771        Ok(Resource {
772            state,
773            rep,
774            _marker: marker::PhantomData,
775        })
776    }
777
778    /// Attempts to convert a [`ResourceAny`] into [`Resource`].
779    ///
780    /// This method will check that `resource` has type
781    /// `ResourceType::host::<T>()` and then convert it into a typed version of
782    /// the resource.
783    ///
784    /// # Errors
785    ///
786    /// This function will return an error if `resource` does not have type
787    /// `ResourceType::host::<T>()`. This function may also return an error if
788    /// `resource` is no longer valid, for example it was previously converted.
789    ///
790    /// # Panics
791    ///
792    /// This function will panic if `resource` does not belong to the `store`
793    /// specified.
794    pub fn try_from_resource_any(
795        resource: ResourceAny,
796        mut store: impl AsContextMut,
797    ) -> Result<Self> {
798        let store = store.as_context_mut();
799        let mut tables = HostResourceTables::new_host(store.0);
800        let ResourceAny { idx, ty, owned } = resource;
801        ensure!(ty == ResourceType::host::<T>(), "resource type mismatch");
802        let (state, rep) = if owned {
803            let rep = tables.host_resource_lift_own(idx)?;
804            (AtomicResourceState::NOT_IN_TABLE, rep)
805        } else {
806            // For borrowed handles, first acquire the `rep` via lifting the
807            // borrow. Afterwards though remove any dynamic state associated
808            // with this borrow. `Resource<T>` doesn't participate in dynamic
809            // state tracking and it's assumed embedders know what they're
810            // doing, so the drop call will clear out that a borrow is active
811            //
812            // Note that the result of `drop` should always be `None` as it's a
813            // borrowed handle, so assert so.
814            let rep = tables.host_resource_lift_borrow(idx)?;
815            let res = tables.host_resource_drop(idx)?;
816            assert!(res.is_none());
817            (AtomicResourceState::BORROW, rep)
818        };
819        Ok(Resource {
820            state,
821            rep,
822            _marker: marker::PhantomData,
823        })
824    }
825
826    /// See [`ResourceAny::try_from_resource`]
827    pub fn try_into_resource_any(self, store: impl AsContextMut) -> Result<ResourceAny> {
828        ResourceAny::try_from_resource(self, store)
829    }
830}
831
832unsafe impl<T: 'static> ComponentType for Resource<T> {
833    const ABI: CanonicalAbiInfo = CanonicalAbiInfo::SCALAR4;
834
835    type Lower = <u32 as ComponentType>::Lower;
836
837    fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> {
838        let resource = match ty {
839            InterfaceType::Own(t) | InterfaceType::Borrow(t) => *t,
840            other => bail!("expected `own` or `borrow`, found `{}`", desc(other)),
841        };
842        match types.resource_type(resource).kind {
843            ResourceTypeKind::Host(id) if TypeId::of::<T>() == id => {}
844            _ => bail!("resource type mismatch"),
845        }
846
847        Ok(())
848    }
849}
850
851unsafe impl<T: 'static> Lower for Resource<T> {
852    fn lower<U>(
853        &self,
854        cx: &mut LowerContext<'_, U>,
855        ty: InterfaceType,
856        dst: &mut MaybeUninit<Self::Lower>,
857    ) -> Result<()> {
858        self.lower_to_index(cx, ty)?
859            .lower(cx, InterfaceType::U32, dst)
860    }
861
862    fn store<U>(
863        &self,
864        cx: &mut LowerContext<'_, U>,
865        ty: InterfaceType,
866        offset: usize,
867    ) -> Result<()> {
868        self.lower_to_index(cx, ty)?
869            .store(cx, InterfaceType::U32, offset)
870    }
871}
872
873unsafe impl<T: 'static> Lift for Resource<T> {
874    fn lift(cx: &mut LiftContext<'_>, ty: InterfaceType, src: &Self::Lower) -> Result<Self> {
875        let index = u32::lift(cx, InterfaceType::U32, src)?;
876        Resource::lift_from_index(cx, ty, index)
877    }
878
879    fn load(cx: &mut LiftContext<'_>, ty: InterfaceType, bytes: &[u8]) -> Result<Self> {
880        let index = u32::load(cx, InterfaceType::U32, bytes)?;
881        Resource::lift_from_index(cx, ty, index)
882    }
883}
884
885impl<T> fmt::Debug for Resource<T> {
886    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
887        let state = match self.state.get() {
888            ResourceState::Borrow => "borrow",
889            ResourceState::NotInTable => "own (not in table)",
890            ResourceState::Taken => "taken",
891            ResourceState::Index(_) => "own",
892        };
893        f.debug_struct("Resource")
894            .field("rep", &self.rep)
895            .field("state", &state)
896            .finish()
897    }
898}
899
900/// Representation of a resource in the component model, either a guest-defined
901/// or a host-defined resource.
902///
903/// This type is similar to [`Resource`] except that it can be used to represent
904/// any resource, either host or guest. This type cannot be directly constructed
905/// and is only available if the guest returns it to the host (e.g. a function
906/// returning a guest-defined resource) or by a conversion from [`Resource`] via
907/// [`ResourceAny::try_from_resource`].
908/// This type also does not carry a static type parameter `T` for example and
909/// does not have as much information about its type.
910/// This means that it's possible to get runtime type-errors when
911/// using this type because it cannot statically prevent mismatching resource
912/// types.
913///
914/// Like [`Resource`] this type represents either an `own` or a `borrow`
915/// resource internally. Unlike [`Resource`], however, a [`ResourceAny`] must
916/// always be explicitly destroyed with the [`ResourceAny::resource_drop`]
917/// method. This will update internal dynamic state tracking and invoke the
918/// WebAssembly-defined destructor for a resource, if any.
919///
920/// Note that it is required to call `resource_drop` for all instances of
921/// [`ResourceAny`]: even borrows. Both borrows and own handles have state
922/// associated with them that must be discarded by the time they're done being
923/// used.
924#[derive(Debug, PartialEq, Eq, Copy, Clone)]
925pub struct ResourceAny {
926    idx: HostResourceIndex,
927    ty: ResourceType,
928    owned: bool,
929}
930
931impl ResourceAny {
932    /// Attempts to convert an imported [`Resource`] into [`ResourceAny`].
933    ///
934    /// * `resource` is the resource to convert.
935    /// * `store` is the store to place the returned resource into.
936    ///
937    /// The returned `ResourceAny` will not have a destructor attached to it
938    /// meaning that if `resource_drop` is called then it will not invoked a
939    /// host-defined destructor. This is similar to how `Resource<T>` does not
940    /// have a destructor associated with it.
941    ///
942    /// # Errors
943    ///
944    /// This method will return an error if `resource` has already been "taken"
945    /// and has ownership transferred elsewhere which can happen in situations
946    /// such as when it's already lowered into a component.
947    pub fn try_from_resource<T: 'static>(
948        resource: Resource<T>,
949        mut store: impl AsContextMut,
950    ) -> Result<Self> {
951        let Resource { rep, state, .. } = resource;
952        let store = store.as_context_mut();
953
954        let mut tables = HostResourceTables::new_host(store.0);
955        let (idx, owned) = match state.get() {
956            ResourceState::Borrow => (tables.host_resource_lower_borrow(rep)?, false),
957            ResourceState::NotInTable => {
958                let idx = tables.host_resource_lower_own(rep, None, None)?;
959                (idx, true)
960            }
961            ResourceState::Taken => bail!("host resource already consumed"),
962            ResourceState::Index(idx) => (idx, true),
963        };
964        Ok(Self {
965            idx,
966            ty: ResourceType::host::<T>(),
967            owned,
968        })
969    }
970
971    /// See [`Resource::try_from_resource_any`]
972    pub fn try_into_resource<T: 'static>(self, store: impl AsContextMut) -> Result<Resource<T>> {
973        Resource::try_from_resource_any(self, store)
974    }
975
976    /// Returns the corresponding type associated with this resource, either a
977    /// host-defined type or a guest-defined type.
978    ///
979    /// This can be compared against [`ResourceType::host`] for example to see
980    /// if it's a host-resource or against a type extracted with
981    /// [`Instance::get_resource`] to see if it's a guest-defined resource.
982    ///
983    /// [`Instance::get_resource`]: crate::component::Instance::get_resource
984    pub fn ty(&self) -> ResourceType {
985        self.ty
986    }
987
988    /// Returns whether this is an owned resource, and if not it's a borrowed
989    /// resource.
990    pub fn owned(&self) -> bool {
991        self.owned
992    }
993
994    /// Destroy this resource and release any state associated with it.
995    ///
996    /// This is required to be called (or the async version) for all instances
997    /// of [`ResourceAny`] to ensure that state associated with this resource is
998    /// properly cleaned up. For owned resources this may execute the
999    /// guest-defined destructor if applicable (or the host-defined destructor
1000    /// if one was specified).
1001    pub fn resource_drop(self, mut store: impl AsContextMut) -> Result<()> {
1002        let mut store = store.as_context_mut();
1003        assert!(
1004            !store.0.async_support(),
1005            "must use `resource_drop_async` when async support is enabled on the config"
1006        );
1007        self.resource_drop_impl(&mut store.as_context_mut())
1008    }
1009
1010    /// Same as [`ResourceAny::resource_drop`] except for use with async stores
1011    /// to execute the destructor asynchronously.
1012    #[cfg(feature = "async")]
1013    pub async fn resource_drop_async<T>(self, mut store: impl AsContextMut<Data = T>) -> Result<()>
1014    where
1015        T: Send,
1016    {
1017        let mut store = store.as_context_mut();
1018        assert!(
1019            store.0.async_support(),
1020            "cannot use `resource_drop_async` without enabling async support in the config"
1021        );
1022        store
1023            .on_fiber(|store| self.resource_drop_impl(store))
1024            .await?
1025    }
1026
1027    fn resource_drop_impl<T>(self, store: &mut StoreContextMut<'_, T>) -> Result<()> {
1028        // Attempt to remove `self.idx` from the host table in `store`.
1029        //
1030        // This could fail if the index is invalid or if this is removing an
1031        // `Own` entry which is currently being borrowed.
1032        let pair = HostResourceTables::new_host(store.0).host_resource_drop(self.idx)?;
1033
1034        let (rep, slot) = match (pair, self.owned) {
1035            (Some(pair), true) => pair,
1036
1037            // A `borrow` was removed from the table and no further
1038            // destruction, e.g. the destructor, is required so we're done.
1039            (None, false) => return Ok(()),
1040
1041            _ => unreachable!(),
1042        };
1043
1044        // Implement the reentrance check required by the canonical ABI. Note
1045        // that this happens whether or not a destructor is present.
1046        //
1047        // Note that this should be safe because the raw pointer access in
1048        // `flags` is valid due to `store` being the owner of the flags and
1049        // flags are never destroyed within the store.
1050        if let Some(flags) = slot.flags {
1051            unsafe {
1052                if !flags.may_enter() {
1053                    bail!(Trap::CannotEnterComponent);
1054                }
1055            }
1056        }
1057
1058        let dtor = match slot.dtor {
1059            Some(dtor) => dtor.as_non_null(),
1060            None => return Ok(()),
1061        };
1062        let mut args = [ValRaw::u32(rep)];
1063
1064        // This should be safe because `dtor` has been checked to belong to the
1065        // `store` provided which means it's valid and still alive. Additionally
1066        // destructors have al been previously type-checked and are guaranteed
1067        // to take one i32 argument and return no results, so the parameters
1068        // here should be configured correctly.
1069        unsafe { crate::Func::call_unchecked_raw(store, dtor, NonNull::from(&mut args)) }
1070    }
1071
1072    fn lower_to_index<U>(&self, cx: &mut LowerContext<'_, U>, ty: InterfaceType) -> Result<u32> {
1073        match ty {
1074            InterfaceType::Own(t) => {
1075                if cx.resource_type(t) != self.ty {
1076                    bail!("mismatched resource types");
1077                }
1078                let rep = cx.host_resource_lift_own(self.idx)?;
1079                cx.guest_resource_lower_own(t, rep)
1080            }
1081            InterfaceType::Borrow(t) => {
1082                if cx.resource_type(t) != self.ty {
1083                    bail!("mismatched resource types");
1084                }
1085                let rep = cx.host_resource_lift_borrow(self.idx)?;
1086                cx.guest_resource_lower_borrow(t, rep)
1087            }
1088            _ => bad_type_info(),
1089        }
1090    }
1091
1092    fn lift_from_index(cx: &mut LiftContext<'_>, ty: InterfaceType, index: u32) -> Result<Self> {
1093        match ty {
1094            InterfaceType::Own(t) => {
1095                let ty = cx.resource_type(t);
1096                let (rep, dtor, flags) = cx.guest_resource_lift_own(t, index)?;
1097                let idx = cx.host_resource_lower_own(rep, dtor, flags)?;
1098                Ok(ResourceAny {
1099                    idx,
1100                    ty,
1101                    owned: true,
1102                })
1103            }
1104            InterfaceType::Borrow(t) => {
1105                let ty = cx.resource_type(t);
1106                let rep = cx.guest_resource_lift_borrow(t, index)?;
1107                let idx = cx.host_resource_lower_borrow(rep)?;
1108                Ok(ResourceAny {
1109                    idx,
1110                    ty,
1111                    owned: false,
1112                })
1113            }
1114            _ => bad_type_info(),
1115        }
1116    }
1117}
1118
1119unsafe impl ComponentType for ResourceAny {
1120    const ABI: CanonicalAbiInfo = CanonicalAbiInfo::SCALAR4;
1121
1122    type Lower = <u32 as ComponentType>::Lower;
1123
1124    fn typecheck(ty: &InterfaceType, _types: &InstanceType<'_>) -> Result<()> {
1125        match ty {
1126            InterfaceType::Own(_) | InterfaceType::Borrow(_) => Ok(()),
1127            other => bail!("expected `own` or `borrow`, found `{}`", desc(other)),
1128        }
1129    }
1130}
1131
1132unsafe impl Lower for ResourceAny {
1133    fn lower<T>(
1134        &self,
1135        cx: &mut LowerContext<'_, T>,
1136        ty: InterfaceType,
1137        dst: &mut MaybeUninit<Self::Lower>,
1138    ) -> Result<()> {
1139        self.lower_to_index(cx, ty)?
1140            .lower(cx, InterfaceType::U32, dst)
1141    }
1142
1143    fn store<T>(
1144        &self,
1145        cx: &mut LowerContext<'_, T>,
1146        ty: InterfaceType,
1147        offset: usize,
1148    ) -> Result<()> {
1149        self.lower_to_index(cx, ty)?
1150            .store(cx, InterfaceType::U32, offset)
1151    }
1152}
1153
1154unsafe impl Lift for ResourceAny {
1155    fn lift(cx: &mut LiftContext<'_>, ty: InterfaceType, src: &Self::Lower) -> Result<Self> {
1156        let index = u32::lift(cx, InterfaceType::U32, src)?;
1157        ResourceAny::lift_from_index(cx, ty, index)
1158    }
1159
1160    fn load(cx: &mut LiftContext<'_>, ty: InterfaceType, bytes: &[u8]) -> Result<Self> {
1161        let index = u32::load(cx, InterfaceType::U32, bytes)?;
1162        ResourceAny::lift_from_index(cx, ty, index)
1163    }
1164}