cadmpeg_core/decode/
arena.rs1use std::cell::RefCell;
5use std::ptr::NonNull;
6
7#[derive(Debug, Default)]
9pub struct DecodeArena {
10 buffers: RefCell<Vec<OwnedBuffer>>,
11}
12
13impl DecodeArena {
14 pub fn new() -> Self {
16 Self::default()
17 }
18
19 pub fn alloc(&self, bytes: Box<[u8]>) -> &[u8] {
23 let mut buffers = self.buffers.borrow_mut();
24 let buffer = OwnedBuffer(NonNull::from(Box::leak(bytes)));
25 let pointer = buffer.0;
26 buffers.push(buffer);
27 unsafe { pointer.as_ref() }
30 }
31}
32
33#[derive(Debug)]
35struct OwnedBuffer(NonNull<[u8]>);
36
37unsafe impl Send for OwnedBuffer {}
41
42impl Drop for OwnedBuffer {
43 fn drop(&mut self) {
44 unsafe { drop(Box::from_raw(self.0.as_ptr())) };
47 }
48}
49
50#[cfg(test)]
51mod tests {
52 use super::DecodeArena;
53
54 fn buffer(index: usize) -> Box<[u8]> {
55 let len = (index % 7) + 1;
56 vec![u8::try_from(index).expect("test index fits u8"); len].into_boxed_slice()
57 }
58
59 fn check(index: usize, slice: &[u8]) {
60 assert_eq!(slice.len(), (index % 7) + 1, "length of buffer {index}");
61 assert!(
62 slice
63 .iter()
64 .all(|&byte| byte == u8::try_from(index).expect("test index fits u8")),
65 "contents of buffer {index}",
66 );
67 }
68
69 #[test]
70 fn empty_buffer_borrows_survive_later_allocations() {
71 let arena = DecodeArena::new();
72 let empty = arena.alloc(Vec::new().into_boxed_slice());
73 let present = arena.alloc(vec![7].into_boxed_slice());
74 assert!(empty.is_empty());
75 assert_eq!(present, &[7]);
76 }
77
78 #[test]
79 fn an_owned_arena_can_move_between_threads() {
80 let arena = DecodeArena::new();
81 {
82 arena.alloc(vec![7].into_boxed_slice());
83 }
84 let arena = std::thread::spawn(move || {
85 {
86 assert_eq!(arena.alloc(vec![9].into_boxed_slice()), &[9]);
87 }
88 arena
89 })
90 .join()
91 .expect("the receiving thread retains and reads the arena");
92 assert_eq!(arena.alloc(vec![11].into_boxed_slice()), &[11]);
93 }
94
95 #[test]
98 fn interleaved_alloc_and_read_across_many_buffers() {
99 let arena = DecodeArena::new();
100 let mut borrows: Vec<&[u8]> = Vec::new();
101 for index in 0..256usize {
102 borrows.push(arena.alloc(buffer(index)));
103 for (i, slice) in borrows.iter().enumerate() {
104 check(i, slice);
105 }
106 }
107 }
108}