Struct wasmtime::ManuallyRooted
source · pub struct ManuallyRooted<T>where
T: GcRef,{ /* private fields */ }
Expand description
A rooted reference to a garbage-collected T
with arbitrary lifetime.
A ManuallyRooted<T>
is a strong handle to a garbage-collected T
,
preventing its referent (and anything else transitively referenced) from
being collected by the GC until unroot
is
explicitly called.
The primary way to create a ManuallyRooted<T>
is to promote a temporary
Rooted<T>
into a ManuallyRooted<T>
via its
to_manually_rooted
method.
ManuallyRooted<T>
dereferences to its underlying T
, allowing you to call
T
’s methods.
§Example
let mut store = Store::<Option<ManuallyRooted<ExternRef>>>::default();
// Create our `ManuallyRooted` in a nested scope to avoid rooting it for
// the duration of the store's lifetime.
let x = {
let mut scope = RootScope::new(&mut store);
let x = ExternRef::new(&mut scope, 1234)?;
x.to_manually_rooted(&mut scope)?
};
// Place `x` into our store.
*store.data_mut() = Some(x);
// Do a bunch stuff that may or may not access, replace, or take `x`...
// At any time, in any arbitrary scope, we can remove `x` from the store
// and unroot it:
if let Some(x) = store.data_mut().take() {
x.unroot(&mut store);
}
§Differences Between ManuallyRooted<T>
and Rooted<T>
While ManuallyRooted<T>
can have arbitrary lifetimes, it requires manual
unrooting. This is in contrast to Rooted<T>
which is
restricted to strictly last-in-first-out (LIFO, aka stack order) lifetimes,
but comes with automatic unrooting.
Type | Supported Lifetimes | Unrooting |
---|---|---|
Rooted<T> | Strictly LIFO / stack order | Automatic |
ManuallyRooted<T> | Arbitrary | Manual |
Rooted<T>
should suffice for most use cases, and provides better
ergonomics, but ManuallyRooted<T>
exists as a fully-general escape hatch.
§Manual Unrooting
Failure to explicitly call unroot
(or
another method that consumes self
and unroots the reference, such as
into_rooted
) will leak the
underlying GC object, preventing it from being garbage collected until its
owning Store
is dropped. That means all of the following
will result in permanently rooting the underlying GC object:
-
Implicitly dropping a
ManuallyRooted<T>
:{ let perma_root: ManuallyRooted<_> = get_manually_rooted(); // `perma_root` is implicitly dropped at the end of its scope, // permanently rooting/leaking its referent. }
-
Explicitly dropping a
ManuallyRooted<T>
:drop(my_manually_rooted)
. -
Forgetting a
ManuallyRooted<T>
:std::mem::forget(my_manually_rooted)
. -
Inserting a
ManuallyRooted<T>
into astd::sync::Arc
orstd::rc::Rc
cycle. -
Etc…
Wasmtime does not assert that a ManuallyRooted<T>
is unrooted on Drop
,
or otherwise raise a panic, log a warning, or etc… on failure to manually
unroot. Sometimes leaking is intentional and desirable, particularly when
dealing with short-lived Store
s where unrooting would just
be busy work since the whole store is about to be dropped.
Implementations§
source§impl ManuallyRooted<ArrayRef>
impl ManuallyRooted<ArrayRef>
sourcepub fn to_anyref(self) -> ManuallyRooted<AnyRef>
pub fn to_anyref(self) -> ManuallyRooted<AnyRef>
Upcast this arrayref
into an anyref
.
source§impl<T> ManuallyRooted<T>where
T: GcRef,
impl<T> ManuallyRooted<T>where
T: GcRef,
sourcepub fn clone(&self, store: impl AsContextMut) -> Self
pub fn clone(&self, store: impl AsContextMut) -> Self
Clone this ManuallyRooted
.
Does not consume or unroot self
: both self
and the new
ManuallyRooted
return value will need to be manually unrooted.
§Panics
Panics if self
is not associated with the given store
.
§Example
let mut store = Store::<Vec<ManuallyRooted<ExternRef>>>::default();
// Create our `ManuallyRooted` in a nested scope to avoid rooting it for
// the duration of the store's lifetime.
let x = {
let mut scope = RootScope::new(&mut store);
let x = ExternRef::new(&mut scope, 1234)?;
x.to_manually_rooted(&mut scope)?
};
// Push five clones of `x` into our store.
for _ in 0..5 {
let x_clone = x.clone(&mut store);
store.data_mut().push(x_clone);
}
sourcepub fn unroot(self, store: impl AsContextMut)
pub fn unroot(self, store: impl AsContextMut)
Unroot this GC object.
Failure to call this method will result in the GC object, and anything it transitively references, being kept alive (aka “leaking”) for the entirety of the store’s lifetime.
See the type-level docs for example usage.
sourcepub fn to_rooted(&self, context: impl AsContextMut) -> Rooted<T>
pub fn to_rooted(&self, context: impl AsContextMut) -> Rooted<T>
Clone this ManuallyRooted<T>
into a Rooted<T>
.
This operation does not consume or unroot this ManuallyRooted<T>
.
The underlying GC object is re-rooted in the given context’s scope. The
resulting Rooted<T>
is only valid during the given context’s
scope. See the Rooted<T>
documentation for more
details on rooting scopes.
This operation does not consume or unroot this ManuallyRooted<T>
.
§Panics
Panics if this object is not associated with the given context’s store.
§Example
let mut store = Store::<()>::default();
let root1: Rooted<_>;
let manual = {
let mut scope = RootScope::new(&mut store);
root1 = ExternRef::new(&mut scope, 1234)?;
root1.to_manually_rooted(&mut scope)?
};
// `root1` is no longer accessible because it was unrooted when `scope`
// was dropped.
assert!(root1.data(&store).is_err());
// But we can re-root `manual` into this scope.
let root2 = manual.to_rooted(&mut store);
assert!(root2.data(&store).is_ok());
// And we also still have access to `manual` and we still have to
// manually unroot it.
assert!(manual.data(&store).is_ok());
manual.unroot(&mut store);
sourcepub fn into_rooted(self, context: impl AsContextMut) -> Rooted<T>
pub fn into_rooted(self, context: impl AsContextMut) -> Rooted<T>
Convert this ManuallyRooted<T>
into a Rooted<T>
.
The underlying GC object is re-rooted in the given context’s scope. The
resulting Rooted<T>
is only valid during the given context’s
scope. See the Rooted<T>
documentation for more
details on rooting scopes.
This operation consumes and unroots this ManuallyRooted<T>
.
§Panics
Panics if this object is not associate with the given context’s store.
§Example
let mut store = Store::<()>::default();
let root1: Rooted<_>;
let manual = {
let mut scope = RootScope::new(&mut store);
root1 = ExternRef::new(&mut scope, 1234)?;
root1.to_manually_rooted(&mut scope)?
};
// `root1` is no longer accessible because it was unrooted when `scope`
// was dropped.
assert!(root1.data(&store).is_err());
// But we can re-root `manual` into this scope.
let root2 = manual.into_rooted(&mut store);
assert!(root2.data(&store).is_ok());
// `manual` was consumed by the `into_rooted` call, and we no longer
// have access to it, nor need to manually unroot it.
sourcepub fn ref_eq(
store: impl AsContext,
a: &impl RootedGcRef<T>,
b: &impl RootedGcRef<T>,
) -> Result<bool>
pub fn ref_eq( store: impl AsContext, a: &impl RootedGcRef<T>, b: &impl RootedGcRef<T>, ) -> Result<bool>
Are these two GC roots referencing the same underlying GC object?
This function will return true
even when a
and b
are different GC
roots (for example because they were rooted in different scopes) if they
are rooting the same underlying GC object.
Because this method takes any impl RootedGcRef<T>
arguments, it can be
used to compare, for example, a Rooted<T>
and a ManuallyRooted<T>
.
§Panics
Panics if either a
or b
is not associated with the given store
.
§Example
let mut store = Store::<()>::default();
let a = ExternRef::new_manually_rooted(&mut store, "hello")?;
let b = a.clone(&mut store);
// `a` and `b` are rooting the same object.
assert!(ManuallyRooted::ref_eq(&store, &a, &b)?);
{
let mut scope = RootScope::new(&mut store);
// `c` is a different GC root, is in a different scope, and is a
// `Rooted<T>` instead of a `ManuallyRooted<T>`, but is still rooting
// the same object.
let c = a.to_rooted(&mut scope);
assert!(ManuallyRooted::ref_eq(&scope, &a, &c)?);
}
let x = ExternRef::new_manually_rooted(&mut store, "goodbye")?;
// `a` and `x` are rooting different objects.
assert!(!ManuallyRooted::ref_eq(&store, &a, &x)?);
a.unroot(&mut store);
b.unroot(&mut store);
x.unroot(&mut store);
sourcepub fn rooted_hash<H>(&self, state: &mut H)where
H: Hasher,
pub fn rooted_hash<H>(&self, state: &mut H)where
H: Hasher,
Hash this root.
Note that, similar to Rooted::rooted_eq
, this only operates on the
root and not the underlying GC reference. That means that two
different rootings of the same object will hash to different values
(modulo hash collisions). If this is undesirable, use the
ref_hash
method instead.
sourcepub fn ref_hash<H>(&self, store: impl AsContext, state: &mut H)where
H: Hasher,
pub fn ref_hash<H>(&self, store: impl AsContext, state: &mut H)where
H: Hasher,
Hash the underlying rooted object reference.
Note that, similar to Rooted::ref_eq
, and operates on the underlying
rooted GC object reference, not the root. That means that two
different rootings of the same object will hash to the same
value. If this is undesirable, use the
rooted_hash
method instead.
source§impl ManuallyRooted<StructRef>
impl ManuallyRooted<StructRef>
sourcepub fn to_anyref(self) -> ManuallyRooted<AnyRef>
pub fn to_anyref(self) -> ManuallyRooted<AnyRef>
Upcast this structref
into an anyref
.
Trait Implementations§
source§impl<T: GcRef> Debug for ManuallyRooted<T>
impl<T: GcRef> Debug for ManuallyRooted<T>
source§impl<T: GcRef> Deref for ManuallyRooted<T>
impl<T: GcRef> Deref for ManuallyRooted<T>
source§impl From<ManuallyRooted<ArrayRef>> for ManuallyRooted<AnyRef>
impl From<ManuallyRooted<ArrayRef>> for ManuallyRooted<AnyRef>
source§fn from(s: ManuallyRooted<ArrayRef>) -> Self
fn from(s: ManuallyRooted<ArrayRef>) -> Self
source§impl From<ManuallyRooted<StructRef>> for ManuallyRooted<AnyRef>
impl From<ManuallyRooted<StructRef>> for ManuallyRooted<AnyRef>
source§fn from(s: ManuallyRooted<StructRef>) -> Self
fn from(s: ManuallyRooted<StructRef>) -> Self
impl WasmTy for ManuallyRooted<AnyRef>
impl WasmTy for ManuallyRooted<ArrayRef>
impl WasmTy for ManuallyRooted<ExternRef>
impl WasmTy for ManuallyRooted<StructRef>
Auto Trait Implementations§
impl<T> Freeze for ManuallyRooted<T>
impl<T> RefUnwindSafe for ManuallyRooted<T>where
T: RefUnwindSafe,
impl<T> Send for ManuallyRooted<T>where
T: Send,
impl<T> Sync for ManuallyRooted<T>where
T: Sync,
impl<T> Unpin for ManuallyRooted<T>where
T: Unpin,
impl<T> UnwindSafe for ManuallyRooted<T>where
T: UnwindSafe,
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> 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