1183891f0SNick Fitzgerald use super::{TryClone, TryNew, TryVec, try_alloc};
20c673b70SNick Fitzgerald use crate::{alloc::str_ptr_from_slice_ptr, error::OutOfMemory};
335483cc4SNick Fitzgerald use core::{
435483cc4SNick Fitzgerald alloc::Layout,
535483cc4SNick Fitzgerald mem::{self, MaybeUninit},
635483cc4SNick Fitzgerald };
7233f1875SNick Fitzgerald use std_alloc::boxed::Box;
8233f1875SNick Fitzgerald
9233f1875SNick Fitzgerald /// Allocate an `Box<MaybeUninit<T>>` with uninitialized contents, returning
10233f1875SNick Fitzgerald /// `Err(OutOfMemory)` on allocation failure.
11233f1875SNick Fitzgerald ///
12233f1875SNick Fitzgerald /// You can initialize the resulting box's value via [`Box::write`].
13233f1875SNick Fitzgerald #[inline]
new_uninit_box<T>() -> Result<Box<MaybeUninit<T>>, OutOfMemory>14233f1875SNick Fitzgerald fn new_uninit_box<T>() -> Result<Box<MaybeUninit<T>>, OutOfMemory> {
15233f1875SNick Fitzgerald let layout = Layout::new::<MaybeUninit<T>>();
16233f1875SNick Fitzgerald
17233f1875SNick Fitzgerald if layout.size() == 0 {
18233f1875SNick Fitzgerald // NB: no actual allocation takes place when boxing zero-sized
19233f1875SNick Fitzgerald // types.
20233f1875SNick Fitzgerald return Ok(Box::new(MaybeUninit::uninit()));
21233f1875SNick Fitzgerald }
22233f1875SNick Fitzgerald
23233f1875SNick Fitzgerald // Safety: layout size is non-zero.
24233f1875SNick Fitzgerald let ptr = unsafe { try_alloc(layout)? };
25233f1875SNick Fitzgerald
26233f1875SNick Fitzgerald let ptr = ptr.cast::<MaybeUninit<T>>();
27233f1875SNick Fitzgerald
28233f1875SNick Fitzgerald // Safety: The pointer's memory block was allocated by the global allocator.
29233f1875SNick Fitzgerald Ok(unsafe { Box::from_raw(ptr.as_ptr()) })
30233f1875SNick Fitzgerald }
31233f1875SNick Fitzgerald
32233f1875SNick Fitzgerald impl<T> TryNew for Box<T> {
33233f1875SNick Fitzgerald type Value = T;
34233f1875SNick Fitzgerald
35233f1875SNick Fitzgerald #[inline]
try_new(value: T) -> Result<Self, OutOfMemory> where Self: Sized,36233f1875SNick Fitzgerald fn try_new(value: T) -> Result<Self, OutOfMemory>
37233f1875SNick Fitzgerald where
38233f1875SNick Fitzgerald Self: Sized,
39233f1875SNick Fitzgerald {
40233f1875SNick Fitzgerald let boxed = new_uninit_box::<T>()?;
41233f1875SNick Fitzgerald Ok(Box::write(boxed, value))
42233f1875SNick Fitzgerald }
43233f1875SNick Fitzgerald }
44233f1875SNick Fitzgerald
45b8e97b5bSNick Fitzgerald impl<T> TryClone for Box<T>
46b8e97b5bSNick Fitzgerald where
47b8e97b5bSNick Fitzgerald T: TryClone,
48b8e97b5bSNick Fitzgerald {
try_clone(&self) -> Result<Self, OutOfMemory>49b8e97b5bSNick Fitzgerald fn try_clone(&self) -> Result<Self, OutOfMemory> {
50b8e97b5bSNick Fitzgerald let b = new_uninit_box::<T>()?;
51b8e97b5bSNick Fitzgerald let v = (**self).try_clone()?;
52b8e97b5bSNick Fitzgerald Ok(Box::write(b, v))
53b8e97b5bSNick Fitzgerald }
54b8e97b5bSNick Fitzgerald }
55b8e97b5bSNick Fitzgerald
56b8e97b5bSNick Fitzgerald impl<T> TryClone for Box<[T]>
57b8e97b5bSNick Fitzgerald where
58b8e97b5bSNick Fitzgerald T: TryClone,
59b8e97b5bSNick Fitzgerald {
try_clone(&self) -> Result<Self, OutOfMemory>60b8e97b5bSNick Fitzgerald fn try_clone(&self) -> Result<Self, OutOfMemory> {
61b8e97b5bSNick Fitzgerald let mut builder = BoxedSliceBuilder::new(self.len())?;
62b8e97b5bSNick Fitzgerald for v in &*self {
63b8e97b5bSNick Fitzgerald builder.push(v.try_clone()?).expect("reserved capacity");
64b8e97b5bSNick Fitzgerald }
65b8e97b5bSNick Fitzgerald debug_assert_eq!(builder.init_len(), builder.capacity());
66b8e97b5bSNick Fitzgerald Ok(builder.finish())
67b8e97b5bSNick Fitzgerald }
68b8e97b5bSNick Fitzgerald }
69b8e97b5bSNick Fitzgerald
700c673b70SNick Fitzgerald impl TryClone for Box<str> {
try_clone(&self) -> Result<Self, OutOfMemory>710c673b70SNick Fitzgerald fn try_clone(&self) -> Result<Self, OutOfMemory> {
720c673b70SNick Fitzgerald let mut builder = BoxedSliceBuilder::new(self.len())?;
730c673b70SNick Fitzgerald for b in self.as_bytes() {
740c673b70SNick Fitzgerald builder.push(*b).expect("reserved capacity");
750c673b70SNick Fitzgerald }
760c673b70SNick Fitzgerald debug_assert_eq!(builder.init_len(), builder.capacity());
770c673b70SNick Fitzgerald let boxed = builder.finish();
780c673b70SNick Fitzgerald let ptr = Box::into_raw(boxed);
790c673b70SNick Fitzgerald let ptr = str_ptr_from_slice_ptr(ptr);
800c673b70SNick Fitzgerald // SAFETY: the pointer is allocated with the global allocator and points
810c673b70SNick Fitzgerald // to a valid utf8 sequence.
820c673b70SNick Fitzgerald let boxed = unsafe { Box::from_raw(ptr) };
830c673b70SNick Fitzgerald Ok(boxed)
840c673b70SNick Fitzgerald }
850c673b70SNick Fitzgerald }
860c673b70SNick Fitzgerald
87c0e42072SNick Fitzgerald /// Allocate a new `Box<[MaybeUninit<T>]>` of the given length with
88c0e42072SNick Fitzgerald /// uninitialized contents, returning `Err(OutOfMemory)` on allocation failure.
89c0e42072SNick Fitzgerald ///
90c0e42072SNick Fitzgerald /// You can initialize the resulting boxed slice with
91c0e42072SNick Fitzgerald /// [`boxed_slice_write_iter`].
new_uninit_boxed_slice<T>(len: usize) -> Result<Box<[MaybeUninit<T>]>, OutOfMemory>92c0e42072SNick Fitzgerald pub fn new_uninit_boxed_slice<T>(len: usize) -> Result<Box<[MaybeUninit<T>]>, OutOfMemory> {
93c0e42072SNick Fitzgerald let layout = Layout::array::<MaybeUninit<T>>(len)
94c0e42072SNick Fitzgerald .map_err(|_| OutOfMemory::new(mem::size_of::<T>().saturating_mul(len)))?;
95c0e42072SNick Fitzgerald
96c0e42072SNick Fitzgerald if layout.size() == 0 {
97c0e42072SNick Fitzgerald // NB: no actual allocation takes place when boxing zero-sized
98c0e42072SNick Fitzgerald // types.
99c0e42072SNick Fitzgerald return Ok(Box::new_uninit_slice(len));
100c0e42072SNick Fitzgerald }
101c0e42072SNick Fitzgerald
102c0e42072SNick Fitzgerald // Safety: layout size is non-zero.
103c0e42072SNick Fitzgerald let ptr = unsafe { try_alloc(layout)? };
104c0e42072SNick Fitzgerald
105c0e42072SNick Fitzgerald let ptr = ptr.cast::<MaybeUninit<T>>().as_ptr();
106c0e42072SNick Fitzgerald let ptr = core::ptr::slice_from_raw_parts_mut(ptr, len);
107c0e42072SNick Fitzgerald
108c0e42072SNick Fitzgerald // Safety: The pointer's memory block was allocated by the global allocator
109c0e42072SNick Fitzgerald // and holds room for `[T; len]`.
110c0e42072SNick Fitzgerald Ok(unsafe { Box::from_raw(ptr) })
111c0e42072SNick Fitzgerald }
112c0e42072SNick Fitzgerald
11335483cc4SNick Fitzgerald use boxed_slice_builder::BoxedSliceBuilder;
11435483cc4SNick Fitzgerald mod boxed_slice_builder {
11535483cc4SNick Fitzgerald use super::*;
116233f1875SNick Fitzgerald
117*ab78bd82SHo Kim /// Builder for constructing and initializing a boxed slice.
11835483cc4SNick Fitzgerald ///
11935483cc4SNick Fitzgerald /// Also acts as an RAII guard to handle dropping the already-initialized
12035483cc4SNick Fitzgerald /// elements when we get too few items or an iterator panics during
12135483cc4SNick Fitzgerald /// construction.
12235483cc4SNick Fitzgerald pub struct BoxedSliceBuilder<T> {
123183891f0SNick Fitzgerald vec: TryVec<T>,
124233f1875SNick Fitzgerald }
125233f1875SNick Fitzgerald
12635483cc4SNick Fitzgerald impl<T> BoxedSliceBuilder<T> {
new(len: usize) -> Result<Self, OutOfMemory>12735483cc4SNick Fitzgerald pub fn new(len: usize) -> Result<Self, OutOfMemory> {
128183891f0SNick Fitzgerald let mut vec = TryVec::new();
12935483cc4SNick Fitzgerald vec.reserve_exact(len)?;
130c0e42072SNick Fitzgerald Ok(Self { vec })
131c0e42072SNick Fitzgerald }
132c0e42072SNick Fitzgerald
from_boxed_slice(boxed: Box<[MaybeUninit<T>]>) -> Self133c0e42072SNick Fitzgerald pub fn from_boxed_slice(boxed: Box<[MaybeUninit<T>]>) -> Self {
134c0e42072SNick Fitzgerald let len = boxed.len();
135c0e42072SNick Fitzgerald let ptr = Box::into_raw(boxed);
136c0e42072SNick Fitzgerald let ptr = ptr.cast::<T>();
137c0e42072SNick Fitzgerald // Safety: the pointer was allocated by the global allocator and is
138c0e42072SNick Fitzgerald // valid for `[T; len]` since it was a boxed slice.
139183891f0SNick Fitzgerald let vec = unsafe { TryVec::from_raw_parts(ptr, 0, len) };
140c0e42072SNick Fitzgerald Self { vec }
14135483cc4SNick Fitzgerald }
142233f1875SNick Fitzgerald
init_len(&self) -> usize14335483cc4SNick Fitzgerald pub fn init_len(&self) -> usize {
14435483cc4SNick Fitzgerald self.vec.len()
14535483cc4SNick Fitzgerald }
14635483cc4SNick Fitzgerald
capacity(&self) -> usize14735483cc4SNick Fitzgerald pub fn capacity(&self) -> usize {
14835483cc4SNick Fitzgerald self.vec.capacity()
14935483cc4SNick Fitzgerald }
15035483cc4SNick Fitzgerald
push(&mut self, value: T) -> Result<(), OutOfMemory>15135483cc4SNick Fitzgerald pub fn push(&mut self, value: T) -> Result<(), OutOfMemory> {
15235483cc4SNick Fitzgerald self.vec.push(value)
15335483cc4SNick Fitzgerald }
15435483cc4SNick Fitzgerald
15535483cc4SNick Fitzgerald /// Finish this builder and take its boxed slice out.
15635483cc4SNick Fitzgerald ///
15735483cc4SNick Fitzgerald /// Panics if `self.init_len() != self.capacity()`. Call
15835483cc4SNick Fitzgerald /// `self.shrink_to_fit()` if necessary.
finish(mut self) -> Box<[T]>15935483cc4SNick Fitzgerald pub fn finish(mut self) -> Box<[T]> {
16035483cc4SNick Fitzgerald assert_eq!(self.init_len(), self.capacity());
16135483cc4SNick Fitzgerald let vec = mem::take(&mut self.vec);
16235483cc4SNick Fitzgerald mem::forget(self);
16335483cc4SNick Fitzgerald let (ptr, len, cap) = vec.into_raw_parts();
16435483cc4SNick Fitzgerald debug_assert_eq!(len, cap);
165233f1875SNick Fitzgerald let ptr = core::ptr::slice_from_raw_parts_mut(ptr, len);
16635483cc4SNick Fitzgerald unsafe { Box::from_raw(ptr) }
16735483cc4SNick Fitzgerald }
168233f1875SNick Fitzgerald
16935483cc4SNick Fitzgerald /// Shrink this builder's allocation such that `self.init_len() ==
17035483cc4SNick Fitzgerald /// self.capacity()`.
shrink_to_fit(&mut self) -> Result<(), OutOfMemory>17135483cc4SNick Fitzgerald pub fn shrink_to_fit(&mut self) -> Result<(), OutOfMemory> {
17235483cc4SNick Fitzgerald if self.init_len() == self.capacity() {
17335483cc4SNick Fitzgerald return Ok(());
17435483cc4SNick Fitzgerald }
17535483cc4SNick Fitzgerald
17635483cc4SNick Fitzgerald let len = self.init_len();
17735483cc4SNick Fitzgerald let cap = self.capacity();
17835483cc4SNick Fitzgerald let vec = mem::take(&mut self.vec);
17935483cc4SNick Fitzgerald
18035483cc4SNick Fitzgerald let old_layout = Layout::array::<T>(cap).expect(
18135483cc4SNick Fitzgerald "already have an allocation with this layout so should be able to recreate it",
18235483cc4SNick Fitzgerald );
18335483cc4SNick Fitzgerald let new_layout = Layout::array::<T>(len)
18435483cc4SNick Fitzgerald .expect("if `cap` is fine for an array layout, then `len` must be as well");
18535483cc4SNick Fitzgerald debug_assert_eq!(old_layout.align(), new_layout.align());
18635483cc4SNick Fitzgerald
18735483cc4SNick Fitzgerald // Handle zero-sized reallocations, since the global `realloc` function
18835483cc4SNick Fitzgerald // does not.
18935483cc4SNick Fitzgerald if new_layout.size() == 0 {
19035483cc4SNick Fitzgerald debug_assert!(mem::size_of::<T>() == 0 || len == 0);
19135483cc4SNick Fitzgerald if len == 0 {
19235483cc4SNick Fitzgerald debug_assert_eq!(self.capacity(), 0);
19335483cc4SNick Fitzgerald debug_assert_eq!(self.init_len(), 0);
19435483cc4SNick Fitzgerald } else {
19535483cc4SNick Fitzgerald debug_assert_eq!(mem::size_of::<T>(), 0);
19635483cc4SNick Fitzgerald let ptr = core::ptr::dangling_mut::<T>();
19735483cc4SNick Fitzgerald debug_assert!(!ptr.is_null());
19835483cc4SNick Fitzgerald debug_assert!(ptr.is_aligned());
19935483cc4SNick Fitzgerald // Safety: T's dangling pointer is always non-null and aligned.
200183891f0SNick Fitzgerald self.vec = unsafe { TryVec::from_raw_parts(ptr, len, len) };
20135483cc4SNick Fitzgerald }
20235483cc4SNick Fitzgerald debug_assert_eq!(self.capacity(), self.init_len());
20335483cc4SNick Fitzgerald return Ok(());
20435483cc4SNick Fitzgerald }
20535483cc4SNick Fitzgerald
20635483cc4SNick Fitzgerald let (ptr, _len, _cap) = vec.into_raw_parts();
20735483cc4SNick Fitzgerald debug_assert_eq!(len, _len);
20835483cc4SNick Fitzgerald debug_assert_eq!(cap, _cap);
20935483cc4SNick Fitzgerald
21035483cc4SNick Fitzgerald // Safety: `ptr` was allocated by the global allocator, its memory block
21135483cc4SNick Fitzgerald // is described by `old_layout`, the new size is non-zero, and the new
21235483cc4SNick Fitzgerald // size will not overflow `isize::MAX` when rounded up to the layout's
21335483cc4SNick Fitzgerald // alignment (this is checked in the construction of `new_layout`).
21435483cc4SNick Fitzgerald let new_ptr = unsafe {
21535483cc4SNick Fitzgerald std_alloc::alloc::realloc(ptr.cast::<u8>(), old_layout, new_layout.size())
21635483cc4SNick Fitzgerald };
21735483cc4SNick Fitzgerald
21835483cc4SNick Fitzgerald // Update `self` based on whether the reallocation succeeded or not,
21935483cc4SNick Fitzgerald // either inserting the new vec or reconstructing and replacing the
22035483cc4SNick Fitzgerald // old one.
22135483cc4SNick Fitzgerald if new_ptr.is_null() {
22235483cc4SNick Fitzgerald // Safety: The allocation failed so we retain ownership of `ptr`,
22335483cc4SNick Fitzgerald // which was a valid vec and we can safely make it a vec again.
224183891f0SNick Fitzgerald self.vec = unsafe { TryVec::from_raw_parts(ptr, len, cap) };
22535483cc4SNick Fitzgerald Err(OutOfMemory::new(new_layout.size()))
22635483cc4SNick Fitzgerald } else {
22735483cc4SNick Fitzgerald let new_ptr = new_ptr.cast::<T>();
22835483cc4SNick Fitzgerald // Safety: The allocation succeeded, `new_ptr` was reallocated by
22935483cc4SNick Fitzgerald // the global allocator and points to a valid boxed slice of length
23035483cc4SNick Fitzgerald // `len`.
231183891f0SNick Fitzgerald self.vec = unsafe { TryVec::from_raw_parts(new_ptr, len, len) };
23235483cc4SNick Fitzgerald debug_assert_eq!(self.capacity(), self.init_len());
23335483cc4SNick Fitzgerald Ok(())
23435483cc4SNick Fitzgerald }
23535483cc4SNick Fitzgerald }
23635483cc4SNick Fitzgerald }
237233f1875SNick Fitzgerald }
238233f1875SNick Fitzgerald
239c0e42072SNick Fitzgerald /// An error returned when an iterator yields too few items to fully initialize
240c0e42072SNick Fitzgerald /// a `Box<[MaybeUninit<T>]>`.
241c0e42072SNick Fitzgerald #[non_exhaustive]
242c0e42072SNick Fitzgerald #[derive(Debug, Clone, Copy)]
243c0e42072SNick Fitzgerald pub struct TooFewItems;
244c0e42072SNick Fitzgerald
245c0e42072SNick Fitzgerald impl core::fmt::Display for TooFewItems {
fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result246c0e42072SNick Fitzgerald fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
247c0e42072SNick Fitzgerald f.write_str("iterator yielded too few items to fully initialize boxed slice")
248c0e42072SNick Fitzgerald }
249c0e42072SNick Fitzgerald }
250c0e42072SNick Fitzgerald
251c0e42072SNick Fitzgerald impl core::error::Error for TooFewItems {}
252c0e42072SNick Fitzgerald
253233f1875SNick Fitzgerald /// An error returned by [`new_boxed_slice_from_iter`].
254233f1875SNick Fitzgerald #[derive(Debug)]
255c0e42072SNick Fitzgerald pub enum TooFewItemsOrOom {
256233f1875SNick Fitzgerald /// The iterator did not yield enough items to fill the boxed slice.
257c0e42072SNick Fitzgerald TooFewItems(TooFewItems),
258233f1875SNick Fitzgerald /// Failed to allocate space for the boxed slice.
259233f1875SNick Fitzgerald Oom(OutOfMemory),
260233f1875SNick Fitzgerald }
261233f1875SNick Fitzgerald
262c0e42072SNick Fitzgerald impl TooFewItemsOrOom {
263c0e42072SNick Fitzgerald /// Unwrap the inner `OutOfMemory` error, or panic if this is a different
264c0e42072SNick Fitzgerald /// error variant.
unwrap_oom(&self) -> OutOfMemory265c0e42072SNick Fitzgerald pub fn unwrap_oom(&self) -> OutOfMemory {
266c0e42072SNick Fitzgerald match self {
267c0e42072SNick Fitzgerald TooFewItemsOrOom::TooFewItems(_) => panic!("`unwrap_oom` on non-OOM error"),
268c0e42072SNick Fitzgerald TooFewItemsOrOom::Oom(oom) => *oom,
269c0e42072SNick Fitzgerald }
270c0e42072SNick Fitzgerald }
271c0e42072SNick Fitzgerald }
272c0e42072SNick Fitzgerald
273c0e42072SNick Fitzgerald impl From<TooFewItems> for TooFewItemsOrOom {
from(e: TooFewItems) -> Self274c0e42072SNick Fitzgerald fn from(e: TooFewItems) -> Self {
275c0e42072SNick Fitzgerald Self::TooFewItems(e)
276c0e42072SNick Fitzgerald }
277c0e42072SNick Fitzgerald }
278c0e42072SNick Fitzgerald
279c0e42072SNick Fitzgerald impl From<OutOfMemory> for TooFewItemsOrOom {
from(oom: OutOfMemory) -> Self280233f1875SNick Fitzgerald fn from(oom: OutOfMemory) -> Self {
281233f1875SNick Fitzgerald Self::Oom(oom)
282233f1875SNick Fitzgerald }
283233f1875SNick Fitzgerald }
284233f1875SNick Fitzgerald
285c0e42072SNick Fitzgerald impl core::fmt::Display for TooFewItemsOrOom {
fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result286233f1875SNick Fitzgerald fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
287233f1875SNick Fitzgerald match self {
288c0e42072SNick Fitzgerald Self::TooFewItems(_) => {
289233f1875SNick Fitzgerald f.write_str("The iterator did not yield enough items to fill the boxed slice")
290233f1875SNick Fitzgerald }
29135483cc4SNick Fitzgerald Self::Oom(_) => f.write_str("Failed to allocate space for the boxed slice"),
292233f1875SNick Fitzgerald }
293233f1875SNick Fitzgerald }
294233f1875SNick Fitzgerald }
295233f1875SNick Fitzgerald
296c0e42072SNick Fitzgerald impl core::error::Error for TooFewItemsOrOom {
cause(&self) -> Option<&dyn core::error::Error>297233f1875SNick Fitzgerald fn cause(&self) -> Option<&dyn core::error::Error> {
298233f1875SNick Fitzgerald match self {
299c0e42072SNick Fitzgerald Self::TooFewItems(e) => Some(e),
30035483cc4SNick Fitzgerald Self::Oom(oom) => Some(oom),
301233f1875SNick Fitzgerald }
302233f1875SNick Fitzgerald }
303233f1875SNick Fitzgerald }
304233f1875SNick Fitzgerald
305c0e42072SNick Fitzgerald /// Initialize a `Box<[MaybeUninit<T>]>` slice by writing the elements of the
306c0e42072SNick Fitzgerald /// given iterator into it.
boxed_slice_write_iter<T>( boxed: Box<[MaybeUninit<T>]>, iter: impl IntoIterator<Item = T>, ) -> Result<Box<[T]>, TooFewItems>307c0e42072SNick Fitzgerald pub fn boxed_slice_write_iter<T>(
308c0e42072SNick Fitzgerald boxed: Box<[MaybeUninit<T>]>,
309c0e42072SNick Fitzgerald iter: impl IntoIterator<Item = T>,
310c0e42072SNick Fitzgerald ) -> Result<Box<[T]>, TooFewItems> {
311c0e42072SNick Fitzgerald let len = boxed.len();
312c0e42072SNick Fitzgerald let builder = BoxedSliceBuilder::from_boxed_slice(boxed);
313c0e42072SNick Fitzgerald assert_eq!(len, builder.capacity());
314c0e42072SNick Fitzgerald write_iter_into_builder(builder, iter)
315c0e42072SNick Fitzgerald }
316c0e42072SNick Fitzgerald
317233f1875SNick Fitzgerald /// Create a `Box<[T]>` of length `len` from the given iterator's elements.
318233f1875SNick Fitzgerald ///
319233f1875SNick Fitzgerald /// Returns an error on allocation failure, or if `iter` yields fewer than `len`
320233f1875SNick Fitzgerald /// elements.
321233f1875SNick Fitzgerald ///
322233f1875SNick Fitzgerald /// The iterator is dropped after `len` elements have been yielded, this
323233f1875SNick Fitzgerald /// 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>32435483cc4SNick Fitzgerald pub fn new_boxed_slice_from_iter_with_len<T>(
325233f1875SNick Fitzgerald len: usize,
326233f1875SNick Fitzgerald iter: impl IntoIterator<Item = T>,
327c0e42072SNick Fitzgerald ) -> Result<Box<[T]>, TooFewItemsOrOom> {
328c0e42072SNick Fitzgerald let builder = BoxedSliceBuilder::new(len)?;
32935483cc4SNick Fitzgerald assert_eq!(len, builder.capacity());
330c0e42072SNick Fitzgerald let boxed = write_iter_into_builder(builder, iter)?;
331c0e42072SNick Fitzgerald Ok(boxed)
332c0e42072SNick Fitzgerald }
333c0e42072SNick Fitzgerald
write_iter_into_builder<T>( mut builder: BoxedSliceBuilder<T>, iter: impl IntoIterator<Item = T>, ) -> Result<Box<[T]>, TooFewItems>334c0e42072SNick Fitzgerald fn write_iter_into_builder<T>(
335c0e42072SNick Fitzgerald mut builder: BoxedSliceBuilder<T>,
336c0e42072SNick Fitzgerald iter: impl IntoIterator<Item = T>,
337c0e42072SNick Fitzgerald ) -> Result<Box<[T]>, TooFewItems> {
338c0e42072SNick Fitzgerald let len = builder.capacity();
33935483cc4SNick Fitzgerald
34035483cc4SNick Fitzgerald for elem in iter.into_iter().take(len) {
34135483cc4SNick Fitzgerald builder.push(elem).expect("reserved capacity");
342233f1875SNick Fitzgerald }
343233f1875SNick Fitzgerald
34435483cc4SNick Fitzgerald if builder.init_len() < builder.capacity() {
345c0e42072SNick Fitzgerald return Err(TooFewItems);
346233f1875SNick Fitzgerald }
347233f1875SNick Fitzgerald
34835483cc4SNick Fitzgerald debug_assert_eq!(builder.init_len(), builder.capacity());
34935483cc4SNick Fitzgerald Ok(builder.finish())
350233f1875SNick Fitzgerald }
35135483cc4SNick Fitzgerald
35235483cc4SNick Fitzgerald /// An error returned by [`new_boxed_slice_from_fallible_iter`].
35335483cc4SNick Fitzgerald #[derive(Debug)]
35435483cc4SNick Fitzgerald pub enum BoxedSliceFromFallibleIterError<E> {
35535483cc4SNick Fitzgerald /// The fallible iterator produced an error.
35635483cc4SNick Fitzgerald IterError(E),
35735483cc4SNick Fitzgerald /// Failed to allocate space for the boxed slice.
35835483cc4SNick Fitzgerald Oom(OutOfMemory),
359233f1875SNick Fitzgerald }
36035483cc4SNick Fitzgerald
36135483cc4SNick Fitzgerald impl<E> From<OutOfMemory> for BoxedSliceFromFallibleIterError<E> {
from(oom: OutOfMemory) -> Self36235483cc4SNick Fitzgerald fn from(oom: OutOfMemory) -> Self {
36335483cc4SNick Fitzgerald Self::Oom(oom)
364233f1875SNick Fitzgerald }
365233f1875SNick Fitzgerald }
366233f1875SNick Fitzgerald
36735483cc4SNick Fitzgerald impl<E> core::fmt::Display for BoxedSliceFromFallibleIterError<E> {
fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result36835483cc4SNick Fitzgerald fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
36935483cc4SNick Fitzgerald match self {
37035483cc4SNick Fitzgerald Self::IterError(_) => f.write_str("The fallible iterator produced an error"),
37135483cc4SNick Fitzgerald Self::Oom(_) => f.write_str("Failed to allocate space for the boxed slice"),
37235483cc4SNick Fitzgerald }
37335483cc4SNick Fitzgerald }
374233f1875SNick Fitzgerald }
375233f1875SNick Fitzgerald
37635483cc4SNick Fitzgerald impl<E> core::error::Error for BoxedSliceFromFallibleIterError<E>
37735483cc4SNick Fitzgerald where
37835483cc4SNick Fitzgerald E: core::error::Error,
37935483cc4SNick Fitzgerald {
cause(&self) -> Option<&dyn core::error::Error>38035483cc4SNick Fitzgerald fn cause(&self) -> Option<&dyn core::error::Error> {
38135483cc4SNick Fitzgerald match self {
38235483cc4SNick Fitzgerald Self::IterError(e) => Some(e),
38335483cc4SNick Fitzgerald Self::Oom(oom) => Some(oom),
38435483cc4SNick Fitzgerald }
38535483cc4SNick Fitzgerald }
386233f1875SNick Fitzgerald }
387233f1875SNick Fitzgerald
38835483cc4SNick Fitzgerald impl BoxedSliceFromFallibleIterError<OutOfMemory> {
38935483cc4SNick Fitzgerald /// Flatten this error into its inner OOM.
flatten(self) -> OutOfMemory39035483cc4SNick Fitzgerald pub fn flatten(self) -> OutOfMemory {
39135483cc4SNick Fitzgerald match self {
39235483cc4SNick Fitzgerald Self::IterError(oom) | Self::Oom(oom) => oom,
39335483cc4SNick Fitzgerald }
39435483cc4SNick Fitzgerald }
39535483cc4SNick Fitzgerald }
396233f1875SNick Fitzgerald
39735483cc4SNick Fitzgerald /// Create a `Box<[T]>` from the given iterator's `Result<T, E>` items.
39835483cc4SNick Fitzgerald ///
39935483cc4SNick Fitzgerald /// 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>>40035483cc4SNick Fitzgerald pub fn new_boxed_slice_from_fallible_iter<T, E>(
40135483cc4SNick Fitzgerald iter: impl IntoIterator<Item = Result<T, E>>,
40235483cc4SNick Fitzgerald ) -> Result<Box<[T]>, BoxedSliceFromFallibleIterError<E>> {
40335483cc4SNick Fitzgerald let iter = iter.into_iter();
404233f1875SNick Fitzgerald
40535483cc4SNick Fitzgerald let (min, max) = iter.size_hint();
40635483cc4SNick Fitzgerald let len = max.unwrap_or_else(|| min);
407233f1875SNick Fitzgerald
40835483cc4SNick Fitzgerald let mut builder = BoxedSliceBuilder::new(len)?;
40935483cc4SNick Fitzgerald assert_eq!(len, builder.capacity());
41035483cc4SNick Fitzgerald
41135483cc4SNick Fitzgerald for result in iter {
41235483cc4SNick Fitzgerald let elem = result.map_err(BoxedSliceFromFallibleIterError::IterError)?;
41335483cc4SNick Fitzgerald builder.push(elem)?;
41435483cc4SNick Fitzgerald }
41535483cc4SNick Fitzgerald
41635483cc4SNick Fitzgerald debug_assert!(builder.init_len() <= builder.capacity());
41735483cc4SNick Fitzgerald builder.shrink_to_fit()?;
41835483cc4SNick Fitzgerald debug_assert_eq!(builder.init_len(), builder.capacity());
41935483cc4SNick Fitzgerald
42035483cc4SNick Fitzgerald Ok(builder.finish())
42135483cc4SNick Fitzgerald }
42235483cc4SNick Fitzgerald
42335483cc4SNick Fitzgerald /// Create a `Box<[T]>` from the given iterator's elements.
42435483cc4SNick Fitzgerald ///
42535483cc4SNick Fitzgerald /// Returns an error on allocation failure.
new_boxed_slice_from_iter<T>( iter: impl IntoIterator<Item = T>, ) -> Result<Box<[T]>, OutOfMemory>42635483cc4SNick Fitzgerald pub fn new_boxed_slice_from_iter<T>(
42735483cc4SNick Fitzgerald iter: impl IntoIterator<Item = T>,
42835483cc4SNick Fitzgerald ) -> Result<Box<[T]>, OutOfMemory> {
42935483cc4SNick Fitzgerald let iter = iter
43035483cc4SNick Fitzgerald .into_iter()
43135483cc4SNick Fitzgerald .map(Result::<T, core::convert::Infallible>::Ok);
43235483cc4SNick Fitzgerald new_boxed_slice_from_fallible_iter(iter).map_err(|e| match e {
43335483cc4SNick Fitzgerald BoxedSliceFromFallibleIterError::Oom(oom) => oom,
43435483cc4SNick Fitzgerald BoxedSliceFromFallibleIterError::IterError(_) => unreachable!(),
43535483cc4SNick Fitzgerald })
436233f1875SNick Fitzgerald }
437233f1875SNick Fitzgerald
438233f1875SNick Fitzgerald #[cfg(test)]
439233f1875SNick Fitzgerald mod tests {
440233f1875SNick Fitzgerald use super::*;
441233f1875SNick Fitzgerald use core::cell::Cell;
442233f1875SNick Fitzgerald use std_alloc::rc::Rc;
443233f1875SNick Fitzgerald
444233f1875SNick Fitzgerald struct SetFlagOnDrop(Rc<Cell<bool>>);
445233f1875SNick Fitzgerald
446233f1875SNick Fitzgerald impl Drop for SetFlagOnDrop {
drop(&mut self)447233f1875SNick Fitzgerald fn drop(&mut self) {
448233f1875SNick Fitzgerald let old_value = self.0.replace(true);
449233f1875SNick Fitzgerald assert_eq!(old_value, false);
450233f1875SNick Fitzgerald }
451233f1875SNick Fitzgerald }
452233f1875SNick Fitzgerald
453233f1875SNick Fitzgerald impl SetFlagOnDrop {
new() -> (Rc<Cell<bool>>, Self)454233f1875SNick Fitzgerald fn new() -> (Rc<Cell<bool>>, Self) {
455233f1875SNick Fitzgerald let flag = Rc::new(Cell::new(false));
456233f1875SNick Fitzgerald (flag.clone(), SetFlagOnDrop(flag))
457233f1875SNick Fitzgerald }
458233f1875SNick Fitzgerald }
459233f1875SNick Fitzgerald
460233f1875SNick Fitzgerald #[test]
try_new()4619acefdfeSAlex Crichton fn try_new() {
4629acefdfeSAlex Crichton <Box<_> as TryNew>::try_new(4).unwrap();
4639acefdfeSAlex Crichton }
4649acefdfeSAlex Crichton
4659acefdfeSAlex Crichton #[test]
new_boxed_slice_from_iter_with_len_smoke_test()46635483cc4SNick Fitzgerald fn new_boxed_slice_from_iter_with_len_smoke_test() {
46735483cc4SNick Fitzgerald let slice = new_boxed_slice_from_iter_with_len(3, [42, 36, 1337]).unwrap();
468233f1875SNick Fitzgerald assert_eq!(&*slice, &[42, 36, 1337]);
469233f1875SNick Fitzgerald }
470233f1875SNick Fitzgerald
471233f1875SNick Fitzgerald #[test]
new_boxed_slice_from_iter_with_len_with_too_few_elems()47235483cc4SNick Fitzgerald fn new_boxed_slice_from_iter_with_len_with_too_few_elems() {
473233f1875SNick Fitzgerald let (a_dropped, a) = SetFlagOnDrop::new();
474233f1875SNick Fitzgerald let (b_dropped, b) = SetFlagOnDrop::new();
475233f1875SNick Fitzgerald let (c_dropped, c) = SetFlagOnDrop::new();
476233f1875SNick Fitzgerald
47735483cc4SNick Fitzgerald match new_boxed_slice_from_iter_with_len(4, [a, b, c]) {
478c0e42072SNick Fitzgerald Err(TooFewItemsOrOom::TooFewItems(_)) => {}
479c0e42072SNick Fitzgerald Ok(_) | Err(TooFewItemsOrOom::Oom(_)) => unreachable!(),
480233f1875SNick Fitzgerald }
481233f1875SNick Fitzgerald
482233f1875SNick Fitzgerald assert!(a_dropped.get());
483233f1875SNick Fitzgerald assert!(b_dropped.get());
484233f1875SNick Fitzgerald assert!(c_dropped.get());
485233f1875SNick Fitzgerald }
486233f1875SNick Fitzgerald
487233f1875SNick Fitzgerald #[test]
new_boxed_slice_from_iter_with_len_with_too_many_elems()48835483cc4SNick Fitzgerald fn new_boxed_slice_from_iter_with_len_with_too_many_elems() {
489233f1875SNick Fitzgerald let (a_dropped, a) = SetFlagOnDrop::new();
490233f1875SNick Fitzgerald let (b_dropped, b) = SetFlagOnDrop::new();
491233f1875SNick Fitzgerald let (c_dropped, c) = SetFlagOnDrop::new();
492233f1875SNick Fitzgerald
49335483cc4SNick Fitzgerald let slice = new_boxed_slice_from_iter_with_len(2, [a, b, c]).unwrap();
494233f1875SNick Fitzgerald
495233f1875SNick Fitzgerald assert!(!a_dropped.get());
496233f1875SNick Fitzgerald assert!(!b_dropped.get());
497233f1875SNick Fitzgerald assert!(c_dropped.get());
498233f1875SNick Fitzgerald
499233f1875SNick Fitzgerald drop(slice);
500233f1875SNick Fitzgerald
501233f1875SNick Fitzgerald assert!(a_dropped.get());
502233f1875SNick Fitzgerald assert!(b_dropped.get());
503233f1875SNick Fitzgerald assert!(c_dropped.get());
504233f1875SNick Fitzgerald }
50535483cc4SNick Fitzgerald
50635483cc4SNick Fitzgerald #[test]
new_boxed_slice_from_iter_smoke_test()50735483cc4SNick Fitzgerald fn new_boxed_slice_from_iter_smoke_test() {
50835483cc4SNick Fitzgerald let slice = new_boxed_slice_from_iter([10, 20, 30]).unwrap();
50935483cc4SNick Fitzgerald assert_eq!(&*slice, &[10, 20, 30]);
51035483cc4SNick Fitzgerald }
51135483cc4SNick Fitzgerald
51235483cc4SNick Fitzgerald #[test]
new_boxed_slice_from_fallible_iter_smoke_test()51335483cc4SNick Fitzgerald fn new_boxed_slice_from_fallible_iter_smoke_test() {
51435483cc4SNick Fitzgerald let slice =
51535483cc4SNick Fitzgerald new_boxed_slice_from_fallible_iter::<_, &str>([Ok(10), Ok(20), Ok(30)]).unwrap();
51635483cc4SNick Fitzgerald assert_eq!(&*slice, &[10, 20, 30]);
51735483cc4SNick Fitzgerald }
51835483cc4SNick Fitzgerald
51935483cc4SNick Fitzgerald #[test]
new_boxed_slice_from_fallible_iter_error()52035483cc4SNick Fitzgerald fn new_boxed_slice_from_fallible_iter_error() {
52135483cc4SNick Fitzgerald let result = new_boxed_slice_from_fallible_iter::<_, u32>([Ok(10), Ok(20), Err(30)]);
52235483cc4SNick Fitzgerald let Err(BoxedSliceFromFallibleIterError::IterError(err)) = result else {
52335483cc4SNick Fitzgerald panic!("unexpected result: {result:?}");
52435483cc4SNick Fitzgerald };
52535483cc4SNick Fitzgerald assert_eq!(err, 30);
52635483cc4SNick Fitzgerald }
527c0e42072SNick Fitzgerald
528c0e42072SNick Fitzgerald #[test]
new_uninit_boxed_slice_smoke_test()529c0e42072SNick Fitzgerald fn new_uninit_boxed_slice_smoke_test() {
530c0e42072SNick Fitzgerald let slice = new_uninit_boxed_slice::<u32>(5).unwrap();
531c0e42072SNick Fitzgerald assert_eq!(slice.len(), 5);
532c0e42072SNick Fitzgerald }
533c0e42072SNick Fitzgerald
534c0e42072SNick Fitzgerald #[test]
boxed_slice_write_iter_smoke_test()535c0e42072SNick Fitzgerald fn boxed_slice_write_iter_smoke_test() {
536c0e42072SNick Fitzgerald let uninit = new_uninit_boxed_slice(3).unwrap();
537c0e42072SNick Fitzgerald let init = boxed_slice_write_iter(uninit, [10, 20, 30]).unwrap();
538c0e42072SNick Fitzgerald assert_eq!(&*init, &[10, 20, 30]);
539c0e42072SNick Fitzgerald }
540c0e42072SNick Fitzgerald
541c0e42072SNick Fitzgerald #[test]
boxed_slice_write_iter_with_too_few_elems()542c0e42072SNick Fitzgerald fn boxed_slice_write_iter_with_too_few_elems() {
543c0e42072SNick Fitzgerald let (a_dropped, a) = SetFlagOnDrop::new();
544c0e42072SNick Fitzgerald let (b_dropped, b) = SetFlagOnDrop::new();
545c0e42072SNick Fitzgerald let (c_dropped, c) = SetFlagOnDrop::new();
546c0e42072SNick Fitzgerald
547c0e42072SNick Fitzgerald let uninit = new_uninit_boxed_slice(4).unwrap();
548c0e42072SNick Fitzgerald match boxed_slice_write_iter(uninit, [a, b, c]) {
549c0e42072SNick Fitzgerald Err(_) => {}
550c0e42072SNick Fitzgerald Ok(_) => unreachable!(),
551c0e42072SNick Fitzgerald }
552c0e42072SNick Fitzgerald
553c0e42072SNick Fitzgerald assert!(a_dropped.get());
554c0e42072SNick Fitzgerald assert!(b_dropped.get());
555c0e42072SNick Fitzgerald assert!(c_dropped.get());
556c0e42072SNick Fitzgerald }
557c0e42072SNick Fitzgerald
558c0e42072SNick Fitzgerald #[test]
boxed_slice_write_iter_with_too_many_elems()559c0e42072SNick Fitzgerald fn boxed_slice_write_iter_with_too_many_elems() {
560c0e42072SNick Fitzgerald let (a_dropped, a) = SetFlagOnDrop::new();
561c0e42072SNick Fitzgerald let (b_dropped, b) = SetFlagOnDrop::new();
562c0e42072SNick Fitzgerald let (c_dropped, c) = SetFlagOnDrop::new();
563c0e42072SNick Fitzgerald
564c0e42072SNick Fitzgerald let uninit = new_uninit_boxed_slice(2).unwrap();
565c0e42072SNick Fitzgerald let slice = boxed_slice_write_iter(uninit, [a, b, c]).unwrap();
566c0e42072SNick Fitzgerald
567c0e42072SNick Fitzgerald assert!(!a_dropped.get());
568c0e42072SNick Fitzgerald assert!(!b_dropped.get());
569c0e42072SNick Fitzgerald assert!(c_dropped.get());
570c0e42072SNick Fitzgerald
571c0e42072SNick Fitzgerald drop(slice);
572c0e42072SNick Fitzgerald
573c0e42072SNick Fitzgerald assert!(a_dropped.get());
574c0e42072SNick Fitzgerald assert!(b_dropped.get());
575c0e42072SNick Fitzgerald assert!(c_dropped.get());
576c0e42072SNick Fitzgerald }
577233f1875SNick Fitzgerald }
578