stack_arena/
obstack.rs

1use std::ptr::NonNull;
2
3use crate::Allocator;
4
5#[derive(Debug)]
6pub struct Obstack {
7    store: Vec<Box<[u8]>>,
8    stack: Vec<NonNull<[u8]>>,
9    current: Vec<u8>,
10}
11
12impl Obstack {
13    pub fn new() -> Self {
14        Self {
15            store: Vec::new(),
16            stack: Vec::new(),
17            current: Vec::with_capacity(1024),
18        }
19    }
20
21    pub fn len(&self) -> usize {
22        self.stack.len()
23    }
24
25    pub fn is_empty(&self) -> bool {
26        self.len() == 0
27    }
28
29    pub fn push<P: AsRef<[u8]>>(&mut self, s: P) {
30        let mut object = s.as_ref().to_vec().into_boxed_slice();
31        self.stack.push(NonNull::slice_from_raw_parts(
32            unsafe { NonNull::new_unchecked(object.as_mut_ptr()) },
33            object.len(),
34        ));
35        self.store.push(object);
36    }
37
38    pub fn pop(&mut self) {
39        self.store.pop();
40        self.stack.pop();
41    }
42
43    pub fn extend<P: AsRef<[u8]>>(&mut self, s: P) {
44        self.current.extend_from_slice(s.as_ref());
45    }
46
47    pub fn finish(&mut self) -> NonNull<[u8]> {
48        let mut object =
49            std::mem::replace(&mut self.current, Vec::with_capacity(1024)).into_boxed_slice();
50        self.stack.push(NonNull::slice_from_raw_parts(
51            unsafe { NonNull::new_unchecked(object.as_mut_ptr()) },
52            object.len(),
53        ));
54        self.store.push(object);
55        self.stack.last().map(|&ptr| ptr).unwrap()
56    }
57
58    pub fn free(&mut self, s: &[u8]) {
59        while let Some(o) = self.stack.pop() {
60            if std::ptr::addr_eq(unsafe { o.as_ref() }, s) {
61                break;
62            }
63        }
64    }
65}
66
67impl std::fmt::Write for Obstack {
68    fn write_str(&mut self, s: &str) -> std::fmt::Result {
69        self.extend(s.as_bytes());
70        Ok(())
71    }
72}
73
74impl Allocator for Obstack {
75    fn allocate(
76        &self,
77        layout: std::alloc::Layout,
78    ) -> Result<std::ptr::NonNull<[u8]>, crate::AllocError> {
79        todo!()
80    }
81
82    unsafe fn deallocate(&self, ptr: std::ptr::NonNull<u8>, layout: std::alloc::Layout) {
83        todo!()
84    }
85}
86
87#[cfg(test)]
88mod tests {
89    use std::fmt::Write;
90
91    use super::*;
92
93    #[test]
94    fn test_lifecycle() {
95        let mut stack = Obstack::new();
96        write!(&mut stack, "ab").expect("write");
97        let s = "c";
98        stack.extend(s);
99        let p = unsafe { stack.finish().as_ref() };
100        assert_eq!(p, b"abc");
101    }
102}