use alloc::boxed::Box;
use crate::ResourceLimiter;
use crate::shared::StoreShared;
#[derive(Clone, Default)]
#[cfg_attr(feature = "debug", derive(Debug))]
pub struct Engine {
pub(crate) config: Config,
}
impl Engine {
pub fn new(config: Config) -> Self {
Self { config }
}
pub fn config(&self) -> &Config {
&self.config
}
}
#[non_exhaustive]
#[derive(Default, Clone, Copy)]
#[cfg_attr(feature = "debug", derive(Debug))]
pub enum FuelPolicy {
#[default]
PerInstruction,
Weighted,
}
const DEFAULT_VALUE_STACK_32_SIZE: usize = 36 * 1024;
const DEFAULT_VALUE_STACK_64_SIZE: usize = 32 * 1024;
const DEFAULT_VALUE_STACK_128_SIZE: usize = 4 * 1024;
const DEFAULT_MAX_CALL_STACK_SIZE: usize = 1024;
#[derive(Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "debug", derive(Debug))]
pub struct StackConfig {
pub initial_size: usize,
pub max_size: usize,
pub dynamic: bool,
}
impl StackConfig {
pub const fn fixed(size: usize) -> Self {
Self { initial_size: size, max_size: size, dynamic: false }
}
pub const fn dynamic(initial_size: usize, max_size: usize) -> Self {
assert!(initial_size <= max_size, "initial_size must be less than or equal to max_size");
Self { initial_size, max_size, dynamic: true }
}
}
#[derive(Clone)]
#[non_exhaustive]
pub struct Config {
pub value_stack_32: StackConfig,
pub value_stack_64: StackConfig,
pub value_stack_128: StackConfig,
pub call_stack: StackConfig,
pub fuel_policy: FuelPolicy,
pub resource_limiter: Option<StoreShared<dyn ResourceLimiter>>,
pub gc_collection_threshold: usize,
}
impl Config {
pub fn new() -> Self {
Self::default()
}
pub fn with_fuel_policy(mut self, fuel_policy: FuelPolicy) -> Self {
self.fuel_policy = fuel_policy;
self
}
pub fn with_value_stack_32(mut self, stack: StackConfig) -> Self {
self.value_stack_32 = stack;
self
}
pub fn with_value_stack(mut self, stack: StackConfig) -> Self {
self.value_stack_32 = stack;
self.value_stack_64 = stack;
self.value_stack_128 = stack;
self
}
pub fn with_value_stack_64(mut self, stack: StackConfig) -> Self {
self.value_stack_64 = stack;
self
}
pub fn with_value_stack_128(mut self, stack: StackConfig) -> Self {
self.value_stack_128 = stack;
self
}
pub fn with_call_stack(mut self, stack: StackConfig) -> Self {
self.call_stack = stack;
self
}
pub fn with_resource_limiter(mut self, limiter: impl ResourceLimiter + 'static) -> Self {
self.resource_limiter = Some(StoreShared::from(Box::new(limiter) as Box<dyn ResourceLimiter>));
self
}
pub fn with_gc_collection_threshold(mut self, threshold: usize) -> Self {
self.gc_collection_threshold = threshold;
self
}
pub fn fuel_policy(&self) -> FuelPolicy {
self.fuel_policy
}
}
impl Default for Config {
fn default() -> Self {
Self {
value_stack_32: StackConfig::fixed(DEFAULT_VALUE_STACK_32_SIZE),
value_stack_64: StackConfig::fixed(DEFAULT_VALUE_STACK_64_SIZE),
value_stack_128: StackConfig::fixed(DEFAULT_VALUE_STACK_128_SIZE),
call_stack: StackConfig::fixed(DEFAULT_MAX_CALL_STACK_SIZE),
fuel_policy: FuelPolicy::default(),
resource_limiter: None,
gc_collection_threshold: 1024 * 1024,
}
}
}
#[cfg(feature = "debug")]
impl core::fmt::Debug for Config {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Config")
.field("value_stack_32", &self.value_stack_32)
.field("value_stack_64", &self.value_stack_64)
.field("value_stack_128", &self.value_stack_128)
.field("call_stack", &self.call_stack)
.field("fuel_policy", &self.fuel_policy)
.field("resource_limiter", &self.resource_limiter.is_some())
.field("gc_collection_threshold", &self.gc_collection_threshold)
.finish()
}
}