1use std::marker::PhantomData;
2
3use sim_lib_control::WorkLimit;
4
5use crate::ValueWidthPolicy;
6
7#[derive(Clone, Copy, Debug, PartialEq, Eq)]
9pub enum StackError {
10 Overflow {
12 depth: usize,
14 width: usize,
16 limit: usize,
18 },
19 Underflow {
21 depth: usize,
23 },
24 ZeroWidth {
26 depth: usize,
28 },
29}
30
31pub struct UnitStack<P: ValueWidthPolicy> {
33 pub(crate) values: Vec<P::Value>,
34 pub(crate) depth: usize,
35 pub(crate) limit: WorkLimit,
36 _policy: PhantomData<P>,
37}
38
39impl<P: ValueWidthPolicy> UnitStack<P> {
40 pub fn new(limit: WorkLimit) -> Self {
42 Self {
43 values: Vec::new(),
44 depth: 0,
45 limit,
46 _policy: PhantomData,
47 }
48 }
49
50 pub fn depth(&self) -> usize {
52 self.depth
53 }
54
55 pub fn is_empty(&self) -> bool {
57 self.values.is_empty()
58 }
59
60 pub fn top(&self) -> Result<&P::Value, StackError> {
62 self.values
63 .last()
64 .ok_or(StackError::Underflow { depth: self.depth })
65 }
66
67 pub fn visit_values(&self, mut visit: impl FnMut(&P::Value)) {
69 for value in &self.values {
70 visit(value);
71 }
72 }
73
74 pub fn push(&mut self, value: P::Value) -> Result<(), StackError> {
76 let width = P::width(&value);
77 if width == 0 {
78 return Err(StackError::ZeroWidth { depth: self.depth });
79 }
80 let next = self
81 .depth
82 .checked_add(width)
83 .filter(|next| *next <= self.limit.0)
84 .ok_or(StackError::Overflow {
85 depth: self.depth,
86 width,
87 limit: self.limit.0,
88 })?;
89 self.values.push(value);
90 self.depth = next;
91 Ok(())
92 }
93
94 pub fn pop(&mut self) -> Result<P::Value, StackError> {
96 let value = self
97 .values
98 .pop()
99 .ok_or(StackError::Underflow { depth: self.depth })?;
100 self.depth -= P::width(&value);
101 Ok(value)
102 }
103
104 pub fn clear(&mut self) {
106 while self.pop().is_ok() {}
107 }
108}