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