bitcoin_script_analyzer/script/
stack.rs

1use crate::expr::Expr;
2use core::{array, cmp::max};
3
4#[derive(Clone)]
5pub struct Stack {
6    elements: Vec<Expr>,
7    next_element_id: u32,
8}
9
10impl Stack {
11    pub fn new() -> Self {
12        Self {
13            elements: Vec::new(),
14            next_element_id: 0,
15        }
16    }
17
18    pub fn len(&self) -> usize {
19        self.elements.len()
20    }
21
22    pub fn items_used(&self) -> u32 {
23        self.next_element_id
24    }
25
26    fn grow_to(&mut self, min_len: usize) {
27        if self.elements.len() >= min_len {
28            return;
29        }
30
31        let to_insert = min_len - self.elements.len();
32        self.next_element_id += to_insert as u32;
33        self.elements.splice(
34            0..0,
35            (0..to_insert).map(|i| Expr::stack(self.next_element_id - i as u32 - 1)),
36        );
37    }
38
39    pub fn get_back(&mut self, index: usize) -> &Expr {
40        self.grow_to(index + 1);
41
42        &self.elements[self.len() - 1 - index]
43    }
44
45    pub fn push(&mut self, value: Expr) {
46        self.elements.push(value);
47    }
48
49    pub fn extend_from_within_back(&mut self, amount: usize, offset: usize) {
50        self.grow_to(amount + offset);
51
52        let to = self.len() - offset;
53        let from = to - amount;
54        self.elements.extend_from_within(from..to);
55    }
56
57    pub fn remove_back(&mut self, index: usize) -> Expr {
58        self.grow_to(index + 1);
59
60        self.elements.remove(self.len() - 1 - index)
61    }
62
63    pub fn swap_back(&mut self, a: usize, b: usize) {
64        self.grow_to(max(a, b) + 1);
65
66        let last = self.len() - 1;
67        self.elements.swap(last - a, last - b);
68    }
69
70    pub fn pop<const N: usize>(&mut self) -> [Expr; N] {
71        self.grow_to(N);
72
73        let mut drain = self.elements.drain(self.len() - N..);
74        array::from_fn(|_| drain.next().unwrap())
75    }
76
77    pub fn pop_to_box(&mut self, amount: usize) -> Box<[Expr]> {
78        self.grow_to(amount);
79
80        self.elements
81            .split_off(self.len() - amount)
82            .into_boxed_slice()
83    }
84}