use crate::{
ResourceLimiter,
core::LimiterError,
errors::{MemoryError, TableError},
};
pub const DEFAULT_INSTANCE_LIMIT: usize = 10_000;
pub const DEFAULT_TABLE_LIMIT: usize = 10_000;
pub const DEFAULT_MEMORY_LIMIT: usize = 10_000;
pub struct StoreLimitsBuilder(StoreLimits);
impl StoreLimitsBuilder {
pub fn new() -> Self {
Self(StoreLimits::default())
}
pub fn memory_size(mut self, limit: usize) -> Self {
self.0.memory_size = Some(limit);
self
}
pub fn table_elements(mut self, limit: usize) -> Self {
self.0.table_elements = Some(limit);
self
}
pub fn instances(mut self, limit: usize) -> Self {
self.0.instances = limit;
self
}
pub fn tables(mut self, tables: usize) -> Self {
self.0.tables = tables;
self
}
pub fn memories(mut self, memories: usize) -> Self {
self.0.memories = memories;
self
}
pub fn trap_on_grow_failure(mut self, trap: bool) -> Self {
self.0.trap_on_grow_failure = trap;
self
}
pub fn build(self) -> StoreLimits {
self.0
}
}
impl Default for StoreLimitsBuilder {
fn default() -> Self {
Self::new()
}
}
#[derive(Clone, Debug)]
pub struct StoreLimits {
memory_size: Option<usize>,
table_elements: Option<usize>,
instances: usize,
tables: usize,
memories: usize,
trap_on_grow_failure: bool,
}
impl Default for StoreLimits {
fn default() -> Self {
Self {
memory_size: None,
table_elements: None,
instances: DEFAULT_INSTANCE_LIMIT,
tables: DEFAULT_TABLE_LIMIT,
memories: DEFAULT_MEMORY_LIMIT,
trap_on_grow_failure: false,
}
}
}
impl ResourceLimiter for StoreLimits {
fn memory_growing(
&mut self,
_current: usize,
desired: usize,
maximum: Option<usize>,
) -> Result<bool, LimiterError> {
let allow = match self.memory_size {
Some(limit) if desired > limit => false,
_ => match maximum {
Some(max) if desired > max => false,
Some(_) | None => true,
},
};
if !allow && self.trap_on_grow_failure {
return Err(LimiterError::ResourceLimiterDeniedAllocation);
}
Ok(allow)
}
fn memory_grow_failed(&mut self, _error: &MemoryError) -> Result<(), LimiterError> {
if self.trap_on_grow_failure {
return Err(LimiterError::ResourceLimiterDeniedAllocation);
}
Ok(())
}
fn table_growing(
&mut self,
_current: usize,
desired: usize,
maximum: Option<usize>,
) -> Result<bool, LimiterError> {
let allow = match self.table_elements {
Some(limit) if desired > limit => false,
_ => match maximum {
Some(max) if desired > max => false,
Some(_) | None => true,
},
};
if !allow && self.trap_on_grow_failure {
return Err(LimiterError::ResourceLimiterDeniedAllocation);
}
Ok(allow)
}
fn table_grow_failed(&mut self, _error: &TableError) -> Result<(), LimiterError> {
if self.trap_on_grow_failure {
return Err(LimiterError::ResourceLimiterDeniedAllocation);
}
Ok(())
}
fn instances(&self) -> usize {
self.instances
}
fn tables(&self) -> usize {
self.tables
}
fn memories(&self) -> usize {
self.memories
}
}