use crate::{MemoryError, TableError};
use core::{
error::Error,
fmt,
fmt::{Debug, Display},
};
/// An error either returned by a [`ResourceLimiter`] or back to one.
#[derive(Debug, Copy, Clone)]
pub enum LimiterError {
/// Returned if a [`ResourceLimiter`] denies allocation or growth.
///
/// Used to signal that `memory.grow` or `table.grow` failure should panic.
ResourceLimiterDeniedAllocation,
}
impl Error for LimiterError {}
impl Display for LimiterError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let message = match self {
Self::ResourceLimiterDeniedAllocation => "resource limiter denied allocation",
};
f.write_str(message)
}
}
/// Used by hosts to limit resource consumption of instances.
///
/// Resources limited via this trait are primarily related to memory.
///
/// Note that this trait does not limit 100% of memory allocated.
/// Implementers might still allocate memory to track data structures
/// and additionally embedder-specific memory allocations are not
/// tracked via this trait.
pub trait ResourceLimiter {
/// Notifies the resource limiter that an instance's linear memory has been
/// requested to grow.
///
/// * `current` is the current size of the linear memory in bytes.
/// * `desired` is the desired size of the linear memory in bytes.
/// * `maximum` is either the linear memory's maximum or a maximum from an
/// instance allocator, also in bytes. A value of `None`
/// indicates that the linear memory is unbounded.
///
/// The `current` and `desired` amounts are guaranteed to always be
/// multiples of the WebAssembly page size, 64KiB.
///
/// ## Return Value
///
/// If `Ok(true)` is returned from this function then the growth operation
/// is allowed. This means that the wasm `memory.grow` or `table.grow` instructions
/// will return with the `desired` size, in wasm pages. Note that even if
/// `Ok(true)` is returned, though, if `desired` exceeds `maximum` then the
/// growth operation will still fail.
///
/// If `Ok(false)` is returned then this will cause the `grow` instruction
/// in a module to return -1 (failure), or in the case of an embedder API
/// calling any of the below methods an error will be returned.
///
/// - [`Memory::new`]
/// - [`Memory::grow`]
///
/// # Errors
///
/// If `Err(e)` is returned then the `memory.grow` or `table.grow` functions
/// will behave as if a trap has been raised. Note that this is not necessarily
/// compliant with the WebAssembly specification but it can be a handy and
/// useful tool to get a precise backtrace at "what requested so much memory
/// to cause a growth failure?".
///
/// [`Memory::new`]: crate::Memory::new
/// [`Memory::grow`]: crate::Memory::grow
fn memory_growing(
&mut self,
current: usize,
desired: usize,
maximum: Option<usize>,
) -> Result<bool, LimiterError>;
/// Notifies the resource limiter that an instance's table has been
/// requested to grow.
///
/// * `current` is the current number of elements in the table.
/// * `desired` is the desired number of elements in the table.
/// * `maximum` is either the table's maximum or a maximum from an instance
/// allocator. A value of `None` indicates that the table is unbounded.
///
/// # Errors
///
/// See the details on the return values for [`ResourceLimiter::memory_growing`]
/// for what the return values of this function indicates.
fn table_growing(
&mut self,
current: usize,
desired: usize,
maximum: Option<usize>,
) -> Result<bool, LimiterError>;
/// Notifies the resource limiter that growing a memory, permitted by
/// the [`ResourceLimiter::memory_growing`] method, has failed.
///
/// # Errors
///
/// To signal to the caller that `memory.grow` failure should panic.
fn memory_grow_failed(&mut self, _error: &MemoryError) -> Result<(), LimiterError> {
Ok(())
}
/// Notifies the resource limiter that growing a table, permitted by
/// the [`ResourceLimiter::table_growing`] method, has failed.
///
/// # Errors
///
/// To signal to the caller that `table.grow` failure should panic.
fn table_grow_failed(&mut self, _error: &TableError) -> Result<(), LimiterError> {
Ok(())
}
/// The maximum number of instances that can be created for a Wasm store.
///
/// Module instantiation will fail if this limit is exceeded.
fn instances(&self) -> usize;
/// The maximum number of tables that can be created for a Wasm store.
///
/// Creation of tables will fail if this limit is exceeded.
fn tables(&self) -> usize;
/// The maximum number of linear memories that can be created for a Wasm store.
///
/// Creation of memories will fail with an error if this limit is exceeded.
fn memories(&self) -> usize;
}
/// Wrapper around an optional `&mut dyn` [`ResourceLimiter`].
///
/// # Note
///
/// This type exists both to make types a little easier to read and to provide
/// a `Debug` impl so that `#[derive(Debug)]` works on structs that contain it.
#[derive(Default)]
pub struct ResourceLimiterRef<'a>(Option<&'a mut dyn ResourceLimiter>);
impl Debug for ResourceLimiterRef<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "ResourceLimiterRef(...)")
}
}
impl<'a> From<&'a mut dyn ResourceLimiter> for ResourceLimiterRef<'a> {
fn from(limiter: &'a mut dyn ResourceLimiter) -> Self {
Self(Some(limiter))
}
}
impl ResourceLimiterRef<'_> {
/// Returns an exclusive reference to the underlying [`ResourceLimiter`] if any.
pub fn as_resource_limiter(&mut self) -> Option<&mut dyn ResourceLimiter> {
match self.0.as_mut() {
Some(limiter) => Some(*limiter),
None => None,
}
}
}
use crate::;
use ;
/// An error either returned by a [`ResourceLimiter`] or back to one.
/// Used by hosts to limit resource consumption of instances.
///
/// Resources limited via this trait are primarily related to memory.
///
/// Note that this trait does not limit 100% of memory allocated.
/// Implementers might still allocate memory to track data structures
/// and additionally embedder-specific memory allocations are not
/// tracked via this trait.
/// Wrapper around an optional `&mut dyn` [`ResourceLimiter`].
///
/// # Note
///
/// This type exists both to make types a little easier to read and to provide
/// a `Debug` impl so that `#[derive(Debug)]` works on structs that contain it.
;