reifydb_flow_operator_sdk/ffi/
arena.rs1use std::{
7 alloc::{Layout, alloc, dealloc},
8 ptr,
9};
10
11pub struct Arena {
15 allocations: Vec<Allocation>,
16}
17
18struct Allocation {
19 ptr: *mut u8,
20 layout: Layout,
21}
22
23unsafe impl Send for Arena {}
25unsafe impl Sync for Arena {}
26
27impl Arena {
28 pub fn new() -> Self {
30 Self {
31 allocations: Vec::new(),
32 }
33 }
34
35 pub fn alloc(&mut self, size: usize) -> *mut u8 {
39 if size == 0 {
40 return ptr::null_mut();
41 }
42
43 let layout = match Layout::from_size_align(size, 8) {
45 Ok(layout) => layout,
46 Err(_) => return ptr::null_mut(),
47 };
48
49 let ptr = unsafe { alloc(layout) };
51
52 if ptr.is_null() {
53 return ptr::null_mut();
54 }
55
56 self.allocations.push(Allocation {
57 ptr,
58 layout,
59 });
60 ptr
61 }
62
63 pub fn alloc_zeroed(&mut self, size: usize) -> *mut u8 {
65 let ptr = self.alloc(size);
66 if !ptr.is_null() {
67 unsafe {
69 ptr::write_bytes(ptr, 0, size);
70 }
71 }
72 ptr
73 }
74
75 pub fn alloc_type<T>(&mut self) -> *mut T {
77 self.alloc(std::mem::size_of::<T>()) as *mut T
78 }
79
80 pub fn copy_bytes(&mut self, bytes: &[u8]) -> *mut u8 {
82 if bytes.is_empty() {
83 return ptr::null_mut();
84 }
85
86 let ptr = self.alloc(bytes.len());
87 if !ptr.is_null() {
88 unsafe {
90 ptr::copy_nonoverlapping(bytes.as_ptr(), ptr, bytes.len());
91 }
92 }
93 ptr
94 }
95
96 pub fn clear(&mut self) {
98 for allocation in self.allocations.drain(..) {
100 unsafe {
102 dealloc(allocation.ptr, allocation.layout);
103 }
104 }
105 }
106
107 pub fn allocation_count(&self) -> usize {
109 self.allocations.len()
110 }
111
112 pub fn total_size(&self) -> usize {
114 self.allocations.iter().map(|a| a.layout.size()).sum()
115 }
116}
117
118impl Default for Arena {
119 fn default() -> Self {
120 Self::new()
121 }
122}
123
124impl Drop for Arena {
125 fn drop(&mut self) {
126 self.clear();
127 }
128}
129
130#[cfg(test)]
131mod tests {
132 use super::*;
133
134 #[test]
135 fn test_arena_basic() {
136 let mut arena = Arena::new();
137
138 let ptr1 = arena.alloc(100);
139 assert!(!ptr1.is_null());
140
141 let ptr2 = arena.alloc(200);
142 assert!(!ptr2.is_null());
143
144 assert_eq!(arena.allocation_count(), 2);
145 assert_eq!(arena.total_size(), 300);
146 }
147
148 #[test]
149 fn test_arena_zeroed() {
150 let mut arena = Arena::new();
151
152 let ptr = arena.alloc_zeroed(100);
153 assert!(!ptr.is_null());
154
155 unsafe {
156 for i in 0..100 {
157 assert_eq!(*ptr.add(i), 0);
158 }
159 }
160 }
161
162 #[test]
163 fn test_arena_copy_bytes() {
164 let mut arena = Arena::new();
165
166 let data = vec![1u8, 2, 3, 4, 5];
167 let ptr = arena.copy_bytes(&data);
168 assert!(!ptr.is_null());
169
170 unsafe {
171 for i in 0..5 {
172 assert_eq!(*ptr.add(i), data[i]);
173 }
174 }
175 }
176
177 #[test]
178 fn test_arena_clear() {
179 let mut arena = Arena::new();
180
181 arena.alloc(100);
182 arena.alloc(200);
183 assert_eq!(arena.allocation_count(), 2);
184
185 arena.clear();
186 assert_eq!(arena.allocation_count(), 0);
187 }
188}