1use crate::allocator::{AllocError, Allocator, DefaultAllocator};
8use core::mem::MaybeUninit;
9use core::ops::{Deref, DerefMut};
10use core::ptr::NonNull;
11
12fn dangling_slice<T>(len: usize) -> NonNull<[MaybeUninit<T>]> {
14 let dangling = NonNull::<T>::dangling();
15 NonNull::slice_from_raw_parts(dangling.cast::<MaybeUninit<T>>(), len)
16}
17
18fn allocate_slice<T, A: Allocator>(
20 allocator: &A,
21 len: usize,
22) -> Result<NonNull<[MaybeUninit<T>]>, AllocError> {
23 let layout = core::alloc::Layout::array::<T>(len).map_err(|_| AllocError)?;
24 if layout.size() == 0 {
25 return Ok(dangling_slice::<T>(len));
26 }
27 let ptr = allocator.allocate(layout)?;
28 let casted_thin = ptr.cast::<MaybeUninit<T>>();
29 Ok(NonNull::slice_from_raw_parts(casted_thin, len))
30}
31
32fn allocate_zeroed_slice<T, A: Allocator>(
34 allocator: &A,
35 len: usize,
36) -> Result<NonNull<[MaybeUninit<T>]>, AllocError> {
37 let layout = core::alloc::Layout::array::<T>(len).map_err(|_| AllocError)?;
38 if layout.size() == 0 {
39 return Ok(dangling_slice::<T>(len));
40 }
41 let ptr = allocator.allocate_zeroed(layout)?;
42 let casted_thin = ptr.cast::<MaybeUninit<T>>();
43 Ok(NonNull::slice_from_raw_parts(casted_thin, len))
44}
45
46unsafe fn deallocate_slice<T, A: Allocator>(allocator: &A, ptr: NonNull<[MaybeUninit<T>]>) {
53 let len = ptr.len();
54 unsafe {
56 let layout = core::alloc::Layout::array::<T>(len).unwrap_unchecked();
57 if layout.size() == 0 {
58 return;
59 }
60 allocator.deallocate(ptr.cast::<u8>(), layout);
61 }
62}
63
64unsafe fn grow_slice<T, A: Allocator>(
71 allocator: &A,
72 ptr: NonNull<[MaybeUninit<T>]>,
73 new_len: usize,
74) -> Result<NonNull<[MaybeUninit<T>]>, AllocError> {
75 let old_len = ptr.len();
76 assert!(new_len > old_len);
77
78 let old_layout = core::alloc::Layout::array::<T>(old_len).map_err(|_| AllocError)?;
79 let new_layout = core::alloc::Layout::array::<T>(new_len).map_err(|_| AllocError)?;
80
81 if old_layout.size() == 0 {
82 return allocate_slice(allocator, new_len);
83 }
84
85 let new_ptr = unsafe { allocator.grow(ptr.cast::<u8>(), old_layout, new_layout)? };
87 Ok(NonNull::slice_from_raw_parts(new_ptr.cast::<MaybeUninit<T>>(), new_len))
88}
89
90unsafe fn shrink_slice<T, A: Allocator>(
97 allocator: &A,
98 ptr: NonNull<[MaybeUninit<T>]>,
99 new_len: usize,
100) -> Result<NonNull<[MaybeUninit<T>]>, AllocError> {
101 let old_len = ptr.len();
102 assert!(new_len < old_len);
103
104 let old_layout = core::alloc::Layout::array::<T>(old_len).map_err(|_| AllocError)?;
105 let new_layout = core::alloc::Layout::array::<T>(new_len).map_err(|_| AllocError)?;
106
107 if new_layout.size() == 0 {
108 unsafe {
110 deallocate_slice::<T, A>(allocator, ptr);
111 }
112 return Ok(dangling_slice::<T>(new_len));
113 }
114
115 let new_ptr = unsafe { allocator.shrink(ptr.cast::<u8>(), old_layout, new_layout)? };
117 Ok(NonNull::slice_from_raw_parts(new_ptr.cast::<MaybeUninit<T>>(), new_len))
118}
119
120pub struct Box<T: ?Sized, A: Allocator = DefaultAllocator> {
122 ptr: NonNull<T>,
134 allocator: A,
135}
136
137impl<T: ?Sized, A: Allocator> Box<T, A> {
138 pub const unsafe fn from_raw_in(ptr: *mut T, allocator: A) -> Self {
150 unsafe { Self::from_non_null_in(NonNull::new_unchecked(ptr), allocator) }
153 }
154
155 pub const unsafe fn from_non_null_in(ptr: NonNull<T>, allocator: A) -> Self {
164 Self { ptr, allocator }
165 }
166
167 pub fn as_ptr(this: &Self) -> *mut T {
169 this.ptr.as_ptr()
170 }
171
172 pub fn into_raw_with_allocator(this: Self) -> (*mut T, A) {
186 let me = core::mem::ManuallyDrop::new(this);
187 let ptr = me.ptr.as_ptr();
188 let allocator = unsafe { core::ptr::read(&me.allocator) };
191 (ptr, allocator)
192 }
193}
194
195impl<T: ?Sized> Box<T, DefaultAllocator> {
196 pub const unsafe fn from_raw(ptr: *mut T) -> Self {
205 unsafe { Self::from_raw_in(ptr, DefaultAllocator) }
206 }
207
208 pub const unsafe fn from_non_null(ptr: NonNull<T>) -> Self {
217 unsafe { Self::from_non_null_in(ptr, DefaultAllocator) }
218 }
219
220 pub fn into_raw(this: Self) -> *mut T {
224 let (ptr, _) = Box::into_raw_with_allocator(this);
225 ptr
226 }
227}
228
229impl<T, A: Allocator> Box<[T], A> {
230 pub const fn empty_slice_in(allocator: A) -> Self {
234 unsafe { Self::from_non_null_in(NonNull::from_ref(&[]), allocator) }
237 }
238
239 pub fn try_new_uninit_slice_in(
241 len: usize,
242 allocator: A,
243 ) -> Result<Box<[MaybeUninit<T>], A>, AllocError> {
244 let fat_ptr = allocate_slice::<T, A>(&allocator, len)?;
245 Ok(unsafe { Box::from_non_null_in(fat_ptr, allocator) })
247 }
248
249 pub fn try_new_zeroed_slice_in(
251 len: usize,
252 allocator: A,
253 ) -> Result<Box<[MaybeUninit<T>], A>, AllocError> {
254 let fat_ptr = allocate_zeroed_slice::<T, A>(&allocator, len)?;
255 Ok(unsafe { Box::from_non_null_in(fat_ptr, allocator) })
257 }
258}
259
260impl<T> Box<[T], DefaultAllocator> {
261 pub const fn empty_slice() -> Self {
262 Self::empty_slice_in(DefaultAllocator)
263 }
264
265 pub fn try_new_uninit_slice(
266 len: usize,
267 ) -> Result<Box<[MaybeUninit<T>], DefaultAllocator>, AllocError> {
268 Self::try_new_uninit_slice_in(len, DefaultAllocator)
269 }
270
271 pub fn try_new_zeroed_slice(
272 len: usize,
273 ) -> Result<Box<[MaybeUninit<T>], DefaultAllocator>, AllocError> {
274 Self::try_new_zeroed_slice_in(len, DefaultAllocator)
275 }
276}
277
278impl<T, A: Allocator> Box<[MaybeUninit<T>], A> {
279 pub unsafe fn assume_init(self) -> Box<[T], A> {
285 let (ptr, allocator) = Box::into_raw_with_allocator(self);
286 let ptr = ptr as *mut [core::mem::MaybeUninit<T>] as *mut [T];
287 unsafe { Box::from_raw_in(ptr, allocator) }
289 }
290
291 pub fn try_grow(this: &mut Self, new_len: usize) -> Result<(), AllocError> {
294 this.ptr = unsafe { grow_slice::<T, A>(&this.allocator, this.ptr, new_len)? };
296 Ok(())
297 }
298
299 pub unsafe fn try_shrink(this: &mut Self, new_len: usize) -> Result<(), AllocError> {
309 this.ptr = unsafe { shrink_slice::<T, A>(&this.allocator, this.ptr, new_len)? };
311 Ok(())
312 }
313}
314
315impl<T, A: Allocator> Box<T, A> {
316 const fn new_zst_in(allocator: A) -> Self {
322 assert!(core::mem::size_of::<T>() == 0);
323 Self { ptr: NonNull::<T>::dangling(), allocator }
325 }
326
327 pub fn try_new_in(value: T, allocator: A) -> Result<Self, AllocError> {
329 let mut b = Self::try_new_uninit_in(allocator)?;
330 b.write(value);
331 Ok(unsafe { b.assume_init() })
332 }
333
334 pub fn try_new_uninit_in(allocator: A) -> Result<Box<MaybeUninit<T>, A>, AllocError> {
336 if core::mem::size_of::<T>() == 0 {
337 return Ok(Box::<MaybeUninit<T>, A>::new_zst_in(allocator));
338 }
339 let layout = core::alloc::Layout::new::<T>();
340 let ptr = allocator.allocate(layout)?.cast::<MaybeUninit<T>>();
341 Ok(unsafe { Box::from_non_null_in(ptr, allocator) })
343 }
344
345 pub fn try_new_zeroed_in(allocator: A) -> Result<Box<MaybeUninit<T>, A>, AllocError> {
347 if core::mem::size_of::<T>() == 0 {
348 return Ok(Box::<MaybeUninit<T>, A>::new_zst_in(allocator));
349 }
350 let layout = core::alloc::Layout::new::<T>();
351 let ptr = allocator.allocate_zeroed(layout)?.cast::<MaybeUninit<T>>();
352 Ok(unsafe { Box::from_non_null_in(ptr, allocator) })
354 }
355}
356
357impl<T> Box<T, DefaultAllocator> {
358 pub fn try_new(value: T) -> Result<Self, AllocError> {
359 Self::try_new_in(value, DefaultAllocator)
360 }
361
362 pub fn try_new_uninit() -> Result<Box<MaybeUninit<T>>, AllocError> {
363 Self::try_new_uninit_in(DefaultAllocator)
364 }
365
366 pub fn try_new_zeroed() -> Result<Box<MaybeUninit<T>>, AllocError> {
367 Self::try_new_zeroed_in(DefaultAllocator)
368 }
369}
370
371impl<T, A: Allocator> Box<MaybeUninit<T>, A> {
372 pub unsafe fn assume_init(self) -> Box<T, A> {
378 let (ptr, allocator) = Box::into_raw_with_allocator(self);
379 unsafe { Box::from_raw_in(ptr as *mut T, allocator) }
381 }
382}
383
384impl<T> Default for Box<[T]> {
385 fn default() -> Self {
386 Self::empty_slice()
387 }
388}
389
390impl<T: ?Sized, A: Allocator> Deref for Box<T, A> {
391 type Target = T;
392 fn deref(&self) -> &Self::Target {
393 unsafe { self.ptr.as_ref() }
395 }
396}
397
398impl<T: ?Sized, A: Allocator> DerefMut for Box<T, A> {
399 fn deref_mut(&mut self) -> &mut Self::Target {
400 unsafe { self.ptr.as_mut() }
402 }
403}
404
405impl<T: ?Sized, A: Allocator> Drop for Box<T, A> {
406 fn drop(&mut self) {
407 unsafe {
409 let value = self.ptr.as_mut();
410 let layout = core::alloc::Layout::for_value(value);
411 core::ptr::drop_in_place(value);
412 if layout.size() > 0 {
413 self.allocator.deallocate(self.ptr.cast::<u8>(), layout);
414 }
415 }
416 }
417}
418
419#[cfg(test)]
420mod tests {
421 use super::*;
422 use core::alloc::Layout;
423
424 #[test]
425 fn test_box_default_slice() {
426 let b = Box::<[u32]>::default();
427 assert_eq!(b.len(), 0);
428 }
429
430 #[test]
431 fn test_box_empty_slice() {
432 let b = Box::<[u32]>::empty_slice();
433 assert_eq!(b.len(), 0);
434 assert!(Box::as_ptr(&b) as *mut u8 == NonNull::<u32>::dangling().as_ptr() as *mut u8);
435 }
436
437 #[test]
438 fn test_box_try_new() {
439 let b = Box::<u32>::try_new(42).unwrap();
440 assert_eq!(*b, 42);
441 }
442
443 #[test]
444 fn test_box() {
445 let b = Box::<[u32]>::try_new_uninit_slice(10).unwrap();
446 assert_eq!(b.len(), 10);
447 }
448
449 #[test]
450 fn test_box_deref() {
451 let b = Box::<[u32]>::try_new_uninit_slice(1).unwrap();
452 let mut b = unsafe { b.assume_init() };
453 b[0] = 42;
454 assert_eq!(b[0], 42);
455 }
456
457 #[test]
458 fn test_box_as_ptr() {
459 let b = Box::<[u32]>::try_new_uninit_slice(10).unwrap();
460 let ptr = Box::as_ptr(&b);
461 assert!(!ptr.is_null());
462 }
463
464 #[test]
465 fn test_box_from_raw() {
466 let b = Box::<[u32]>::try_new_uninit_slice(10).unwrap();
467 let raw_ptr = Box::into_raw(b);
468 let fat_ptr = raw_ptr as *mut [u32];
469
470 let b2: Box<[u32]> = unsafe { Box::from_raw(fat_ptr) };
472 assert_eq!(b2.len(), 10);
473 }
475
476 struct DropObserver<'a> {
477 dropped: &'a core::cell::Cell<bool>,
478 }
479
480 impl<'a> Drop for DropObserver<'a> {
481 fn drop(&mut self) {
482 self.dropped.set(true);
483 }
484 }
485
486 #[test]
487 fn test_box_drops_content() {
488 use core::cell::Cell;
489 let dropped = Cell::new(false);
490 {
491 let observer = DropObserver { dropped: &dropped };
492 let _b: Box<DropObserver<'_>> = Box::try_new(observer).unwrap();
493 assert_eq!(dropped.get(), false);
494 } assert_eq!(dropped.get(), true);
496 }
497
498 #[test]
499 #[should_panic]
500 fn test_box_slice_out_of_bounds() {
501 let b = Box::<[u32]>::try_new_uninit_slice(5).unwrap();
502 let _ = b[5]; }
504
505 #[derive(Clone, Default)]
506 struct AlwaysFailingAllocator;
507
508 impl Allocator for AlwaysFailingAllocator {
509 fn allocate(&self, _layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
510 Err(AllocError)
511 }
512
513 unsafe fn deallocate(&self, _ptr: NonNull<u8>, _layout: Layout) {
514 panic!("Deallocate called on AlwaysFailingAllocator");
515 }
516
517 unsafe fn grow(
518 &self,
519 _ptr: NonNull<u8>,
520 _old_layout: Layout,
521 _new_layout: Layout,
522 ) -> Result<NonNull<[u8]>, AllocError> {
523 Err(AllocError)
524 }
525
526 unsafe fn shrink(
527 &self,
528 _ptr: NonNull<u8>,
529 _old_layout: Layout,
530 _new_layout: Layout,
531 ) -> Result<NonNull<[u8]>, AllocError> {
532 Err(AllocError)
533 }
534
535 fn allocate_zeroed(&self, _layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
536 Err(AllocError)
537 }
538 }
539
540 #[test]
541 fn test_box_try_new_failing() {
542 let b =
543 Box::<u32, AlwaysFailingAllocator>::try_new_in(42, AlwaysFailingAllocator::default());
544 assert!(b.is_err());
545 }
546
547 #[test]
548 fn test_box_try_new_slice_failing() {
549 let b = Box::<[u32], AlwaysFailingAllocator>::try_new_uninit_slice_in(
550 10,
551 AlwaysFailingAllocator::default(),
552 );
553 assert!(b.is_err());
554 }
555
556 #[test]
557 fn test_box_try_new_zeroed() {
558 let b = Box::<u32>::try_new_zeroed().unwrap();
559 let b = unsafe { b.assume_init() };
560 assert_eq!(*b, 0);
561 }
562
563 #[test]
564 fn test_box_try_new_zeroed_slice() {
565 let b = Box::<[u32]>::try_new_zeroed_slice(3).unwrap();
566 let b = unsafe { b.assume_init() };
567 assert_eq!(*b, [0, 0, 0]);
568 }
569
570 #[test]
571 fn test_box_try_grow() {
572 let mut b = Box::<[u32]>::try_new_uninit_slice(2).unwrap();
573 unsafe {
574 b[0].as_mut_ptr().write(10);
575 b[1].as_mut_ptr().write(20);
576 }
577
578 Box::try_grow(&mut b, 5).unwrap();
579 assert_eq!(b.len(), 5);
580 assert_eq!(unsafe { b[0].assume_init() }, 10);
581 assert_eq!(unsafe { b[1].assume_init() }, 20);
582 }
583
584 #[test]
585 fn test_box_try_shrink() {
586 let mut b = Box::<[u32]>::try_new_uninit_slice(5).unwrap();
587 unsafe {
588 b[0].as_mut_ptr().write(10);
589 b[1].as_mut_ptr().write(20);
590 }
591
592 unsafe {
593 Box::try_shrink(&mut b, 2).unwrap();
594 }
595 assert_eq!(b.len(), 2);
596 assert_eq!(unsafe { b[0].assume_init() }, 10);
597 assert_eq!(unsafe { b[1].assume_init() }, 20);
598 }
599
600 #[test]
601 fn test_box_from_non_null() {
602 use core::alloc::Layout;
603 let layout = Layout::new::<u32>();
604 let ptr = DefaultAllocator::default().allocate(layout).unwrap();
605 let thin_ptr = unsafe { NonNull::new_unchecked(ptr.as_ptr() as *mut u8) };
606 let casted = thin_ptr.cast::<u32>();
607 unsafe {
608 casted.as_ptr().write(42);
609 }
610 let b: Box<u32, DefaultAllocator> = unsafe { Box::from_non_null(casted) };
611 assert_eq!(*b, 42);
612 }
613
614 #[test]
615 fn test_box_into_raw() {
616 let b = Box::try_new(42u32).unwrap();
617 let ptr = Box::into_raw(b);
618 assert_eq!(unsafe { *ptr }, 42);
619 unsafe {
620 *ptr = 100;
621 }
622 assert_eq!(unsafe { *ptr }, 100);
623
624 let b = unsafe { Box::from_raw(ptr) };
626 assert_eq!(*b, 100);
627 }
628
629 #[test]
630 fn test_box_into_raw_with_allocator() {
631 let b = Box::try_new(42u32).unwrap();
632 let (ptr, allocator) = Box::into_raw_with_allocator(b);
633 assert_eq!(unsafe { *ptr }, 42);
634
635 let b = unsafe { Box::from_raw_in(ptr, allocator) };
637 assert_eq!(*b, 42);
638 }
639
640 #[test]
641 fn test_box_assume_init_range() {
642 let mut b = Box::<[u32]>::try_new_uninit_slice(5).unwrap();
643 unsafe {
644 b[1].as_mut_ptr().write(10);
645 b[2].as_mut_ptr().write(20);
646 }
647
648 let slice = unsafe { b[1..3].assume_init_ref() };
649 assert_eq!(slice, [10, 20]);
650
651 let slice_mut = unsafe { b[1..3].assume_init_mut() };
652 slice_mut[0] = 30;
653 assert_eq!(unsafe { b[1].assume_init() }, 30);
654 }
655
656 #[derive(Clone)]
657 struct TrackingAllocator {
658 allocated: alloc::sync::Arc<core::cell::RefCell<alloc::collections::BTreeSet<usize>>>,
659 }
660
661 impl TrackingAllocator {
662 fn new() -> Self {
663 Self {
664 allocated: alloc::sync::Arc::new(core::cell::RefCell::new(
665 alloc::collections::BTreeSet::new(),
666 )),
667 }
668 }
669 }
670
671 impl Allocator for TrackingAllocator {
672 fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
673 let ptr = DefaultAllocator::default().allocate(layout)?;
674 let addr = ptr.as_ptr() as *mut u8 as usize;
675 self.allocated.borrow_mut().insert(addr);
676 Ok(ptr)
677 }
678
679 fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
680 let ptr = DefaultAllocator::default().allocate_zeroed(layout)?;
681 let addr = ptr.as_ptr() as *mut u8 as usize;
682 self.allocated.borrow_mut().insert(addr);
683 Ok(ptr)
684 }
685
686 unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
687 let addr = ptr.as_ptr() as usize;
688 let mut allocated = self.allocated.borrow_mut();
689 if !allocated.remove(&addr) {
690 panic!("Deallocate called on address not produced by allocator: {:p}", ptr);
691 }
692 unsafe {
694 DefaultAllocator::default().deallocate(ptr, layout);
695 }
696 }
697
698 unsafe fn grow(
699 &self,
700 ptr: NonNull<u8>,
701 old_layout: Layout,
702 new_layout: Layout,
703 ) -> Result<NonNull<[u8]>, AllocError> {
704 let addr = ptr.as_ptr() as usize;
705 let mut allocated = self.allocated.borrow_mut();
706 if !allocated.remove(&addr) {
707 panic!("Grow called on address not produced by allocator: {:p}", ptr);
708 }
709 let new_ptr = unsafe { DefaultAllocator::default().grow(ptr, old_layout, new_layout)? };
711 let new_addr = new_ptr.as_ptr() as *mut u8 as usize;
712 allocated.insert(new_addr);
713 Ok(new_ptr)
714 }
715
716 unsafe fn shrink(
717 &self,
718 ptr: NonNull<u8>,
719 old_layout: Layout,
720 new_layout: Layout,
721 ) -> Result<NonNull<[u8]>, AllocError> {
722 let addr = ptr.as_ptr() as usize;
723 let mut allocated = self.allocated.borrow_mut();
724 if !allocated.remove(&addr) {
725 panic!("Shrink called on address not produced by allocator: {:p}", ptr);
726 }
727 let new_ptr =
729 unsafe { DefaultAllocator::default().shrink(ptr, old_layout, new_layout)? };
730 let new_addr = new_ptr.as_ptr() as *mut u8 as usize;
731 allocated.insert(new_addr);
732 Ok(new_ptr)
733 }
734 }
735
736 #[test]
737 fn test_empty_slice_and_zst_allocator_interactions() {
738 let alloc = TrackingAllocator::new();
739
740 {
742 let b = Box::<[u32], TrackingAllocator>::empty_slice_in(alloc.clone());
743 assert_eq!(b.len(), 0);
744 }
746
747 struct Zst;
749 {
750 let _b = Box::<Zst, TrackingAllocator>::try_new_in(Zst, alloc.clone()).unwrap();
751 }
753
754 {
756 let mut b = Box::<[core::mem::MaybeUninit<u32>], TrackingAllocator>::empty_slice_in(
757 alloc.clone(),
758 );
759 Box::try_grow(&mut b, 5).unwrap();
760 let addr = Box::as_ptr(&b) as *mut u8 as usize;
762 assert!(alloc.allocated.borrow().contains(&addr));
763 } {
767 let mut b =
768 Box::<[u32], TrackingAllocator>::try_new_uninit_slice_in(5, alloc.clone()).unwrap();
769 let addr = Box::as_ptr(&b) as *mut u8 as usize;
770 assert!(alloc.allocated.borrow().contains(&addr));
771
772 unsafe {
773 Box::try_shrink(&mut b, 0).unwrap();
774 }
775 assert_eq!(b.len(), 0);
776 assert!(!alloc.allocated.borrow().contains(&addr));
778 }
779 }
780}