1use core::mem::MaybeUninit;
8use core::ops::{Deref, DerefMut};
9use core::ptr::slice_from_raw_parts_mut;
10use kalloc::{AllocError, Allocator, Box, DefaultAllocator};
11use zerocopy::FromZeros;
12
13pub struct Array<T, A: Allocator = DefaultAllocator> {
16 buf: Box<[T], A>,
17}
18
19zr::static_assert!(core::mem::size_of::<Array<u32>>() == 16);
20zr::static_assert!(core::mem::align_of::<Array<u32>>() == 8);
21
22impl<T, A: Allocator> Array<T, A> {
23 pub const fn new_in(allocator: A) -> Self {
25 Self { buf: Box::empty_slice_in(allocator) }
26 }
27
28 pub fn from_box(buf: Box<[T], A>) -> Self {
30 Self { buf }
31 }
32
33 pub fn try_new_in(len: usize, allocator: A) -> Result<Self, AllocError>
35 where
36 T: Default,
37 {
38 let mut b = Box::<[T], A>::try_new_uninit_slice_in(len, allocator)?;
39 for i in 0..len {
40 b[i].write(T::default());
41 }
42 Ok(Self { buf: unsafe { b.assume_init() } })
44 }
45
46 pub fn try_new_uninit_slice_in(
48 len: usize,
49 allocator: A,
50 ) -> Result<Array<MaybeUninit<T>, A>, AllocError> {
51 Ok(Array { buf: Box::<[T], A>::try_new_uninit_slice_in(len, allocator)? })
52 }
53
54 pub fn into_raw_with_allocator(self) -> (*mut [T], A) {
58 Box::into_raw_with_allocator(self.buf)
59 }
60
61 pub fn into_raw_parts_with_allocator(self) -> (*mut T, usize, A) {
66 let (slice_ptr, allocator) = self.into_raw_with_allocator();
67 (slice_ptr as *mut T, slice_ptr.len(), allocator)
68 }
69
70 pub unsafe fn from_raw_in(ptr: *mut [T], allocator: A) -> Self {
77 Self { buf: unsafe { Box::from_raw_in(ptr, allocator) } }
78 }
79
80 pub unsafe fn from_raw_parts_in(ptr: *mut T, len: usize, allocator: A) -> Self {
89 let slice_ptr = slice_from_raw_parts_mut(ptr, len);
90 unsafe { Self::from_raw_in(slice_ptr, allocator) }
91 }
92
93 pub fn len(&self) -> usize {
95 self.buf.len()
96 }
97
98 pub fn is_empty(&self) -> bool {
100 self.buf.is_empty()
101 }
102
103 pub fn into_box(self) -> Box<[T], A> {
105 self.buf
106 }
107}
108
109impl<T: FromZeros, A: Allocator> Array<T, A> {
110 pub fn try_new_zeroed_slice_in(len: usize, allocator: A) -> Result<Self, AllocError> {
112 Ok(Self { buf: Box::<[T], A>::try_new_zeroed_slice_in(len, allocator)? })
113 }
114}
115
116impl<T: FromZeros> Array<T, DefaultAllocator> {
117 pub fn try_new_zeroed_slice(len: usize) -> Result<Self, AllocError> {
119 Self::try_new_zeroed_slice_in(len, DefaultAllocator)
120 }
121}
122
123impl<T> Array<T, DefaultAllocator> {
124 pub const fn new() -> Self {
126 Self { buf: Box::empty_slice() }
127 }
128
129 pub fn try_new(len: usize) -> Result<Self, AllocError>
131 where
132 T: Default,
133 {
134 Self::try_new_in(len, DefaultAllocator)
135 }
136
137 pub fn try_new_uninit_slice(
139 len: usize,
140 ) -> Result<Array<MaybeUninit<T>, DefaultAllocator>, AllocError> {
141 Self::try_new_uninit_slice_in(len, DefaultAllocator)
142 }
143
144 pub fn into_raw(self) -> *mut [T] {
148 let (ptr, _) = self.into_raw_with_allocator();
149 ptr
150 }
151
152 pub fn into_raw_parts(self) -> (*mut T, usize) {
157 let (ptr, len, _) = self.into_raw_parts_with_allocator();
158 (ptr, len)
159 }
160
161 pub unsafe fn from_raw(ptr: *mut [T]) -> Self {
168 unsafe { Self::from_raw_in(ptr, DefaultAllocator) }
169 }
170
171 pub unsafe fn from_raw_parts(ptr: *mut T, len: usize) -> Self {
180 unsafe { Self::from_raw_parts_in(ptr, len, DefaultAllocator) }
181 }
182}
183
184impl<T, A: Allocator> Array<MaybeUninit<T>, A> {
185 pub unsafe fn assume_init(self) -> Array<T, A> {
191 Array { buf: unsafe { self.buf.assume_init() } }
192 }
193}
194
195impl<T, A: Allocator> Deref for Array<T, A> {
196 type Target = [T];
197
198 fn deref(&self) -> &Self::Target {
199 &self.buf
200 }
201}
202
203impl<T, A: Allocator> DerefMut for Array<T, A> {
204 fn deref_mut(&mut self) -> &mut Self::Target {
205 &mut self.buf
206 }
207}
208
209impl<T> Default for Array<T, DefaultAllocator> {
210 fn default() -> Self {
211 Self::new()
212 }
213}
214
215#[cfg(test)]
216mod tests {
217 use super::*;
218 use core::cell::Cell;
219 use core::ptr::NonNull;
220
221 #[derive(Debug, PartialEq, Eq)]
222 struct TestState {
223 live_obj_count: Cell<usize>,
224 ctor_count: Cell<usize>,
225 dtor_count: Cell<usize>,
226 alloc_count: Cell<usize>,
227 fail_threshold: Cell<usize>,
228 }
229
230 impl Default for TestState {
231 fn default() -> Self {
232 Self {
233 live_obj_count: Cell::new(0),
234 ctor_count: Cell::new(0),
235 dtor_count: Cell::new(0),
236 alloc_count: Cell::new(0),
237 fail_threshold: Cell::new(usize::MAX),
238 }
239 }
240 }
241
242 #[derive(Clone)]
243 struct TestAllocator<'a> {
244 state: &'a TestState,
245 }
246
247 impl<'a> kalloc::Allocator for TestAllocator<'a> {
248 fn allocate(&self, layout: core::alloc::Layout) -> Result<NonNull<[u8]>, AllocError> {
249 let current = self.state.alloc_count.get();
250 self.state.alloc_count.set(current + 1);
251 if current >= self.state.fail_threshold.get() {
252 return Err(AllocError);
253 }
254 DefaultAllocator::default().allocate(layout)
255 }
256
257 unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: core::alloc::Layout) {
258 unsafe { DefaultAllocator::default().deallocate(ptr, layout) }
259 }
260
261 unsafe fn grow(
262 &self,
263 ptr: NonNull<u8>,
264 old_layout: core::alloc::Layout,
265 new_layout: core::alloc::Layout,
266 ) -> Result<NonNull<[u8]>, AllocError> {
267 let current = self.state.alloc_count.get();
268 self.state.alloc_count.set(current + 1);
269 if current >= self.state.fail_threshold.get() {
270 return Err(AllocError);
271 }
272 unsafe { DefaultAllocator::default().grow(ptr, old_layout, new_layout) }
273 }
274
275 unsafe fn shrink(
276 &self,
277 ptr: NonNull<u8>,
278 old_layout: core::alloc::Layout,
279 new_layout: core::alloc::Layout,
280 ) -> Result<NonNull<[u8]>, AllocError> {
281 let current = self.state.alloc_count.get();
282 self.state.alloc_count.set(current + 1);
283 if current >= self.state.fail_threshold.get() {
284 return Err(AllocError);
285 }
286 unsafe { DefaultAllocator::default().shrink(ptr, old_layout, new_layout) }
287 }
288
289 fn allocate_zeroed(
290 &self,
291 layout: core::alloc::Layout,
292 ) -> Result<NonNull<[u8]>, AllocError> {
293 let current = self.state.alloc_count.get();
294 self.state.alloc_count.set(current + 1);
295 if current >= self.state.fail_threshold.get() {
296 return Err(AllocError);
297 }
298 DefaultAllocator::default().allocate_zeroed(layout)
299 }
300 }
301
302 #[derive(Debug, Eq, PartialEq)]
303 struct TestObject<'a> {
304 val: usize,
305 alive: bool,
306 state: &'a TestState,
307 }
308
309 impl<'a> TestObject<'a> {
310 fn new(val: usize, state: &'a TestState) -> Self {
311 state.live_obj_count.set(state.live_obj_count.get() + 1);
312 state.ctor_count.set(state.ctor_count.get() + 1);
313 TestObject { val, alive: true, state }
314 }
315 }
316
317 impl<'a> Drop for TestObject<'a> {
318 fn drop(&mut self) {
319 if self.alive {
320 self.state.live_obj_count.set(self.state.live_obj_count.get() - 1);
321 self.state.dtor_count.set(self.state.dtor_count.get() + 1);
322 }
323 }
324 }
325
326 #[test]
327 fn test_empty_array() {
328 let a: Array<u32> = Array::new();
329 assert_eq!(a.len(), 0);
330 assert!(a.is_empty());
331 }
332
333 #[test]
334 fn test_try_new() {
335 let a = Array::<u32>::try_new(5).unwrap();
336 assert_eq!(a.len(), 5);
337 for i in 0..5 {
338 assert_eq!(a[i], 0);
339 }
340 }
341
342 #[test]
343 fn test_deref() {
344 let mut a = Array::<u32>::try_new(2).unwrap();
345 a[0] = 10;
346 a[1] = 20;
347
348 let slice: &[u32] = &a;
349 assert_eq!(slice, &[10, 20]);
350
351 let slice_mut: &mut [u32] = &mut a;
352 slice_mut[0] = 30;
353 assert_eq!(a[0], 30);
354 }
355
356 #[test]
357 fn test_drop_behavior() {
358 let state = TestState::default();
359 {
360 let mut b = Box::<[TestObject<'_>], TestAllocator<'_>>::try_new_uninit_slice_in(
361 2,
362 TestAllocator { state: &state },
363 )
364 .unwrap();
365 b[0].write(TestObject::new(1, &state));
366 b[1].write(TestObject::new(2, &state));
367 let _a = Array::from_box(unsafe { b.assume_init() });
368 assert_eq!(state.live_obj_count.get(), 2);
369 }
370 assert_eq!(state.live_obj_count.get(), 0);
371 assert_eq!(state.dtor_count.get(), 2);
372 }
373
374 #[test]
375 fn test_allocation_failure() {
376 let state = TestState::default();
377 state.fail_threshold.set(0); let res = Array::<u32, TestAllocator<'_>>::try_new_in(5, TestAllocator { state: &state });
380 assert!(res.is_err());
381 }
382
383 #[test]
384 fn test_try_new_zero_sized() {
385 let state = TestState::default();
386 let a = Array::<u32, TestAllocator<'_>>::try_new_in(0, TestAllocator { state: &state })
387 .unwrap();
388 assert_eq!(a.len(), 0);
389 assert!(a.is_empty());
390 }
391
392 #[test]
393 fn test_non_trivial_default() {
394 #[derive(Debug, PartialEq, Eq)]
395 struct MyInt {
396 value: i32,
397 }
398 impl Default for MyInt {
399 fn default() -> Self {
400 Self { value: 42 }
401 }
402 }
403
404 let a = Array::<MyInt>::try_new(5).unwrap();
405 assert_eq!(a.len(), 5);
406 for i in 0..5 {
407 assert_eq!(a[i].value, 42);
408 }
409 }
410
411 #[test]
412 fn test_array_new_in() {
413 let state = TestState::default();
414 let alloc = TestAllocator { state: &state };
415 let a = Array::<u32, TestAllocator<'_>>::new_in(alloc.clone());
416 assert!(a.is_empty());
417 }
418
419 #[test]
420 fn test_array_default() {
421 let a_def: Array<u32> = Default::default();
422 assert!(a_def.is_empty());
423 }
424
425 #[test]
426 fn test_array_into_box() {
427 let a_try = Array::<u32>::try_new(3).unwrap();
428 let b = a_try.into_box();
429 assert_eq!(b.len(), 3);
430 }
431
432 #[test]
433 fn test_array_test_allocator_happy() {
434 use kalloc::Allocator;
435 let state = TestState::default();
436 let alloc = TestAllocator { state: &state };
437 let layout = core::alloc::Layout::new::<u32>();
438 let ptr = alloc.allocate_zeroed(layout).unwrap();
439
440 let ptr = unsafe {
441 alloc.grow(ptr.cast(), layout, core::alloc::Layout::array::<u32>(2).unwrap()).unwrap()
442 };
443
444 let ptr = unsafe {
445 alloc.shrink(ptr.cast(), core::alloc::Layout::array::<u32>(2).unwrap(), layout).unwrap()
446 };
447
448 unsafe {
449 alloc.deallocate(ptr.cast(), layout);
450 }
451 }
452
453 #[test]
454 fn test_array_test_allocator_failure() {
455 use kalloc::Allocator;
456 let state = TestState::default();
457 let alloc = TestAllocator { state: &state };
458 let layout = core::alloc::Layout::new::<u32>();
459
460 state.fail_threshold.set(0);
462
463 assert!(alloc.allocate_zeroed(layout).is_err());
464
465 let dummy_ptr = core::ptr::NonNull::<u8>::dangling();
466 assert!(
467 unsafe {
468 alloc.grow(dummy_ptr.cast(), layout, core::alloc::Layout::array::<u32>(2).unwrap())
469 }
470 .is_err()
471 );
472 assert!(
473 unsafe {
474 alloc.shrink(
475 dummy_ptr.cast(),
476 core::alloc::Layout::array::<u32>(2).unwrap(),
477 layout,
478 )
479 }
480 .is_err()
481 );
482 }
483
484 #[test]
485 fn test_try_new_zeroed_slice() {
486 let arr = Array::<u32>::try_new_zeroed_slice(4).unwrap();
487 assert_eq!(arr.len(), 4);
488 for &val in arr.iter() {
489 assert_eq!(val, 0);
490 }
491
492 let state = TestState::default();
493 let arr_alloc = Array::<u32, TestAllocator<'_>>::try_new_zeroed_slice_in(
494 3,
495 TestAllocator { state: &state },
496 )
497 .unwrap();
498 assert_eq!(arr_alloc.len(), 3);
499 assert_eq!(state.alloc_count.get(), 1);
500 for &val in arr_alloc.iter() {
501 assert_eq!(val, 0);
502 }
503 }
504
505 #[test]
506 fn test_try_new_uninit_slice_and_assume_init() {
507 let mut uninit = Array::<u32>::try_new_uninit_slice(3).unwrap();
508 assert_eq!(uninit.len(), 3);
509 for i in 0..3 {
510 uninit[i].write((i * 10) as u32);
511 }
512 let arr = unsafe { uninit.assume_init() };
513 assert_eq!(arr.len(), 3);
514 assert_eq!(&arr[..], &[0, 10, 20]);
515 }
516
517 #[test]
518 fn test_uninit_slice_drop_behavior() {
519 let state = TestState::default();
520 {
521 let mut uninit = Array::<TestObject<'_>, TestAllocator<'_>>::try_new_uninit_slice_in(
522 2,
523 TestAllocator { state: &state },
524 )
525 .unwrap();
526 uninit[0].write(TestObject::new(10, &state));
527 uninit[1].write(TestObject::new(20, &state));
528 let arr = unsafe { uninit.assume_init() };
529 assert_eq!(state.live_obj_count.get(), 2);
530 assert_eq!(arr[0].val, 10);
531 assert_eq!(arr[1].val, 20);
532 }
533 assert_eq!(state.live_obj_count.get(), 0);
534 assert_eq!(state.dtor_count.get(), 2);
535 }
536
537 #[test]
538 fn test_into_and_from_raw_parts() {
539 let mut arr = Array::<u32>::try_new(3).unwrap();
540 arr[0] = 100;
541 arr[1] = 200;
542 arr[2] = 300;
543
544 let (ptr, len) = arr.into_raw_parts();
545 assert_eq!(len, 3);
546 assert!(!ptr.is_null());
547
548 let reconstructed = unsafe { Array::<u32>::from_raw_parts(ptr, len) };
549 assert_eq!(reconstructed.len(), 3);
550 assert_eq!(&reconstructed[..], &[100, 200, 300]);
551 }
552
553 #[test]
554 fn test_into_and_from_raw() {
555 let mut arr = Array::<u32>::try_new(2).unwrap();
556 arr[0] = 42;
557 arr[1] = 84;
558
559 let slice_ptr = arr.into_raw();
560 assert_eq!(unsafe { &*slice_ptr }, &[42, 84]);
561
562 let reconstructed = unsafe { Array::<u32>::from_raw(slice_ptr) };
563 assert_eq!(&reconstructed[..], &[42, 84]);
564 }
565
566 #[test]
567 fn test_raw_parts_with_allocator() {
568 let state = TestState::default();
569 let alloc = TestAllocator { state: &state };
570 let mut arr = Array::<u32, TestAllocator<'_>>::try_new_in(2, alloc.clone()).unwrap();
571 arr[0] = 7;
572 arr[1] = 9;
573
574 let (ptr, len, returned_alloc) = arr.into_raw_parts_with_allocator();
575 assert_eq!(len, 2);
576
577 let reconstructed =
578 unsafe { Array::<u32, TestAllocator<'_>>::from_raw_parts_in(ptr, len, returned_alloc) };
579 assert_eq!(&reconstructed[..], &[7, 9]);
580 }
581}