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 mut b = Box::<[u32]>::try_new_uninit_slice(1).unwrap();
473 b[0].write(0);
474 let mut b = unsafe { b.assume_init() };
476 assert_eq!(b[0], 0);
477 b[0] = 42;
478 assert_eq!(b[0], 42);
479 }
480
481 #[test]
482 fn test_box_as_ptr() {
483 let b = Box::<[u32]>::try_new_uninit_slice(10).unwrap();
484 let ptr = Box::as_ptr(&b);
485 assert!(!ptr.is_null());
486 }
487
488 #[test]
489 fn test_box_from_raw() {
490 let mut b = Box::<[u32]>::try_new_uninit_slice(10).unwrap();
491 b.fill(MaybeUninit::new(0));
492 let raw_ptr = Box::into_raw(b);
493 let fat_ptr = raw_ptr as *mut [u32];
494
495 let b2: Box<[u32]> = unsafe { Box::from_raw(fat_ptr) };
500 assert_eq!(b2.len(), 10);
501 assert_eq!(*b2, [0; 10]);
502 }
504
505 struct DropObserver<'a> {
506 dropped: &'a core::cell::Cell<bool>,
507 }
508
509 impl<'a> Drop for DropObserver<'a> {
510 fn drop(&mut self) {
511 self.dropped.set(true);
512 }
513 }
514
515 #[test]
516 fn test_box_drops_content() {
517 use core::cell::Cell;
518 let dropped = Cell::new(false);
519 {
520 let observer = DropObserver { dropped: &dropped };
521 let _b: Box<DropObserver<'_>> = Box::try_new(observer).unwrap();
522 assert_eq!(dropped.get(), false);
523 } assert_eq!(dropped.get(), true);
525 }
526
527 #[test]
528 #[should_panic]
529 fn test_box_slice_out_of_bounds() {
530 let b = Box::<[u32]>::try_new_uninit_slice(5).unwrap();
531 let _ = b[5]; }
533
534 #[derive(Clone, Default)]
535 struct AlwaysFailingAllocator;
536
537 impl Allocator for AlwaysFailingAllocator {
538 fn allocate(&self, _layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
539 Err(AllocError)
540 }
541
542 unsafe fn deallocate(&self, _ptr: NonNull<u8>, _layout: Layout) {
543 panic!("Deallocate called on AlwaysFailingAllocator");
544 }
545
546 unsafe fn grow(
547 &self,
548 _ptr: NonNull<u8>,
549 _old_layout: Layout,
550 _new_layout: Layout,
551 ) -> Result<NonNull<[u8]>, AllocError> {
552 Err(AllocError)
553 }
554
555 unsafe fn shrink(
556 &self,
557 _ptr: NonNull<u8>,
558 _old_layout: Layout,
559 _new_layout: Layout,
560 ) -> Result<NonNull<[u8]>, AllocError> {
561 Err(AllocError)
562 }
563
564 fn allocate_zeroed(&self, _layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
565 Err(AllocError)
566 }
567 }
568
569 #[test]
570 fn test_box_try_new_failing() {
571 let b =
572 Box::<u32, AlwaysFailingAllocator>::try_new_in(42, AlwaysFailingAllocator::default());
573 assert!(b.is_err());
574 }
575
576 #[test]
577 fn test_box_try_new_slice_failing() {
578 let b = Box::<[u32], AlwaysFailingAllocator>::try_new_uninit_slice_in(
579 10,
580 AlwaysFailingAllocator::default(),
581 );
582 assert!(b.is_err());
583 }
584
585 #[test]
586 fn test_box_try_new_zeroed() {
587 let b = Box::<u32>::try_new_zeroed().unwrap();
588 let b = unsafe { b.assume_init() };
589 assert_eq!(*b, 0);
590 }
591
592 #[test]
593 fn test_box_try_new_zeroed_slice() {
594 let b = Box::<[u32]>::try_new_zeroed_slice(3).unwrap();
595 assert_eq!(*b, [0, 0, 0]);
596 }
597
598 #[test]
599 fn test_box_try_grow() {
600 let mut b = Box::<[u32]>::try_new_uninit_slice(2).unwrap();
601 b[0].write(10);
602 b[1].write(20);
603
604 Box::try_grow(&mut b, 5).unwrap();
605 assert_eq!(b.len(), 5);
606 assert_eq!(unsafe { b[0].assume_init() }, 10);
607 assert_eq!(unsafe { b[1].assume_init() }, 20);
608 }
609
610 #[test]
611 fn test_box_try_shrink() {
612 let mut b = Box::<[u32]>::try_new_uninit_slice(5).unwrap();
613 b[0].write(10);
614 b[1].write(20);
615
616 unsafe {
617 Box::try_shrink(&mut b, 2).unwrap();
618 }
619 assert_eq!(b.len(), 2);
620 assert_eq!(unsafe { b[0].assume_init() }, 10);
621 assert_eq!(unsafe { b[1].assume_init() }, 20);
622 }
623
624 #[test]
625 fn test_box_from_non_null() {
626 use core::alloc::Layout;
627 let layout = Layout::new::<u32>();
628 let ptr = DefaultAllocator::default().allocate(layout).unwrap();
629 let casted = ptr.cast::<u32>();
630 unsafe {
631 casted.as_ptr().write(42);
632 }
633 let b: Box<u32, DefaultAllocator> = unsafe { Box::from_non_null(casted) };
634 assert_eq!(*b, 42);
635 }
636
637 #[test]
638 fn test_box_into_raw() {
639 let b = Box::try_new(42u32).unwrap();
640 let ptr = Box::into_raw(b);
641 assert_eq!(unsafe { *ptr }, 42);
642 unsafe {
643 *ptr = 100;
644 }
645 assert_eq!(unsafe { *ptr }, 100);
646
647 let b = unsafe { Box::from_raw(ptr) };
649 assert_eq!(*b, 100);
650 }
651
652 #[test]
653 fn test_box_into_raw_with_allocator() {
654 let b = Box::try_new(42u32).unwrap();
655 let (ptr, allocator) = Box::into_raw_with_allocator(b);
656 assert_eq!(unsafe { *ptr }, 42);
657
658 let b = unsafe { Box::from_raw_in(ptr, allocator) };
660 assert_eq!(*b, 42);
661 }
662
663 #[test]
664 fn test_box_assume_init_range() {
665 let mut b = Box::<[u32]>::try_new_uninit_slice(5).unwrap();
666 unsafe {
667 b[1].as_mut_ptr().write(10);
668 b[2].as_mut_ptr().write(20);
669 }
670
671 let slice = unsafe { b[1..3].assume_init_ref() };
672 assert_eq!(slice, [10, 20]);
673
674 let slice_mut = unsafe { b[1..3].assume_init_mut() };
675 slice_mut[0] = 30;
676 assert_eq!(unsafe { b[1].assume_init() }, 30);
677 }
678
679 #[derive(Clone)]
680 struct TrackingAllocator {
681 allocated: alloc::sync::Arc<core::cell::RefCell<alloc::collections::BTreeSet<usize>>>,
682 }
683
684 impl TrackingAllocator {
685 fn new() -> Self {
686 Self {
687 allocated: alloc::sync::Arc::new(core::cell::RefCell::new(
688 alloc::collections::BTreeSet::new(),
689 )),
690 }
691 }
692 }
693
694 impl Allocator for TrackingAllocator {
695 fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
696 let ptr = DefaultAllocator::default().allocate(layout)?;
697 let addr = ptr.as_ptr() as *mut u8 as usize;
698 self.allocated.borrow_mut().insert(addr);
699 Ok(ptr)
700 }
701
702 fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
703 let ptr = DefaultAllocator::default().allocate_zeroed(layout)?;
704 let addr = ptr.as_ptr() as *mut u8 as usize;
705 self.allocated.borrow_mut().insert(addr);
706 Ok(ptr)
707 }
708
709 unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
710 let addr = ptr.as_ptr() as usize;
711 let mut allocated = self.allocated.borrow_mut();
712 if !allocated.remove(&addr) {
713 panic!("Deallocate called on address not produced by allocator: {:p}", ptr);
714 }
715 unsafe {
717 DefaultAllocator::default().deallocate(ptr, layout);
718 }
719 }
720
721 unsafe fn grow(
722 &self,
723 ptr: NonNull<u8>,
724 old_layout: Layout,
725 new_layout: Layout,
726 ) -> Result<NonNull<[u8]>, AllocError> {
727 let addr = ptr.as_ptr() as usize;
728 let mut allocated = self.allocated.borrow_mut();
729 if !allocated.remove(&addr) {
730 panic!("Grow called on address not produced by allocator: {:p}", ptr);
731 }
732 let new_ptr = unsafe { DefaultAllocator::default().grow(ptr, old_layout, new_layout)? };
734 let new_addr = new_ptr.as_ptr() as *mut u8 as usize;
735 allocated.insert(new_addr);
736 Ok(new_ptr)
737 }
738
739 unsafe fn shrink(
740 &self,
741 ptr: NonNull<u8>,
742 old_layout: Layout,
743 new_layout: Layout,
744 ) -> Result<NonNull<[u8]>, AllocError> {
745 let addr = ptr.as_ptr() as usize;
746 let mut allocated = self.allocated.borrow_mut();
747 if !allocated.remove(&addr) {
748 panic!("Shrink called on address not produced by allocator: {:p}", ptr);
749 }
750 let new_ptr =
752 unsafe { DefaultAllocator::default().shrink(ptr, old_layout, new_layout)? };
753 let new_addr = new_ptr.as_ptr() as *mut u8 as usize;
754 allocated.insert(new_addr);
755 Ok(new_ptr)
756 }
757 }
758
759 #[test]
760 fn test_empty_slice_and_zst_allocator_interactions() {
761 let alloc = TrackingAllocator::new();
762
763 {
765 let b = Box::<[u32], TrackingAllocator>::empty_slice_in(alloc.clone());
766 assert_eq!(b.len(), 0);
767 }
769
770 struct Zst;
772 {
773 let _b = Box::<Zst, TrackingAllocator>::try_new_in(Zst, alloc.clone()).unwrap();
774 }
776
777 {
779 let mut b = Box::<[core::mem::MaybeUninit<u32>], TrackingAllocator>::empty_slice_in(
780 alloc.clone(),
781 );
782 Box::try_grow(&mut b, 5).unwrap();
783 let addr = Box::as_ptr(&b) as *mut u8 as usize;
785 assert!(alloc.allocated.borrow().contains(&addr));
786 } {
790 let mut b =
791 Box::<[u32], TrackingAllocator>::try_new_uninit_slice_in(5, alloc.clone()).unwrap();
792 let addr = Box::as_ptr(&b) as *mut u8 as usize;
793 assert!(alloc.allocated.borrow().contains(&addr));
794
795 unsafe {
796 Box::try_shrink(&mut b, 0).unwrap();
797 }
798 assert_eq!(b.len(), 0);
799 assert!(!alloc.allocated.borrow().contains(&addr));
801 }
802 }
803
804 #[test]
805 fn test_try_new_zeroed_uninit_slice() {
806 let b = Box::<[u32]>::try_new_zeroed_uninit_slice(4).unwrap();
808 assert_eq!(b.len(), 4);
809 for x in b.as_ref() {
810 assert_eq!(unsafe { x.assume_init() }, 0);
811 }
812
813 struct NotZeroable {
815 _a: u32,
816 _b: u32,
817 }
818 let b = Box::<[NotZeroable]>::try_new_zeroed_uninit_slice(4).unwrap();
819 assert_eq!(b.len(), 4);
820 }
821}