Struct Resource
pub struct Resource<T> { /* private fields */ }
Expand description
A host-defined resource in the component model.
This type can be thought of as roughly a newtype wrapper around u32
for
use as a resource with the component model. The main guarantee that the
component model provides is that the u32
is not forgeable by guests and
there are guaranteed semantics about when a u32
may be in use by the guest
and when it’s guaranteed no longer needed. This means that it is safe for
embedders to consider the internal u32
representation “trusted” and use it
for things like table indices with infallible accessors that panic on
out-of-bounds. This should only panic for embedder bugs, not because of any
possible behavior in the guest.
A Resource<T>
value dynamically represents both an (own $t)
in the
component model as well as a (borrow $t)
. It can be inspected via
Resource::owned
to test whether it is an owned handle. An owned handle
which is not actively borrowed can be destroyed at any time as it’s
guaranteed that the guest does not have access to it. A borrowed handle, on
the other hand, may be accessed by the guest so it’s not necessarily
guaranteed to be able to be destroyed.
Note that the “own” and “borrow” here refer to the component model, not
Rust. The semantics of Rust ownership and borrowing are slightly different
than the component model’s (but spiritually the same) in that more dynamic
tracking is employed as part of the component model. This means that it’s
possible to get runtime errors when using a Resource<T>
. For example it is
an error to call Resource::new_borrow
and pass that to a component
function expecting (own $t)
and this is not statically disallowed.
The Resource
type implements both the Lift
and Lower
trait to be
used with typed functions in the component model or as part of aggregate
structures and datatypes.
§Destruction of a resource
Resources in the component model are optionally defined with a destructor, but this host resource type does not specify a destructor. It is left up to the embedder to be able to determine how best to a destroy a resource when it is owned.
Note, though, that while Resource
itself does not specify destructors
it’s still possible to do so via the Linker::resource
definition. When a
resource type is defined for a guest component a destructor can be specified
which can be used to hook into resource destruction triggered by the guest.
This means that there are two ways that resource destruction is handled:
-
Host resources destroyed by the guest can hook into the
Linker::resource
destructor closure to handle resource destruction. This could, for example, remove table entries. -
Host resources owned by the host itself have no automatic means of destruction. The host can make its own determination that its own resource is not lent out to the guest and at that time choose to destroy or deallocate it.
§Dynamic behavior of a resource
A host-defined Resource
does not necessarily represent a static value.
Its internals may change throughout its usage to track the state associated
with the resource. The internal 32-bit host-defined representation never
changes, however.
For example if there’s a component model function of the form:
(func (param "a" (borrow $t)) (param "b" (own $t)))
Then that can be extracted in Rust with:
let func = instance.get_typed_func::<(&Resource<T>, &Resource<T>), ()>(&mut store, "name")?;
Here the exact same resource can be provided as both arguments but that is
not valid to do so because the same resource cannot be actively borrowed and
passed by-value as the second parameter at the same time. The internal state
in Resource<T>
will track this information and provide a dynamic runtime
error in this situation.
Mostly it’s important to be aware that there is dynamic state associated
with a Resource<T>
to provide errors in situations that cannot be
statically ruled out.
§Borrows and host responsibilities
Borrows to resources in the component model are guaranteed to be transient such that if a borrow is passed as part of a function call then when the function returns it’s guaranteed that the guest no longer has access to the resource. This guarantee, however, must be manually upheld by the host when it receives its own borrow.
As mentioned above the Resource<T>
type can represent a borrowed value
in addition to an owned value. This means a guest can provide the host with
a borrow, such as an argument to an imported function:
linker.root().func_wrap("name", |_cx, (r,): (Resource<MyType>,)| {
assert!(!r.owned());
// .. here `r` is a borrowed value provided by the guest and the host
// shouldn't continue to access it beyond the scope of this call
})?;
In this situation the host should take care to not attempt to persist the
resource beyond the scope of the call. It’s the host’s resource so it
technically can do what it wants with it but nothing is statically
preventing r
to stay pinned to the lifetime of the closure invocation.
It’s considered a mistake that the host performed if r
is persisted too
long and accessed at the wrong time.
Implementations§
§impl<T> Resource<T>where
T: 'static,
impl<T> Resource<T>where
T: 'static,
pub fn new_own(rep: u32) -> Resource<T>
pub fn new_own(rep: u32) -> Resource<T>
Creates a new owned resource with the rep
specified.
The returned value is suitable for passing to a guest as either a
(borrow $t)
or (own $t)
.
pub fn new_borrow(rep: u32) -> Resource<T>
pub fn new_borrow(rep: u32) -> Resource<T>
Creates a new borrowed resource which isn’t actually rooted in any ownership.
This can be used to pass to a guest as a borrowed resource and the
embedder will know that the rep
won’t be in use by the guest
afterwards. Exactly how the lifetime of rep
works is up to the
embedder.
pub fn rep(&self) -> u32
pub fn rep(&self) -> u32
Returns the underlying 32-bit representation used to originally create this resource.
pub fn owned(&self) -> bool
pub fn owned(&self) -> bool
Returns whether this is an owned resource or not.
Owned resources can be safely destroyed by the embedder at any time, and borrowed resources have an owner somewhere else on the stack so can only be accessed, not destroyed.
pub fn try_from_resource_any(
resource: ResourceAny,
store: impl AsContextMut,
) -> Result<Resource<T>, Error>
pub fn try_from_resource_any( resource: ResourceAny, store: impl AsContextMut, ) -> Result<Resource<T>, Error>
Attempts to convert a ResourceAny
into Resource
.
This method will check that resource
has type
ResourceType::host::<T>()
and then convert it into a typed version of
the resource.
§Errors
This function will return an error if resource
does not have type
ResourceType::host::<T>()
. This function may also return an error if
resource
is no longer valid, for example it was previously converted.
§Panics
This function will panic if resource
does not belong to the store
specified.
pub fn try_into_resource_any(
self,
store: impl AsContextMut,
) -> Result<ResourceAny, Error>
pub fn try_into_resource_any( self, store: impl AsContextMut, ) -> Result<ResourceAny, Error>
Trait Implementations§
impl<T> ComponentType for Resource<T>where
T: 'static,
impl<T> Lift for Resource<T>where
T: 'static,
impl<T> Lower for Resource<T>where
T: 'static,
Auto Trait Implementations§
impl<T> !Freeze for Resource<T>
impl<T> RefUnwindSafe for Resource<T>
impl<T> Send for Resource<T>
impl<T> Sync for Resource<T>
impl<T> Unpin for Resource<T>
impl<T> UnwindSafe for Resource<T>
Blanket Implementations§
source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
source§impl<T> Instrument for T
impl<T> Instrument for T
source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
source§impl<T> IntoEither for T
impl<T> IntoEither for T
source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self
into a Left
variant of Either<Self, Self>
if into_left
is true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moresource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self
into a Left
variant of Either<Self, Self>
if into_left(&self)
returns true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read more