vm, runtime: add slots! macro and port filter primop to typed slots

This commit is contained in:
2026-08-22 20:59:43 +08:00
parent 5a06fb4c1e
commit c0f2d1a20a
7 changed files with 236 additions and 84 deletions
+2
View File
@@ -4,6 +4,7 @@ mod host;
mod machine;
mod path_util;
mod resolve;
mod slot;
mod state;
mod string_context;
mod value;
@@ -14,6 +15,7 @@ pub use host::*;
pub use machine::*;
pub use path_util::*;
pub use resolve::*;
pub use slot::*;
pub use state::*;
pub use string_context::*;
pub use value::*;
+87
View File
@@ -0,0 +1,87 @@
use std::marker::PhantomData;
use std::ops::ControlFlow;
use fix_bytecode::BytecodeReader;
use gc_arena::Mutation;
use crate::{Break, Forced, Machine, NixType, Step, StrictValue, Value, ValueVariant};
pub trait SlotContent<'gc> {
type Ty: Into<Value<'gc>> + TryFrom<Value<'gc>> + 'gc;
}
impl<'gc> SlotContent<'gc> for Value<'gc> {
type Ty = Value<'gc>;
}
impl<'gc> SlotContent<'gc> for StrictValue<'gc> {
type Ty = StrictValue<'gc>;
}
impl<'gc, T> SlotContent<'gc> for T
where
T: ValueVariant<'gc>,
{
type Ty = T::Ty;
}
pub struct Slot<T> {
depth: u8,
_marker: PhantomData<T>,
}
impl<T> Slot<T> {
#[inline(always)]
pub const fn new(depth: u8) -> Self {
Self {
depth,
_marker: PhantomData,
}
}
}
impl<'gc, T> Slot<T>
where
T: SlotContent<'gc>,
<T::Ty as TryFrom<Value<'gc>>>::Error: std::fmt::Debug,
{
#[inline(always)]
pub fn read<M: Machine<'gc>>(&self, m: &M) -> T::Ty {
T::Ty::try_from(m.peek(self.depth as usize)).expect("slot held a value of the wrong type")
}
#[inline(always)]
pub fn read_checked<M: Machine<'gc>>(&self, m: &M) -> Result<T::Ty, NixType> {
let val = m.peek(self.depth as usize);
T::Ty::try_from(val).map_err(|_err| val.ty())
}
#[inline(always)]
pub fn write<M: Machine<'gc>>(&self, m: &mut M, val: T::Ty) {
m.replace(self.depth as usize, T::Ty::into(val));
}
}
impl<'gc> Slot<Value<'gc>> {
#[inline(always)]
pub fn force<T: Forced<'gc>, M: Machine<'gc>>(
&self,
m: &mut M,
reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>,
) -> ControlFlow<Break, Slot<T>> {
T::force_and_check(m, reader, mc, self.depth as usize, reader.inst_start_pc())?;
ControlFlow::Continue(Slot::new(self.depth))
}
#[inline(always)]
pub fn force_to_pc<M: Machine<'gc>>(
&self,
m: &mut M,
reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>,
pc: usize,
) -> Step {
m.force_slot_to_pc(self.depth as usize, reader, mc, pc)
}
}