use sim_lib_control::{AdmissionLimit, WorkLimit};
use crate::ManagedRootSource;
use crate::{CodeCursor, SlotFile, UnitStack, ValueWidthPolicy};
pub struct Frame<P, K, R, H>
where
P: ValueWidthPolicy,
{
slots: SlotFile<P>,
operands: UnitStack<P>,
cursor: CodeCursor,
continuation: Option<K>,
roots: R,
handlers: H,
}
impl<P, K, R, H> Frame<P, K, R, H>
where
P: ValueWidthPolicy,
{
pub fn new(
slot_limit: AdmissionLimit,
operand_limit: WorkLimit,
cursor: CodeCursor,
continuation: Option<K>,
roots: R,
handlers: H,
) -> Self {
Self {
slots: SlotFile::new(slot_limit),
operands: UnitStack::new(operand_limit),
cursor,
continuation,
roots,
handlers,
}
}
pub fn slots(&self) -> &SlotFile<P> {
&self.slots
}
pub fn slots_mut(&mut self) -> &mut SlotFile<P> {
&mut self.slots
}
pub fn operands(&self) -> &UnitStack<P> {
&self.operands
}
pub fn operands_mut(&mut self) -> &mut UnitStack<P> {
&mut self.operands
}
pub fn cursor(&self) -> CodeCursor {
self.cursor
}
pub fn set_cursor(&mut self, cursor: CodeCursor) {
self.cursor = cursor;
}
pub fn continuation(&self) -> Option<&K> {
self.continuation.as_ref()
}
pub fn roots(&self) -> &R {
&self.roots
}
pub fn roots_mut(&mut self) -> &mut R {
&mut self.roots
}
pub fn handlers(&self) -> &H {
&self.handlers
}
pub fn handlers_mut(&mut self) -> &mut H {
&mut self.handlers
}
}
impl<P, K, R, H> ManagedRootSource for Frame<P, K, R, H>
where
P: ValueWidthPolicy,
P::Value: ManagedRootSource,
K: ManagedRootSource,
R: ManagedRootSource,
H: ManagedRootSource,
{
fn visit_managed_roots(
&self,
visit: &mut dyn FnMut(sim_lib_mutation::ManagedId) -> bool,
) -> bool {
let mut complete = true;
self.slots
.visit_values(|value| complete = complete && value.visit_managed_roots(visit));
if !complete {
return false;
}
self.operands
.visit_values(|value| complete = complete && value.visit_managed_roots(visit));
if !complete {
return false;
}
if let Some(continuation) = &self.continuation
&& !continuation.visit_managed_roots(visit)
{
return false;
}
self.roots.visit_managed_roots(visit) && self.handlers.visit_managed_roots(visit)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum FrameStackError {
DepthExhausted {
depth: usize,
limit: usize,
},
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct FrameStack<F> {
frames: Vec<F>,
limit: WorkLimit,
}
impl<F> FrameStack<F> {
pub fn new(limit: WorkLimit) -> Self {
Self {
frames: Vec::new(),
limit,
}
}
pub fn depth(&self) -> usize {
self.frames.len()
}
pub fn push(&mut self, frame: F) -> Result<(), FrameStackError> {
if self.frames.len() >= self.limit.0 {
return Err(FrameStackError::DepthExhausted {
depth: self.frames.len(),
limit: self.limit.0,
});
}
self.frames.push(frame);
Ok(())
}
pub fn pop(&mut self) -> Option<F> {
self.frames.pop()
}
pub fn current(&self) -> Option<&F> {
self.frames.last()
}
pub fn current_mut(&mut self) -> Option<&mut F> {
self.frames.last_mut()
}
pub fn visit_frames(&self, mut visit: impl FnMut(&F)) {
for frame in &self.frames {
visit(frame);
}
}
}
impl<F: ManagedRootSource> ManagedRootSource for FrameStack<F> {
fn visit_managed_roots(
&self,
visit: &mut dyn FnMut(sim_lib_mutation::ManagedId) -> bool,
) -> bool {
for frame in &self.frames {
if !frame.visit_managed_roots(visit) {
return false;
}
}
true
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum TransferError {
WidthCountMismatch,
ZeroWidth,
}
fn validate_widths<V>(values: &[V], widths: &[usize]) -> Result<(), TransferError> {
if values.len() != widths.len() {
return Err(TransferError::WidthCountMismatch);
}
if widths.contains(&0) {
return Err(TransferError::ZeroWidth);
}
Ok(())
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct CallTransfer<V, C> {
pub values: Vec<V>,
pub widths: Vec<usize>,
pub target: C,
}
impl<V, C> CallTransfer<V, C> {
pub fn new(values: Vec<V>, widths: Vec<usize>, target: C) -> Result<Self, TransferError> {
validate_widths(&values, &widths)?;
Ok(Self {
values,
widths,
target,
})
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ReturnTransfer<V> {
pub values: Vec<V>,
pub widths: Vec<usize>,
}
impl<V> ReturnTransfer<V> {
pub fn new(values: Vec<V>, widths: Vec<usize>) -> Result<Self, TransferError> {
validate_widths(&values, &widths)?;
Ok(Self { values, widths })
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Transfer<V, C> {
Call(CallTransfer<V, C>),
Return(ReturnTransfer<V>),
}