xref: /wasmtime-44.0.1/crates/core/src/alloc/boxed.rs (revision ab78bd82)
1 use super::{TryClone, TryNew, TryVec, try_alloc};
2 use crate::{alloc::str_ptr_from_slice_ptr, error::OutOfMemory};
3 use core::{
4     alloc::Layout,
5     mem::{self, MaybeUninit},
6 };
7 use std_alloc::boxed::Box;
8 
9 /// Allocate an `Box<MaybeUninit<T>>` with uninitialized contents, returning
10 /// `Err(OutOfMemory)` on allocation failure.
11 ///
12 /// You can initialize the resulting box's value via [`Box::write`].
13 #[inline]
new_uninit_box<T>() -> Result<Box<MaybeUninit<T>>, OutOfMemory>14 fn new_uninit_box<T>() -> Result<Box<MaybeUninit<T>>, OutOfMemory> {
15     let layout = Layout::new::<MaybeUninit<T>>();
16 
17     if layout.size() == 0 {
18         // NB: no actual allocation takes place when boxing zero-sized
19         // types.
20         return Ok(Box::new(MaybeUninit::uninit()));
21     }
22 
23     // Safety: layout size is non-zero.
24     let ptr = unsafe { try_alloc(layout)? };
25 
26     let ptr = ptr.cast::<MaybeUninit<T>>();
27 
28     // Safety: The pointer's memory block was allocated by the global allocator.
29     Ok(unsafe { Box::from_raw(ptr.as_ptr()) })
30 }
31 
32 impl<T> TryNew for Box<T> {
33     type Value = T;
34 
35     #[inline]
try_new(value: T) -> Result<Self, OutOfMemory> where Self: Sized,36     fn try_new(value: T) -> Result<Self, OutOfMemory>
37     where
38         Self: Sized,
39     {
40         let boxed = new_uninit_box::<T>()?;
41         Ok(Box::write(boxed, value))
42     }
43 }
44 
45 impl<T> TryClone for Box<T>
46 where
47     T: TryClone,
48 {
try_clone(&self) -> Result<Self, OutOfMemory>49     fn try_clone(&self) -> Result<Self, OutOfMemory> {
50         let b = new_uninit_box::<T>()?;
51         let v = (**self).try_clone()?;
52         Ok(Box::write(b, v))
53     }
54 }
55 
56 impl<T> TryClone for Box<[T]>
57 where
58     T: TryClone,
59 {
try_clone(&self) -> Result<Self, OutOfMemory>60     fn try_clone(&self) -> Result<Self, OutOfMemory> {
61         let mut builder = BoxedSliceBuilder::new(self.len())?;
62         for v in &*self {
63             builder.push(v.try_clone()?).expect("reserved capacity");
64         }
65         debug_assert_eq!(builder.init_len(), builder.capacity());
66         Ok(builder.finish())
67     }
68 }
69 
70 impl TryClone for Box<str> {
try_clone(&self) -> Result<Self, OutOfMemory>71     fn try_clone(&self) -> Result<Self, OutOfMemory> {
72         let mut builder = BoxedSliceBuilder::new(self.len())?;
73         for b in self.as_bytes() {
74             builder.push(*b).expect("reserved capacity");
75         }
76         debug_assert_eq!(builder.init_len(), builder.capacity());
77         let boxed = builder.finish();
78         let ptr = Box::into_raw(boxed);
79         let ptr = str_ptr_from_slice_ptr(ptr);
80         // SAFETY: the pointer is allocated with the global allocator and points
81         // to a valid utf8 sequence.
82         let boxed = unsafe { Box::from_raw(ptr) };
83         Ok(boxed)
84     }
85 }
86 
87 /// Allocate a new `Box<[MaybeUninit<T>]>` of the given length with
88 /// uninitialized contents, returning `Err(OutOfMemory)` on allocation failure.
89 ///
90 /// You can initialize the resulting boxed slice with
91 /// [`boxed_slice_write_iter`].
new_uninit_boxed_slice<T>(len: usize) -> Result<Box<[MaybeUninit<T>]>, OutOfMemory>92 pub fn new_uninit_boxed_slice<T>(len: usize) -> Result<Box<[MaybeUninit<T>]>, OutOfMemory> {
93     let layout = Layout::array::<MaybeUninit<T>>(len)
94         .map_err(|_| OutOfMemory::new(mem::size_of::<T>().saturating_mul(len)))?;
95 
96     if layout.size() == 0 {
97         // NB: no actual allocation takes place when boxing zero-sized
98         // types.
99         return Ok(Box::new_uninit_slice(len));
100     }
101 
102     // Safety: layout size is non-zero.
103     let ptr = unsafe { try_alloc(layout)? };
104 
105     let ptr = ptr.cast::<MaybeUninit<T>>().as_ptr();
106     let ptr = core::ptr::slice_from_raw_parts_mut(ptr, len);
107 
108     // Safety: The pointer's memory block was allocated by the global allocator
109     // and holds room for `[T; len]`.
110     Ok(unsafe { Box::from_raw(ptr) })
111 }
112 
113 use boxed_slice_builder::BoxedSliceBuilder;
114 mod boxed_slice_builder {
115     use super::*;
116 
117     /// Builder for constructing and initializing a boxed slice.
118     ///
119     /// Also acts as an RAII guard to handle dropping the already-initialized
120     /// elements when we get too few items or an iterator panics during
121     /// construction.
122     pub struct BoxedSliceBuilder<T> {
123         vec: TryVec<T>,
124     }
125 
126     impl<T> BoxedSliceBuilder<T> {
new(len: usize) -> Result<Self, OutOfMemory>127         pub fn new(len: usize) -> Result<Self, OutOfMemory> {
128             let mut vec = TryVec::new();
129             vec.reserve_exact(len)?;
130             Ok(Self { vec })
131         }
132 
from_boxed_slice(boxed: Box<[MaybeUninit<T>]>) -> Self133         pub fn from_boxed_slice(boxed: Box<[MaybeUninit<T>]>) -> Self {
134             let len = boxed.len();
135             let ptr = Box::into_raw(boxed);
136             let ptr = ptr.cast::<T>();
137             // Safety: the pointer was allocated by the global allocator and is
138             // valid for `[T; len]` since it was a boxed slice.
139             let vec = unsafe { TryVec::from_raw_parts(ptr, 0, len) };
140             Self { vec }
141         }
142 
init_len(&self) -> usize143         pub fn init_len(&self) -> usize {
144             self.vec.len()
145         }
146 
capacity(&self) -> usize147         pub fn capacity(&self) -> usize {
148             self.vec.capacity()
149         }
150 
push(&mut self, value: T) -> Result<(), OutOfMemory>151         pub fn push(&mut self, value: T) -> Result<(), OutOfMemory> {
152             self.vec.push(value)
153         }
154 
155         /// Finish this builder and take its boxed slice out.
156         ///
157         /// Panics if `self.init_len() != self.capacity()`. Call
158         /// `self.shrink_to_fit()` if necessary.
finish(mut self) -> Box<[T]>159         pub fn finish(mut self) -> Box<[T]> {
160             assert_eq!(self.init_len(), self.capacity());
161             let vec = mem::take(&mut self.vec);
162             mem::forget(self);
163             let (ptr, len, cap) = vec.into_raw_parts();
164             debug_assert_eq!(len, cap);
165             let ptr = core::ptr::slice_from_raw_parts_mut(ptr, len);
166             unsafe { Box::from_raw(ptr) }
167         }
168 
169         /// Shrink this builder's allocation such that `self.init_len() ==
170         /// self.capacity()`.
shrink_to_fit(&mut self) -> Result<(), OutOfMemory>171         pub fn shrink_to_fit(&mut self) -> Result<(), OutOfMemory> {
172             if self.init_len() == self.capacity() {
173                 return Ok(());
174             }
175 
176             let len = self.init_len();
177             let cap = self.capacity();
178             let vec = mem::take(&mut self.vec);
179 
180             let old_layout = Layout::array::<T>(cap).expect(
181                 "already have an allocation with this layout so should be able to recreate it",
182             );
183             let new_layout = Layout::array::<T>(len)
184                 .expect("if `cap` is fine for an array layout, then `len` must be as well");
185             debug_assert_eq!(old_layout.align(), new_layout.align());
186 
187             // Handle zero-sized reallocations, since the global `realloc` function
188             // does not.
189             if new_layout.size() == 0 {
190                 debug_assert!(mem::size_of::<T>() == 0 || len == 0);
191                 if len == 0 {
192                     debug_assert_eq!(self.capacity(), 0);
193                     debug_assert_eq!(self.init_len(), 0);
194                 } else {
195                     debug_assert_eq!(mem::size_of::<T>(), 0);
196                     let ptr = core::ptr::dangling_mut::<T>();
197                     debug_assert!(!ptr.is_null());
198                     debug_assert!(ptr.is_aligned());
199                     // Safety: T's dangling pointer is always non-null and aligned.
200                     self.vec = unsafe { TryVec::from_raw_parts(ptr, len, len) };
201                 }
202                 debug_assert_eq!(self.capacity(), self.init_len());
203                 return Ok(());
204             }
205 
206             let (ptr, _len, _cap) = vec.into_raw_parts();
207             debug_assert_eq!(len, _len);
208             debug_assert_eq!(cap, _cap);
209 
210             // Safety: `ptr` was allocated by the global allocator, its memory block
211             // is described by `old_layout`, the new size is non-zero, and the new
212             // size will not overflow `isize::MAX` when rounded up to the layout's
213             // alignment (this is checked in the construction of `new_layout`).
214             let new_ptr = unsafe {
215                 std_alloc::alloc::realloc(ptr.cast::<u8>(), old_layout, new_layout.size())
216             };
217 
218             // Update `self` based on whether the reallocation succeeded or not,
219             // either inserting the new vec or reconstructing and replacing the
220             // old one.
221             if new_ptr.is_null() {
222                 // Safety: The allocation failed so we retain ownership of `ptr`,
223                 // which was a valid vec and we can safely make it a vec again.
224                 self.vec = unsafe { TryVec::from_raw_parts(ptr, len, cap) };
225                 Err(OutOfMemory::new(new_layout.size()))
226             } else {
227                 let new_ptr = new_ptr.cast::<T>();
228                 // Safety: The allocation succeeded, `new_ptr` was reallocated by
229                 // the global allocator and points to a valid boxed slice of length
230                 // `len`.
231                 self.vec = unsafe { TryVec::from_raw_parts(new_ptr, len, len) };
232                 debug_assert_eq!(self.capacity(), self.init_len());
233                 Ok(())
234             }
235         }
236     }
237 }
238 
239 /// An error returned when an iterator yields too few items to fully initialize
240 /// a `Box<[MaybeUninit<T>]>`.
241 #[non_exhaustive]
242 #[derive(Debug, Clone, Copy)]
243 pub struct TooFewItems;
244 
245 impl core::fmt::Display for TooFewItems {
fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result246     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
247         f.write_str("iterator yielded too few items to fully initialize boxed slice")
248     }
249 }
250 
251 impl core::error::Error for TooFewItems {}
252 
253 /// An error returned by [`new_boxed_slice_from_iter`].
254 #[derive(Debug)]
255 pub enum TooFewItemsOrOom {
256     /// The iterator did not yield enough items to fill the boxed slice.
257     TooFewItems(TooFewItems),
258     /// Failed to allocate space for the boxed slice.
259     Oom(OutOfMemory),
260 }
261 
262 impl TooFewItemsOrOom {
263     /// Unwrap the inner `OutOfMemory` error, or panic if this is a different
264     /// error variant.
unwrap_oom(&self) -> OutOfMemory265     pub fn unwrap_oom(&self) -> OutOfMemory {
266         match self {
267             TooFewItemsOrOom::TooFewItems(_) => panic!("`unwrap_oom` on non-OOM error"),
268             TooFewItemsOrOom::Oom(oom) => *oom,
269         }
270     }
271 }
272 
273 impl From<TooFewItems> for TooFewItemsOrOom {
from(e: TooFewItems) -> Self274     fn from(e: TooFewItems) -> Self {
275         Self::TooFewItems(e)
276     }
277 }
278 
279 impl From<OutOfMemory> for TooFewItemsOrOom {
from(oom: OutOfMemory) -> Self280     fn from(oom: OutOfMemory) -> Self {
281         Self::Oom(oom)
282     }
283 }
284 
285 impl core::fmt::Display for TooFewItemsOrOom {
fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result286     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
287         match self {
288             Self::TooFewItems(_) => {
289                 f.write_str("The iterator did not yield enough items to fill the boxed slice")
290             }
291             Self::Oom(_) => f.write_str("Failed to allocate space for the boxed slice"),
292         }
293     }
294 }
295 
296 impl core::error::Error for TooFewItemsOrOom {
cause(&self) -> Option<&dyn core::error::Error>297     fn cause(&self) -> Option<&dyn core::error::Error> {
298         match self {
299             Self::TooFewItems(e) => Some(e),
300             Self::Oom(oom) => Some(oom),
301         }
302     }
303 }
304 
305 /// Initialize a `Box<[MaybeUninit<T>]>` slice by writing the elements of the
306 /// given iterator into it.
boxed_slice_write_iter<T>( boxed: Box<[MaybeUninit<T>]>, iter: impl IntoIterator<Item = T>, ) -> Result<Box<[T]>, TooFewItems>307 pub fn boxed_slice_write_iter<T>(
308     boxed: Box<[MaybeUninit<T>]>,
309     iter: impl IntoIterator<Item = T>,
310 ) -> Result<Box<[T]>, TooFewItems> {
311     let len = boxed.len();
312     let builder = BoxedSliceBuilder::from_boxed_slice(boxed);
313     assert_eq!(len, builder.capacity());
314     write_iter_into_builder(builder, iter)
315 }
316 
317 /// Create a `Box<[T]>` of length `len` from the given iterator's elements.
318 ///
319 /// Returns an error on allocation failure, or if `iter` yields fewer than `len`
320 /// elements.
321 ///
322 /// The iterator is dropped after `len` elements have been yielded, this
323 /// function does not check that the iterator yields exactly `len` elements.
new_boxed_slice_from_iter_with_len<T>( len: usize, iter: impl IntoIterator<Item = T>, ) -> Result<Box<[T]>, TooFewItemsOrOom>324 pub fn new_boxed_slice_from_iter_with_len<T>(
325     len: usize,
326     iter: impl IntoIterator<Item = T>,
327 ) -> Result<Box<[T]>, TooFewItemsOrOom> {
328     let builder = BoxedSliceBuilder::new(len)?;
329     assert_eq!(len, builder.capacity());
330     let boxed = write_iter_into_builder(builder, iter)?;
331     Ok(boxed)
332 }
333 
write_iter_into_builder<T>( mut builder: BoxedSliceBuilder<T>, iter: impl IntoIterator<Item = T>, ) -> Result<Box<[T]>, TooFewItems>334 fn write_iter_into_builder<T>(
335     mut builder: BoxedSliceBuilder<T>,
336     iter: impl IntoIterator<Item = T>,
337 ) -> Result<Box<[T]>, TooFewItems> {
338     let len = builder.capacity();
339 
340     for elem in iter.into_iter().take(len) {
341         builder.push(elem).expect("reserved capacity");
342     }
343 
344     if builder.init_len() < builder.capacity() {
345         return Err(TooFewItems);
346     }
347 
348     debug_assert_eq!(builder.init_len(), builder.capacity());
349     Ok(builder.finish())
350 }
351 
352 /// An error returned by [`new_boxed_slice_from_fallible_iter`].
353 #[derive(Debug)]
354 pub enum BoxedSliceFromFallibleIterError<E> {
355     /// The fallible iterator produced an error.
356     IterError(E),
357     /// Failed to allocate space for the boxed slice.
358     Oom(OutOfMemory),
359 }
360 
361 impl<E> From<OutOfMemory> for BoxedSliceFromFallibleIterError<E> {
from(oom: OutOfMemory) -> Self362     fn from(oom: OutOfMemory) -> Self {
363         Self::Oom(oom)
364     }
365 }
366 
367 impl<E> core::fmt::Display for BoxedSliceFromFallibleIterError<E> {
fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result368     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
369         match self {
370             Self::IterError(_) => f.write_str("The fallible iterator produced an error"),
371             Self::Oom(_) => f.write_str("Failed to allocate space for the boxed slice"),
372         }
373     }
374 }
375 
376 impl<E> core::error::Error for BoxedSliceFromFallibleIterError<E>
377 where
378     E: core::error::Error,
379 {
cause(&self) -> Option<&dyn core::error::Error>380     fn cause(&self) -> Option<&dyn core::error::Error> {
381         match self {
382             Self::IterError(e) => Some(e),
383             Self::Oom(oom) => Some(oom),
384         }
385     }
386 }
387 
388 impl BoxedSliceFromFallibleIterError<OutOfMemory> {
389     /// Flatten this error into its inner OOM.
flatten(self) -> OutOfMemory390     pub fn flatten(self) -> OutOfMemory {
391         match self {
392             Self::IterError(oom) | Self::Oom(oom) => oom,
393         }
394     }
395 }
396 
397 /// Create a `Box<[T]>` from the given iterator's `Result<T, E>` items.
398 ///
399 /// Returns an error on allocation failure or if an iterator item is an `Err`.
new_boxed_slice_from_fallible_iter<T, E>( iter: impl IntoIterator<Item = Result<T, E>>, ) -> Result<Box<[T]>, BoxedSliceFromFallibleIterError<E>>400 pub fn new_boxed_slice_from_fallible_iter<T, E>(
401     iter: impl IntoIterator<Item = Result<T, E>>,
402 ) -> Result<Box<[T]>, BoxedSliceFromFallibleIterError<E>> {
403     let iter = iter.into_iter();
404 
405     let (min, max) = iter.size_hint();
406     let len = max.unwrap_or_else(|| min);
407 
408     let mut builder = BoxedSliceBuilder::new(len)?;
409     assert_eq!(len, builder.capacity());
410 
411     for result in iter {
412         let elem = result.map_err(BoxedSliceFromFallibleIterError::IterError)?;
413         builder.push(elem)?;
414     }
415 
416     debug_assert!(builder.init_len() <= builder.capacity());
417     builder.shrink_to_fit()?;
418     debug_assert_eq!(builder.init_len(), builder.capacity());
419 
420     Ok(builder.finish())
421 }
422 
423 /// Create a `Box<[T]>` from the given iterator's elements.
424 ///
425 /// Returns an error on allocation failure.
new_boxed_slice_from_iter<T>( iter: impl IntoIterator<Item = T>, ) -> Result<Box<[T]>, OutOfMemory>426 pub fn new_boxed_slice_from_iter<T>(
427     iter: impl IntoIterator<Item = T>,
428 ) -> Result<Box<[T]>, OutOfMemory> {
429     let iter = iter
430         .into_iter()
431         .map(Result::<T, core::convert::Infallible>::Ok);
432     new_boxed_slice_from_fallible_iter(iter).map_err(|e| match e {
433         BoxedSliceFromFallibleIterError::Oom(oom) => oom,
434         BoxedSliceFromFallibleIterError::IterError(_) => unreachable!(),
435     })
436 }
437 
438 #[cfg(test)]
439 mod tests {
440     use super::*;
441     use core::cell::Cell;
442     use std_alloc::rc::Rc;
443 
444     struct SetFlagOnDrop(Rc<Cell<bool>>);
445 
446     impl Drop for SetFlagOnDrop {
drop(&mut self)447         fn drop(&mut self) {
448             let old_value = self.0.replace(true);
449             assert_eq!(old_value, false);
450         }
451     }
452 
453     impl SetFlagOnDrop {
new() -> (Rc<Cell<bool>>, Self)454         fn new() -> (Rc<Cell<bool>>, Self) {
455             let flag = Rc::new(Cell::new(false));
456             (flag.clone(), SetFlagOnDrop(flag))
457         }
458     }
459 
460     #[test]
try_new()461     fn try_new() {
462         <Box<_> as TryNew>::try_new(4).unwrap();
463     }
464 
465     #[test]
new_boxed_slice_from_iter_with_len_smoke_test()466     fn new_boxed_slice_from_iter_with_len_smoke_test() {
467         let slice = new_boxed_slice_from_iter_with_len(3, [42, 36, 1337]).unwrap();
468         assert_eq!(&*slice, &[42, 36, 1337]);
469     }
470 
471     #[test]
new_boxed_slice_from_iter_with_len_with_too_few_elems()472     fn new_boxed_slice_from_iter_with_len_with_too_few_elems() {
473         let (a_dropped, a) = SetFlagOnDrop::new();
474         let (b_dropped, b) = SetFlagOnDrop::new();
475         let (c_dropped, c) = SetFlagOnDrop::new();
476 
477         match new_boxed_slice_from_iter_with_len(4, [a, b, c]) {
478             Err(TooFewItemsOrOom::TooFewItems(_)) => {}
479             Ok(_) | Err(TooFewItemsOrOom::Oom(_)) => unreachable!(),
480         }
481 
482         assert!(a_dropped.get());
483         assert!(b_dropped.get());
484         assert!(c_dropped.get());
485     }
486 
487     #[test]
new_boxed_slice_from_iter_with_len_with_too_many_elems()488     fn new_boxed_slice_from_iter_with_len_with_too_many_elems() {
489         let (a_dropped, a) = SetFlagOnDrop::new();
490         let (b_dropped, b) = SetFlagOnDrop::new();
491         let (c_dropped, c) = SetFlagOnDrop::new();
492 
493         let slice = new_boxed_slice_from_iter_with_len(2, [a, b, c]).unwrap();
494 
495         assert!(!a_dropped.get());
496         assert!(!b_dropped.get());
497         assert!(c_dropped.get());
498 
499         drop(slice);
500 
501         assert!(a_dropped.get());
502         assert!(b_dropped.get());
503         assert!(c_dropped.get());
504     }
505 
506     #[test]
new_boxed_slice_from_iter_smoke_test()507     fn new_boxed_slice_from_iter_smoke_test() {
508         let slice = new_boxed_slice_from_iter([10, 20, 30]).unwrap();
509         assert_eq!(&*slice, &[10, 20, 30]);
510     }
511 
512     #[test]
new_boxed_slice_from_fallible_iter_smoke_test()513     fn new_boxed_slice_from_fallible_iter_smoke_test() {
514         let slice =
515             new_boxed_slice_from_fallible_iter::<_, &str>([Ok(10), Ok(20), Ok(30)]).unwrap();
516         assert_eq!(&*slice, &[10, 20, 30]);
517     }
518 
519     #[test]
new_boxed_slice_from_fallible_iter_error()520     fn new_boxed_slice_from_fallible_iter_error() {
521         let result = new_boxed_slice_from_fallible_iter::<_, u32>([Ok(10), Ok(20), Err(30)]);
522         let Err(BoxedSliceFromFallibleIterError::IterError(err)) = result else {
523             panic!("unexpected result: {result:?}");
524         };
525         assert_eq!(err, 30);
526     }
527 
528     #[test]
new_uninit_boxed_slice_smoke_test()529     fn new_uninit_boxed_slice_smoke_test() {
530         let slice = new_uninit_boxed_slice::<u32>(5).unwrap();
531         assert_eq!(slice.len(), 5);
532     }
533 
534     #[test]
boxed_slice_write_iter_smoke_test()535     fn boxed_slice_write_iter_smoke_test() {
536         let uninit = new_uninit_boxed_slice(3).unwrap();
537         let init = boxed_slice_write_iter(uninit, [10, 20, 30]).unwrap();
538         assert_eq!(&*init, &[10, 20, 30]);
539     }
540 
541     #[test]
boxed_slice_write_iter_with_too_few_elems()542     fn boxed_slice_write_iter_with_too_few_elems() {
543         let (a_dropped, a) = SetFlagOnDrop::new();
544         let (b_dropped, b) = SetFlagOnDrop::new();
545         let (c_dropped, c) = SetFlagOnDrop::new();
546 
547         let uninit = new_uninit_boxed_slice(4).unwrap();
548         match boxed_slice_write_iter(uninit, [a, b, c]) {
549             Err(_) => {}
550             Ok(_) => unreachable!(),
551         }
552 
553         assert!(a_dropped.get());
554         assert!(b_dropped.get());
555         assert!(c_dropped.get());
556     }
557 
558     #[test]
boxed_slice_write_iter_with_too_many_elems()559     fn boxed_slice_write_iter_with_too_many_elems() {
560         let (a_dropped, a) = SetFlagOnDrop::new();
561         let (b_dropped, b) = SetFlagOnDrop::new();
562         let (c_dropped, c) = SetFlagOnDrop::new();
563 
564         let uninit = new_uninit_boxed_slice(2).unwrap();
565         let slice = boxed_slice_write_iter(uninit, [a, b, c]).unwrap();
566 
567         assert!(!a_dropped.get());
568         assert!(!b_dropped.get());
569         assert!(c_dropped.get());
570 
571         drop(slice);
572 
573         assert!(a_dropped.get());
574         assert!(b_dropped.get());
575         assert!(c_dropped.get());
576     }
577 }
578