bitcoin_script_analyzer/script/
stack.rs1use 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}