Resource

Struct Resource 

Source
pub struct Resource<T, D = Register> { /* private fields */ }
Expand description

Host resource exposed to WASM.

Internally, a resource is just an index into the externrefs table; thus, it is completely valid to store Resources on heap (in a Vec, thread-local storage, etc.). The type param can be used for type safety.

§Equality

Resource implements PartialEq, Eq and Hash traits from the standard library, in which it has pointer semantics (i.e., two Resources are equal if they point to the same data, which, since Resource cannot be cloned, means they are the same object). If you want to compare the pointed-to content, it can be accomplished by wrapping a Resource into a higher-level abstraction and implementing PartialEq / Eq / Hash / other traits e.g. by reading data from the host or delegating comparison to the host.

§Cloning

By default, resources may have configurable logic executed on drop (e.g., to have RAII-style resource management on the host side). Dropping the resource also cleans up the resource slot in the externref table. Thus, Resource intentionally doesn’t implement Clone or Copy. To clone such a resource, you may use Rc, Arc or another smart pointer.

As an alternative, you may use ResourceCopy. This is a version of Resource that does not execute any logic on drop (not even cleaning up the externref table entry!). As a consequence, ResourceCopy may be copied across the app.

§Memory layout

Resource with any type params is guaranteed to have the same layout as usize. When cast to usize (e.g., by passing a Resource value to a WASM import fn), the value is the index of the externref in the corresponding WASM table (see How it works in the crate level-docs for details).

§Examples

§Cloning

In this scenario, the Resource is cloneable by wrapping it in an Arc. This retains RAII resource management capabilities.

use externref::{externref, Resource};
use std::sync::Arc;

#[externref]
#[link(wasm_import_module = "data")]
unsafe extern "C" {
    fn alloc_data(capacity: usize) -> Resource<SmartData>;

    fn data_len(handle: &Resource<SmartData>) -> usize;
}

#[derive(Debug, Clone)]
pub struct SmartData {
    // `Resource<Self>` is completely valid (doesn't lead to type size errors),
    // and in fact is encouraged.
    handle: Arc<Resource<Self>>,
}

impl SmartData {
    fn new(capacity: usize) -> Self {
        Self {
            handle: Arc::new(unsafe { alloc_data(capacity) }),
        }
    }

    fn len(&self) -> usize {
        unsafe { data_len(&self.handle) }
    }
}

§Implementing comparisons

This implements Eq, Ord and Hash traits for the pointee based on host imports.

use externref::{externref, Resource};
use core::{cmp, hash::{Hash, Hasher}};

#[externref]
#[link(wasm_import_module = "data")]
unsafe extern "C" {
    /// Compares pointed-to data and returns -1 / 0 / 1.
    fn compare(
        lhs: &Resource<ComparableData>,
        rhs: &Resource<ComparableData>,
    ) -> isize;

    /// Hashes the pointed-to data.
    fn hash(data: &Resource<ComparableData>) -> u64;
}

#[derive(Debug)]
pub struct ComparableData {
    handle: Resource<Self>,
}

impl PartialEq for ComparableData {
    fn eq(&self, other: &Self) -> bool {
        unsafe { compare(&self.handle, &other.handle) == 0 }
    }
}

impl Eq for ComparableData {}

impl PartialOrd for ComparableData {
    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for ComparableData {
    fn cmp(&self, other: &Self) -> cmp::Ordering {
        let ordering = unsafe { compare(&self.handle, &other.handle) };
        ordering.cmp(&0)
    }
}

impl Hash for ComparableData {
    fn hash<H: Hasher>(&self, hasher: &mut H) {
        unsafe { hash(&self.handle) }.hash(hasher)
    }
}

Implementations§

Source§

impl<T> Resource<T>

Source

pub fn leak(self) -> ResourceCopy<T>

Leaks this resource. Similarly to Box::leak() or mem::forget(), this isn’t unsafe, but may lead to resource starvation.

Source§

impl<T, D: DropGuard> Resource<T, D>

Source

pub fn upcast(self) -> Resource<(), D>

Upcasts this resource to a generic resource.

Source

pub fn upcast_ref(&self) -> &Resource<(), D>

Upcasts a reference to this resource to a generic resource reference.

Source§

impl<D: DropGuard> Resource<(), D>

Source

pub unsafe fn downcast_unchecked<T>(self) -> Resource<T, D>

Downcasts this generic resource to a specific type.

§Safety

No checks are performed that the resource actually encapsulates what is meant by Resource<T>. It is up to the caller to check this beforehand (e.g., by calling a WASM import taking &Resource<()> and returning an app-specific resource kind).

Trait Implementations§

Source§

impl<T: Debug, D: Debug> Debug for Resource<T, D>

Source§

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

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

impl<T, D: DropGuard> Hash for Resource<T, D>

Hashes the resource based on its pointer, consistently with the PartialEq / Eq implementation.

Source§

fn hash<H: Hasher>(&self, state: &mut H)

Feeds this value into the given Hasher. Read more
1.3.0 · Source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where H: Hasher, Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
Source§

impl<T, D: DropGuard> PartialEq for Resource<T, D>

Compares resources by their pointers, similar to ptr::eq().

Source§

fn eq(&self, other: &Self) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl<T, D: DropGuard> Eq for Resource<T, D>

Auto Trait Implementations§

§

impl<T, D> Freeze for Resource<T, D>
where D: Freeze,

§

impl<T, D> RefUnwindSafe for Resource<T, D>
where D: RefUnwindSafe,

§

impl<T, D> Send for Resource<T, D>
where D: Send,

§

impl<T, D> Sync for Resource<T, D>
where D: Sync,

§

impl<T, D> Unpin for Resource<T, D>
where D: Unpin,

§

impl<T, D> UnwindSafe for Resource<T, D>
where D: 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> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
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.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

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

Source§

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>,

Source§

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

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more