diff --git a/library/alloc/src/collections/mod.rs b/library/alloc/src/collections/mod.rs index 161a375736c65..d405b13e0fe55 100644 --- a/library/alloc/src/collections/mod.rs +++ b/library/alloc/src/collections/mod.rs @@ -74,6 +74,13 @@ impl TryReserveError { pub fn kind(&self) -> TryReserveErrorKind { self.kind.clone() } + + /// Create a new [`TryReserveError`] indicating that there was an allocation failure. + #[must_use] + #[unstable(feature = "more_fallible_allocation_methods", issue = "86942")] + pub fn alloc_error(layout: Layout) -> Self { + Self { kind: TryReserveErrorKind::AllocError { layout, non_exhaustive: () } } + } } /// Details of the allocation that caused a `TryReserveError` diff --git a/library/alloc/src/macros.rs b/library/alloc/src/macros.rs index 5198bf297d925..417bc2ff1bf4b 100644 --- a/library/alloc/src/macros.rs +++ b/library/alloc/src/macros.rs @@ -54,6 +54,70 @@ macro_rules! vec { ); } +/// Creates a [`Vec`] containing the arguments. +/// +/// `try_vec!` allows `Vec`s to be defined with the same syntax as array expressions. +/// There are two forms of this macro: +/// +/// - Create a [`Vec`] containing a given list of elements: +/// +/// ``` +/// #![feature(more_fallible_allocation_methods)] +/// # #[macro_use] extern crate alloc; +/// let v = try_vec![1, 2, 3]?; +/// assert_eq!(v[0], 1); +/// assert_eq!(v[1], 2); +/// assert_eq!(v[2], 3); +/// # Ok::<(), alloc::collections::TryReserveError>(()) +/// ``` +/// +/// - Create a [`Vec`] from a given element and size: +/// +/// ``` +/// #![feature(more_fallible_allocation_methods)] +/// # #[macro_use] extern crate alloc; +/// let v = try_vec![1; 3]?; +/// assert_eq!(v, [1, 1, 1]); +/// # Ok::<(), alloc::collections::TryReserveError>(()) +/// ``` +/// +/// Note that unlike array expressions this syntax supports all elements +/// which implement [`Clone`] and the number of elements doesn't have to be +/// a constant. +/// +/// This will use `clone` to duplicate an expression, so one should be careful +/// using this with types having a nonstandard `Clone` implementation. For +/// example, `try_vec![Rc::new(1); 5]` will create a vector of five references +/// to the same boxed integer value, not five references pointing to independently +/// boxed integers. +/// +/// Also, note that `try_vec![expr; 0]` is allowed, and produces an empty vector. +/// This will still evaluate `expr`, however, and immediately drop the resulting value, so +/// be mindful of side effects. +/// +/// [`Vec`]: crate::vec::Vec +#[cfg(not(test))] +#[macro_export] +#[allow_internal_unstable(allocator_api, liballoc_internals)] +#[unstable(feature = "more_fallible_allocation_methods", issue = "86942")] +macro_rules! try_vec { + () => ( + $crate::__rust_force_expr!(core::result::Result::Ok($crate::vec::Vec::new())) + ); + ($elem:expr; $n:expr) => ( + $crate::__rust_force_expr!($crate::vec::try_from_elem($elem, $n)) + ); + ($($x:expr),+ $(,)?) => ( + $crate::__rust_force_expr!({ + let values = [$($x),+]; + let layout = $crate::alloc::Layout::for_value(&values); + $crate::boxed::Box::try_new(values) + .map(|b| <[_]>::into_vec(b)) + .map_err(|_| $crate::collections::TryReserveError::alloc_error(layout)) + }) + ); +} + // HACK(japaric): with cfg(test) the inherent `[T]::into_vec` method, which is // required for this macro definition, is not available. Instead use the // `slice::into_vec` function which is only available with cfg(test) @@ -73,6 +137,27 @@ macro_rules! vec { ($($x:expr,)*) => (vec![$($x),*]) } +#[cfg(test)] +#[allow(unused_macros)] +macro_rules! try_vec { + () => ( + core::result::Result::Ok($crate::vec::Vec::new()) + ); + ($elem:expr; $n:expr) => ( + $crate::vec::try_from_elem($elem, $n) + ); + ($($x:expr),*) => ( + { + let values = [$($x),+]; + let layout = $crate::alloc::Layout::for_value(&values); + $crate::boxed::Box::try_new(values) + .map(|b| <[_]>::into_vec(b)) + .map_err(|_| $crate::collections::TryReserveError::alloc_error(layout)) + } + ); + ($($x:expr,)*) => (try_vec![$($x),*]) +} + /// Creates a `String` using interpolation of runtime expressions. /// /// The first argument `format!` receives is a format string. This must be a string diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs index 5a10121bbbe4b..48468a7feb3cd 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec.rs @@ -8,17 +8,14 @@ use core::ops::Drop; use core::ptr::{self, NonNull, Unique}; use core::slice; -#[cfg(not(no_global_oom_handling))] -use crate::alloc::handle_alloc_error; use crate::alloc::{Allocator, Global, Layout}; use crate::boxed::Box; use crate::collections::TryReserveError; -use crate::collections::TryReserveErrorKind::*; +use crate::vec::VecError; #[cfg(test)] mod tests; -#[cfg(not(no_global_oom_handling))] enum AllocInit { /// The contents of the new memory are uninitialized. Uninitialized, @@ -128,14 +125,31 @@ impl RawVec { #[cfg(not(no_global_oom_handling))] #[inline] pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { + Self::with_capacity_in_impl(capacity, alloc).unwrap_infallible() + } + + #[inline] + pub fn with_capacity_in_impl( + capacity: usize, + alloc: A, + ) -> Result { Self::allocate_in(capacity, AllocInit::Uninitialized, alloc) } - /// Like `with_capacity_zeroed`, but parameterized over the choice - /// of allocator for the returned `RawVec`. #[cfg(not(no_global_oom_handling))] + #[cfg(not(test))] #[inline] pub fn with_capacity_zeroed_in(capacity: usize, alloc: A) -> Self { + Self::with_capacity_zeroed_in_impl(capacity, alloc).unwrap_infallible() + } + + /// Like `with_capacity_zeroed`, but parameterized over the choice + /// of allocator for the returned `RawVec`. + #[inline] + pub fn with_capacity_zeroed_in_impl( + capacity: usize, + alloc: A, + ) -> Result { Self::allocate_in(capacity, AllocInit::Zeroed, alloc) } @@ -165,21 +179,24 @@ impl RawVec { } } - #[cfg(not(no_global_oom_handling))] - fn allocate_in(capacity: usize, init: AllocInit, alloc: A) -> Self { + fn allocate_in( + capacity: usize, + init: AllocInit, + alloc: A, + ) -> Result { // Don't allocate here because `Drop` will not deallocate when `capacity` is 0. if T::IS_ZST || capacity == 0 { - Self::new_in(alloc) + Ok(Self::new_in(alloc)) } else { // We avoid `unwrap_or_else` here because it bloats the amount of // LLVM IR generated. let layout = match Layout::array::(capacity) { Ok(layout) => layout, - Err(_) => capacity_overflow(), + Err(_) => return Err(TError::capacity_overflow()), }; match alloc_guard(layout.size()) { Ok(_) => {} - Err(_) => capacity_overflow(), + Err(err) => return Err(err), } let result = match init { AllocInit::Uninitialized => alloc.allocate(layout), @@ -187,17 +204,17 @@ impl RawVec { }; let ptr = match result { Ok(ptr) => ptr, - Err(_) => handle_alloc_error(layout), + Err(_) => return Err(TError::alloc_error(layout)), }; // Allocators currently return a `NonNull<[u8]>` whose length // matches the size requested. If that ever changes, the capacity // here should change to `ptr.len() / mem::size_of::()`. - Self { + Ok(Self { ptr: unsafe { Unique::new_unchecked(ptr.cast().as_ptr()) }, cap: capacity, alloc, - } + }) } } @@ -272,39 +289,40 @@ impl RawVec { #[cfg(not(no_global_oom_handling))] #[inline] pub fn reserve(&mut self, len: usize, additional: usize) { + self.reserve_impl(len, additional).unwrap_infallible() + } + + #[inline] + pub fn reserve_impl( + &mut self, + len: usize, + additional: usize, + ) -> Result<(), TError> { // Callers expect this function to be very cheap when there is already sufficient capacity. // Therefore, we move all the resizing and error-handling logic from grow_amortized and // handle_reserve behind a call, while making sure that this function is likely to be // inlined as just a comparison and a call if the comparison fails. #[cold] - fn do_reserve_and_handle( + fn do_reserve_and_handle( slf: &mut RawVec, len: usize, additional: usize, - ) { - handle_reserve(slf.grow_amortized(len, additional)); + ) -> Result<(), TError> { + slf.grow_amortized(len, additional) } if self.needs_to_grow(len, additional) { - do_reserve_and_handle(self, len, additional); + do_reserve_and_handle(self, len, additional) + } else { + Ok(()) } } /// A specialized version of `reserve()` used only by the hot and /// oft-instantiated `Vec::push()`, which does its own capacity check. - #[cfg(not(no_global_oom_handling))] #[inline(never)] - pub fn reserve_for_push(&mut self, len: usize) { - handle_reserve(self.grow_amortized(len, 1)); - } - - /// The same as `reserve`, but returns on errors instead of panicking or aborting. - pub fn try_reserve(&mut self, len: usize, additional: usize) -> Result<(), TryReserveError> { - if self.needs_to_grow(len, additional) { - self.grow_amortized(len, additional) - } else { - Ok(()) - } + pub fn reserve_for_push_impl(&mut self, len: usize) -> Result<(), TError> { + self.grow_amortized(len, 1) } /// Ensures that the buffer contains at least enough space to hold `len + @@ -326,7 +344,9 @@ impl RawVec { /// Aborts on OOM. #[cfg(not(no_global_oom_handling))] pub fn reserve_exact(&mut self, len: usize, additional: usize) { - handle_reserve(self.try_reserve_exact(len, additional)); + if self.needs_to_grow(len, additional) { + self.grow_exact(len, additional).unwrap_infallible() + } } /// The same as `reserve_exact`, but returns on errors instead of panicking or aborting. @@ -350,11 +370,13 @@ impl RawVec { /// Aborts on OOM. #[cfg(not(no_global_oom_handling))] pub fn shrink_to_fit(&mut self, cap: usize) { - handle_reserve(self.shrink(cap)); + self.shrink(cap).unwrap_infallible() + } + + pub fn shrink_to_fit_impl(&mut self, cap: usize) -> Result<(), TError> { + self.shrink(cap) } -} -impl RawVec { /// Returns if the buffer needs to grow to fulfill the needed extra capacity. /// Mainly used to make inlining reserve-calls possible without inlining `grow`. fn needs_to_grow(&self, len: usize, additional: usize) -> bool { @@ -376,18 +398,25 @@ impl RawVec { // so that all of the code that depends on `T` is within it, while as much // of the code that doesn't depend on `T` as possible is in functions that // are non-generic over `T`. - fn grow_amortized(&mut self, len: usize, additional: usize) -> Result<(), TryReserveError> { + pub fn grow_amortized( + &mut self, + len: usize, + additional: usize, + ) -> Result<(), TError> { // This is ensured by the calling contexts. debug_assert!(additional > 0); if T::IS_ZST { // Since we return a capacity of `usize::MAX` when `elem_size` is // 0, getting to here necessarily means the `RawVec` is overfull. - return Err(CapacityOverflow.into()); + return Err(TError::capacity_overflow()); } // Nothing we can really do about these checks, sadly. - let required_cap = len.checked_add(additional).ok_or(CapacityOverflow)?; + let required_cap = match len.checked_add(additional) { + Some(len) => len, + None => return Err(TError::capacity_overflow()), + }; // This guarantees exponential growth. The doubling cannot overflow // because `cap <= isize::MAX` and the type of `cap` is `usize`. @@ -405,14 +434,21 @@ impl RawVec { // The constraints on this method are much the same as those on // `grow_amortized`, but this method is usually instantiated less often so // it's less critical. - fn grow_exact(&mut self, len: usize, additional: usize) -> Result<(), TryReserveError> { + fn grow_exact( + &mut self, + len: usize, + additional: usize, + ) -> Result<(), TError> { if T::IS_ZST { // Since we return a capacity of `usize::MAX` when the type size is // 0, getting to here necessarily means the `RawVec` is overfull. - return Err(CapacityOverflow.into()); + return Err(TError::capacity_overflow()); } - let cap = len.checked_add(additional).ok_or(CapacityOverflow)?; + let cap = match len.checked_add(additional) { + Some(len) => len, + None => return Err(TError::capacity_overflow()), + }; let new_layout = Layout::array::(cap); // `finish_grow` is non-generic over `T`. @@ -421,8 +457,7 @@ impl RawVec { Ok(()) } - #[cfg(not(no_global_oom_handling))] - fn shrink(&mut self, cap: usize) -> Result<(), TryReserveError> { + fn shrink(&mut self, cap: usize) -> Result<(), TError> { assert!(cap <= self.capacity(), "Tried to shrink to a larger capacity"); let (ptr, layout) = if let Some(mem) = self.current_memory() { mem } else { return Ok(()) }; @@ -431,9 +466,10 @@ impl RawVec { // `Layout::array` cannot overflow here because it would have // overflowed earlier when capacity was larger. let new_layout = Layout::array::(cap).unwrap_unchecked(); - self.alloc - .shrink(ptr, layout, new_layout) - .map_err(|_| AllocError { layout: new_layout, non_exhaustive: () })? + match self.alloc.shrink(ptr, layout, new_layout) { + Ok(ptr) => ptr, + Err(_) => return Err(TError::alloc_error(layout)), + } }; self.set_ptr_and_cap(ptr, cap); Ok(()) @@ -445,16 +481,20 @@ impl RawVec { // significant, because the number of different `A` types seen in practice is // much smaller than the number of `T` types.) #[inline(never)] -fn finish_grow( +fn finish_grow( new_layout: Result, current_memory: Option<(NonNull, Layout)>, alloc: &mut A, -) -> Result, TryReserveError> +) -> Result, TError> where A: Allocator, + TError: VecError, { // Check for the error here to minimize the size of `RawVec::grow_*`. - let new_layout = new_layout.map_err(|_| CapacityOverflow)?; + let new_layout = match new_layout { + Ok(layout) => layout, + Err(_) => return Err(TError::capacity_overflow()), + }; alloc_guard(new_layout.size())?; @@ -469,7 +509,10 @@ where alloc.allocate(new_layout) }; - memory.map_err(|_| AllocError { layout: new_layout, non_exhaustive: () }.into()) + match memory { + Ok(memory) => Ok(memory), + Err(_) => Err(TError::alloc_error(new_layout)), + } } unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawVec { @@ -481,17 +524,6 @@ unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawVec { } } -// Central function for reserve error handling. -#[cfg(not(no_global_oom_handling))] -#[inline] -fn handle_reserve(result: Result<(), TryReserveError>) { - match result.map_err(|e| e.kind()) { - Err(CapacityOverflow) => capacity_overflow(), - Err(AllocError { layout, .. }) => handle_alloc_error(layout), - Ok(()) => { /* yay */ } - } -} - // We need to guarantee the following: // * We don't ever allocate `> isize::MAX` byte-size objects. // * We don't overflow `usize::MAX` and actually allocate too little. @@ -502,18 +534,10 @@ fn handle_reserve(result: Result<(), TryReserveError>) { // all 4GB in user-space, e.g., PAE or x32. #[inline] -fn alloc_guard(alloc_size: usize) -> Result<(), TryReserveError> { +fn alloc_guard(alloc_size: usize) -> Result<(), TError> { if usize::BITS < 64 && alloc_size > isize::MAX as usize { - Err(CapacityOverflow.into()) + Err(TError::capacity_overflow()) } else { Ok(()) } } - -// One central function responsible for reporting capacity overflows. This'll -// ensure that the code generation related to these panics is minimal as there's -// only one location which panics rather than a bunch throughout the module. -#[cfg(not(no_global_oom_handling))] -fn capacity_overflow() -> ! { - panic!("capacity overflow"); -} diff --git a/library/alloc/src/raw_vec/tests.rs b/library/alloc/src/raw_vec/tests.rs index ff322f0da97c6..68bc93e80dffd 100644 --- a/library/alloc/src/raw_vec/tests.rs +++ b/library/alloc/src/raw_vec/tests.rs @@ -104,13 +104,14 @@ fn zst() { let v: RawVec = RawVec::with_capacity_in(100, Global); zst_sanity(&v); - let v: RawVec = RawVec::allocate_in(0, AllocInit::Uninitialized, Global); + let v: RawVec = RawVec::allocate_in::(0, AllocInit::Uninitialized, Global).unwrap(); zst_sanity(&v); - let v: RawVec = RawVec::allocate_in(100, AllocInit::Uninitialized, Global); + let v: RawVec = RawVec::allocate_in::(100, AllocInit::Uninitialized, Global).unwrap(); zst_sanity(&v); - let mut v: RawVec = RawVec::allocate_in(usize::MAX, AllocInit::Uninitialized, Global); + let mut v: RawVec = + RawVec::allocate_in::(usize::MAX, AllocInit::Uninitialized, Global).unwrap(); zst_sanity(&v); // Check all these operations work as expected with zero-sized elements. @@ -127,20 +128,20 @@ fn zst() { //v.reserve_exact(101, usize::MAX - 100); // panics, in `zst_reserve_exact_panic` below zst_sanity(&v); - assert_eq!(v.try_reserve(100, usize::MAX - 100), Ok(())); - assert_eq!(v.try_reserve(101, usize::MAX - 100), cap_err); + assert_eq!(v.reserve_impl::(100, usize::MAX - 100), Ok(())); + assert_eq!(v.reserve_impl::(101, usize::MAX - 100), cap_err); zst_sanity(&v); assert_eq!(v.try_reserve_exact(100, usize::MAX - 100), Ok(())); assert_eq!(v.try_reserve_exact(101, usize::MAX - 100), cap_err); zst_sanity(&v); - assert_eq!(v.grow_amortized(100, usize::MAX - 100), cap_err); - assert_eq!(v.grow_amortized(101, usize::MAX - 100), cap_err); + assert_eq!(v.grow_amortized::(100, usize::MAX - 100), cap_err); + assert_eq!(v.grow_amortized::(101, usize::MAX - 100), cap_err); zst_sanity(&v); - assert_eq!(v.grow_exact(100, usize::MAX - 100), cap_err); - assert_eq!(v.grow_exact(101, usize::MAX - 100), cap_err); + assert_eq!(v.grow_exact::(100, usize::MAX - 100), cap_err); + assert_eq!(v.grow_exact::(101, usize::MAX - 100), cap_err); zst_sanity(&v); } diff --git a/library/alloc/src/vec/in_place_collect.rs b/library/alloc/src/vec/in_place_collect.rs index 87d61deb1eb2f..df3c33e50d4d9 100644 --- a/library/alloc/src/vec/in_place_collect.rs +++ b/library/alloc/src/vec/in_place_collect.rs @@ -141,7 +141,7 @@ use core::iter::{InPlaceIterable, SourceIter, TrustedRandomAccessNoCoerce}; use core::mem::{self, ManuallyDrop, SizedTypeProperties}; use core::ptr::{self}; -use super::{InPlaceDrop, InPlaceDstBufDrop, SpecFromIter, SpecFromIterNested, Vec}; +use super::{InPlaceDrop, InPlaceDstBufDrop, SpecFromIter, SpecFromIterNested, Vec, VecError}; /// Specialization marker for collecting an iterator pipeline into a Vec while reusing the /// source allocation, i.e. executing the pipeline in place. @@ -150,11 +150,11 @@ pub(super) trait InPlaceIterableMarker {} impl InPlaceIterableMarker for T where T: InPlaceIterable {} -impl SpecFromIter for Vec +impl SpecFromIter for Vec where I: Iterator + SourceIter + InPlaceIterableMarker, { - default fn from_iter(mut iterator: I) -> Self { + default fn from_iter(mut iterator: I) -> Result { // See "Layout constraints" section in the module documentation. We rely on const // optimization here since these conditions currently cannot be expressed as trait bounds if T::IS_ZST @@ -208,7 +208,7 @@ where let vec = unsafe { Vec::from_raw_parts(dst_buf, len, cap) }; - vec + Ok(vec) } } diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs index 73d7c90cf78ec..34a115b42b7fb 100644 --- a/library/alloc/src/vec/into_iter.rs +++ b/library/alloc/src/vec/into_iter.rs @@ -1,4 +1,3 @@ -#[cfg(not(no_global_oom_handling))] use super::AsVecIntoIter; use crate::alloc::{Allocator, Global}; use crate::raw_vec::RawVec; @@ -109,7 +108,6 @@ impl IntoIter { /// /// This method is used by in-place iteration, refer to the vec::in_place_collect /// documentation for an overview. - #[cfg(not(no_global_oom_handling))] pub(super) fn forget_allocation_drop_remaining(&mut self) { let remaining = self.as_raw_mut_slice(); @@ -393,7 +391,6 @@ unsafe impl SourceIter for IntoIter { } } -#[cfg(not(no_global_oom_handling))] unsafe impl AsVecIntoIter for IntoIter { type Item = T; diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index b2bb7a5b2e659..52b5ebfbe66a7 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -53,7 +53,6 @@ #![stable(feature = "rust1", since = "1.0.0")] -#[cfg(not(no_global_oom_handling))] use core::cmp; use core::cmp::Ordering; use core::convert::TryFrom; @@ -69,10 +68,12 @@ use core::ops::{self, Index, IndexMut, Range, RangeBounds}; use core::ptr::{self, NonNull}; use core::slice::{self, SliceIndex}; -use crate::alloc::{Allocator, Global}; +#[cfg(not(no_global_oom_handling))] +use crate::alloc::handle_alloc_error; +use crate::alloc::{Allocator, Global, Layout}; use crate::borrow::{Cow, ToOwned}; use crate::boxed::Box; -use crate::collections::TryReserveError; +use crate::collections::{TryReserveError, TryReserveErrorKind}; use crate::raw_vec::RawVec; #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] @@ -95,59 +96,74 @@ mod drain; #[cfg(not(no_global_oom_handling))] mod cow; -#[cfg(not(no_global_oom_handling))] pub(crate) use self::in_place_collect::AsVecIntoIter; #[stable(feature = "rust1", since = "1.0.0")] pub use self::into_iter::IntoIter; mod into_iter; -#[cfg(not(no_global_oom_handling))] use self::is_zero::IsZero; mod is_zero; -#[cfg(not(no_global_oom_handling))] mod in_place_collect; mod partial_eq; -#[cfg(not(no_global_oom_handling))] use self::spec_from_elem::SpecFromElem; -#[cfg(not(no_global_oom_handling))] mod spec_from_elem; -#[cfg(not(no_global_oom_handling))] use self::set_len_on_drop::SetLenOnDrop; -#[cfg(not(no_global_oom_handling))] mod set_len_on_drop; -#[cfg(not(no_global_oom_handling))] use self::in_place_drop::{InPlaceDrop, InPlaceDstBufDrop}; -#[cfg(not(no_global_oom_handling))] mod in_place_drop; -#[cfg(not(no_global_oom_handling))] use self::spec_from_iter_nested::SpecFromIterNested; -#[cfg(not(no_global_oom_handling))] mod spec_from_iter_nested; -#[cfg(not(no_global_oom_handling))] use self::spec_from_iter::SpecFromIter; -#[cfg(not(no_global_oom_handling))] mod spec_from_iter; -#[cfg(not(no_global_oom_handling))] use self::spec_extend::SpecExtend; -#[cfg(not(no_global_oom_handling))] mod spec_extend; +pub(crate) trait VecError { + fn capacity_overflow() -> Self; + fn alloc_error(layout: Layout) -> Self; +} + +#[cfg(not(no_global_oom_handling))] +impl VecError for ! { + #[cold] + fn capacity_overflow() -> Self { + panic!("capacity overflow") + } + + #[cold] + fn alloc_error(layout: Layout) -> Self { + handle_alloc_error(layout) + } +} + +impl VecError for TryReserveError { + #[cold] + fn capacity_overflow() -> Self { + TryReserveErrorKind::CapacityOverflow.into() + } + + #[cold] + fn alloc_error(layout: Layout) -> Self { + TryReserveError::alloc_error(layout) + } +} + /// A contiguous growable array type, written as `Vec`, short for 'vector'. /// /// # Examples @@ -483,6 +499,48 @@ impl Vec { Self::with_capacity_in(capacity, Global) } + /// Constructs a new, empty `Vec` with the specified capacity. + /// + /// The vector will be able to hold exactly `capacity` elements without + /// reallocating. If `capacity` is 0, the vector will not allocate. + /// + /// It is important to note that although the returned vector has the + /// *capacity* specified, the vector will have a zero *length*. For an + /// explanation of the difference between length and capacity, see + /// *[Capacity and reallocation]*. + /// + /// [Capacity and reallocation]: #capacity-and-reallocation + /// + /// # Examples + /// + /// ``` + /// #![feature(more_fallible_allocation_methods)] + /// + /// let mut vec = Vec::try_with_capacity(10)?; + /// + /// // The vector contains no items, even though it has capacity for more + /// assert_eq!(vec.len(), 0); + /// assert_eq!(vec.capacity(), 10); + /// + /// // These are all done without reallocating... + /// for i in 0..10 { + /// vec.try_push(i)?; + /// } + /// assert_eq!(vec.len(), 10); + /// assert_eq!(vec.capacity(), 10); + /// + /// // ...but this may make the vector reallocate + /// vec.try_push(11)?; + /// assert_eq!(vec.len(), 11); + /// assert!(vec.capacity() >= 11); + /// # Ok::<(), alloc::collections::TryReserveError>(()) + /// ``` + #[inline] + #[unstable(feature = "more_fallible_allocation_methods", issue = "86942")] + pub fn try_with_capacity(capacity: usize) -> Result { + Self::try_with_capacity_in(capacity, Global) + } + /// Creates a `Vec` directly from a pointer, a capacity, and a length. /// /// # Safety @@ -670,7 +728,57 @@ impl Vec { #[inline] #[unstable(feature = "allocator_api", issue = "32838")] pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { - Vec { buf: RawVec::with_capacity_in(capacity, alloc), len: 0 } + Self::with_capacity_in_impl(capacity, alloc).unwrap_infallible() + } + + /// Constructs a new, empty `Vec` with the specified capacity with the provided + /// allocator. + /// + /// The vector will be able to hold exactly `capacity` elements without + /// reallocating. If `capacity` is 0, the vector will not allocate. + /// + /// It is important to note that although the returned vector has the + /// *capacity* specified, the vector will have a zero *length*. For an + /// explanation of the difference between length and capacity, see + /// *[Capacity and reallocation]*. + /// + /// [Capacity and reallocation]: #capacity-and-reallocation + /// + /// # Examples + /// + /// ``` + /// #![feature(more_fallible_allocation_methods)] + /// + /// use std::alloc::System; + /// + /// let mut vec = Vec::try_with_capacity_in(10, System)?; + /// + /// // The vector contains no items, even though it has capacity for more + /// assert_eq!(vec.len(), 0); + /// assert_eq!(vec.capacity(), 10); + /// + /// // These are all done without reallocating... + /// for i in 0..10 { + /// vec.try_push(i)?; + /// } + /// assert_eq!(vec.len(), 10); + /// assert_eq!(vec.capacity(), 10); + /// + /// // ...but this may make the vector reallocate + /// vec.try_push(11)?; + /// assert_eq!(vec.len(), 11); + /// assert!(vec.capacity() >= 11); + /// # Ok::<(), alloc::collections::TryReserveError>(()) + /// ``` + #[inline] + #[unstable(feature = "more_fallible_allocation_methods", issue = "86942")] + pub fn try_with_capacity_in(capacity: usize, alloc: A) -> Result { + Self::with_capacity_in_impl(capacity, alloc) + } + + #[inline] + fn with_capacity_in_impl(capacity: usize, alloc: A) -> Result { + Ok(Vec { buf: RawVec::with_capacity_in_impl(capacity, alloc)?, len: 0 }) } /// Creates a `Vec` directly from a pointer, a capacity, a length, @@ -970,7 +1078,12 @@ impl Vec { /// ``` #[stable(feature = "try_reserve", since = "1.57.0")] pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { - self.buf.try_reserve(self.len, additional) + self.reserve_impl(additional) + } + + #[inline] + fn reserve_impl(&mut self, additional: usize) -> Result<(), TError> { + self.buf.reserve_impl(self.len, additional) } /// Tries to reserve the minimum capacity for at least `additional` @@ -1033,12 +1146,39 @@ impl Vec { #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] pub fn shrink_to_fit(&mut self) { + self.shrink_to_fit_impl().unwrap_infallible() + } + + /// Shrinks the capacity of the vector as much as possible. + /// + /// It will drop down as close as possible to the length but the allocator + /// may still inform the vector that there is space for a few more elements. + /// + /// # Examples + /// + /// ``` + /// #![feature(more_fallible_allocation_methods)] + /// + /// let mut vec = Vec::try_with_capacity(10)?; + /// vec.try_extend([1, 2, 3])?; + /// assert_eq!(vec.capacity(), 10); + /// vec.try_shrink_to_fit()?; + /// assert!(vec.capacity() >= 3); + /// # Ok::<(), alloc::collections::TryReserveError>(()) + /// ``` + #[unstable(feature = "more_fallible_allocation_methods", issue = "86942")] + pub fn try_shrink_to_fit(&mut self) -> Result<(), TryReserveError> { + self.shrink_to_fit_impl() + } + + fn shrink_to_fit_impl(&mut self) -> Result<(), TError> { // The capacity is never less than the length, and there's nothing to do when // they are equal, so we can avoid the panic case in `RawVec::shrink_to_fit` // by only calling it with a greater capacity. if self.capacity() > self.len { - self.buf.shrink_to_fit(self.len); + self.buf.shrink_to_fit_impl(self.len)?; } + Ok(()) } /// Shrinks the capacity of the vector with a lower bound. @@ -1062,9 +1202,40 @@ impl Vec { #[cfg(not(no_global_oom_handling))] #[stable(feature = "shrink_to", since = "1.56.0")] pub fn shrink_to(&mut self, min_capacity: usize) { + self.shrink_to_impl(min_capacity).unwrap_infallible() + } + + /// Shrinks the capacity of the vector with a lower bound. + /// + /// The capacity will remain at least as large as both the length + /// and the supplied value. + /// + /// If the current capacity is less than the lower limit, this is a no-op. + /// + /// # Examples + /// + /// ``` + /// #![feature(more_fallible_allocation_methods)] + /// + /// let mut vec = Vec::try_with_capacity(10)?; + /// vec.try_extend([1, 2, 3])?; + /// assert_eq!(vec.capacity(), 10); + /// vec.try_shrink_to(4)?; + /// assert!(vec.capacity() >= 4); + /// vec.try_shrink_to(0)?; + /// assert!(vec.capacity() >= 3); + /// # Ok::<(), alloc::collections::TryReserveError>(()) + /// ``` + #[unstable(feature = "more_fallible_allocation_methods", issue = "86942")] + pub fn try_shrink_to(&mut self, min_capacity: usize) -> Result<(), TryReserveError> { + self.shrink_to_impl(min_capacity) + } + + fn shrink_to_impl(&mut self, min_capacity: usize) -> Result<(), TError> { if self.capacity() > min_capacity { - self.buf.shrink_to_fit(cmp::max(self.len, min_capacity)); + self.buf.shrink_to_fit_impl(cmp::max(self.len, min_capacity))?; } + Ok(()) } /// Converts the vector into [`Box<[T]>`][owned slice]. @@ -1093,13 +1264,53 @@ impl Vec { /// ``` #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] - pub fn into_boxed_slice(mut self) -> Box<[T], A> { + pub fn into_boxed_slice(self) -> Box<[T], A> { + self.into_boxed_slice_impl().unwrap_infallible() + } + + /// Converts the vector into [`Box<[T]>`][owned slice]. + /// + /// Note that this will drop any excess capacity. + /// + /// [owned slice]: Box + /// + /// # Examples + /// + /// ``` + /// #![feature(more_fallible_allocation_methods)] + /// # #[macro_use] extern crate alloc; + /// + /// let v = try_vec![1, 2, 3]?; + /// + /// let slice = v.try_into_boxed_slice()?; + /// # Ok::<(), alloc::collections::TryReserveError>(()) + /// ``` + /// + /// Any excess capacity is removed: + /// + /// ``` + /// #![feature(more_fallible_allocation_methods)] + /// + /// let mut vec = Vec::try_with_capacity(10)?; + /// vec.try_extend([1, 2, 3])?; + /// + /// assert_eq!(vec.capacity(), 10); + /// let slice = vec.try_into_boxed_slice()?; + /// assert_eq!(slice.into_vec().capacity(), 3); + /// # Ok::<(), alloc::collections::TryReserveError>(()) + /// ``` + #[unstable(feature = "more_fallible_allocation_methods", issue = "86942")] + pub fn try_into_boxed_slice(self) -> Result, TryReserveError> { + self.into_boxed_slice_impl() + } + + fn into_boxed_slice_impl(mut self) -> Result, TError> { unsafe { - self.shrink_to_fit(); + self.shrink_to_fit_impl()?; let me = ManuallyDrop::new(self); let buf = ptr::read(&me.buf); let len = me.len(); - buf.into_box(len).assume_init() + Ok(buf.into_box(len).assume_init()) } } @@ -1438,6 +1649,35 @@ impl Vec { #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] pub fn insert(&mut self, index: usize, element: T) { + self.insert_impl(index, element).unwrap_infallible() + } + + /// Inserts an element at position `index` within the vector, shifting all + /// elements after it to the right. + /// + /// # Panics + /// + /// Panics if `index > len`. + /// + /// # Examples + /// + /// ``` + /// #![feature(more_fallible_allocation_methods)] + /// # #[macro_use] extern crate alloc; + /// + /// let mut vec = try_vec![1, 2, 3]?; + /// vec.try_insert(1, 4)?; + /// assert_eq!(vec, [1, 4, 2, 3]); + /// vec.try_insert(4, 5)?; + /// assert_eq!(vec, [1, 4, 2, 3, 5]); + /// # Ok::<(), alloc::collections::TryReserveError>(()) + /// ``` + #[unstable(feature = "more_fallible_allocation_methods", issue = "86942")] + pub fn try_insert(&mut self, index: usize, element: T) -> Result<(), TryReserveError> { + self.insert_impl(index, element) + } + + fn insert_impl(&mut self, index: usize, element: T) -> Result<(), TError> { #[cold] #[inline(never)] fn assert_failed(index: usize, len: usize) -> ! { @@ -1448,7 +1688,7 @@ impl Vec { // space for the new element if len == self.buf.capacity() { - self.reserve(1); + self.buf.reserve_for_push_impl(len)?; } unsafe { @@ -1471,6 +1711,8 @@ impl Vec { } self.set_len(len + 1); } + + Ok(()) } /// Removes and returns the element at position `index` within the vector, @@ -1827,16 +2069,42 @@ impl Vec { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn push(&mut self, value: T) { + self.push_impl(value).unwrap_infallible() + } + + /// Appends an element to the back of a collection. + /// + /// # Examples + /// + /// ``` + /// #![feature(more_fallible_allocation_methods)] + /// # #[macro_use] extern crate alloc; + /// + /// let mut vec = try_vec![1, 2]?; + /// vec.try_push(3)?; + /// assert_eq!(vec, [1, 2, 3]); + /// # Ok::<(), alloc::collections::TryReserveError>(()) + /// ``` + #[inline] + #[unstable(feature = "more_fallible_allocation_methods", issue = "86942")] + pub fn try_push(&mut self, value: T) -> Result<(), TryReserveError> { + self.push_impl(value) + } + + #[inline] + fn push_impl(&mut self, value: T) -> Result<(), TError> { // This will panic or abort if we would allocate > isize::MAX bytes // or if the length increment would overflow for zero-sized types. if self.len == self.buf.capacity() { - self.buf.reserve_for_push(self.len); + self.buf.reserve_for_push_impl(self.len)?; } unsafe { let end = self.as_mut_ptr().add(self.len); ptr::write(end, value); self.len += 1; } + + Ok(()) } /// Appends an element if there is sufficient spare capacity, otherwise an error is returned @@ -1932,20 +2200,49 @@ impl Vec { #[stable(feature = "append", since = "1.4.0")] pub fn append(&mut self, other: &mut Self) { unsafe { - self.append_elements(other.as_slice() as _); + self.append_elements(other.as_slice() as _).unwrap_infallible(); other.set_len(0); } } + /// Moves all the elements of `other` into `self`, leaving `other` empty. + /// + /// # Examples + /// + /// ``` + /// #![feature(more_fallible_allocation_methods)] + /// # #[macro_use] extern crate alloc; + /// + /// let mut vec = try_vec![1, 2, 3]?; + /// let mut vec2 = try_vec![4, 5, 6]?; + /// vec.try_append(&mut vec2)?; + /// assert_eq!(vec, [1, 2, 3, 4, 5, 6]); + /// assert_eq!(vec2, []); + /// # Ok::<(), alloc::collections::TryReserveError>(()) + /// ``` + #[unstable(feature = "more_fallible_allocation_methods", issue = "86942")] + #[inline] + pub fn try_append(&mut self, other: &mut Self) -> Result<(), TryReserveError> { + unsafe { + self.append_elements::(other.as_slice() as _)?; + other.set_len(0); + } + + Ok(()) + } + /// Appends elements to `self` from other buffer. - #[cfg(not(no_global_oom_handling))] #[inline] - unsafe fn append_elements(&mut self, other: *const [T]) { + unsafe fn append_elements( + &mut self, + other: *const [T], + ) -> Result<(), TError> { let count = unsafe { (*other).len() }; - self.reserve(count); + self.reserve_impl(count)?; let len = self.len(); unsafe { ptr::copy_nonoverlapping(other as *const T, self.as_mut_ptr().add(len), count) }; self.len += count; + Ok(()) } /// Removes the specified range from the vector in bulk, returning all @@ -2096,6 +2393,46 @@ impl Vec { #[must_use = "use `.truncate()` if you don't need the other half"] #[stable(feature = "split_off", since = "1.4.0")] pub fn split_off(&mut self, at: usize) -> Self + where + A: Clone, + { + self.split_off_impl(at).unwrap_infallible() + } + + /// Splits the collection into two at the given index. + /// + /// Returns a newly allocated vector containing the elements in the range + /// `[at, len)`. After the call, the original vector will be left containing + /// the elements `[0, at)` with its previous capacity unchanged. + /// + /// # Panics + /// + /// Panics if `at > len`. + /// + /// # Examples + /// + /// ``` + /// #![feature(more_fallible_allocation_methods)] + /// # #[macro_use] extern crate alloc; + /// + /// let mut vec = try_vec![1, 2, 3]?; + /// let vec2 = vec.try_split_off(1)?; + /// assert_eq!(vec, [1]); + /// assert_eq!(vec2, [2, 3]); + /// # Ok::<(), alloc::collections::TryReserveError>(()) + /// ``` + #[inline] + #[must_use = "use `.truncate()` if you don't need the other half"] + #[unstable(feature = "more_fallible_allocation_methods", issue = "86942")] + pub fn try_split_off(&mut self, at: usize) -> Result + where + A: Clone, + { + self.split_off_impl(at) + } + + #[inline] + fn split_off_impl(&mut self, at: usize) -> Result where A: Clone, { @@ -2111,14 +2448,14 @@ impl Vec { if at == 0 { // the new vector can take over the original buffer and avoid the copy - return mem::replace( + return Ok(mem::replace( self, - Vec::with_capacity_in(self.capacity(), self.allocator().clone()), - ); + Self::with_capacity_in_impl(self.capacity(), self.allocator().clone())?, + )); } let other_len = self.len - at; - let mut other = Vec::with_capacity_in(other_len, self.allocator().clone()); + let mut other = Self::with_capacity_in_impl(other_len, self.allocator().clone())?; // Unsafely `set_len` and copy items to `other`. unsafe { @@ -2127,7 +2464,7 @@ impl Vec { ptr::copy_nonoverlapping(self.as_ptr().add(at), other.as_mut_ptr(), other.len()); } - other + Ok(other) } /// Resizes the `Vec` in-place so that `len` is equal to `new_len`. @@ -2170,6 +2507,49 @@ impl Vec { } } + /// Resizes the `Vec` in-place so that `len` is equal to `new_len`. + /// + /// If `new_len` is greater than `len`, the `Vec` is extended by the + /// difference, with each additional slot filled with the result of + /// calling the closure `f`. The return values from `f` will end up + /// in the `Vec` in the order they have been generated. + /// + /// If `new_len` is less than `len`, the `Vec` is simply truncated. + /// + /// This method uses a closure to create new values on every push. If + /// you'd rather [`Clone`] a given value, use [`Vec::try_resize`]. If you + /// want to use the [`Default`] trait to generate values, you can + /// pass [`Default::default`] as the second argument. + /// + /// # Examples + /// + /// ``` + /// #![feature(more_fallible_allocation_methods)] + /// # #[macro_use] extern crate alloc; + /// + /// let mut vec = try_vec![1, 2, 3]?; + /// vec.try_resize_with(5, Default::default)?; + /// assert_eq!(vec, [1, 2, 3, 0, 0]); + /// + /// let mut vec = vec![]; + /// let mut p = 1; + /// vec.try_resize_with(4, || { p *= 2; p })?; + /// assert_eq!(vec, [2, 4, 8, 16]); + /// # Ok::<(), alloc::collections::TryReserveError>(()) + /// ``` + #[unstable(feature = "more_fallible_allocation_methods", issue = "86942")] + pub fn try_resize_with(&mut self, new_len: usize, f: F) -> Result<(), TryReserveError> + where + F: FnMut() -> T, + { + let len = self.len(); + if new_len > len { + self.try_extend_with(new_len - len, ExtendFunc(f)) + } else { + Ok(self.truncate(new_len)) + } + } + /// Consumes and leaks the `Vec`, returning a mutable reference to the contents, /// `&'a mut [T]`. Note that the type `T` must outlive the chosen lifetime /// `'a`. If the type has only static references, or none at all, then this @@ -2193,7 +2573,6 @@ impl Vec { /// static_ref[0] += 1; /// assert_eq!(static_ref, &[2, 2, 3]); /// ``` - #[cfg(not(no_global_oom_handling))] #[stable(feature = "vec_leak", since = "1.47.0")] #[inline] pub fn leak<'a>(self) -> &'a mut [T] @@ -2331,6 +2710,27 @@ impl Vec { (initialized, spare, &mut self.len) } } + + /// Extends the `Vec` using the items from the given iterator. + /// + /// # Examples + /// + /// ``` + /// #![feature(more_fallible_allocation_methods)] + /// # #[macro_use] extern crate alloc; + /// + /// let mut vec = try_vec![1, 2]?; + /// vec.try_extend([3, 4, 5])?; + /// assert_eq!(vec, [1, 2, 3, 4, 5]); + /// # Ok::<(), alloc::collections::TryReserveError>(()) + /// ``` + #[unstable(feature = "more_fallible_allocation_methods", issue = "86942")] + pub fn try_extend>( + &mut self, + iter: I, + ) -> Result<(), TryReserveError> { + >::spec_extend(self, iter.into_iter()) + } } impl Vec { @@ -2369,6 +2769,44 @@ impl Vec { } } + /// Resizes the `Vec` in-place so that `len` is equal to `new_len`. + /// + /// If `new_len` is greater than `len`, the `Vec` is extended by the + /// difference, with each additional slot filled with `value`. + /// If `new_len` is less than `len`, the `Vec` is simply truncated. + /// + /// This method requires `T` to implement [`Clone`], + /// in order to be able to clone the passed value. + /// If you need more flexibility (or want to rely on [`Default`] instead of + /// [`Clone`]), use [`Vec::try_resize_with`]. + /// If you only need to resize to a smaller size, use [`Vec::truncate`]. + /// + /// # Examples + /// + /// ``` + /// #![feature(more_fallible_allocation_methods)] + /// # #[macro_use] extern crate alloc; + /// + /// let mut vec = try_vec!["hello"]?; + /// vec.try_resize(3, "world")?; + /// assert_eq!(vec, ["hello", "world", "world"]); + /// + /// let mut vec = try_vec![1, 2, 3, 4]?; + /// vec.try_resize(2, 0)?; + /// assert_eq!(vec, [1, 2]); + /// # Ok::<(), alloc::collections::TryReserveError>(()) + /// ``` + #[unstable(feature = "more_fallible_allocation_methods", issue = "86942")] + pub fn try_resize(&mut self, new_len: usize, value: T) -> Result<(), TryReserveError> { + let len = self.len(); + + if new_len > len { + self.try_extend_with(new_len - len, ExtendElement(value)) + } else { + Ok(self.truncate(new_len)) + } + } + /// Clones and appends all elements in a slice to the `Vec`. /// /// Iterates over the slice `other`, clones each element, and then appends @@ -2391,6 +2829,34 @@ impl Vec { #[cfg(not(no_global_oom_handling))] #[stable(feature = "vec_extend_from_slice", since = "1.6.0")] pub fn extend_from_slice(&mut self, other: &[T]) { + self.spec_extend(other.iter()).unwrap_infallible() + } + + /// Clones and appends all elements in a slice to the `Vec`. + /// + /// Iterates over the slice `other`, clones each element, and then appends + /// it to this `Vec`. The `other` slice is traversed in-order. + /// + /// Note that this function is same as [`try_extend`] except that it is + /// specialized to work with slices instead. If and when Rust gets + /// specialization this function will likely be deprecated (but still + /// available). + /// + /// # Examples + /// + /// ``` + /// #![feature(more_fallible_allocation_methods)] + /// # #[macro_use] extern crate alloc; + /// + /// let mut vec = try_vec![1]?; + /// vec.try_extend_from_slice(&[2, 3, 4])?; + /// assert_eq!(vec, [1, 2, 3, 4]); + /// # Ok::<(), alloc::collections::TryReserveError>(()) + /// ``` + /// + /// [`try_extend`]: Vec::try_extend + #[unstable(feature = "more_fallible_allocation_methods", issue = "86942")] + pub fn try_extend_from_slice(&mut self, other: &[T]) -> Result<(), TryReserveError> { self.spec_extend(other.iter()) } @@ -2430,6 +2896,48 @@ impl Vec { self.spec_extend_from_within(range); } } + + /// Copies elements from `src` range to the end of the vector. + /// + /// # Panics + /// + /// Panics if the starting point is greater than the end point or if + /// the end point is greater than the length of the vector. + /// + /// # Examples + /// + /// ``` + /// #![feature(more_fallible_allocation_methods)] + /// # #[macro_use] extern crate alloc; + /// + /// let mut vec = try_vec![0, 1, 2, 3, 4]?; + /// + /// vec.try_extend_from_within(2..)?; + /// assert_eq!(vec, [0, 1, 2, 3, 4, 2, 3, 4]); + /// + /// vec.try_extend_from_within(..2)?; + /// assert_eq!(vec, [0, 1, 2, 3, 4, 2, 3, 4, 0, 1]); + /// + /// vec.try_extend_from_within(4..8)?; + /// assert_eq!(vec, [0, 1, 2, 3, 4, 2, 3, 4, 0, 1, 4, 2, 3, 4]); + /// # Ok::<(), alloc::collections::TryReserveError>(()) + /// ``` + #[unstable(feature = "more_fallible_allocation_methods", issue = "86942")] + pub fn try_extend_from_within(&mut self, src: R) -> Result<(), TryReserveError> + where + R: RangeBounds, + { + let range = slice::range(src, ..self.len()); + self.try_reserve(range.len())?; + + // SAFETY: + // - `slice::range` guarantees that the given range is valid for indexing self + unsafe { + self.spec_extend_from_within(range); + } + + Ok(()) + } } impl Vec<[T; N], A> { @@ -2506,8 +3014,24 @@ impl T> ExtendWith for ExtendFunc { impl Vec { #[cfg(not(no_global_oom_handling))] /// Extend the vector by `n` values, using the given generator. - fn extend_with>(&mut self, n: usize, mut value: E) { - self.reserve(n); + fn extend_with>(&mut self, n: usize, value: E) { + self.extend_with_impl(n, value).unwrap_infallible() + } + + fn try_extend_with>( + &mut self, + n: usize, + value: E, + ) -> Result<(), TryReserveError> { + self.extend_with_impl(n, value) + } + + fn extend_with_impl, TError: VecError>( + &mut self, + n: usize, + mut value: E, + ) -> Result<(), TError> { + self.reserve_impl(n)?; unsafe { let mut ptr = self.as_mut_ptr().add(self.len()); @@ -2532,6 +3056,8 @@ impl Vec { // len set by scope guard } + + Ok(()) } } @@ -2565,6 +3091,12 @@ impl Vec { #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] pub fn from_elem(elem: T, n: usize) -> Vec { + ::from_elem(elem, n, Global).unwrap_infallible() +} + +#[doc(hidden)] +#[unstable(feature = "more_fallible_allocation_methods", issue = "86942")] +pub fn try_from_elem(elem: T, n: usize) -> Result, TryReserveError> { ::from_elem(elem, n, Global) } @@ -2572,6 +3104,16 @@ pub fn from_elem(elem: T, n: usize) -> Vec { #[cfg(not(no_global_oom_handling))] #[unstable(feature = "allocator_api", issue = "32838")] pub fn from_elem_in(elem: T, n: usize, alloc: A) -> Vec { + ::from_elem(elem, n, alloc).unwrap_infallible() +} + +#[doc(hidden)] +#[unstable(feature = "more_fallible_allocation_methods", issue = "86942")] +pub fn try_from_elem_in( + elem: T, + n: usize, + alloc: A, +) -> Result, TryReserveError> { ::from_elem(elem, n, alloc) } @@ -2756,7 +3298,25 @@ impl, A: Allocator> IndexMut for Vec { impl FromIterator for Vec { #[inline] fn from_iter>(iter: I) -> Vec { - >::from_iter(iter.into_iter()) + >::from_iter(iter.into_iter()).unwrap_infallible() + } +} + +impl Vec { + /// Creates a `Vec` using the items from the given iterator. + /// + /// # Examples + /// + /// ``` + /// #![feature(more_fallible_allocation_methods)] + /// + /// let vec = Vec::try_from_iter([1, 2, 3, 4, 5])?; + /// assert_eq!(vec, [1, 2, 3, 4, 5]); + /// # Ok::<(), alloc::collections::TryReserveError>(()) + /// ``` + #[unstable(feature = "more_fallible_allocation_methods", issue = "86942")] + pub fn try_from_iter>(iter: I) -> Result, TryReserveError> { + >::from_iter(iter.into_iter()) } } @@ -2831,6 +3391,7 @@ impl Extend for Vec { #[inline] fn extend>(&mut self, iter: I) { >::spec_extend(self, iter.into_iter()) + .unwrap_infallible() } #[inline] @@ -2847,8 +3408,10 @@ impl Extend for Vec { impl Vec { // leaf method to which various SpecFrom/SpecExtend implementations delegate when // they have no further optimizations to apply - #[cfg(not(no_global_oom_handling))] - fn extend_desugared>(&mut self, mut iterator: I) { + fn extend_desugared, TError: VecError>( + &mut self, + mut iterator: I, + ) -> Result<(), TError> { // This is the case for a general iterator. // // This function should be the moral equivalent of: @@ -2860,7 +3423,7 @@ impl Vec { let len = self.len(); if len == self.capacity() { let (lower, _) = iterator.size_hint(); - self.reserve(lower.saturating_add(1)); + self.buf.grow_amortized(len, lower.saturating_add(1))?; } unsafe { ptr::write(self.as_mut_ptr().add(len), element); @@ -2870,6 +3433,8 @@ impl Vec { self.set_len(len + 1); } } + + Ok(()) } /// Creates a splicing iterator that replaces the specified range in the vector @@ -2986,7 +3551,7 @@ impl Vec { #[stable(feature = "extend_ref", since = "1.2.0")] impl<'a, T: Copy + 'a, A: Allocator + 'a> Extend<&'a T> for Vec { fn extend>(&mut self, iter: I) { - self.spec_extend(iter.into_iter()) + self.spec_extend(iter.into_iter()).unwrap_infallible() } #[inline] diff --git a/library/alloc/src/vec/spec_extend.rs b/library/alloc/src/vec/spec_extend.rs index 1ea9c827afd70..4ce3dff470e34 100644 --- a/library/alloc/src/vec/spec_extend.rs +++ b/library/alloc/src/vec/spec_extend.rs @@ -3,18 +3,18 @@ use core::iter::TrustedLen; use core::ptr::{self}; use core::slice::{self}; -use super::{IntoIter, SetLenOnDrop, Vec}; +use super::{IntoIter, SetLenOnDrop, Vec, VecError}; // Specialization trait used for Vec::extend pub(super) trait SpecExtend { - fn spec_extend(&mut self, iter: I); + fn spec_extend(&mut self, iter: I) -> Result<(), TError>; } impl SpecExtend for Vec where I: Iterator, { - default fn spec_extend(&mut self, iter: I) { + default fn spec_extend(&mut self, iter: I) -> Result<(), TError> { self.extend_desugared(iter) } } @@ -23,7 +23,7 @@ impl SpecExtend for Vec where I: TrustedLen, { - default fn spec_extend(&mut self, iterator: I) { + default fn spec_extend(&mut self, iterator: I) -> Result<(), TError> { // This is the case for a TrustedLen iterator. let (low, high) = iterator.size_hint(); if let Some(additional) = high { @@ -33,7 +33,7 @@ where "TrustedLen iterator's size hint is not exact: {:?}", (low, high) ); - self.reserve(additional); + self.reserve_impl(additional)?; unsafe { let mut ptr = self.as_mut_ptr().add(self.len()); let mut local_len = SetLenOnDrop::new(&mut self.len); @@ -46,23 +46,26 @@ where local_len.increment_len(1); }); } + + Ok(()) } else { // Per TrustedLen contract a `None` upper bound means that the iterator length // truly exceeds usize::MAX, which would eventually lead to a capacity overflow anyway. // Since the other branch already panics eagerly (via `reserve()`) we do the same here. // This avoids additional codegen for a fallback code path which would eventually // panic anyway. - panic!("capacity overflow"); + Err(TError::capacity_overflow()) } } } impl SpecExtend> for Vec { - fn spec_extend(&mut self, mut iterator: IntoIter) { + fn spec_extend(&mut self, mut iterator: IntoIter) -> Result<(), TError> { unsafe { - self.append_elements(iterator.as_slice() as _); + self.append_elements(iterator.as_slice() as _)?; } iterator.forget_remaining_elements(); + Ok(()) } } @@ -71,7 +74,7 @@ where I: Iterator, T: Clone, { - default fn spec_extend(&mut self, iterator: I) { + default fn spec_extend(&mut self, iterator: I) -> Result<(), TError> { self.spec_extend(iterator.cloned()) } } @@ -80,8 +83,11 @@ impl<'a, T: 'a, A: Allocator + 'a> SpecExtend<&'a T, slice::Iter<'a, T>> for Vec where T: Copy, { - fn spec_extend(&mut self, iterator: slice::Iter<'a, T>) { + fn spec_extend( + &mut self, + iterator: slice::Iter<'a, T>, + ) -> Result<(), TError> { let slice = iterator.as_slice(); - unsafe { self.append_elements(slice) }; + unsafe { self.append_elements(slice) } } } diff --git a/library/alloc/src/vec/spec_from_elem.rs b/library/alloc/src/vec/spec_from_elem.rs index ff364c033ee98..35c1013df6456 100644 --- a/library/alloc/src/vec/spec_from_elem.rs +++ b/library/alloc/src/vec/spec_from_elem.rs @@ -3,59 +3,79 @@ use core::ptr; use crate::alloc::Allocator; use crate::raw_vec::RawVec; -use super::{ExtendElement, IsZero, Vec}; +use super::{ExtendElement, IsZero, Vec, VecError}; // Specialization trait used for Vec::from_elem pub(super) trait SpecFromElem: Sized { - fn from_elem(elem: Self, n: usize, alloc: A) -> Vec; + fn from_elem( + elem: Self, + n: usize, + alloc: A, + ) -> Result, TError>; } impl SpecFromElem for T { - default fn from_elem(elem: Self, n: usize, alloc: A) -> Vec { - let mut v = Vec::with_capacity_in(n, alloc); - v.extend_with(n, ExtendElement(elem)); - v + default fn from_elem( + elem: Self, + n: usize, + alloc: A, + ) -> Result, TError> { + let mut v = Vec::with_capacity_in_impl(n, alloc)?; + v.extend_with_impl(n, ExtendElement(elem))?; + Ok(v) } } impl SpecFromElem for T { #[inline] - default fn from_elem(elem: T, n: usize, alloc: A) -> Vec { + default fn from_elem( + elem: T, + n: usize, + alloc: A, + ) -> Result, TError> { if elem.is_zero() { - return Vec { buf: RawVec::with_capacity_zeroed_in(n, alloc), len: n }; + return Ok(Vec { buf: RawVec::with_capacity_zeroed_in_impl(n, alloc)?, len: n }); } - let mut v = Vec::with_capacity_in(n, alloc); - v.extend_with(n, ExtendElement(elem)); - v + let mut v = Vec::with_capacity_in_impl(n, alloc)?; + v.extend_with_impl(n, ExtendElement(elem))?; + Ok(v) } } impl SpecFromElem for i8 { #[inline] - fn from_elem(elem: i8, n: usize, alloc: A) -> Vec { + fn from_elem( + elem: i8, + n: usize, + alloc: A, + ) -> Result, TError> { if elem == 0 { - return Vec { buf: RawVec::with_capacity_zeroed_in(n, alloc), len: n }; + return Ok(Vec { buf: RawVec::with_capacity_zeroed_in_impl(n, alloc)?, len: n }); } unsafe { - let mut v = Vec::with_capacity_in(n, alloc); + let mut v = Vec::with_capacity_in_impl(n, alloc)?; ptr::write_bytes(v.as_mut_ptr(), elem as u8, n); v.set_len(n); - v + Ok(v) } } } impl SpecFromElem for u8 { #[inline] - fn from_elem(elem: u8, n: usize, alloc: A) -> Vec { + fn from_elem( + elem: u8, + n: usize, + alloc: A, + ) -> Result, TError> { if elem == 0 { - return Vec { buf: RawVec::with_capacity_zeroed_in(n, alloc), len: n }; + return Ok(Vec { buf: RawVec::with_capacity_zeroed_in_impl(n, alloc)?, len: n }); } unsafe { - let mut v = Vec::with_capacity_in(n, alloc); + let mut v = Vec::with_capacity_in_impl(n, alloc)?; ptr::write_bytes(v.as_mut_ptr(), elem, n); v.set_len(n); - v + Ok(v) } } } diff --git a/library/alloc/src/vec/spec_from_iter.rs b/library/alloc/src/vec/spec_from_iter.rs index efa6868473e49..0d3358f410237 100644 --- a/library/alloc/src/vec/spec_from_iter.rs +++ b/library/alloc/src/vec/spec_from_iter.rs @@ -1,7 +1,7 @@ use core::mem::ManuallyDrop; use core::ptr::{self}; -use super::{IntoIter, SpecExtend, SpecFromIterNested, Vec}; +use super::{IntoIter, SpecExtend, SpecFromIterNested, Vec, VecError}; /// Specialization trait used for Vec::from_iter /// @@ -21,21 +21,24 @@ use super::{IntoIter, SpecExtend, SpecFromIterNested, Vec}; /// | SourceIterMarker---fallback-+ | +---------------------+ /// +---------------------------------+ /// ``` -pub(super) trait SpecFromIter { - fn from_iter(iter: I) -> Self; +pub(super) trait SpecFromIter +where + Self: Sized, +{ + fn from_iter(iter: I) -> Result; } -impl SpecFromIter for Vec +impl SpecFromIter for Vec where I: Iterator, { - default fn from_iter(iterator: I) -> Self { + default fn from_iter(iterator: I) -> Result { SpecFromIterNested::from_iter(iterator) } } -impl SpecFromIter> for Vec { - fn from_iter(iterator: IntoIter) -> Self { +impl SpecFromIter, TError> for Vec { + fn from_iter(iterator: IntoIter) -> Result { // A common case is passing a vector into a function which immediately // re-collects into a vector. We can short circuit this if the IntoIter // has not been advanced at all. @@ -51,14 +54,14 @@ impl SpecFromIter> for Vec { if has_advanced { ptr::copy(it.ptr, it.buf.as_ptr(), it.len()); } - return Vec::from_raw_parts(it.buf.as_ptr(), it.len(), it.cap); + return Ok(Vec::from_raw_parts(it.buf.as_ptr(), it.len(), it.cap)); } } let mut vec = Vec::new(); // must delegate to spec_extend() since extend() itself delegates // to spec_from for empty Vecs - vec.spec_extend(iterator); - vec + vec.spec_extend(iterator)?; + Ok(vec) } } diff --git a/library/alloc/src/vec/spec_from_iter_nested.rs b/library/alloc/src/vec/spec_from_iter_nested.rs index f915ebb86e5a5..91bd00153904a 100644 --- a/library/alloc/src/vec/spec_from_iter_nested.rs +++ b/library/alloc/src/vec/spec_from_iter_nested.rs @@ -2,34 +2,37 @@ use core::cmp; use core::iter::TrustedLen; use core::ptr; -use crate::raw_vec::RawVec; +use crate::{alloc::Global, raw_vec::RawVec}; -use super::{SpecExtend, Vec}; +use super::{SpecExtend, Vec, VecError}; /// Another specialization trait for Vec::from_iter /// necessary to manually prioritize overlapping specializations /// see [`SpecFromIter`](super::SpecFromIter) for details. -pub(super) trait SpecFromIterNested { - fn from_iter(iter: I) -> Self; +pub(super) trait SpecFromIterNested +where + Self: Sized, +{ + fn from_iter(iter: I) -> Result; } -impl SpecFromIterNested for Vec +impl SpecFromIterNested for Vec where I: Iterator, { - default fn from_iter(mut iterator: I) -> Self { + default fn from_iter(mut iterator: I) -> Result { // Unroll the first iteration, as the vector is going to be // expanded on this iteration in every case when the iterable is not // empty, but the loop in extend_desugared() is not going to see the // vector being full in the few subsequent loop iterations. // So we get better branch prediction. let mut vector = match iterator.next() { - None => return Vec::new(), + None => return Ok(Vec::new()), Some(element) => { let (lower, _) = iterator.size_hint(); let initial_capacity = cmp::max(RawVec::::MIN_NON_ZERO_CAP, lower.saturating_add(1)); - let mut vector = Vec::with_capacity(initial_capacity); + let mut vector = Self::with_capacity_in_impl(initial_capacity, Global)?; unsafe { // SAFETY: We requested capacity at least 1 ptr::write(vector.as_mut_ptr(), element); @@ -40,18 +43,18 @@ where }; // must delegate to spec_extend() since extend() itself delegates // to spec_from for empty Vecs - as SpecExtend>::spec_extend(&mut vector, iterator); - vector + as SpecExtend>::spec_extend(&mut vector, iterator)?; + Ok(vector) } } -impl SpecFromIterNested for Vec +impl SpecFromIterNested for Vec where I: TrustedLen, { - fn from_iter(iterator: I) -> Self { + fn from_iter(iterator: I) -> Result { let mut vector = match iterator.size_hint() { - (_, Some(upper)) => Vec::with_capacity(upper), + (_, Some(upper)) => Self::with_capacity_in_impl(upper, Global)?, // TrustedLen contract guarantees that `size_hint() == (_, None)` means that there // are more than `usize::MAX` elements. // Since the previous branch would eagerly panic if the capacity is too large @@ -59,7 +62,7 @@ where _ => panic!("capacity overflow"), }; // reuse extend specialization for TrustedLen - vector.spec_extend(iterator); - vector + as SpecExtend>::spec_extend(&mut vector, iterator)?; + Ok(vector) } } diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 3f33c5fd6ca36..f370f28c5c255 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -2123,3 +2123,24 @@ impl> ops::FromResidual> for Result { impl const ops::Residual for Result { type TryType = Result; } + +#[unstable(feature = "never_type", issue = "35121")] +impl Result { + /// Returns the contained [`Ok`] value, consuming the `self` value, + /// where the [`Err`] variant is known to be unreachable. + /// + /// # Examples + /// + /// ``` + /// #![feature(never_type)] + /// + /// let x: Result = Ok(2); + /// assert_eq!(x.unwrap_infallible(), 2); + /// ``` + #[inline(always)] + pub fn unwrap_infallible(self) -> T { + match self { + Ok(t) => t, + } + } +}