pub trait ReturnStack: Sized {
fn new(max_depth: usize) -> Option<Self>;
fn push(&mut self, addr: u64);
fn pop(&mut self) -> Option<u64>;
fn depth(&self) -> usize;
fn max_depth(&self) -> usize;
}
#[derive(Clone, Debug)]
pub struct StaticStack<const N: usize> {
data: [u64; N],
max_depth: usize,
depth: usize,
base: usize,
}
impl<const N: usize> ReturnStack for StaticStack<N> {
fn new(max_depth: usize) -> Option<Self> {
if max_depth > N {
None
} else {
Some(Self {
data: [0; N],
max_depth,
depth: 0,
base: 0,
})
}
}
fn push(&mut self, addr: u64) {
let depth = self.depth;
self.data[(self.base + depth) % N] = addr;
if depth < self.max_depth {
self.depth = depth.saturating_add(1);
} else {
let base = self.base + 1;
if base < N {
self.base = base;
} else {
self.base = 0;
}
}
}
fn pop(&mut self) -> Option<u64> {
let depth = self.depth.checked_sub(1)?;
self.depth = depth;
Some(self.data[(self.base + depth) % N])
}
fn depth(&self) -> usize {
self.depth
}
fn max_depth(&self) -> usize {
self.max_depth
}
}
pub struct NoStack;
impl ReturnStack for NoStack {
fn new(max_depth: usize) -> Option<Self> {
(max_depth == 0).then_some(Self)
}
fn push(&mut self, _: u64) {}
fn pop(&mut self) -> Option<u64> {
None
}
fn depth(&self) -> usize {
0
}
fn max_depth(&self) -> usize {
0
}
}