wasm_static_alloc/
lib.rs

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}