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