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}