use crate::EngineError;
use any_fn::AnyFn;
use stak_dynamic::DynamicPrimitiveSet;
use stak_file::VoidFileSystem;
use stak_process_context::VoidProcessContext;
use stak_r7rs::SmallPrimitiveSet;
use stak_time::VoidClock;
use stak_vm::{Heap, Memory, PrimitiveSet};
use winter_maybe_async::{maybe_async, maybe_await};
const DYNAMIC_PRIMITIVE_OFFSET: usize = 1000;
cfg_select! {
feature = "std" => {
type Device = stak_device::StdioDevice;
}
feature = "libc" => {
type Device = stak_device::LibcDevice;
}
_ => {
type Device = stak_device::VoidDevice;
}
}
pub struct EnginePrimitiveSet<'a, 'b, H> {
small: SmallPrimitiveSet<Device, VoidFileSystem, VoidProcessContext, VoidClock>,
dynamic: DynamicPrimitiveSet<'a, 'b, H>,
}
impl<'a, 'b, H: Heap> EnginePrimitiveSet<'a, 'b, H> {
pub fn new(functions: &'a mut [(&'a str, AnyFn<'b>)]) -> Self {
Self {
small: SmallPrimitiveSet::new(
Default::default(),
Default::default(),
Default::default(),
Default::default(),
),
dynamic: DynamicPrimitiveSet::new(functions),
}
}
pub(crate) const fn dynamic_mut(&mut self) -> &mut DynamicPrimitiveSet<'a, 'b, H> {
&mut self.dynamic
}
}
impl<H: Heap> PrimitiveSet<H> for EnginePrimitiveSet<'_, '_, H> {
type Error = EngineError;
#[maybe_async]
fn operate(&mut self, memory: &mut Memory<H>, primitive: usize) -> Result<(), Self::Error> {
if primitive >= DYNAMIC_PRIMITIVE_OFFSET {
maybe_await!(
self.dynamic
.operate(memory, primitive - DYNAMIC_PRIMITIVE_OFFSET)
)?
} else {
maybe_await!(self.small.operate(memory, primitive))?
}
Ok(())
}
}