Auto merge of #87408 - kornelski:try_reserve_error, r=yaahc

Hide allocator details from TryReserveError

I think there's [no need for TryReserveError to carry detailed information](https://github.com/rust-lang/rust/issues/48043#issuecomment-825139280), but I wouldn't want that issue to delay stabilization of the `try_reserve` feature.

So I'm proposing to stabilize `try_reserve` with a `TryReserveError` as an opaque structure, and if needed, expose error details later.

This PR moves the `enum` to an unstable inner `TryReserveErrorKind` that lives under a separate feature flag. `TryReserveErrorKind` could possibly be left as an implementation detail forever, and the `TryReserveError` get methods such as `allocation_size() -> Option<usize>` or `layout() -> Option<Layout>` instead, or the details could be dropped completely to make try-reserve errors just a unit struct, and thus smaller and cheaper.
This commit is contained in:
bors 2021-08-07 01:26:15 +00:00
commit 996ff2e0a0
13 changed files with 269 additions and 109 deletions

View file

@ -51,6 +51,7 @@
#![feature(iter_zip)] #![feature(iter_zip)]
#![feature(thread_local_const_init)] #![feature(thread_local_const_init)]
#![feature(try_reserve)] #![feature(try_reserve)]
#![feature(try_reserve_kind)]
#![feature(nonzero_ops)] #![feature(nonzero_ops)]
#![recursion_limit = "512"] #![recursion_limit = "512"]

View file

@ -30,6 +30,7 @@ Rust MIR: a lowered representation of Rust.
#![feature(once_cell)] #![feature(once_cell)]
#![feature(control_flow_enum)] #![feature(control_flow_enum)]
#![feature(try_reserve)] #![feature(try_reserve)]
#![feature(try_reserve_kind)]
#![recursion_limit = "256"] #![recursion_limit = "256"]
#[macro_use] #[macro_use]

View file

@ -58,7 +58,31 @@ use core::fmt::Display;
/// The error type for `try_reserve` methods. /// The error type for `try_reserve` methods.
#[derive(Clone, PartialEq, Eq, Debug)] #[derive(Clone, PartialEq, Eq, Debug)]
#[unstable(feature = "try_reserve", reason = "new API", issue = "48043")] #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")]
pub enum TryReserveError { pub struct TryReserveError {
kind: TryReserveErrorKind,
}
impl TryReserveError {
/// Details about the allocation that caused the error
#[inline]
#[unstable(
feature = "try_reserve_kind",
reason = "Uncertain how much info should be exposed",
issue = "48043"
)]
pub fn kind(&self) -> TryReserveErrorKind {
self.kind.clone()
}
}
/// Details of the allocation that caused a `TryReserveError`
#[derive(Clone, PartialEq, Eq, Debug)]
#[unstable(
feature = "try_reserve_kind",
reason = "Uncertain how much info should be exposed",
issue = "48043"
)]
pub enum TryReserveErrorKind {
/// Error due to the computed capacity exceeding the collection's maximum /// Error due to the computed capacity exceeding the collection's maximum
/// (usually `isize::MAX` bytes). /// (usually `isize::MAX` bytes).
CapacityOverflow, CapacityOverflow,
@ -81,12 +105,23 @@ pub enum TryReserveError {
}, },
} }
#[unstable(
feature = "try_reserve_kind",
reason = "Uncertain how much info should be exposed",
issue = "48043"
)]
impl From<TryReserveErrorKind> for TryReserveError {
fn from(kind: TryReserveErrorKind) -> Self {
Self { kind }
}
}
#[unstable(feature = "try_reserve", reason = "new API", issue = "48043")] #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")]
impl From<LayoutError> for TryReserveError { impl From<LayoutError> for TryReserveError {
/// Always evaluates to [`TryReserveError::CapacityOverflow`]. /// Always evaluates to [`TryReserveErrorKind::CapacityOverflow`].
#[inline] #[inline]
fn from(_: LayoutError) -> Self { fn from(_: LayoutError) -> Self {
TryReserveError::CapacityOverflow TryReserveErrorKind::CapacityOverflow.into()
} }
} }
@ -97,11 +132,13 @@ impl Display for TryReserveError {
fmt: &mut core::fmt::Formatter<'_>, fmt: &mut core::fmt::Formatter<'_>,
) -> core::result::Result<(), core::fmt::Error> { ) -> core::result::Result<(), core::fmt::Error> {
fmt.write_str("memory allocation failed")?; fmt.write_str("memory allocation failed")?;
let reason = match &self { let reason = match self.kind {
TryReserveError::CapacityOverflow => { TryReserveErrorKind::CapacityOverflow => {
" because the computed capacity exceeded the collection's maximum" " because the computed capacity exceeded the collection's maximum"
} }
TryReserveError::AllocError { .. } => " because the memory allocator returned a error", TryReserveErrorKind::AllocError { .. } => {
" because the memory allocator returned a error"
}
}; };
fmt.write_str(reason) fmt.write_str(reason)
} }

View file

@ -19,6 +19,7 @@ use core::slice;
use crate::alloc::{Allocator, Global}; use crate::alloc::{Allocator, Global};
use crate::collections::TryReserveError; use crate::collections::TryReserveError;
use crate::collections::TryReserveErrorKind;
use crate::raw_vec::RawVec; use crate::raw_vec::RawVec;
use crate::vec::Vec; use crate::vec::Vec;
@ -773,7 +774,7 @@ impl<T, A: Allocator> VecDeque<T, A> {
let new_cap = used_cap let new_cap = used_cap
.checked_add(additional) .checked_add(additional)
.and_then(|needed_cap| needed_cap.checked_next_power_of_two()) .and_then(|needed_cap| needed_cap.checked_next_power_of_two())
.ok_or(TryReserveError::CapacityOverflow)?; .ok_or(TryReserveErrorKind::CapacityOverflow)?;
if new_cap > old_cap { if new_cap > old_cap {
self.buf.try_reserve_exact(used_cap, new_cap - used_cap)?; self.buf.try_reserve_exact(used_cap, new_cap - used_cap)?;

View file

@ -13,7 +13,8 @@ use core::slice;
use crate::alloc::handle_alloc_error; use crate::alloc::handle_alloc_error;
use crate::alloc::{Allocator, Global, Layout}; use crate::alloc::{Allocator, Global, Layout};
use crate::boxed::Box; use crate::boxed::Box;
use crate::collections::TryReserveError::{self, *}; use crate::collections::TryReserveError;
use crate::collections::TryReserveErrorKind::*;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
@ -425,7 +426,7 @@ impl<T, A: Allocator> RawVec<T, A> {
if mem::size_of::<T>() == 0 { if mem::size_of::<T>() == 0 {
// Since we return a capacity of `usize::MAX` when `elem_size` is // Since we return a capacity of `usize::MAX` when `elem_size` is
// 0, getting to here necessarily means the `RawVec` is overfull. // 0, getting to here necessarily means the `RawVec` is overfull.
return Err(CapacityOverflow); return Err(CapacityOverflow.into());
} }
// Nothing we can really do about these checks, sadly. // Nothing we can really do about these checks, sadly.
@ -451,7 +452,7 @@ impl<T, A: Allocator> RawVec<T, A> {
if mem::size_of::<T>() == 0 { if mem::size_of::<T>() == 0 {
// Since we return a capacity of `usize::MAX` when the type size is // Since we return a capacity of `usize::MAX` when the type size is
// 0, getting to here necessarily means the `RawVec` is overfull. // 0, getting to here necessarily means the `RawVec` is overfull.
return Err(CapacityOverflow); return Err(CapacityOverflow.into());
} }
let cap = len.checked_add(additional).ok_or(CapacityOverflow)?; let cap = len.checked_add(additional).ok_or(CapacityOverflow)?;
@ -471,10 +472,9 @@ impl<T, A: Allocator> RawVec<T, A> {
let ptr = unsafe { let ptr = unsafe {
let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
self.alloc.shrink(ptr, layout, new_layout).map_err(|_| TryReserveError::AllocError { self.alloc
layout: new_layout, .shrink(ptr, layout, new_layout)
non_exhaustive: (), .map_err(|_| AllocError { layout: new_layout, non_exhaustive: () })?
})?
}; };
self.set_ptr(ptr); self.set_ptr(ptr);
Ok(()) Ok(())
@ -510,7 +510,7 @@ where
alloc.allocate(new_layout) alloc.allocate(new_layout)
}; };
memory.map_err(|_| AllocError { layout: new_layout, non_exhaustive: () }) memory.map_err(|_| AllocError { layout: new_layout, non_exhaustive: () }.into())
} }
unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawVec<T, A> { unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawVec<T, A> {
@ -526,7 +526,7 @@ unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawVec<T, A> {
#[cfg(not(no_global_oom_handling))] #[cfg(not(no_global_oom_handling))]
#[inline] #[inline]
fn handle_reserve(result: Result<(), TryReserveError>) { fn handle_reserve(result: Result<(), TryReserveError>) {
match result { match result.map_err(|e| e.kind()) {
Err(CapacityOverflow) => capacity_overflow(), Err(CapacityOverflow) => capacity_overflow(),
Err(AllocError { layout, .. }) => handle_alloc_error(layout), Err(AllocError { layout, .. }) => handle_alloc_error(layout),
Ok(()) => { /* yay */ } Ok(()) => { /* yay */ }
@ -545,7 +545,7 @@ fn handle_reserve(result: Result<(), TryReserveError>) {
#[inline] #[inline]
fn alloc_guard(alloc_size: usize) -> Result<(), TryReserveError> { fn alloc_guard(alloc_size: usize) -> Result<(), TryReserveError> {
if usize::BITS < 64 && alloc_size > isize::MAX as usize { if usize::BITS < 64 && alloc_size > isize::MAX as usize {
Err(CapacityOverflow) Err(CapacityOverflow.into())
} else { } else {
Ok(()) Ok(())
} }

View file

@ -8,6 +8,7 @@
#![feature(pattern)] #![feature(pattern)]
#![feature(trusted_len)] #![feature(trusted_len)]
#![feature(try_reserve)] #![feature(try_reserve)]
#![feature(try_reserve_kind)]
#![feature(unboxed_closures)] #![feature(unboxed_closures)]
#![feature(associated_type_bounds)] #![feature(associated_type_bounds)]
#![feature(binary_heap_into_iter_sorted)] #![feature(binary_heap_into_iter_sorted)]

View file

@ -1,6 +1,6 @@
use std::borrow::Cow; use std::borrow::Cow;
use std::cell::Cell; use std::cell::Cell;
use std::collections::TryReserveError::*; use std::collections::TryReserveErrorKind::*;
use std::ops::Bound; use std::ops::Bound;
use std::ops::Bound::*; use std::ops::Bound::*;
use std::ops::RangeBounds; use std::ops::RangeBounds;
@ -703,35 +703,42 @@ fn test_try_reserve() {
let mut empty_string: String = String::new(); let mut empty_string: String = String::new();
// Check isize::MAX doesn't count as an overflow // Check isize::MAX doesn't count as an overflow
if let Err(CapacityOverflow) = empty_string.try_reserve(MAX_CAP) { if let Err(CapacityOverflow) = empty_string.try_reserve(MAX_CAP).map_err(|e| e.kind()) {
panic!("isize::MAX shouldn't trigger an overflow!"); panic!("isize::MAX shouldn't trigger an overflow!");
} }
// Play it again, frank! (just to be sure) // Play it again, frank! (just to be sure)
if let Err(CapacityOverflow) = empty_string.try_reserve(MAX_CAP) { if let Err(CapacityOverflow) = empty_string.try_reserve(MAX_CAP).map_err(|e| e.kind()) {
panic!("isize::MAX shouldn't trigger an overflow!"); panic!("isize::MAX shouldn't trigger an overflow!");
} }
if guards_against_isize { if guards_against_isize {
// Check isize::MAX + 1 does count as overflow // Check isize::MAX + 1 does count as overflow
if let Err(CapacityOverflow) = empty_string.try_reserve(MAX_CAP + 1) { if let Err(CapacityOverflow) =
empty_string.try_reserve(MAX_CAP + 1).map_err(|e| e.kind())
{
} else { } else {
panic!("isize::MAX + 1 should trigger an overflow!") panic!("isize::MAX + 1 should trigger an overflow!")
} }
// Check usize::MAX does count as overflow // Check usize::MAX does count as overflow
if let Err(CapacityOverflow) = empty_string.try_reserve(MAX_USIZE) { if let Err(CapacityOverflow) = empty_string.try_reserve(MAX_USIZE).map_err(|e| e.kind())
{
} else { } else {
panic!("usize::MAX should trigger an overflow!") panic!("usize::MAX should trigger an overflow!")
} }
} else { } else {
// Check isize::MAX + 1 is an OOM // Check isize::MAX + 1 is an OOM
if let Err(AllocError { .. }) = empty_string.try_reserve(MAX_CAP + 1) { if let Err(AllocError { .. }) =
empty_string.try_reserve(MAX_CAP + 1).map_err(|e| e.kind())
{
} else { } else {
panic!("isize::MAX + 1 should trigger an OOM!") panic!("isize::MAX + 1 should trigger an OOM!")
} }
// Check usize::MAX is an OOM // Check usize::MAX is an OOM
if let Err(AllocError { .. }) = empty_string.try_reserve(MAX_USIZE) { if let Err(AllocError { .. }) =
empty_string.try_reserve(MAX_USIZE).map_err(|e| e.kind())
{
} else { } else {
panic!("usize::MAX should trigger an OOM!") panic!("usize::MAX should trigger an OOM!")
} }
@ -742,25 +749,27 @@ fn test_try_reserve() {
// Same basic idea, but with non-zero len // Same basic idea, but with non-zero len
let mut ten_bytes: String = String::from("0123456789"); let mut ten_bytes: String = String::from("0123456789");
if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10) { if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) {
panic!("isize::MAX shouldn't trigger an overflow!"); panic!("isize::MAX shouldn't trigger an overflow!");
} }
if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10) { if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) {
panic!("isize::MAX shouldn't trigger an overflow!"); panic!("isize::MAX shouldn't trigger an overflow!");
} }
if guards_against_isize { if guards_against_isize {
if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 9) { if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind())
{
} else { } else {
panic!("isize::MAX + 1 should trigger an overflow!"); panic!("isize::MAX + 1 should trigger an overflow!");
} }
} else { } else {
if let Err(AllocError { .. }) = ten_bytes.try_reserve(MAX_CAP - 9) { if let Err(AllocError { .. }) = ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind())
{
} else { } else {
panic!("isize::MAX + 1 should trigger an OOM!") panic!("isize::MAX + 1 should trigger an OOM!")
} }
} }
// Should always overflow in the add-to-len // Should always overflow in the add-to-len
if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_USIZE) { if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()) {
} else { } else {
panic!("usize::MAX should trigger an overflow!") panic!("usize::MAX should trigger an overflow!")
} }
@ -782,30 +791,40 @@ fn test_try_reserve_exact() {
{ {
let mut empty_string: String = String::new(); let mut empty_string: String = String::new();
if let Err(CapacityOverflow) = empty_string.try_reserve_exact(MAX_CAP) { if let Err(CapacityOverflow) = empty_string.try_reserve_exact(MAX_CAP).map_err(|e| e.kind())
{
panic!("isize::MAX shouldn't trigger an overflow!"); panic!("isize::MAX shouldn't trigger an overflow!");
} }
if let Err(CapacityOverflow) = empty_string.try_reserve_exact(MAX_CAP) { if let Err(CapacityOverflow) = empty_string.try_reserve_exact(MAX_CAP).map_err(|e| e.kind())
{
panic!("isize::MAX shouldn't trigger an overflow!"); panic!("isize::MAX shouldn't trigger an overflow!");
} }
if guards_against_isize { if guards_against_isize {
if let Err(CapacityOverflow) = empty_string.try_reserve_exact(MAX_CAP + 1) { if let Err(CapacityOverflow) =
empty_string.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind())
{
} else { } else {
panic!("isize::MAX + 1 should trigger an overflow!") panic!("isize::MAX + 1 should trigger an overflow!")
} }
if let Err(CapacityOverflow) = empty_string.try_reserve_exact(MAX_USIZE) { if let Err(CapacityOverflow) =
empty_string.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind())
{
} else { } else {
panic!("usize::MAX should trigger an overflow!") panic!("usize::MAX should trigger an overflow!")
} }
} else { } else {
if let Err(AllocError { .. }) = empty_string.try_reserve_exact(MAX_CAP + 1) { if let Err(AllocError { .. }) =
empty_string.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind())
{
} else { } else {
panic!("isize::MAX + 1 should trigger an OOM!") panic!("isize::MAX + 1 should trigger an OOM!")
} }
if let Err(AllocError { .. }) = empty_string.try_reserve_exact(MAX_USIZE) { if let Err(AllocError { .. }) =
empty_string.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind())
{
} else { } else {
panic!("usize::MAX should trigger an OOM!") panic!("usize::MAX should trigger an OOM!")
} }
@ -815,24 +834,33 @@ fn test_try_reserve_exact() {
{ {
let mut ten_bytes: String = String::from("0123456789"); let mut ten_bytes: String = String::from("0123456789");
if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 10) { if let Err(CapacityOverflow) =
ten_bytes.try_reserve_exact(MAX_CAP - 10).map_err(|e| e.kind())
{
panic!("isize::MAX shouldn't trigger an overflow!"); panic!("isize::MAX shouldn't trigger an overflow!");
} }
if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 10) { if let Err(CapacityOverflow) =
ten_bytes.try_reserve_exact(MAX_CAP - 10).map_err(|e| e.kind())
{
panic!("isize::MAX shouldn't trigger an overflow!"); panic!("isize::MAX shouldn't trigger an overflow!");
} }
if guards_against_isize { if guards_against_isize {
if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { if let Err(CapacityOverflow) =
ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind())
{
} else { } else {
panic!("isize::MAX + 1 should trigger an overflow!"); panic!("isize::MAX + 1 should trigger an overflow!");
} }
} else { } else {
if let Err(AllocError { .. }) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { if let Err(AllocError { .. }) =
ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind())
{
} else { } else {
panic!("isize::MAX + 1 should trigger an OOM!") panic!("isize::MAX + 1 should trigger an OOM!")
} }
} }
if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_USIZE) { if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind())
{
} else { } else {
panic!("usize::MAX should trigger an overflow!") panic!("usize::MAX should trigger an overflow!")
} }

View file

@ -1,6 +1,6 @@
use std::borrow::Cow; use std::borrow::Cow;
use std::cell::Cell; use std::cell::Cell;
use std::collections::TryReserveError::*; use std::collections::TryReserveErrorKind::*;
use std::fmt::Debug; use std::fmt::Debug;
use std::iter::InPlaceIterable; use std::iter::InPlaceIterable;
use std::mem::{size_of, swap}; use std::mem::{size_of, swap};
@ -1478,35 +1478,41 @@ fn test_try_reserve() {
let mut empty_bytes: Vec<u8> = Vec::new(); let mut empty_bytes: Vec<u8> = Vec::new();
// Check isize::MAX doesn't count as an overflow // Check isize::MAX doesn't count as an overflow
if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP) { if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP).map_err(|e| e.kind()) {
panic!("isize::MAX shouldn't trigger an overflow!"); panic!("isize::MAX shouldn't trigger an overflow!");
} }
// Play it again, frank! (just to be sure) // Play it again, frank! (just to be sure)
if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP) { if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP).map_err(|e| e.kind()) {
panic!("isize::MAX shouldn't trigger an overflow!"); panic!("isize::MAX shouldn't trigger an overflow!");
} }
if guards_against_isize { if guards_against_isize {
// Check isize::MAX + 1 does count as overflow // Check isize::MAX + 1 does count as overflow
if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP + 1) { if let Err(CapacityOverflow) =
empty_bytes.try_reserve(MAX_CAP + 1).map_err(|e| e.kind())
{
} else { } else {
panic!("isize::MAX + 1 should trigger an overflow!") panic!("isize::MAX + 1 should trigger an overflow!")
} }
// Check usize::MAX does count as overflow // Check usize::MAX does count as overflow
if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_USIZE) { if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind())
{
} else { } else {
panic!("usize::MAX should trigger an overflow!") panic!("usize::MAX should trigger an overflow!")
} }
} else { } else {
// Check isize::MAX + 1 is an OOM // Check isize::MAX + 1 is an OOM
if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_CAP + 1) { if let Err(AllocError { .. }) =
empty_bytes.try_reserve(MAX_CAP + 1).map_err(|e| e.kind())
{
} else { } else {
panic!("isize::MAX + 1 should trigger an OOM!") panic!("isize::MAX + 1 should trigger an OOM!")
} }
// Check usize::MAX is an OOM // Check usize::MAX is an OOM
if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_USIZE) { if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind())
{
} else { } else {
panic!("usize::MAX should trigger an OOM!") panic!("usize::MAX should trigger an OOM!")
} }
@ -1517,25 +1523,27 @@ fn test_try_reserve() {
// Same basic idea, but with non-zero len // Same basic idea, but with non-zero len
let mut ten_bytes: Vec<u8> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; let mut ten_bytes: Vec<u8> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10) { if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) {
panic!("isize::MAX shouldn't trigger an overflow!"); panic!("isize::MAX shouldn't trigger an overflow!");
} }
if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10) { if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) {
panic!("isize::MAX shouldn't trigger an overflow!"); panic!("isize::MAX shouldn't trigger an overflow!");
} }
if guards_against_isize { if guards_against_isize {
if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 9) { if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind())
{
} else { } else {
panic!("isize::MAX + 1 should trigger an overflow!"); panic!("isize::MAX + 1 should trigger an overflow!");
} }
} else { } else {
if let Err(AllocError { .. }) = ten_bytes.try_reserve(MAX_CAP - 9) { if let Err(AllocError { .. }) = ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind())
{
} else { } else {
panic!("isize::MAX + 1 should trigger an OOM!") panic!("isize::MAX + 1 should trigger an OOM!")
} }
} }
// Should always overflow in the add-to-len // Should always overflow in the add-to-len
if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_USIZE) { if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()) {
} else { } else {
panic!("usize::MAX should trigger an overflow!") panic!("usize::MAX should trigger an overflow!")
} }
@ -1545,25 +1553,31 @@ fn test_try_reserve() {
// Same basic idea, but with interesting type size // Same basic idea, but with interesting type size
let mut ten_u32s: Vec<u32> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; let mut ten_u32s: Vec<u32> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP / 4 - 10) { if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP / 4 - 10).map_err(|e| e.kind())
{
panic!("isize::MAX shouldn't trigger an overflow!"); panic!("isize::MAX shouldn't trigger an overflow!");
} }
if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP / 4 - 10) { if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP / 4 - 10).map_err(|e| e.kind())
{
panic!("isize::MAX shouldn't trigger an overflow!"); panic!("isize::MAX shouldn't trigger an overflow!");
} }
if guards_against_isize { if guards_against_isize {
if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP / 4 - 9) { if let Err(CapacityOverflow) =
ten_u32s.try_reserve(MAX_CAP / 4 - 9).map_err(|e| e.kind())
{
} else { } else {
panic!("isize::MAX + 1 should trigger an overflow!"); panic!("isize::MAX + 1 should trigger an overflow!");
} }
} else { } else {
if let Err(AllocError { .. }) = ten_u32s.try_reserve(MAX_CAP / 4 - 9) { if let Err(AllocError { .. }) =
ten_u32s.try_reserve(MAX_CAP / 4 - 9).map_err(|e| e.kind())
{
} else { } else {
panic!("isize::MAX + 1 should trigger an OOM!") panic!("isize::MAX + 1 should trigger an OOM!")
} }
} }
// Should fail in the mul-by-size // Should fail in the mul-by-size
if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_USIZE - 20) { if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_USIZE - 20).map_err(|e| e.kind()) {
} else { } else {
panic!("usize::MAX should trigger an overflow!"); panic!("usize::MAX should trigger an overflow!");
} }
@ -1585,30 +1599,40 @@ fn test_try_reserve_exact() {
{ {
let mut empty_bytes: Vec<u8> = Vec::new(); let mut empty_bytes: Vec<u8> = Vec::new();
if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP) { if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP).map_err(|e| e.kind())
{
panic!("isize::MAX shouldn't trigger an overflow!"); panic!("isize::MAX shouldn't trigger an overflow!");
} }
if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP) { if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP).map_err(|e| e.kind())
{
panic!("isize::MAX shouldn't trigger an overflow!"); panic!("isize::MAX shouldn't trigger an overflow!");
} }
if guards_against_isize { if guards_against_isize {
if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP + 1) { if let Err(CapacityOverflow) =
empty_bytes.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind())
{
} else { } else {
panic!("isize::MAX + 1 should trigger an overflow!") panic!("isize::MAX + 1 should trigger an overflow!")
} }
if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_USIZE) { if let Err(CapacityOverflow) =
empty_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind())
{
} else { } else {
panic!("usize::MAX should trigger an overflow!") panic!("usize::MAX should trigger an overflow!")
} }
} else { } else {
if let Err(AllocError { .. }) = empty_bytes.try_reserve_exact(MAX_CAP + 1) { if let Err(AllocError { .. }) =
empty_bytes.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind())
{
} else { } else {
panic!("isize::MAX + 1 should trigger an OOM!") panic!("isize::MAX + 1 should trigger an OOM!")
} }
if let Err(AllocError { .. }) = empty_bytes.try_reserve_exact(MAX_USIZE) { if let Err(AllocError { .. }) =
empty_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind())
{
} else { } else {
panic!("usize::MAX should trigger an OOM!") panic!("usize::MAX should trigger an OOM!")
} }
@ -1618,24 +1642,33 @@ fn test_try_reserve_exact() {
{ {
let mut ten_bytes: Vec<u8> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; let mut ten_bytes: Vec<u8> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 10) { if let Err(CapacityOverflow) =
ten_bytes.try_reserve_exact(MAX_CAP - 10).map_err(|e| e.kind())
{
panic!("isize::MAX shouldn't trigger an overflow!"); panic!("isize::MAX shouldn't trigger an overflow!");
} }
if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 10) { if let Err(CapacityOverflow) =
ten_bytes.try_reserve_exact(MAX_CAP - 10).map_err(|e| e.kind())
{
panic!("isize::MAX shouldn't trigger an overflow!"); panic!("isize::MAX shouldn't trigger an overflow!");
} }
if guards_against_isize { if guards_against_isize {
if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { if let Err(CapacityOverflow) =
ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind())
{
} else { } else {
panic!("isize::MAX + 1 should trigger an overflow!"); panic!("isize::MAX + 1 should trigger an overflow!");
} }
} else { } else {
if let Err(AllocError { .. }) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { if let Err(AllocError { .. }) =
ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind())
{
} else { } else {
panic!("isize::MAX + 1 should trigger an OOM!") panic!("isize::MAX + 1 should trigger an OOM!")
} }
} }
if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_USIZE) { if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind())
{
} else { } else {
panic!("usize::MAX should trigger an overflow!") panic!("usize::MAX should trigger an overflow!")
} }
@ -1644,24 +1677,34 @@ fn test_try_reserve_exact() {
{ {
let mut ten_u32s: Vec<u32> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; let mut ten_u32s: Vec<u32> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_CAP / 4 - 10) { if let Err(CapacityOverflow) =
ten_u32s.try_reserve_exact(MAX_CAP / 4 - 10).map_err(|e| e.kind())
{
panic!("isize::MAX shouldn't trigger an overflow!"); panic!("isize::MAX shouldn't trigger an overflow!");
} }
if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_CAP / 4 - 10) { if let Err(CapacityOverflow) =
ten_u32s.try_reserve_exact(MAX_CAP / 4 - 10).map_err(|e| e.kind())
{
panic!("isize::MAX shouldn't trigger an overflow!"); panic!("isize::MAX shouldn't trigger an overflow!");
} }
if guards_against_isize { if guards_against_isize {
if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9) { if let Err(CapacityOverflow) =
ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9).map_err(|e| e.kind())
{
} else { } else {
panic!("isize::MAX + 1 should trigger an overflow!"); panic!("isize::MAX + 1 should trigger an overflow!");
} }
} else { } else {
if let Err(AllocError { .. }) = ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9) { if let Err(AllocError { .. }) =
ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9).map_err(|e| e.kind())
{
} else { } else {
panic!("isize::MAX + 1 should trigger an OOM!") panic!("isize::MAX + 1 should trigger an OOM!")
} }
} }
if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_USIZE - 20) { if let Err(CapacityOverflow) =
ten_u32s.try_reserve_exact(MAX_USIZE - 20).map_err(|e| e.kind())
{
} else { } else {
panic!("usize::MAX should trigger an overflow!") panic!("usize::MAX should trigger an overflow!")
} }

View file

@ -1,4 +1,4 @@
use std::collections::TryReserveError::*; use std::collections::TryReserveErrorKind::*;
use std::collections::{vec_deque::Drain, VecDeque}; use std::collections::{vec_deque::Drain, VecDeque};
use std::fmt::Debug; use std::fmt::Debug;
use std::mem::size_of; use std::mem::size_of;
@ -1171,23 +1171,26 @@ fn test_try_reserve() {
let mut empty_bytes: VecDeque<u8> = VecDeque::new(); let mut empty_bytes: VecDeque<u8> = VecDeque::new();
// Check isize::MAX doesn't count as an overflow // Check isize::MAX doesn't count as an overflow
if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP) { if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP).map_err(|e| e.kind()) {
panic!("isize::MAX shouldn't trigger an overflow!"); panic!("isize::MAX shouldn't trigger an overflow!");
} }
// Play it again, frank! (just to be sure) // Play it again, frank! (just to be sure)
if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP) { if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP).map_err(|e| e.kind()) {
panic!("isize::MAX shouldn't trigger an overflow!"); panic!("isize::MAX shouldn't trigger an overflow!");
} }
if guards_against_isize { if guards_against_isize {
// Check isize::MAX + 1 does count as overflow // Check isize::MAX + 1 does count as overflow
if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP + 1) { if let Err(CapacityOverflow) =
empty_bytes.try_reserve(MAX_CAP + 1).map_err(|e| e.kind())
{
} else { } else {
panic!("isize::MAX + 1 should trigger an overflow!") panic!("isize::MAX + 1 should trigger an overflow!")
} }
// Check usize::MAX does count as overflow // Check usize::MAX does count as overflow
if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_USIZE) { if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind())
{
} else { } else {
panic!("usize::MAX should trigger an overflow!") panic!("usize::MAX should trigger an overflow!")
} }
@ -1196,7 +1199,7 @@ fn test_try_reserve() {
// VecDeque starts with capacity 7, always adds 1 to the capacity // VecDeque starts with capacity 7, always adds 1 to the capacity
// and also rounds the number to next power of 2 so this is the // and also rounds the number to next power of 2 so this is the
// furthest we can go without triggering CapacityOverflow // furthest we can go without triggering CapacityOverflow
if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_CAP) { if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_CAP).map_err(|e| e.kind()) {
} else { } else {
panic!("isize::MAX + 1 should trigger an OOM!") panic!("isize::MAX + 1 should trigger an OOM!")
} }
@ -1207,25 +1210,27 @@ fn test_try_reserve() {
// Same basic idea, but with non-zero len // Same basic idea, but with non-zero len
let mut ten_bytes: VecDeque<u8> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect(); let mut ten_bytes: VecDeque<u8> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10) { if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) {
panic!("isize::MAX shouldn't trigger an overflow!"); panic!("isize::MAX shouldn't trigger an overflow!");
} }
if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10) { if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) {
panic!("isize::MAX shouldn't trigger an overflow!"); panic!("isize::MAX shouldn't trigger an overflow!");
} }
if guards_against_isize { if guards_against_isize {
if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 9) { if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind())
{
} else { } else {
panic!("isize::MAX + 1 should trigger an overflow!"); panic!("isize::MAX + 1 should trigger an overflow!");
} }
} else { } else {
if let Err(AllocError { .. }) = ten_bytes.try_reserve(MAX_CAP - 9) { if let Err(AllocError { .. }) = ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind())
{
} else { } else {
panic!("isize::MAX + 1 should trigger an OOM!") panic!("isize::MAX + 1 should trigger an OOM!")
} }
} }
// Should always overflow in the add-to-len // Should always overflow in the add-to-len
if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_USIZE) { if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()) {
} else { } else {
panic!("usize::MAX should trigger an overflow!") panic!("usize::MAX should trigger an overflow!")
} }
@ -1235,25 +1240,31 @@ fn test_try_reserve() {
// Same basic idea, but with interesting type size // Same basic idea, but with interesting type size
let mut ten_u32s: VecDeque<u32> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect(); let mut ten_u32s: VecDeque<u32> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP / 4 - 10) { if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP / 4 - 10).map_err(|e| e.kind())
{
panic!("isize::MAX shouldn't trigger an overflow!"); panic!("isize::MAX shouldn't trigger an overflow!");
} }
if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP / 4 - 10) { if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP / 4 - 10).map_err(|e| e.kind())
{
panic!("isize::MAX shouldn't trigger an overflow!"); panic!("isize::MAX shouldn't trigger an overflow!");
} }
if guards_against_isize { if guards_against_isize {
if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP / 4 - 9) { if let Err(CapacityOverflow) =
ten_u32s.try_reserve(MAX_CAP / 4 - 9).map_err(|e| e.kind())
{
} else { } else {
panic!("isize::MAX + 1 should trigger an overflow!"); panic!("isize::MAX + 1 should trigger an overflow!");
} }
} else { } else {
if let Err(AllocError { .. }) = ten_u32s.try_reserve(MAX_CAP / 4 - 9) { if let Err(AllocError { .. }) =
ten_u32s.try_reserve(MAX_CAP / 4 - 9).map_err(|e| e.kind())
{
} else { } else {
panic!("isize::MAX + 1 should trigger an OOM!") panic!("isize::MAX + 1 should trigger an OOM!")
} }
} }
// Should fail in the mul-by-size // Should fail in the mul-by-size
if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_USIZE - 20) { if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_USIZE - 20).map_err(|e| e.kind()) {
} else { } else {
panic!("usize::MAX should trigger an overflow!"); panic!("usize::MAX should trigger an overflow!");
} }
@ -1275,20 +1286,26 @@ fn test_try_reserve_exact() {
{ {
let mut empty_bytes: VecDeque<u8> = VecDeque::new(); let mut empty_bytes: VecDeque<u8> = VecDeque::new();
if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP) { if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP).map_err(|e| e.kind())
{
panic!("isize::MAX shouldn't trigger an overflow!"); panic!("isize::MAX shouldn't trigger an overflow!");
} }
if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP) { if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP).map_err(|e| e.kind())
{
panic!("isize::MAX shouldn't trigger an overflow!"); panic!("isize::MAX shouldn't trigger an overflow!");
} }
if guards_against_isize { if guards_against_isize {
if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP + 1) { if let Err(CapacityOverflow) =
empty_bytes.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind())
{
} else { } else {
panic!("isize::MAX + 1 should trigger an overflow!") panic!("isize::MAX + 1 should trigger an overflow!")
} }
if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_USIZE) { if let Err(CapacityOverflow) =
empty_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind())
{
} else { } else {
panic!("usize::MAX should trigger an overflow!") panic!("usize::MAX should trigger an overflow!")
} }
@ -1297,7 +1314,9 @@ fn test_try_reserve_exact() {
// VecDeque starts with capacity 7, always adds 1 to the capacity // VecDeque starts with capacity 7, always adds 1 to the capacity
// and also rounds the number to next power of 2 so this is the // and also rounds the number to next power of 2 so this is the
// furthest we can go without triggering CapacityOverflow // furthest we can go without triggering CapacityOverflow
if let Err(AllocError { .. }) = empty_bytes.try_reserve_exact(MAX_CAP) { if let Err(AllocError { .. }) =
empty_bytes.try_reserve_exact(MAX_CAP).map_err(|e| e.kind())
{
} else { } else {
panic!("isize::MAX + 1 should trigger an OOM!") panic!("isize::MAX + 1 should trigger an OOM!")
} }
@ -1307,24 +1326,33 @@ fn test_try_reserve_exact() {
{ {
let mut ten_bytes: VecDeque<u8> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect(); let mut ten_bytes: VecDeque<u8> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 10) { if let Err(CapacityOverflow) =
ten_bytes.try_reserve_exact(MAX_CAP - 10).map_err(|e| e.kind())
{
panic!("isize::MAX shouldn't trigger an overflow!"); panic!("isize::MAX shouldn't trigger an overflow!");
} }
if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 10) { if let Err(CapacityOverflow) =
ten_bytes.try_reserve_exact(MAX_CAP - 10).map_err(|e| e.kind())
{
panic!("isize::MAX shouldn't trigger an overflow!"); panic!("isize::MAX shouldn't trigger an overflow!");
} }
if guards_against_isize { if guards_against_isize {
if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { if let Err(CapacityOverflow) =
ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind())
{
} else { } else {
panic!("isize::MAX + 1 should trigger an overflow!"); panic!("isize::MAX + 1 should trigger an overflow!");
} }
} else { } else {
if let Err(AllocError { .. }) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { if let Err(AllocError { .. }) =
ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind())
{
} else { } else {
panic!("isize::MAX + 1 should trigger an OOM!") panic!("isize::MAX + 1 should trigger an OOM!")
} }
} }
if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_USIZE) { if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind())
{
} else { } else {
panic!("usize::MAX should trigger an overflow!") panic!("usize::MAX should trigger an overflow!")
} }
@ -1333,24 +1361,34 @@ fn test_try_reserve_exact() {
{ {
let mut ten_u32s: VecDeque<u32> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect(); let mut ten_u32s: VecDeque<u32> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_CAP / 4 - 10) { if let Err(CapacityOverflow) =
ten_u32s.try_reserve_exact(MAX_CAP / 4 - 10).map_err(|e| e.kind())
{
panic!("isize::MAX shouldn't trigger an overflow!"); panic!("isize::MAX shouldn't trigger an overflow!");
} }
if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_CAP / 4 - 10) { if let Err(CapacityOverflow) =
ten_u32s.try_reserve_exact(MAX_CAP / 4 - 10).map_err(|e| e.kind())
{
panic!("isize::MAX shouldn't trigger an overflow!"); panic!("isize::MAX shouldn't trigger an overflow!");
} }
if guards_against_isize { if guards_against_isize {
if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9) { if let Err(CapacityOverflow) =
ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9).map_err(|e| e.kind())
{
} else { } else {
panic!("isize::MAX + 1 should trigger an overflow!"); panic!("isize::MAX + 1 should trigger an overflow!");
} }
} else { } else {
if let Err(AllocError { .. }) = ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9) { if let Err(AllocError { .. }) =
ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9).map_err(|e| e.kind())
{
} else { } else {
panic!("isize::MAX + 1 should trigger an OOM!") panic!("isize::MAX + 1 should trigger an OOM!")
} }
} }
if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_USIZE - 20) { if let Err(CapacityOverflow) =
ten_u32s.try_reserve_exact(MAX_USIZE - 20).map_err(|e| e.kind())
{
} else { } else {
panic!("usize::MAX should trigger an overflow!") panic!("usize::MAX should trigger an overflow!")
} }

View file

@ -8,6 +8,7 @@ use hashbrown::hash_map as base;
use crate::borrow::Borrow; use crate::borrow::Borrow;
use crate::cell::Cell; use crate::cell::Cell;
use crate::collections::TryReserveError; use crate::collections::TryReserveError;
use crate::collections::TryReserveErrorKind;
use crate::fmt::{self, Debug}; use crate::fmt::{self, Debug};
#[allow(deprecated)] #[allow(deprecated)]
use crate::hash::{BuildHasher, Hash, Hasher, SipHasher13}; use crate::hash::{BuildHasher, Hash, Hasher, SipHasher13};
@ -2990,9 +2991,11 @@ fn map_entry<'a, K: 'a, V: 'a>(raw: base::RustcEntry<'a, K, V>) -> Entry<'a, K,
#[inline] #[inline]
pub(super) fn map_try_reserve_error(err: hashbrown::TryReserveError) -> TryReserveError { pub(super) fn map_try_reserve_error(err: hashbrown::TryReserveError) -> TryReserveError {
match err { match err {
hashbrown::TryReserveError::CapacityOverflow => TryReserveError::CapacityOverflow, hashbrown::TryReserveError::CapacityOverflow => {
TryReserveErrorKind::CapacityOverflow.into()
}
hashbrown::TryReserveError::AllocError { layout } => { hashbrown::TryReserveError::AllocError { layout } => {
TryReserveError::AllocError { layout, non_exhaustive: () } TryReserveErrorKind::AllocError { layout, non_exhaustive: () }.into()
} }
} }
} }

View file

@ -3,7 +3,7 @@ use super::HashMap;
use super::RandomState; use super::RandomState;
use crate::cell::RefCell; use crate::cell::RefCell;
use rand::{thread_rng, Rng}; use rand::{thread_rng, Rng};
use realstd::collections::TryReserveError::*; use realstd::collections::TryReserveErrorKind::*;
// https://github.com/rust-lang/rust/issues/62301 // https://github.com/rust-lang/rust/issues/62301
fn _assert_hashmap_is_unwind_safe() { fn _assert_hashmap_is_unwind_safe() {
@ -821,12 +821,12 @@ fn test_try_reserve() {
const MAX_USIZE: usize = usize::MAX; const MAX_USIZE: usize = usize::MAX;
if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_USIZE) { if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()) {
} else { } else {
panic!("usize::MAX should trigger an overflow!"); panic!("usize::MAX should trigger an overflow!");
} }
if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_USIZE / 8) { if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_USIZE / 8).map_err(|e| e.kind()) {
} else { } else {
panic!("usize::MAX / 8 should trigger an OOM!") panic!("usize::MAX / 8 should trigger an OOM!")
} }

View file

@ -422,6 +422,12 @@ pub use self::hash_set::HashSet;
#[unstable(feature = "try_reserve", reason = "new API", issue = "48043")] #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")]
pub use alloc_crate::collections::TryReserveError; pub use alloc_crate::collections::TryReserveError;
#[unstable(
feature = "try_reserve_kind",
reason = "Uncertain how much info should be exposed",
issue = "48043"
)]
pub use alloc_crate::collections::TryReserveErrorKind;
mod hash; mod hash;

View file

@ -326,6 +326,7 @@
#![feature(trace_macros)] #![feature(trace_macros)]
#![feature(try_blocks)] #![feature(try_blocks)]
#![feature(try_reserve)] #![feature(try_reserve)]
#![feature(try_reserve_kind)]
#![feature(unboxed_closures)] #![feature(unboxed_closures)]
#![feature(unsafe_cell_raw_get)] #![feature(unsafe_cell_raw_get)]
#![feature(unwrap_infallible)] #![feature(unwrap_infallible)]