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>
impl<T> Resource<T>
Sourcepub fn leak(self) -> ResourceCopy<T>
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<D: DropGuard> Resource<(), D>
impl<D: DropGuard> Resource<(), D>
Sourcepub unsafe fn downcast_unchecked<T>(self) -> Resource<T, D>
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, D: DropGuard> PartialEq for Resource<T, D>
Compares resources by their pointers, similar to ptr::eq().
impl<T, D: DropGuard> PartialEq for Resource<T, D>
Compares resources by their pointers, similar to ptr::eq().
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> 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> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.