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