//! Implement Fallible Vec use super::TryClone; use crate::TryReserveError; #[allow(unused_imports)] use alloc::alloc::{alloc, realloc, Layout}; use alloc::vec::Vec; use core::convert::TryInto as _; #[cfg(feature = "unstable")] #[macro_export] /// macro trying to create a vec, return a /// Result,TryReserveError> macro_rules! try_vec { ($elem:expr; $n:expr) => ( $crate::vec::try_from_elem($elem, $n) ); ($($x:expr),*) => ( match as $crate::boxed::FallibleBox<_>>::try_new([$($x),*]) { Err(e) => Err(e), Ok(b) => Ok(<[_]>::into_vec(b)), } ); ($($x:expr,)*) => ($crate::try_vec![$($x),*]) } /// trait implementing all fallible methods on vec pub trait FallibleVec { /// see reserve fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError>; /// see push fn try_push(&mut self, elem: T) -> Result<(), TryReserveError>; /// try push and give back ownership in case of error fn try_push_give_back(&mut self, elem: T) -> Result<(), (T, TryReserveError)>; /// see with capacity, (Self must be sized by the constraint of Result) fn try_with_capacity(capacity: usize) -> Result where Self: core::marker::Sized; /// see insert fn try_insert(&mut self, index: usize, element: T) -> Result<(), (T, TryReserveError)>; /// see append fn try_append(&mut self, other: &mut Self) -> Result<(), TryReserveError>; /// see resize, only works when the `value` implements Copy, otherwise, look at try_resize_no_copy fn try_resize(&mut self, new_len: usize, value: T) -> Result<(), TryReserveError> where T: Copy + Clone; fn try_resize_with(&mut self, new_len: usize, f: F) -> Result<(), TryReserveError> where F: FnMut() -> T; /// resize the vec by trying to clone the value repeatingly fn try_resize_no_copy(&mut self, new_len: usize, value: T) -> Result<(), TryReserveError> where T: TryClone; /// see resize, only works when the `value` implements Copy, otherwise, look at try_extend_from_slice_no_copy fn try_extend_from_slice(&mut self, other: &[T]) -> Result<(), TryReserveError> where T: Copy + Clone; /// extend the vec by trying to clone the value in `other` fn try_extend_from_slice_no_copy(&mut self, other: &[T]) -> Result<(), TryReserveError> where T: TryClone; } /// TryVec is a thin wrapper around alloc::vec::Vec to provide support for /// fallible allocation. /// /// See the crate documentation for more. #[derive(PartialEq)] pub struct TryVec { inner: Vec, } impl Default for TryVec { #[inline(always)] fn default() -> Self { Self { inner: Default::default(), } } } impl core::fmt::Debug for TryVec { #[inline] fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { self.inner.fmt(f) } } impl TryVec { #[inline(always)] pub fn new() -> Self { Self { inner: Vec::new() } } #[inline] pub fn with_capacity(capacity: usize) -> Result { Ok(Self { inner: FallibleVec::try_with_capacity(capacity)?, }) } #[inline(always)] pub fn append(&mut self, other: &mut Self) -> Result<(), TryReserveError> { FallibleVec::try_append(&mut self.inner, &mut other.inner) } #[inline(always)] pub fn as_mut_slice(&mut self) -> &mut [T] { self } #[inline(always)] pub fn as_slice(&self) -> &[T] { self } #[inline(always)] pub fn clear(&mut self) { self.inner.clear() } #[cfg(test)] pub fn into_inner(self) -> Vec { self.inner } #[inline(always)] pub fn is_empty(&self) -> bool { self.inner.is_empty() } #[inline(always)] pub fn iter_mut(&mut self) -> IterMut { IterMut { inner: self.inner.iter_mut(), } } #[inline(always)] pub fn iter(&self) -> Iter { Iter { inner: self.inner.iter(), } } #[inline(always)] pub fn pop(&mut self) -> Option { self.inner.pop() } #[inline(always)] pub fn push(&mut self, value: T) -> Result<(), TryReserveError> { FallibleVec::try_push(&mut self.inner, value) } #[inline(always)] pub fn reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { FallibleVec::try_reserve(&mut self.inner, additional) } #[inline(always)] pub fn resize_with(&mut self, new_len: usize, f: F) -> Result<(), TryReserveError> where F: FnMut() -> T, { FallibleVec::try_resize_with(&mut self.inner, new_len, f) } } impl TryClone for TryVec { #[inline] fn try_clone(&self) -> Result { self.as_slice().try_into() } } impl TryVec> { pub fn concat(&self) -> Result, TryReserveError> { let size = self.iter().map(|v| v.inner.len()).sum(); let mut result = TryVec::with_capacity(size)?; for v in self.iter() { result.inner.try_extend_from_slice_no_copy(&v.inner)?; } Ok(result) } } impl TryVec { #[inline(always)] pub fn extend_from_slice(&mut self, other: &[T]) -> Result<(), TryReserveError> { self.inner.try_extend_from_slice_no_copy(other) } } impl IntoIterator for TryVec { type Item = T; type IntoIter = alloc::vec::IntoIter; #[inline(always)] fn into_iter(self) -> Self::IntoIter { self.inner.into_iter() } } impl<'a, T> IntoIterator for &'a TryVec { type Item = &'a T; type IntoIter = alloc::slice::Iter<'a, T>; #[inline(always)] fn into_iter(self) -> Self::IntoIter { self.inner.iter() } } #[cfg(feature = "std_io")] pub mod std_io { use super::*; use std::io::{self, Read, Take, Write}; pub trait TryRead { fn try_read_to_end(&mut self, buf: &mut TryVec) -> io::Result; #[inline] fn read_into_try_vec(&mut self) -> io::Result> { let mut buf = TryVec::new(); self.try_read_to_end(&mut buf)?; Ok(buf) } } impl TryRead for Take { /// This function reserves the upper limit of what `src` can generate before /// reading all bytes until EOF in this source, placing them into `buf`. If the /// allocation is unsuccessful, or reading from the source generates an error /// before reaching EOF, this will return an error. Otherwise, it will return /// the number of bytes read. /// /// Since `Take::limit()` may return a value greater than the number of bytes /// which can be read from the source, it's possible this function may fail /// in the allocation phase even though allocating the number of bytes available /// to read would have succeeded. In general, it is assumed that the callers /// have accurate knowledge of the number of bytes of interest and have created /// `src` accordingly. #[inline] fn try_read_to_end(&mut self, buf: &mut TryVec) -> io::Result { try_read_up_to(self, self.limit(), buf) } } /// Read up to `limit` bytes from `src`, placing them into `buf` and returning the /// number of bytes read. Space for `limit` additional bytes is reserved in `buf`, so /// this function will return an error if the allocation fails. pub fn try_read_up_to( src: &mut R, limit: u64, buf: &mut TryVec, ) -> io::Result { let additional = limit .try_into() .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; buf.reserve(additional) .map_err(|_| io::Error::new(io::ErrorKind::Other, "reserve allocation failed"))?; let bytes_read = src.take(limit).read_to_end(&mut buf.inner)?; Ok(bytes_read) } impl Write for TryVec { fn write(&mut self, buf: &[u8]) -> io::Result { self.extend_from_slice(buf) .map_err(|_| io::Error::new(io::ErrorKind::Other, "extend_from_slice failed"))?; Ok(buf.len()) } #[inline(always)] fn flush(&mut self) -> io::Result<()> { Ok(()) } } #[cfg(test)] mod tests { use super::*; #[test] fn try_read_to_end() { let mut src = b"1234567890".take(5); let mut buf = TryVec::new(); src.try_read_to_end(&mut buf).unwrap(); assert_eq!(buf.len(), 5); assert_eq!(buf, b"12345".as_ref()); } #[test] fn read_into_try_vec() { let mut src = b"1234567890".take(5); let buf = src.read_into_try_vec().unwrap(); assert_eq!(buf.len(), 5); assert_eq!(buf, b"12345".as_ref()); } #[test] fn read_into_try_vec_oom() { let mut src = b"1234567890".take(core::usize::MAX.try_into().expect("usize < u64")); assert!(src.read_into_try_vec().is_err()); } #[test] fn try_read_up_to() { let src = b"1234567890"; let mut buf = TryVec::new(); super::try_read_up_to(&mut src.as_ref(), 5, &mut buf).unwrap(); assert_eq!(buf.len(), 5); assert_eq!(buf, b"12345".as_ref()); } #[test] fn try_read_up_to_oom() { let src = b"1234567890"; let mut buf = TryVec::new(); let limit = core::usize::MAX.try_into().expect("usize < u64"); let res = super::try_read_up_to(&mut src.as_ref(), limit, &mut buf); assert!(res.is_err()); } } } impl PartialEq> for TryVec { #[inline(always)] fn eq(&self, other: &Vec) -> bool { self.inner.eq(other) } } impl<'a, T: PartialEq> PartialEq<&'a [T]> for TryVec { #[inline(always)] fn eq(&self, other: &&[T]) -> bool { self.inner.eq(other) } } impl PartialEq<&str> for TryVec { #[inline] fn eq(&self, other: &&str) -> bool { self.as_slice() == other.as_bytes() } } impl core::convert::AsRef<[u8]> for TryVec { #[inline(always)] fn as_ref(&self) -> &[u8] { self.inner.as_ref() } } impl core::convert::From> for TryVec { #[inline(always)] fn from(value: Vec) -> Self { Self { inner: value } } } impl core::convert::TryFrom<&[T]> for TryVec { type Error = TryReserveError; #[inline] fn try_from(value: &[T]) -> Result { let mut v = Self::new(); v.inner.try_extend_from_slice_no_copy(value)?; Ok(v) } } impl core::convert::TryFrom<&str> for TryVec { type Error = TryReserveError; #[inline] fn try_from(value: &str) -> Result { let mut v = Self::new(); v.extend_from_slice(value.as_bytes())?; Ok(v) } } impl core::ops::Deref for TryVec { type Target = [T]; #[inline(always)] fn deref(&self) -> &[T] { self.inner.deref() } } impl core::ops::DerefMut for TryVec { fn deref_mut(&mut self) -> &mut [T] { self.inner.deref_mut() } } pub struct Iter<'a, T> { inner: alloc::slice::Iter<'a, T>, } impl<'a, T> Iterator for Iter<'a, T> { type Item = &'a T; #[inline(always)] fn next(&mut self) -> Option { self.inner.next() } #[inline(always)] fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } pub struct IterMut<'a, T> { inner: alloc::slice::IterMut<'a, T>, } impl<'a, T> Iterator for IterMut<'a, T> { type Item = &'a mut T; #[inline(always)] fn next(&mut self) -> Option { self.inner.next() } #[inline(always)] fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } } /// Grow capacity exponentially #[cold] fn vec_try_reserve_for_growth(v: &mut Vec, additional: usize) -> Result<(), TryReserveError> { // saturating, because can't use CapacityOverflow here if rust_1_57 flag is enabled FallibleVec::try_reserve(v, additional.max(v.capacity().saturating_mul(2) - v.len())) } fn needs_to_grow(v: &Vec, len: usize) -> bool { v.len().checked_add(len).map_or(true, |needed| needed > v.capacity()) } #[cfg(not(any(feature = "unstable", feature = "rust_1_57")))] fn vec_try_reserve(v: &mut Vec, additional: usize) -> Result<(), TryReserveError> { let available = v.capacity().checked_sub(v.len()).expect("capacity >= len"); if additional > available { let increase = additional .checked_sub(available) .expect("additional > available"); let new_cap = v .capacity() .checked_add(increase) .ok_or(TryReserveError::CapacityOverflow)?; vec_try_extend(v, new_cap)?; debug_assert!(v.capacity() == new_cap); } Ok(()) } #[cfg(not(any(feature = "unstable", feature = "rust_1_57")))] fn vec_try_extend(v: &mut Vec, new_cap: usize) -> Result<(), TryReserveError> { let old_len = v.len(); let old_cap: usize = v.capacity(); if old_cap >= new_cap { return Ok(()); } let elem_size = core::mem::size_of::(); let new_alloc_size = new_cap .checked_mul(elem_size) .filter(|size| *size <= isize::MAX as usize) .ok_or(TryReserveError::CapacityOverflow)?; // required for alloc safety // See https://doc.rust-lang.org/stable/std/alloc/trait.GlobalAlloc.html#safety-1 // Should be unreachable given prior `old_cap >= new_cap` check. assert!(new_alloc_size > 0); let align = core::mem::align_of::(); let (new_ptr, layout) = { if old_cap == 0 { let layout = Layout::from_size_align(new_alloc_size, align).expect("Invalid layout"); let new_ptr = unsafe { alloc(layout) }; (new_ptr, layout) } else { let old_alloc_size = old_cap .checked_mul(elem_size) .ok_or(TryReserveError::CapacityOverflow)?; let layout = Layout::from_size_align(old_alloc_size, align).expect("Invalid layout"); let new_ptr = unsafe { realloc(v.as_mut_ptr() as *mut u8, layout, new_alloc_size) }; (new_ptr, layout) } }; if new_ptr.is_null() { return Err(TryReserveError::AllocError { layout }); } let new_vec = unsafe { Vec::from_raw_parts(new_ptr.cast(), old_len, new_cap) }; core::mem::forget(core::mem::replace(v, new_vec)); Ok(()) } impl FallibleVec for Vec { #[inline(always)] fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { #[cfg(all(feature = "unstable", not(feature = "rust_1_57")))] { self.try_reserve(additional) } #[cfg(all(not(feature = "unstable"), not(feature = "rust_1_57")))] { vec_try_reserve(self, additional) } #[cfg(feature = "rust_1_57")] { // TryReserveError is an opaque type in 1.57 self.try_reserve(additional).map_err(|_| { crate::make_try_reserve_error(self.len(), additional, core::mem::size_of::(), core::mem::align_of::()) }) } } #[inline] fn try_push(&mut self, elem: T) -> Result<(), TryReserveError> { if self.len() == self.capacity() { vec_try_reserve_for_growth(self, 1)?; } Ok(self.push(elem)) } #[inline] fn try_push_give_back(&mut self, elem: T) -> Result<(), (T, TryReserveError)> { if self.len() == self.capacity() { if let Err(e) = vec_try_reserve_for_growth(self, 1) { return Err((elem, e)); } } Ok(self.push(elem)) } #[inline] fn try_with_capacity(capacity: usize) -> Result where Self: core::marker::Sized, { let mut n = Self::new(); FallibleVec::try_reserve(&mut n, capacity)?; Ok(n) } #[inline] fn try_insert(&mut self, index: usize, element: T) -> Result<(), (T, TryReserveError)> { if self.len() == self.capacity() { if let Err(e) = vec_try_reserve_for_growth(self, 1) { return Err((element, e)); } } Ok(self.insert(index, element)) } #[inline] fn try_append(&mut self, other: &mut Self) -> Result<(), TryReserveError> { FallibleVec::try_reserve(self, other.len())?; Ok(self.append(other)) } fn try_resize(&mut self, new_len: usize, value: T) -> Result<(), TryReserveError> where T: Copy + Clone, { let len = self.len(); if new_len > len { FallibleVec::try_reserve(self, new_len - len)?; } Ok(self.resize(new_len, value)) } 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 { FallibleVec::try_reserve(self, new_len - len)?; } Ok(self.resize_with(new_len, f)) } fn try_resize_no_copy(&mut self, new_len: usize, value: T) -> Result<(), TryReserveError> where T: TryClone, { let len = self.len(); if new_len > len { self.try_extend_with(new_len - len, TryExtendElement(value)) } else { Ok(self.truncate(new_len)) } } #[inline] fn try_extend_from_slice(&mut self, other: &[T]) -> Result<(), TryReserveError> where T: Clone, { if needs_to_grow(self, other.len()) { vec_try_reserve_for_growth(self, other.len())?; } Ok(self.extend_from_slice(other)) } fn try_extend_from_slice_no_copy(&mut self, other: &[T]) -> Result<(), TryReserveError> where T: TryClone, { if needs_to_grow(self, other.len()) { vec_try_reserve_for_growth(self, other.len())?; } let mut len = self.len(); let mut iterator = other.iter(); while let Some(element) = iterator.next() { unsafe { core::ptr::write(self.as_mut_ptr().add(len), element.try_clone()?); // NB can't overflow since we would have had to alloc the address space len += 1; self.set_len(len); } } Ok(()) } } trait ExtendWith { fn next(&mut self) -> Result; fn last(self) -> T; } struct TryExtendElement(T); impl ExtendWith for TryExtendElement { #[inline(always)] fn next(&mut self) -> Result { self.0.try_clone() } #[inline(always)] fn last(self) -> T { self.0 } } trait TryExtend { fn try_extend_with>( &mut self, n: usize, value: E, ) -> Result<(), TryReserveError>; } impl TryExtend for Vec { /// Extend the vector by `n` values, using the given generator. fn try_extend_with>( &mut self, n: usize, mut value: E, ) -> Result<(), TryReserveError> { if needs_to_grow(self, n) { vec_try_reserve_for_growth(self, n)?; } unsafe { let mut ptr = self.as_mut_ptr().add(self.len()); let mut local_len = self.len(); // Write all elements except the last one for _ in 1..n { core::ptr::write(ptr, value.next()?); ptr = ptr.offset(1); // Increment the length in every step in case next() panics local_len += 1; self.set_len(local_len); } if n > 0 { // We can write the last element directly without cloning needlessly core::ptr::write(ptr, value.last()); local_len += 1; self.set_len(local_len); } // len set by scope guard } Ok(()) } } trait Truncate { fn truncate(&mut self, len: usize); } impl Truncate for Vec { fn truncate(&mut self, len: usize) { let current_len = self.len(); unsafe { let mut ptr = self.as_mut_ptr().add(current_len); // Set the final length at the end, keeping in mind that // dropping an element might panic. Works around a missed // optimization, as seen in the following issue: // https://github.com/rust-lang/rust/issues/51802 let mut local_len = self.len(); // drop any extra elements for _ in len..current_len { ptr = ptr.offset(-1); core::ptr::drop_in_place(ptr); local_len -= 1; self.set_len(local_len); } } } } /// try creating a vec from an `elem` cloned `n` times, see std::from_elem #[cfg(feature = "unstable")] pub fn try_from_elem(elem: T, n: usize) -> Result, TryReserveError> { ::try_from_elem(elem, n) } // Specialization trait used for Vec::from_elem #[cfg(feature = "unstable")] trait SpecFromElem: Sized { fn try_from_elem(elem: Self, n: usize) -> Result, TryReserveError>; } #[cfg(feature = "unstable")] impl SpecFromElem for T { default fn try_from_elem(elem: Self, n: usize) -> Result, TryReserveError> { let mut v = Vec::new(); v.try_resize_no_copy(n, elem)?; Ok(v) } } #[cfg(feature = "unstable")] impl SpecFromElem for u8 { #[inline] fn try_from_elem(elem: u8, n: usize) -> Result, TryReserveError> { unsafe { let mut v: Vec = FallibleVec::try_with_capacity(n)?; core::ptr::write_bytes(v.as_mut_ptr(), elem, n); v.set_len(n); Ok(v) } } } impl TryClone for Vec { #[inline] fn try_clone(&self) -> Result where Self: core::marker::Sized, { let mut v = Vec::new(); v.try_extend_from_slice_no_copy(self)?; Ok(v) } } pub trait TryFromIterator: Sized { fn try_from_iterator>(iterator: T) -> Result; } impl TryFromIterator for Vec { fn try_from_iterator>(iterator: T) -> Result where T: IntoIterator, { let mut new = Self::new(); for i in iterator { new.try_push(i)?; } Ok(new) } } pub trait TryCollect { fn try_collect>(self) -> Result; } impl TryCollect for T where T: IntoIterator, { #[inline(always)] fn try_collect>(self) -> Result { C::try_from_iterator(self) } } #[cfg(test)] mod tests { use super::*; #[test] #[cfg(feature = "unstable")] fn vec() { // let v: Vec = from_elem(1, 10); let v: Vec> = try_vec![try_vec![42; 10].unwrap(); 100].unwrap(); println!("{:?}", v); let v2 = try_vec![0, 1, 2]; println!("{:?}", v2); assert_eq!(2 + 2, 4); } #[test] fn try_clone_vec() { // let v: Vec = from_elem(1, 10); let v = vec![42; 100]; assert_eq!(v.try_clone().unwrap(), v); } #[test] fn try_clone_oom() { let layout = Layout::new::(); let v = unsafe { Vec::::from_raw_parts(alloc(layout), core::isize::MAX as usize, core::isize::MAX as usize) }; assert!(v.try_clone().is_err()); } #[test] fn tryvec_try_clone_oom() { let layout = Layout::new::(); let inner = unsafe { Vec::::from_raw_parts(alloc(layout), core::isize::MAX as usize, core::isize::MAX as usize) }; let tv = TryVec { inner }; assert!(tv.try_clone().is_err()); } // #[test] // fn try_out_of_mem() { // let v = try_vec![42_u8; 1000000000]; // assert_eq!(v.try_clone().unwrap(), v); // } #[test] fn oom() { let mut vec: Vec = Vec::new(); match FallibleVec::try_reserve(&mut vec, core::usize::MAX / std::mem::size_of::()) { Ok(_) => panic!("it should be OOM"), _ => (), } match FallibleVec::try_reserve(&mut vec, core::usize::MAX) { Ok(_) => panic!("it should be OOM"), _ => (), } } #[test] fn tryvec_oom() { let mut vec: TryVec = TryVec::new(); match vec.reserve(core::usize::MAX / std::mem::size_of::()) { Ok(_) => panic!("it should be OOM"), _ => (), } match vec.reserve(core::usize::MAX) { Ok(_) => panic!("it should be OOM"), _ => (), } } #[test] fn try_reserve() { let mut vec: Vec<_> = vec![1]; let additional_room = vec.capacity() - vec.len(); let additional = additional_room + 1; let old_cap = vec.capacity(); FallibleVec::try_reserve(&mut vec, additional).unwrap(); assert!(vec.capacity() > old_cap); } #[test] fn tryvec_reserve() { let mut vec: TryVec<_> = vec![1].into(); let old_cap = vec.inner.capacity(); let new_cap = old_cap + 1; vec.reserve(new_cap).unwrap(); assert!(vec.inner.capacity() >= new_cap); } #[test] fn try_reserve_idempotent() { let mut vec: Vec<_> = vec![1]; let additional_room = vec.capacity() - vec.len(); let additional = additional_room + 1; FallibleVec::try_reserve(&mut vec, additional).unwrap(); let cap_after_reserve = vec.capacity(); FallibleVec::try_reserve(&mut vec, additional).unwrap(); assert_eq!(vec.capacity(), cap_after_reserve); } #[test] fn tryvec_reserve_idempotent() { let mut vec: TryVec<_> = vec![1].into(); let old_cap = vec.inner.capacity(); let new_cap = old_cap + 1; vec.reserve(new_cap).unwrap(); let cap_after_reserve = vec.inner.capacity(); vec.reserve(new_cap).unwrap(); assert_eq!(cap_after_reserve, vec.inner.capacity()); } #[test] fn capacity_overflow() { let mut vec: Vec<_> = vec![1]; match FallibleVec::try_reserve(&mut vec, core::usize::MAX) { Ok(_) => panic!("capacity calculation should overflow"), _ => (), } } #[test] fn tryvec_capacity_overflow() { let mut vec: TryVec<_> = vec![1].into(); match vec.reserve(core::usize::MAX) { Ok(_) => panic!("capacity calculation should overflow"), _ => (), } } #[test] fn extend_from_slice() { let mut vec: Vec = b"foo".as_ref().into(); vec.shrink_to_fit(); vec.reserve(5); assert_eq!(8, vec.capacity()); vec.try_extend_from_slice(b"bar").unwrap(); assert_eq!(vec, b"foobar".as_ref()); vec.try_extend_from_slice(b"1").unwrap(); assert_eq!(vec, b"foobar1".as_ref()); assert_eq!(8, vec.capacity()); vec.try_extend_from_slice(b"11").unwrap(); assert_eq!(16, vec.capacity()); } #[test] fn tryvec_extend_from_slice() { let mut vec: TryVec = b"foo".as_ref().try_into().unwrap(); vec.extend_from_slice(b"bar").unwrap(); assert_eq!(vec, b"foobar".as_ref()); } #[test] #[cfg(not(any(feature = "unstable", feature = "rust_1_57")))] fn try_extend_zst() { let mut vec: Vec<()> = Vec::new(); assert_eq!(vec.capacity(), core::usize::MAX); assert!(vec_try_extend(&mut vec, 10).is_ok()); assert!(vec_try_extend(&mut vec, core::usize::MAX).is_ok()); } #[test] fn try_reserve_zst() { let mut vec: Vec<()> = Vec::new(); assert!(FallibleVec::try_reserve(&mut vec, core::usize::MAX).is_ok()); } }