Struct wasmtime::ManuallyRooted

source ·
pub struct ManuallyRooted<T>
where T: GcRef,
{ /* private fields */ }
Available on crate feature runtime only.
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.

TypeSupported LifetimesUnrooting
Rooted<T>Strictly LIFO / stack orderAutomatic
ManuallyRooted<T>ArbitraryManual

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 a std::sync::Arc or std::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 Stores where unrooting would just be busy work since the whole store is about to be dropped.

Implementations§

source§

impl<T> ManuallyRooted<T>
where T: GcRef,

source

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);
}
source

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.

source

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);
source

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.
source

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);
source

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.

source

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.

Trait Implementations§

source§

impl<T: GcRef> Debug for ManuallyRooted<T>

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl<T: GcRef> Deref for ManuallyRooted<T>

§

type Target = T

The resulting type after dereferencing.
source§

fn deref(&self) -> &Self::Target

Dereferences the value.
source§

impl WasmTy for ManuallyRooted<AnyRef>

source§

impl WasmTy for ManuallyRooted<ExternRef>

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> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

§

impl<T> Pointable for T

§

const ALIGN: usize = _

The alignment of pointer.
§

type Init = T

The type for initializers.
§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<T> WasmParams for T
where T: WasmTy,

§

type Abi = <(T,) as WasmParams>::Abi

source§

fn typecheck( engine: &Engine, params: impl ExactSizeIterator<Item = ValType>, position: TypeCheckPosition ) -> Result<(), Error>

source§

fn non_i31_gc_refs_count(&self) -> usize

source§

fn into_abi( self, store: &mut AutoAssertNoGc<'_>, func_ty: &FuncType ) -> Result<<T as WasmParams>::Abi, Error>

source§

unsafe fn invoke<R>( func: NonNull<VMNativeCallFunction>, vmctx1: *mut VMOpaqueContext, vmctx2: *mut VMContext, abi: <T as WasmParams>::Abi ) -> <R as WasmResults>::ResultAbi
where R: WasmResults,

source§

impl<T> WasmResults for T
where T: WasmTy, (<T as WasmTy>::Abi,): HostAbi,

§

type ResultAbi = <(T,) as WasmResults>::ResultAbi

source§

unsafe fn from_abi( store: &mut AutoAssertNoGc<'_>, abi: <T as WasmResults>::ResultAbi ) -> T

source§

impl<T> WasmRet for T
where T: WasmTy,

§

type Abi = <T as WasmTy>::Abi

§

type Retptr = ()

§

type Fallible = Result<T, Error>

source§

fn compatible_with_store(&self, store: &StoreOpaque) -> bool

source§

unsafe fn into_abi_for_ret( self, store: &mut AutoAssertNoGc<'_>, _retptr: () ) -> Result<<T as WasmRet>::Abi, Error>

source§

fn func_type(engine: &Engine, params: impl Iterator<Item = ValType>) -> FuncType

source§

unsafe fn wrap_trampoline( ptr: *mut ValRaw, f: impl FnOnce(<T as WasmRet>::Retptr) -> <T as WasmRet>::Abi )

source§

fn into_fallible(self) -> Result<T, Error>

source§

fn fallible_from_error(error: Error) -> Result<T, Error>

source§

impl<T, U> RootedGcRef<T> for U
where T: GcRef, U: RootedGcRefImpl<T> + Deref<Target = T>,