1use core::ops::{Deref, DerefMut};
8use kalloc::{AllocError, Allocator, Box, DefaultAllocator};
9
10pub struct Array<T, A: Allocator = DefaultAllocator> {
13 buf: Box<[T], A>,
14}
15
16zr::static_assert!(core::mem::size_of::<Array<u32>>() == 16);
17zr::static_assert!(core::mem::align_of::<Array<u32>>() == 8);
18
19impl<T, A: Allocator> Array<T, A> {
20 pub const fn new_in(allocator: A) -> Self {
22 Self { buf: Box::empty_slice_in(allocator) }
23 }
24
25 pub fn from_box(buf: Box<[T], A>) -> Self {
27 Self { buf }
28 }
29
30 pub fn try_new_in(len: usize, allocator: A) -> Result<Self, AllocError>
32 where
33 T: Default,
34 {
35 let mut b = Box::<[T], A>::try_new_uninit_slice_in(len, allocator)?;
36 for i in 0..len {
37 b[i].write(T::default());
38 }
39 Ok(Self { buf: unsafe { b.assume_init() } })
41 }
42
43 pub fn len(&self) -> usize {
45 self.buf.len()
46 }
47
48 pub fn is_empty(&self) -> bool {
50 self.buf.is_empty()
51 }
52
53 pub fn into_box(self) -> Box<[T], A> {
55 self.buf
56 }
57}
58
59impl<T> Array<T, DefaultAllocator> {
60 pub const fn new() -> Self {
62 Self { buf: Box::empty_slice() }
63 }
64
65 pub fn try_new(len: usize) -> Result<Self, AllocError>
67 where
68 T: Default,
69 {
70 Self::try_new_in(len, DefaultAllocator)
71 }
72}
73
74impl<T, A: Allocator> Deref for Array<T, A> {
75 type Target = [T];
76
77 fn deref(&self) -> &Self::Target {
78 &self.buf
79 }
80}
81
82impl<T, A: Allocator> DerefMut for Array<T, A> {
83 fn deref_mut(&mut self) -> &mut Self::Target {
84 &mut self.buf
85 }
86}
87
88impl<T> Default for Array<T, DefaultAllocator> {
89 fn default() -> Self {
90 Self::new()
91 }
92}
93
94#[cfg(test)]
95mod tests {
96 use super::*;
97 use core::cell::Cell;
98 use core::ptr::NonNull;
99
100 #[derive(Debug, PartialEq, Eq)]
101 struct TestState {
102 live_obj_count: Cell<usize>,
103 ctor_count: Cell<usize>,
104 dtor_count: Cell<usize>,
105 alloc_count: Cell<usize>,
106 fail_threshold: Cell<usize>,
107 }
108
109 impl Default for TestState {
110 fn default() -> Self {
111 Self {
112 live_obj_count: Cell::new(0),
113 ctor_count: Cell::new(0),
114 dtor_count: Cell::new(0),
115 alloc_count: Cell::new(0),
116 fail_threshold: Cell::new(usize::MAX),
117 }
118 }
119 }
120
121 #[derive(Clone)]
122 struct TestAllocator<'a> {
123 state: &'a TestState,
124 }
125
126 impl<'a> kalloc::Allocator for TestAllocator<'a> {
127 fn allocate(&self, layout: core::alloc::Layout) -> Result<NonNull<[u8]>, AllocError> {
128 let current = self.state.alloc_count.get();
129 self.state.alloc_count.set(current + 1);
130 if current >= self.state.fail_threshold.get() {
131 return Err(AllocError);
132 }
133 DefaultAllocator::default().allocate(layout)
134 }
135
136 unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: core::alloc::Layout) {
137 unsafe { DefaultAllocator::default().deallocate(ptr, layout) }
138 }
139
140 unsafe fn grow(
141 &self,
142 ptr: NonNull<u8>,
143 old_layout: core::alloc::Layout,
144 new_layout: core::alloc::Layout,
145 ) -> Result<NonNull<[u8]>, AllocError> {
146 let current = self.state.alloc_count.get();
147 self.state.alloc_count.set(current + 1);
148 if current >= self.state.fail_threshold.get() {
149 return Err(AllocError);
150 }
151 unsafe { DefaultAllocator::default().grow(ptr, old_layout, new_layout) }
152 }
153
154 unsafe fn shrink(
155 &self,
156 ptr: NonNull<u8>,
157 old_layout: core::alloc::Layout,
158 new_layout: core::alloc::Layout,
159 ) -> Result<NonNull<[u8]>, AllocError> {
160 let current = self.state.alloc_count.get();
161 self.state.alloc_count.set(current + 1);
162 if current >= self.state.fail_threshold.get() {
163 return Err(AllocError);
164 }
165 unsafe { DefaultAllocator::default().shrink(ptr, old_layout, new_layout) }
166 }
167
168 fn allocate_zeroed(
169 &self,
170 layout: core::alloc::Layout,
171 ) -> Result<NonNull<[u8]>, AllocError> {
172 let current = self.state.alloc_count.get();
173 self.state.alloc_count.set(current + 1);
174 if current >= self.state.fail_threshold.get() {
175 return Err(AllocError);
176 }
177 DefaultAllocator::default().allocate_zeroed(layout)
178 }
179 }
180
181 #[derive(Debug, Eq, PartialEq)]
182 struct TestObject<'a> {
183 val: usize,
184 alive: bool,
185 state: &'a TestState,
186 }
187
188 impl<'a> TestObject<'a> {
189 fn new(val: usize, state: &'a TestState) -> Self {
190 state.live_obj_count.set(state.live_obj_count.get() + 1);
191 state.ctor_count.set(state.ctor_count.get() + 1);
192 TestObject { val, alive: true, state }
193 }
194 }
195
196 impl<'a> Drop for TestObject<'a> {
197 fn drop(&mut self) {
198 if self.alive {
199 self.state.live_obj_count.set(self.state.live_obj_count.get() - 1);
200 self.state.dtor_count.set(self.state.dtor_count.get() + 1);
201 }
202 }
203 }
204
205 #[test]
206 fn test_empty_array() {
207 let a: Array<u32> = Array::new();
208 assert_eq!(a.len(), 0);
209 assert!(a.is_empty());
210 }
211
212 #[test]
213 fn test_try_new() {
214 let a = Array::<u32>::try_new(5).unwrap();
215 assert_eq!(a.len(), 5);
216 for i in 0..5 {
217 assert_eq!(a[i], 0);
218 }
219 }
220
221 #[test]
222 fn test_deref() {
223 let mut a = Array::<u32>::try_new(2).unwrap();
224 a[0] = 10;
225 a[1] = 20;
226
227 let slice: &[u32] = &a;
228 assert_eq!(slice, &[10, 20]);
229
230 let slice_mut: &mut [u32] = &mut a;
231 slice_mut[0] = 30;
232 assert_eq!(a[0], 30);
233 }
234
235 #[test]
236 fn test_drop_behavior() {
237 let state = TestState::default();
238 {
239 let mut b = Box::<[TestObject<'_>], TestAllocator<'_>>::try_new_uninit_slice_in(
240 2,
241 TestAllocator { state: &state },
242 )
243 .unwrap();
244 b[0].write(TestObject::new(1, &state));
245 b[1].write(TestObject::new(2, &state));
246 let _a = Array::from_box(unsafe { b.assume_init() });
247 assert_eq!(state.live_obj_count.get(), 2);
248 }
249 assert_eq!(state.live_obj_count.get(), 0);
250 assert_eq!(state.dtor_count.get(), 2);
251 }
252
253 #[test]
254 fn test_allocation_failure() {
255 let state = TestState::default();
256 state.fail_threshold.set(0); let res = Array::<u32, TestAllocator<'_>>::try_new_in(5, TestAllocator { state: &state });
259 assert!(res.is_err());
260 }
261
262 #[test]
263 fn test_try_new_zero_sized() {
264 let state = TestState::default();
265 let a = Array::<u32, TestAllocator<'_>>::try_new_in(0, TestAllocator { state: &state })
266 .unwrap();
267 assert_eq!(a.len(), 0);
268 assert!(a.is_empty());
269 }
270
271 #[test]
272 fn test_non_trivial_default() {
273 #[derive(Debug, PartialEq, Eq)]
274 struct MyInt {
275 value: i32,
276 }
277 impl Default for MyInt {
278 fn default() -> Self {
279 Self { value: 42 }
280 }
281 }
282
283 let a = Array::<MyInt>::try_new(5).unwrap();
284 assert_eq!(a.len(), 5);
285 for i in 0..5 {
286 assert_eq!(a[i].value, 42);
287 }
288 }
289
290 #[test]
291 fn test_array_new_in() {
292 let state = TestState::default();
293 let alloc = TestAllocator { state: &state };
294 let a = Array::<u32, TestAllocator<'_>>::new_in(alloc.clone());
295 assert!(a.is_empty());
296 }
297
298 #[test]
299 fn test_array_default() {
300 let a_def: Array<u32> = Default::default();
301 assert!(a_def.is_empty());
302 }
303
304 #[test]
305 fn test_array_into_box() {
306 let a_try = Array::<u32>::try_new(3).unwrap();
307 let b = a_try.into_box();
308 assert_eq!(b.len(), 3);
309 }
310
311 #[test]
312 fn test_array_test_allocator_happy() {
313 use kalloc::Allocator;
314 let state = TestState::default();
315 let alloc = TestAllocator { state: &state };
316 let layout = core::alloc::Layout::new::<u32>();
317 let ptr = alloc.allocate_zeroed(layout).unwrap();
318
319 let ptr = unsafe {
320 alloc.grow(ptr.cast(), layout, core::alloc::Layout::array::<u32>(2).unwrap()).unwrap()
321 };
322
323 let ptr = unsafe {
324 alloc.shrink(ptr.cast(), core::alloc::Layout::array::<u32>(2).unwrap(), layout).unwrap()
325 };
326
327 unsafe {
328 alloc.deallocate(ptr.cast(), layout);
329 }
330 }
331
332 #[test]
333 fn test_array_test_allocator_failure() {
334 use kalloc::Allocator;
335 let state = TestState::default();
336 let alloc = TestAllocator { state: &state };
337 let layout = core::alloc::Layout::new::<u32>();
338
339 state.fail_threshold.set(0);
341
342 assert!(alloc.allocate_zeroed(layout).is_err());
343
344 let dummy_ptr = core::ptr::NonNull::<u8>::dangling();
345 assert!(
346 unsafe {
347 alloc.grow(dummy_ptr.cast(), layout, core::alloc::Layout::array::<u32>(2).unwrap())
348 }
349 .is_err()
350 );
351 assert!(
352 unsafe {
353 alloc.shrink(
354 dummy_ptr.cast(),
355 core::alloc::Layout::array::<u32>(2).unwrap(),
356 layout,
357 )
358 }
359 .is_err()
360 );
361 }
362}