1struct Entry {
2 alignment: usize,
3 data: Vec<u8>,
4}
5
6pub struct Stack {
7 entries: Vec<Entry>,
8}
9
10impl Stack {
11 pub fn new() -> Self {
12 Self { entries: vec![] }
13 }
14
15 pub fn push<D>(&mut self, data: D, alignment: usize)
16 where
17 D: IntoIterator<Item = u8>,
18 D::IntoIter: ExactSizeIterator,
19 {
20 self.entries.push(Entry {
21 alignment,
22 data: data.into_iter().collect(),
23 });
24 }
25
26 pub fn iter_entry(&self) -> DataEntryIterator {
27 DataEntryIterator {
28 stack: self,
29 next_idx: 0,
30 prev_end_offset: 0,
31 }
32 }
33
34 pub fn memory_pages_needed(&self) -> usize {
35 const PAGE_SIZE_BYTES: usize = 65536;
36
37 let entry = match self.iter_entry().last() {
38 | None => return 0,
39 | Some(e) => e,
40 };
41 let data_len = entry.offset + entry.data.len();
42 let extra_page_needed = data_len % PAGE_SIZE_BYTES > 0;
43
44 (entry.offset + entry.data.len()) / PAGE_SIZE_BYTES + if extra_page_needed { 1 } else { 0 }
45 }
46}
47
48pub struct DataEntryIterator<'a> {
49 stack: &'a Stack,
50 next_idx: usize,
51 prev_end_offset: usize,
52}
53
54impl<'a> Iterator for DataEntryIterator<'a> {
55 type Item = DataEntry<'a>;
56
57 fn next(&mut self) -> Option<Self::Item> {
58 let entry = self.stack.entries.get(self.next_idx)?;
59 let offset = self.prev_end_offset
60 + (entry.alignment - self.prev_end_offset % entry.alignment) % entry.alignment;
61
62 self.next_idx += 1;
63 self.prev_end_offset = offset + entry.data.len();
64
65 Some(DataEntry {
66 offset,
67 data: &entry.data,
68 })
69 }
70}
71
72impl ExactSizeIterator for DataEntryIterator<'_> {
73 fn len(&self) -> usize {
74 self.stack.entries.len()
75 }
76}
77
78#[derive(PartialEq, Eq, Clone, Debug)]
79pub struct DataEntry<'a> {
80 pub offset: usize,
81 pub data: &'a [u8],
82}
83
84impl Default for Stack {
85 fn default() -> Self {
86 Self::new()
87 }
88}
89
90#[cfg(test)]
91mod tests {
92 use super::*;
93
94 #[test]
95 fn ok() {
96 let mut stack = Stack::default();
97
98 stack.push([1; 4], 4);
99 stack.push([2; 5], 1);
100 stack.push([3; 4], 4);
101 stack.push([4; 65536], 8);
102
103 let mut entries = stack.iter_entry();
104 let expected_entries = [
105 DataEntry {
106 offset: 0,
107 data: &[1; 4],
108 },
109 DataEntry {
110 offset: 4,
111 data: &[2; 5],
112 },
113 DataEntry {
114 offset: 12,
115 data: &[3; 4],
116 },
117 DataEntry {
118 offset: 16,
119 data: &[4; 65536],
120 },
121 ];
122
123 for expected_entry in expected_entries {
124 let entry = entries.next().unwrap();
125
126 assert_eq!(entry, expected_entry);
127 }
128
129 assert_eq!(stack.memory_pages_needed(), 2);
130 }
131}