diff options
| author | Laurențiu Nicola <lnicola@users.noreply.github.com> | 2024-12-23 10:12:23 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-12-23 10:12:23 +0000 |
| commit | 8dbdcc03ebfd5d3c21671d8a021669dc79d93038 (patch) | |
| tree | e61d058d30fdd35c4a306fde5be669b08092a4fd /library/alloc | |
| parent | 63a3c394617b114a8fa6e54401700b3adee65a7d (diff) | |
| parent | 0180d2d16f5f5d60384a594568a98a6e6f8eea59 (diff) | |
Merge pull request #18746 from lnicola/sync-from-rust
minor: Sync from downstream
Diffstat (limited to 'library/alloc')
23 files changed, 550 insertions, 162 deletions
diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index 04b7315e650..ae34fc65326 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -10,9 +10,6 @@ use core::hint; #[cfg(not(test))] use core::ptr::{self, NonNull}; -#[cfg(test)] -mod tests; - extern "Rust" { // These are the magic symbols to call the global allocator. rustc generates // them to call `__rg_alloc` etc. if there is a `#[global_allocator]` attribute diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index e0f94428cfa..23b85fbd4eb 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -1985,7 +1985,8 @@ impl<Args: Tuple, F: Fn<Args> + ?Sized, A: Allocator> Fn<Args> for Box<F, A> { } } -#[unstable(feature = "async_fn_traits", issue = "none")] +#[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] +#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))] impl<Args: Tuple, F: AsyncFnOnce<Args> + ?Sized, A: Allocator> AsyncFnOnce<Args> for Box<F, A> { type Output = F::Output; type CallOnceFuture = F::CallOnceFuture; @@ -1995,7 +1996,8 @@ impl<Args: Tuple, F: AsyncFnOnce<Args> + ?Sized, A: Allocator> AsyncFnOnce<Args> } } -#[unstable(feature = "async_fn_traits", issue = "none")] +#[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] +#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))] impl<Args: Tuple, F: AsyncFnMut<Args> + ?Sized, A: Allocator> AsyncFnMut<Args> for Box<F, A> { type CallRefFuture<'a> = F::CallRefFuture<'a> @@ -2007,7 +2009,8 @@ impl<Args: Tuple, F: AsyncFnMut<Args> + ?Sized, A: Allocator> AsyncFnMut<Args> f } } -#[unstable(feature = "async_fn_traits", issue = "none")] +#[cfg_attr(bootstrap, unstable(feature = "async_closure", issue = "62290"))] +#[cfg_attr(not(bootstrap), stable(feature = "async_closure", since = "CURRENT_RUSTC_VERSION"))] impl<Args: Tuple, F: AsyncFn<Args> + ?Sized, A: Allocator> AsyncFn<Args> for Box<F, A> { extern "rust-call" fn async_call(&self, args: Args) -> Self::CallRefFuture<'_> { F::async_call(self, args) diff --git a/library/alloc/src/collections/binary_heap/mod.rs b/library/alloc/src/collections/binary_heap/mod.rs index 5d3997e14e3..965fd63a529 100644 --- a/library/alloc/src/collections/binary_heap/mod.rs +++ b/library/alloc/src/collections/binary_heap/mod.rs @@ -155,9 +155,6 @@ use crate::collections::TryReserveError; use crate::slice; use crate::vec::{self, AsVecIntoIter, Vec}; -#[cfg(test)] -mod tests; - /// A priority queue implemented with a binary heap. /// /// This will be a max-heap. @@ -534,8 +531,7 @@ impl<T: Ord, A: Allocator> BinaryHeap<T, A> { /// heap.push(1); /// heap.push(5); /// heap.push(2); - /// { - /// let mut val = heap.peek_mut().unwrap(); + /// if let Some(mut val) = heap.peek_mut() { /// *val = 0; /// } /// assert_eq!(heap.peek(), Some(&2)); diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs index ca0ea1ec8b2..13168b7a39f 100644 --- a/library/alloc/src/collections/linked_list.rs +++ b/library/alloc/src/collections/linked_list.rs @@ -1939,9 +1939,7 @@ pub struct ExtractIf< T: 'a, F: 'a, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, -> where - F: FnMut(&mut T) -> bool, -{ +> { list: &'a mut LinkedList<T, A>, it: Option<NonNull<Node<T>>>, pred: F, @@ -1979,10 +1977,7 @@ where } #[unstable(feature = "extract_if", reason = "recently added", issue = "43244")] -impl<T: fmt::Debug, F> fmt::Debug for ExtractIf<'_, T, F> -where - F: FnMut(&mut T) -> bool, -{ +impl<T: fmt::Debug, F> fmt::Debug for ExtractIf<'_, T, F> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("ExtractIf").field(&self.list).finish() } diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index cf51a84bb6f..0b6a55297e1 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -1869,7 +1869,7 @@ impl<T, A: Allocator> VecDeque<T, A> { /// /// # Panics /// - /// Panics if `index` is greater than deque's length + /// Panics if `index` is strictly greater than deque's length /// /// # Examples /// @@ -1884,6 +1884,9 @@ impl<T, A: Allocator> VecDeque<T, A> { /// /// vec_deque.insert(1, 'd'); /// assert_eq!(vec_deque, &['a', 'd', 'b', 'c']); + /// + /// vec_deque.insert(4, 'e'); + /// assert_eq!(vec_deque, &['a', 'd', 'b', 'c', 'e']); /// ``` #[stable(feature = "deque_extras_15", since = "1.5.0")] #[track_caller] @@ -1928,13 +1931,13 @@ impl<T, A: Allocator> VecDeque<T, A> { /// use std::collections::VecDeque; /// /// let mut buf = VecDeque::new(); - /// buf.push_back(1); - /// buf.push_back(2); - /// buf.push_back(3); - /// assert_eq!(buf, [1, 2, 3]); + /// buf.push_back('a'); + /// buf.push_back('b'); + /// buf.push_back('c'); + /// assert_eq!(buf, ['a', 'b', 'c']); /// - /// assert_eq!(buf.remove(1), Some(2)); - /// assert_eq!(buf, [1, 3]); + /// assert_eq!(buf.remove(1), Some('b')); + /// assert_eq!(buf, ['a', 'c']); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_confusables("delete", "take")] @@ -1982,10 +1985,10 @@ impl<T, A: Allocator> VecDeque<T, A> { /// ``` /// use std::collections::VecDeque; /// - /// let mut buf: VecDeque<_> = [1, 2, 3].into(); + /// let mut buf: VecDeque<_> = ['a', 'b', 'c'].into(); /// let buf2 = buf.split_off(1); - /// assert_eq!(buf, [1]); - /// assert_eq!(buf2, [2, 3]); + /// assert_eq!(buf, ['a']); + /// assert_eq!(buf2, ['b', 'c']); /// ``` #[inline] #[must_use = "use `.truncate()` if you don't need the other half"] diff --git a/library/alloc/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs index 9c074383a5e..c7d6d8a55c2 100644 --- a/library/alloc/src/ffi/c_str.rs +++ b/library/alloc/src/ffi/c_str.rs @@ -1,8 +1,5 @@ //! [`CString`] and its related types. -#[cfg(test)] -mod tests; - use core::borrow::Borrow; use core::ffi::{CStr, c_char}; use core::num::NonZero; diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 927c3aa23b9..40759cb0ba8 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -91,6 +91,7 @@ // // Library features: // tidy-alphabetical-start +#![cfg_attr(bootstrap, feature(async_closure))] #![cfg_attr(test, feature(str_as_str))] #![feature(alloc_layout_extra)] #![feature(allocator_api)] @@ -99,7 +100,6 @@ #![feature(array_windows)] #![feature(ascii_char)] #![feature(assert_matches)] -#![feature(async_closure)] #![feature(async_fn_traits)] #![feature(async_iterator)] #![feature(box_uninit_write)] @@ -239,8 +239,6 @@ pub mod string; pub mod sync; #[cfg(all(not(no_global_oom_handling), not(no_rc), not(no_sync)))] pub mod task; -#[cfg(test)] -mod tests; pub mod vec; #[doc(hidden)] diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 7aa1457b1df..b7ec3af9818 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -795,7 +795,7 @@ impl<T, A: Allocator> Rc<T, A> { let uninit_ptr: NonNull<_> = (unsafe { &mut *uninit_raw_ptr }).into(); let init_ptr: NonNull<RcInner<T>> = uninit_ptr.cast(); - let weak = Weak { ptr: init_ptr, alloc: alloc }; + let weak = Weak { ptr: init_ptr, alloc }; // It's important we don't give up ownership of the weak pointer, or // else the memory might be freed by the time `data_fn` returns. If @@ -2232,12 +2232,20 @@ impl<T: ?Sized, A: Allocator> Deref for Rc<T, A> { #[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")] unsafe impl<T: ?Sized, A: Allocator> PinCoerceUnsized for Rc<T, A> {} +//#[unstable(feature = "unique_rc_arc", issue = "112566")] +#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")] +unsafe impl<T: ?Sized, A: Allocator> PinCoerceUnsized for UniqueRc<T, A> {} + #[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")] unsafe impl<T: ?Sized, A: Allocator> PinCoerceUnsized for Weak<T, A> {} #[unstable(feature = "deref_pure_trait", issue = "87121")] unsafe impl<T: ?Sized, A: Allocator> DerefPure for Rc<T, A> {} +//#[unstable(feature = "unique_rc_arc", issue = "112566")] +#[unstable(feature = "deref_pure_trait", issue = "87121")] +unsafe impl<T: ?Sized, A: Allocator> DerefPure for UniqueRc<T, A> {} + #[unstable(feature = "legacy_receiver_trait", issue = "none")] impl<T: ?Sized> LegacyReceiver for Rc<T> {} @@ -3684,7 +3692,6 @@ fn data_offset_align(align: usize) -> usize { /// previous example, `UniqueRc` allows for more flexibility in the construction of cyclic data, /// including fallible or async constructors. #[unstable(feature = "unique_rc_arc", issue = "112566")] -#[derive(Debug)] pub struct UniqueRc< T: ?Sized, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, @@ -3694,12 +3701,253 @@ pub struct UniqueRc< alloc: A, } +// Not necessary for correctness since `UniqueRc` contains `NonNull`, +// but having an explicit negative impl is nice for documentation purposes +// and results in nicer error messages. +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl<T: ?Sized, A: Allocator> !Send for UniqueRc<T, A> {} + +// Not necessary for correctness since `UniqueRc` contains `NonNull`, +// but having an explicit negative impl is nice for documentation purposes +// and results in nicer error messages. +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl<T: ?Sized, A: Allocator> !Sync for UniqueRc<T, A> {} + #[unstable(feature = "unique_rc_arc", issue = "112566")] impl<T: ?Sized + Unsize<U>, U: ?Sized, A: Allocator> CoerceUnsized<UniqueRc<U, A>> for UniqueRc<T, A> { } +//#[unstable(feature = "unique_rc_arc", issue = "112566")] +#[unstable(feature = "dispatch_from_dyn", issue = "none")] +impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<UniqueRc<U>> for UniqueRc<T> {} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl<T: ?Sized + fmt::Display, A: Allocator> fmt::Display for UniqueRc<T, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&**self, f) + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl<T: ?Sized + fmt::Debug, A: Allocator> fmt::Debug for UniqueRc<T, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl<T: ?Sized, A: Allocator> fmt::Pointer for UniqueRc<T, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Pointer::fmt(&(&raw const **self), f) + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl<T: ?Sized, A: Allocator> borrow::Borrow<T> for UniqueRc<T, A> { + fn borrow(&self) -> &T { + &**self + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl<T: ?Sized, A: Allocator> borrow::BorrowMut<T> for UniqueRc<T, A> { + fn borrow_mut(&mut self) -> &mut T { + &mut **self + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl<T: ?Sized, A: Allocator> AsRef<T> for UniqueRc<T, A> { + fn as_ref(&self) -> &T { + &**self + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl<T: ?Sized, A: Allocator> AsMut<T> for UniqueRc<T, A> { + fn as_mut(&mut self) -> &mut T { + &mut **self + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl<T: ?Sized, A: Allocator> Unpin for UniqueRc<T, A> {} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl<T: ?Sized + PartialEq, A: Allocator> PartialEq for UniqueRc<T, A> { + /// Equality for two `UniqueRc`s. + /// + /// Two `UniqueRc`s are equal if their inner values are equal. + /// + /// # Examples + /// + /// ``` + /// #![feature(unique_rc_arc)] + /// use std::rc::UniqueRc; + /// + /// let five = UniqueRc::new(5); + /// + /// assert!(five == UniqueRc::new(5)); + /// ``` + #[inline] + fn eq(&self, other: &Self) -> bool { + PartialEq::eq(&**self, &**other) + } + + /// Inequality for two `UniqueRc`s. + /// + /// Two `UniqueRc`s are not equal if their inner values are not equal. + /// + /// # Examples + /// + /// ``` + /// #![feature(unique_rc_arc)] + /// use std::rc::UniqueRc; + /// + /// let five = UniqueRc::new(5); + /// + /// assert!(five != UniqueRc::new(6)); + /// ``` + #[inline] + fn ne(&self, other: &Self) -> bool { + PartialEq::ne(&**self, &**other) + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl<T: ?Sized + PartialOrd, A: Allocator> PartialOrd for UniqueRc<T, A> { + /// Partial comparison for two `UniqueRc`s. + /// + /// The two are compared by calling `partial_cmp()` on their inner values. + /// + /// # Examples + /// + /// ``` + /// #![feature(unique_rc_arc)] + /// use std::rc::UniqueRc; + /// use std::cmp::Ordering; + /// + /// let five = UniqueRc::new(5); + /// + /// assert_eq!(Some(Ordering::Less), five.partial_cmp(&UniqueRc::new(6))); + /// ``` + #[inline(always)] + fn partial_cmp(&self, other: &UniqueRc<T, A>) -> Option<Ordering> { + (**self).partial_cmp(&**other) + } + + /// Less-than comparison for two `UniqueRc`s. + /// + /// The two are compared by calling `<` on their inner values. + /// + /// # Examples + /// + /// ``` + /// #![feature(unique_rc_arc)] + /// use std::rc::UniqueRc; + /// + /// let five = UniqueRc::new(5); + /// + /// assert!(five < UniqueRc::new(6)); + /// ``` + #[inline(always)] + fn lt(&self, other: &UniqueRc<T, A>) -> bool { + **self < **other + } + + /// 'Less than or equal to' comparison for two `UniqueRc`s. + /// + /// The two are compared by calling `<=` on their inner values. + /// + /// # Examples + /// + /// ``` + /// #![feature(unique_rc_arc)] + /// use std::rc::UniqueRc; + /// + /// let five = UniqueRc::new(5); + /// + /// assert!(five <= UniqueRc::new(5)); + /// ``` + #[inline(always)] + fn le(&self, other: &UniqueRc<T, A>) -> bool { + **self <= **other + } + + /// Greater-than comparison for two `UniqueRc`s. + /// + /// The two are compared by calling `>` on their inner values. + /// + /// # Examples + /// + /// ``` + /// #![feature(unique_rc_arc)] + /// use std::rc::UniqueRc; + /// + /// let five = UniqueRc::new(5); + /// + /// assert!(five > UniqueRc::new(4)); + /// ``` + #[inline(always)] + fn gt(&self, other: &UniqueRc<T, A>) -> bool { + **self > **other + } + + /// 'Greater than or equal to' comparison for two `UniqueRc`s. + /// + /// The two are compared by calling `>=` on their inner values. + /// + /// # Examples + /// + /// ``` + /// #![feature(unique_rc_arc)] + /// use std::rc::UniqueRc; + /// + /// let five = UniqueRc::new(5); + /// + /// assert!(five >= UniqueRc::new(5)); + /// ``` + #[inline(always)] + fn ge(&self, other: &UniqueRc<T, A>) -> bool { + **self >= **other + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl<T: ?Sized + Ord, A: Allocator> Ord for UniqueRc<T, A> { + /// Comparison for two `UniqueRc`s. + /// + /// The two are compared by calling `cmp()` on their inner values. + /// + /// # Examples + /// + /// ``` + /// #![feature(unique_rc_arc)] + /// use std::rc::UniqueRc; + /// use std::cmp::Ordering; + /// + /// let five = UniqueRc::new(5); + /// + /// assert_eq!(Ordering::Less, five.cmp(&UniqueRc::new(6))); + /// ``` + #[inline] + fn cmp(&self, other: &UniqueRc<T, A>) -> Ordering { + (**self).cmp(&**other) + } +} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl<T: ?Sized + Eq, A: Allocator> Eq for UniqueRc<T, A> {} + +#[unstable(feature = "unique_rc_arc", issue = "112566")] +impl<T: ?Sized + Hash, A: Allocator> Hash for UniqueRc<T, A> { + fn hash<H: Hasher>(&self, state: &mut H) { + (**self).hash(state); + } +} + // Depends on A = Global impl<T> UniqueRc<T> { /// Creates a new `UniqueRc`. @@ -3791,9 +4039,6 @@ impl<T: ?Sized, A: Allocator> Deref for UniqueRc<T, A> { } } -#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")] -unsafe impl<T: ?Sized> PinCoerceUnsized for UniqueRc<T> {} - #[unstable(feature = "unique_rc_arc", issue = "112566")] impl<T: ?Sized, A: Allocator> DerefMut for UniqueRc<T, A> { fn deref_mut(&mut self) -> &mut T { diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index e3c7835f1d1..edc8d99f2f9 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -27,6 +27,8 @@ pub use core::slice::ArrayChunksMut; pub use core::slice::ArrayWindows; #[stable(feature = "inherent_ascii_escape", since = "1.60.0")] pub use core::slice::EscapeAscii; +#[unstable(feature = "get_many_mut", issue = "104642")] +pub use core::slice::GetManyMutError; #[stable(feature = "slice_get_slice", since = "1.28.0")] pub use core::slice::SliceIndex; #[cfg(not(no_global_oom_handling))] diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index c5378d78d59..23d060d2158 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -2675,12 +2675,25 @@ pub trait ToString { #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl<T: fmt::Display + ?Sized> ToString for T { + #[inline] + fn to_string(&self) -> String { + <Self as SpecToString>::spec_to_string(self) + } +} + +#[cfg(not(no_global_oom_handling))] +trait SpecToString { + fn spec_to_string(&self) -> String; +} + +#[cfg(not(no_global_oom_handling))] +impl<T: fmt::Display + ?Sized> SpecToString for T { // A common guideline is to not inline generic functions. However, // removing `#[inline]` from this method causes non-negligible regressions. // See <https://github.com/rust-lang/rust/pull/74852>, the last attempt // to try to remove it. #[inline] - default fn to_string(&self) -> String { + default fn spec_to_string(&self) -> String { let mut buf = String::new(); let mut formatter = core::fmt::Formatter::new(&mut buf, core::fmt::FormattingOptions::new()); @@ -2691,42 +2704,34 @@ impl<T: fmt::Display + ?Sized> ToString for T { } } -#[doc(hidden)] #[cfg(not(no_global_oom_handling))] -#[unstable(feature = "ascii_char", issue = "110998")] -impl ToString for core::ascii::Char { +impl SpecToString for core::ascii::Char { #[inline] - fn to_string(&self) -> String { + fn spec_to_string(&self) -> String { self.as_str().to_owned() } } -#[doc(hidden)] #[cfg(not(no_global_oom_handling))] -#[stable(feature = "char_to_string_specialization", since = "1.46.0")] -impl ToString for char { +impl SpecToString for char { #[inline] - fn to_string(&self) -> String { + fn spec_to_string(&self) -> String { String::from(self.encode_utf8(&mut [0; 4])) } } -#[doc(hidden)] #[cfg(not(no_global_oom_handling))] -#[stable(feature = "bool_to_string_specialization", since = "1.68.0")] -impl ToString for bool { +impl SpecToString for bool { #[inline] - fn to_string(&self) -> String { + fn spec_to_string(&self) -> String { String::from(if *self { "true" } else { "false" }) } } -#[doc(hidden)] #[cfg(not(no_global_oom_handling))] -#[stable(feature = "u8_to_string_specialization", since = "1.54.0")] -impl ToString for u8 { +impl SpecToString for u8 { #[inline] - fn to_string(&self) -> String { + fn spec_to_string(&self) -> String { let mut buf = String::with_capacity(3); let mut n = *self; if n >= 10 { @@ -2742,12 +2747,10 @@ impl ToString for u8 { } } -#[doc(hidden)] #[cfg(not(no_global_oom_handling))] -#[stable(feature = "i8_to_string_specialization", since = "1.54.0")] -impl ToString for i8 { +impl SpecToString for i8 { #[inline] - fn to_string(&self) -> String { + fn spec_to_string(&self) -> String { let mut buf = String::with_capacity(4); if self.is_negative() { buf.push('-'); @@ -2788,11 +2791,9 @@ macro_rules! to_string_expr_wrap_in_deref { macro_rules! to_string_str { {$($($x:ident)*),+} => { $( - #[doc(hidden)] - #[stable(feature = "str_to_string_specialization", since = "1.9.0")] - impl ToString for to_string_str_wrap_in_ref!($($x)*) { + impl SpecToString for to_string_str_wrap_in_ref!($($x)*) { #[inline] - fn to_string(&self) -> String { + fn spec_to_string(&self) -> String { String::from(to_string_expr_wrap_in_deref!(self ; $($x)*)) } } @@ -2816,32 +2817,26 @@ to_string_str! { x, } -#[doc(hidden)] #[cfg(not(no_global_oom_handling))] -#[stable(feature = "cow_str_to_string_specialization", since = "1.17.0")] -impl ToString for Cow<'_, str> { +impl SpecToString for Cow<'_, str> { #[inline] - fn to_string(&self) -> String { + fn spec_to_string(&self) -> String { self[..].to_owned() } } -#[doc(hidden)] #[cfg(not(no_global_oom_handling))] -#[stable(feature = "string_to_string_specialization", since = "1.17.0")] -impl ToString for String { +impl SpecToString for String { #[inline] - fn to_string(&self) -> String { + fn spec_to_string(&self) -> String { self.to_owned() } } -#[doc(hidden)] #[cfg(not(no_global_oom_handling))] -#[stable(feature = "fmt_arguments_to_string_specialization", since = "1.71.0")] -impl ToString for fmt::Arguments<'_> { +impl SpecToString for fmt::Arguments<'_> { #[inline] - fn to_string(&self) -> String { + fn spec_to_string(&self) -> String { crate::fmt::format(*self) } } diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index b8bdd298c27..9be0b3e3e88 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -39,9 +39,6 @@ use crate::string::String; #[cfg(not(no_global_oom_handling))] use crate::vec::Vec; -#[cfg(test)] -mod tests; - /// A soft limit on the amount of references that may be made to an `Arc`. /// /// Going above this limit will abort your program (although not @@ -787,7 +784,7 @@ impl<T, A: Allocator> Arc<T, A> { let uninit_ptr: NonNull<_> = (unsafe { &mut *uninit_raw_ptr }).into(); let init_ptr: NonNull<ArcInner<T>> = uninit_ptr.cast(); - let weak = Weak { ptr: init_ptr, alloc: alloc }; + let weak = Weak { ptr: init_ptr, alloc }; // It's important we don't give up ownership of the weak pointer, or // else the memory might be freed by the time `data_fn` returns. If diff --git a/library/alloc/src/vec/extract_if.rs b/library/alloc/src/vec/extract_if.rs index 72d51e89044..4db13981596 100644 --- a/library/alloc/src/vec/extract_if.rs +++ b/library/alloc/src/vec/extract_if.rs @@ -1,3 +1,4 @@ +use core::ops::{Range, RangeBounds}; use core::{ptr, slice}; use super::Vec; @@ -14,7 +15,7 @@ use crate::alloc::{Allocator, Global}; /// #![feature(extract_if)] /// /// let mut v = vec![0, 1, 2]; -/// let iter: std::vec::ExtractIf<'_, _, _> = v.extract_if(|x| *x % 2 == 0); +/// let iter: std::vec::ExtractIf<'_, _, _> = v.extract_if(.., |x| *x % 2 == 0); /// ``` #[unstable(feature = "extract_if", reason = "recently added", issue = "43244")] #[derive(Debug)] @@ -24,24 +25,32 @@ pub struct ExtractIf< T, F, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, -> where - F: FnMut(&mut T) -> bool, -{ - pub(super) vec: &'a mut Vec<T, A>, +> { + vec: &'a mut Vec<T, A>, /// The index of the item that will be inspected by the next call to `next`. - pub(super) idx: usize, + idx: usize, + /// Elements at and beyond this point will be retained. Must be equal or smaller than `old_len`. + end: usize, /// The number of items that have been drained (removed) thus far. - pub(super) del: usize, + del: usize, /// The original length of `vec` prior to draining. - pub(super) old_len: usize, + old_len: usize, /// The filter test predicate. - pub(super) pred: F, + pred: F, } -impl<T, F, A: Allocator> ExtractIf<'_, T, F, A> -where - F: FnMut(&mut T) -> bool, -{ +impl<'a, T, F, A: Allocator> ExtractIf<'a, T, F, A> { + pub(super) fn new<R: RangeBounds<usize>>(vec: &'a mut Vec<T, A>, pred: F, range: R) -> Self { + let old_len = vec.len(); + let Range { start, end } = slice::range(range, ..old_len); + + // Guard against the vec getting leaked (leak amplification) + unsafe { + vec.set_len(0); + } + ExtractIf { vec, idx: start, del: 0, end, old_len, pred } + } + /// Returns a reference to the underlying allocator. #[unstable(feature = "allocator_api", issue = "32838")] #[inline] @@ -59,7 +68,7 @@ where fn next(&mut self) -> Option<T> { unsafe { - while self.idx < self.old_len { + while self.idx < self.end { let i = self.idx; let v = slice::from_raw_parts_mut(self.vec.as_mut_ptr(), self.old_len); let drained = (self.pred)(&mut v[i]); @@ -82,24 +91,15 @@ where } fn size_hint(&self) -> (usize, Option<usize>) { - (0, Some(self.old_len - self.idx)) + (0, Some(self.end - self.idx)) } } #[unstable(feature = "extract_if", reason = "recently added", issue = "43244")] -impl<T, F, A: Allocator> Drop for ExtractIf<'_, T, F, A> -where - F: FnMut(&mut T) -> bool, -{ +impl<T, F, A: Allocator> Drop for ExtractIf<'_, T, F, A> { fn drop(&mut self) { unsafe { if self.idx < self.old_len && self.del > 0 { - // This is a pretty messed up state, and there isn't really an - // obviously right thing to do. We don't want to keep trying - // to execute `pred`, so we just backshift all the unprocessed - // elements and tell the vec that they still exist. The backshift - // is required to prevent a double-drop of the last successfully - // drained item prior to a panic in the predicate. let ptr = self.vec.as_mut_ptr(); let src = ptr.add(self.idx); let dst = src.sub(self.del); diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 457be3ae77f..3a706d5f36b 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -56,7 +56,6 @@ #[cfg(not(no_global_oom_handling))] use core::cmp; use core::cmp::Ordering; -use core::fmt; use core::hash::{Hash, Hasher}; #[cfg(not(no_global_oom_handling))] use core::iter; @@ -65,6 +64,7 @@ use core::mem::{self, ManuallyDrop, MaybeUninit, SizedTypeProperties}; use core::ops::{self, Index, IndexMut, Range, RangeBounds}; use core::ptr::{self, NonNull}; use core::slice::{self, SliceIndex}; +use core::{fmt, intrinsics}; #[unstable(feature = "extract_if", reason = "recently added", issue = "43244")] pub use self::extract_if::ExtractIf; @@ -1824,7 +1824,10 @@ impl<T, A: Allocator> Vec<T, A> { /// /// # Examples /// - /// This method can be useful for situations in which the vector + /// See [`spare_capacity_mut()`] for an example with safe + /// initialization of capacity elements and use of this method. + /// + /// `set_len()` can be useful for situations in which the vector /// is serving as a buffer for other code, particularly over FFI: /// /// ```no_run @@ -1884,6 +1887,8 @@ impl<T, A: Allocator> Vec<T, A> { /// /// Normally, here, one would use [`clear`] instead to correctly drop /// the contents and thus not leak memory. + /// + /// [`spare_capacity_mut()`]: Vec::spare_capacity_mut #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn set_len(&mut self, new_len: usize) { @@ -1953,11 +1958,11 @@ impl<T, A: Allocator> Vec<T, A> { /// # Examples /// /// ``` - /// let mut vec = vec![1, 2, 3]; - /// vec.insert(1, 4); - /// assert_eq!(vec, [1, 4, 2, 3]); - /// vec.insert(4, 5); - /// assert_eq!(vec, [1, 4, 2, 3, 5]); + /// let mut vec = vec!['a', 'b', 'c']; + /// vec.insert(1, 'd'); + /// assert_eq!(vec, ['a', 'd', 'b', 'c']); + /// vec.insert(4, 'e'); + /// assert_eq!(vec, ['a', 'd', 'b', 'c', 'e']); /// ``` /// /// # Time complexity @@ -2024,9 +2029,9 @@ impl<T, A: Allocator> Vec<T, A> { /// # Examples /// /// ``` - /// let mut v = vec![1, 2, 3]; - /// assert_eq!(v.remove(1), 2); - /// assert_eq!(v, [1, 3]); + /// let mut v = vec!['a', 'b', 'c']; + /// assert_eq!(v.remove(1), 'b'); + /// assert_eq!(v, ['a', 'c']); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[track_caller] @@ -2675,7 +2680,14 @@ impl<T, A: Allocator> Vec<T, A> { #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] #[rustc_confusables("length", "size")] pub const fn len(&self) -> usize { - self.len + let len = self.len; + + // SAFETY: The maximum capacity of `Vec<T>` is `isize::MAX` bytes, so the maximum value can + // be returned is `usize::checked_div(mem::size_of::<T>()).unwrap_or(usize::MAX)`, which + // matches the definition of `T::MAX_SLICE_LEN`. + unsafe { intrinsics::assume(len <= T::MAX_SLICE_LEN) }; + + len } /// Returns `true` if the vector contains no elements. @@ -2715,10 +2727,10 @@ impl<T, A: Allocator> Vec<T, A> { /// # Examples /// /// ``` - /// let mut vec = vec![1, 2, 3]; + /// let mut vec = vec!['a', 'b', 'c']; /// let vec2 = vec.split_off(1); - /// assert_eq!(vec, [1]); - /// assert_eq!(vec2, [2, 3]); + /// assert_eq!(vec, ['a']); + /// assert_eq!(vec2, ['b', 'c']); /// ``` #[cfg(not(no_global_oom_handling))] #[inline] @@ -2982,9 +2994,9 @@ impl<T: Clone, A: Allocator> Vec<T, A> { /// vec.resize(3, "world"); /// assert_eq!(vec, ["hello", "world", "world"]); /// - /// let mut vec = vec![1, 2, 3, 4]; - /// vec.resize(2, 0); - /// assert_eq!(vec, [1, 2]); + /// let mut vec = vec!['a', 'b', 'c', 'd']; + /// vec.resize(2, '_'); + /// assert_eq!(vec, ['a', 'b']); /// ``` #[cfg(not(no_global_oom_handling))] #[stable(feature = "vec_resize", since = "1.5.0")] @@ -3615,12 +3627,15 @@ impl<T, A: Allocator> Vec<T, A> { Splice { drain: self.drain(range), replace_with: replace_with.into_iter() } } - /// Creates an iterator which uses a closure to determine if an element should be removed. + /// Creates an iterator which uses a closure to determine if element in the range should be removed. /// /// If the closure returns true, then the element is removed and yielded. /// If the closure returns false, the element will remain in the vector and will not be yielded /// by the iterator. /// + /// Only elements that fall in the provided range are considered for extraction, but any elements + /// after the range will still have to be moved if any element has been extracted. + /// /// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating /// or the iteration short-circuits, then the remaining elements will be retained. /// Use [`retain`] with a negated predicate if you do not need the returned iterator. @@ -3630,10 +3645,12 @@ impl<T, A: Allocator> Vec<T, A> { /// Using this method is equivalent to the following code: /// /// ``` + /// # use std::cmp::min; /// # let some_predicate = |x: &mut i32| { *x == 2 || *x == 3 || *x == 6 }; /// # let mut vec = vec![1, 2, 3, 4, 5, 6]; - /// let mut i = 0; - /// while i < vec.len() { + /// # let range = 1..4; + /// let mut i = range.start; + /// while i < min(vec.len(), range.end) { /// if some_predicate(&mut vec[i]) { /// let val = vec.remove(i); /// // your code here @@ -3648,8 +3665,12 @@ impl<T, A: Allocator> Vec<T, A> { /// But `extract_if` is easier to use. `extract_if` is also more efficient, /// because it can backshift the elements of the array in bulk. /// - /// Note that `extract_if` also lets you mutate every element in the filter closure, - /// regardless of whether you choose to keep or remove it. + /// Note that `extract_if` also lets you mutate the elements passed to the filter closure, + /// regardless of whether you choose to keep or remove them. + /// + /// # Panics + /// + /// If `range` is out of bounds. /// /// # Examples /// @@ -3659,25 +3680,29 @@ impl<T, A: Allocator> Vec<T, A> { /// #![feature(extract_if)] /// let mut numbers = vec![1, 2, 3, 4, 5, 6, 8, 9, 11, 13, 14, 15]; /// - /// let evens = numbers.extract_if(|x| *x % 2 == 0).collect::<Vec<_>>(); + /// let evens = numbers.extract_if(.., |x| *x % 2 == 0).collect::<Vec<_>>(); /// let odds = numbers; /// /// assert_eq!(evens, vec![2, 4, 6, 8, 14]); /// assert_eq!(odds, vec![1, 3, 5, 9, 11, 13, 15]); /// ``` + /// + /// Using the range argument to only process a part of the vector: + /// + /// ``` + /// #![feature(extract_if)] + /// let mut items = vec![0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 2, 1, 2]; + /// let ones = items.extract_if(7.., |x| *x == 1).collect::<Vec<_>>(); + /// assert_eq!(items, vec![0, 0, 0, 0, 0, 0, 0, 2, 2, 2]); + /// assert_eq!(ones.len(), 3); + /// ``` #[unstable(feature = "extract_if", reason = "recently added", issue = "43244")] - pub fn extract_if<F>(&mut self, filter: F) -> ExtractIf<'_, T, F, A> + pub fn extract_if<F, R>(&mut self, range: R, filter: F) -> ExtractIf<'_, T, F, A> where F: FnMut(&mut T) -> bool, + R: RangeBounds<usize>, { - let old_len = self.len(); - - // Guard against us getting leaked (leak amplification) - unsafe { - self.set_len(0); - } - - ExtractIf { vec: self, idx: 0, del: 0, old_len, pred: filter } + ExtractIf::new(self, filter, range) } } diff --git a/library/alloc/src/alloc/tests.rs b/library/alloc/tests/alloc.rs index 5d6077f057a..1e722d66795 100644 --- a/library/alloc/src/alloc/tests.rs +++ b/library/alloc/tests/alloc.rs @@ -1,10 +1,9 @@ -use super::*; +use alloc::alloc::*; +use alloc::boxed::Box; extern crate test; use test::Bencher; -use crate::boxed::Box; - #[test] fn allocate_zeroed() { unsafe { diff --git a/library/alloc/src/ffi/c_str/tests.rs b/library/alloc/tests/c_str2.rs index d6b797347c2..0f4c27fa123 100644 --- a/library/alloc/src/ffi/c_str/tests.rs +++ b/library/alloc/tests/c_str2.rs @@ -1,11 +1,12 @@ +use alloc::ffi::CString; +use alloc::rc::Rc; +use alloc::sync::Arc; use core::assert_matches::assert_matches; -use core::ffi::FromBytesUntilNulError; +use core::ffi::{CStr, FromBytesUntilNulError, c_char}; #[allow(deprecated)] use core::hash::SipHasher13 as DefaultHasher; use core::hash::{Hash, Hasher}; -use super::*; - #[test] fn c_to_rust() { let data = b"123\0"; diff --git a/library/alloc/src/collections/binary_heap/tests.rs b/library/alloc/tests/collections/binary_heap.rs index ad0a020a1a9..55405ffe8c4 100644 --- a/library/alloc/src/collections/binary_heap/tests.rs +++ b/library/alloc/tests/collections/binary_heap.rs @@ -1,7 +1,9 @@ +use alloc::boxed::Box; +use alloc::collections::binary_heap::*; +use std::iter::TrustedLen; +use std::mem; use std::panic::{AssertUnwindSafe, catch_unwind}; -use super::*; -use crate::boxed::Box; use crate::testing::crash_test::{CrashTestDummy, Panic}; #[test] @@ -531,7 +533,7 @@ fn panic_safe() { self.0.partial_cmp(&other.0) } } - let mut rng = crate::test_helpers::test_rng(); + let mut rng = crate::test_rng(); const DATASZ: usize = 32; // Miri is too slow let ntest = if cfg!(miri) { 1 } else { 10 }; diff --git a/library/alloc/tests/collections/mod.rs b/library/alloc/tests/collections/mod.rs new file mode 100644 index 00000000000..e73f3aaef8c --- /dev/null +++ b/library/alloc/tests/collections/mod.rs @@ -0,0 +1 @@ +mod binary_heap; diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index bcab17e7b2d..393bdfe48b7 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -5,8 +5,10 @@ #![feature(btree_extract_if)] #![feature(cow_is_borrowed)] #![feature(core_intrinsics)] +#![feature(downcast_unchecked)] #![feature(extract_if)] #![feature(exact_size_is_empty)] +#![feature(hashmap_internals)] #![feature(linked_list_cursors)] #![feature(map_try_insert)] #![feature(pattern)] @@ -29,9 +31,11 @@ #![feature(const_str_from_utf8)] #![feature(panic_update_hook)] #![feature(pointer_is_aligned_to)] +#![feature(test)] #![feature(thin_box)] #![feature(drain_keep_rest)] #![feature(local_waker)] +#![feature(str_as_str)] #![feature(strict_provenance_lints)] #![feature(vec_pop_if)] #![feature(unique_rc_arc)] @@ -40,25 +44,33 @@ #![deny(fuzzy_provenance_casts)] #![deny(unsafe_op_in_unsafe_fn)] +extern crate test; + use std::hash::{DefaultHasher, Hash, Hasher}; +mod alloc; mod arc; mod autotraits; mod borrow; mod boxed; mod btree_set_hash; mod c_str; +mod c_str2; +mod collections; mod const_fns; mod cow_str; mod fmt; mod heap; mod linked_list; +mod misc_tests; mod rc; mod slice; mod sort; mod str; mod string; +mod sync; mod task; +mod testing; mod thin_box; mod vec; mod vec_deque; @@ -69,6 +81,18 @@ fn hash<T: Hash>(t: &T) -> u64 { s.finish() } +/// Copied from `std::test_helpers::test_rng`, since these tests rely on the +/// seed not being the same for every RNG invocation too. +fn test_rng() -> rand_xorshift::XorShiftRng { + use std::hash::{BuildHasher, Hash, Hasher}; + let mut hasher = std::hash::RandomState::new().build_hasher(); + std::panic::Location::caller().hash(&mut hasher); + let hc64 = hasher.finish(); + let seed_vec = hc64.to_le_bytes().into_iter().chain(0u8..8).collect::<Vec<u8>>(); + let seed: [u8; 16] = seed_vec.as_slice().try_into().unwrap(); + rand::SeedableRng::from_seed(seed) +} + // FIXME: Instantiated functions with i128 in the signature is not supported in Emscripten. // See https://github.com/kripken/emscripten-fastcomp/issues/169 #[cfg(not(target_os = "emscripten"))] diff --git a/library/alloc/src/tests.rs b/library/alloc/tests/misc_tests.rs index b95d11cb07e..b95d11cb07e 100644 --- a/library/alloc/src/tests.rs +++ b/library/alloc/tests/misc_tests.rs diff --git a/library/alloc/src/sync/tests.rs b/library/alloc/tests/sync.rs index de5816fda97..7a9a4abfdc6 100644 --- a/library/alloc/src/sync/tests.rs +++ b/library/alloc/tests/sync.rs @@ -1,14 +1,16 @@ +use alloc::sync::*; +use std::alloc::{AllocError, Allocator, Layout}; +use std::any::Any; use std::clone::Clone; use std::mem::MaybeUninit; use std::option::Option::None; +use std::ptr::NonNull; use std::sync::Mutex; -use std::sync::atomic::AtomicUsize; -use std::sync::atomic::Ordering::SeqCst; +use std::sync::atomic::Ordering::*; +use std::sync::atomic::{self, AtomicUsize}; use std::sync::mpsc::channel; use std::thread; -use super::*; - struct Canary(*mut AtomicUsize); impl Drop for Canary { diff --git a/library/alloc/tests/testing/crash_test.rs b/library/alloc/tests/testing/crash_test.rs new file mode 100644 index 00000000000..502fe6c10c6 --- /dev/null +++ b/library/alloc/tests/testing/crash_test.rs @@ -0,0 +1,80 @@ +use std::cmp::Ordering; +use std::fmt::Debug; +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering::SeqCst; + +/// A blueprint for crash test dummy instances that monitor drops. +/// Some instances may be configured to panic at some point. +/// +/// Crash test dummies are identified and ordered by an id, so they can be used +/// as keys in a BTreeMap. +#[derive(Debug)] +pub struct CrashTestDummy { + pub id: usize, + dropped: AtomicUsize, +} + +impl CrashTestDummy { + /// Creates a crash test dummy design. The `id` determines order and equality of instances. + pub fn new(id: usize) -> CrashTestDummy { + CrashTestDummy { id, dropped: AtomicUsize::new(0) } + } + + /// Creates an instance of a crash test dummy that records what events it experiences + /// and optionally panics. + pub fn spawn(&self, panic: Panic) -> Instance<'_> { + Instance { origin: self, panic } + } + + /// Returns how many times instances of the dummy have been dropped. + pub fn dropped(&self) -> usize { + self.dropped.load(SeqCst) + } +} + +#[derive(Debug)] +pub struct Instance<'a> { + origin: &'a CrashTestDummy, + panic: Panic, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum Panic { + Never, + InDrop, +} + +impl Instance<'_> { + pub fn id(&self) -> usize { + self.origin.id + } +} + +impl Drop for Instance<'_> { + fn drop(&mut self) { + self.origin.dropped.fetch_add(1, SeqCst); + if self.panic == Panic::InDrop { + panic!("panic in `drop`"); + } + } +} + +impl PartialOrd for Instance<'_> { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + self.id().partial_cmp(&other.id()) + } +} + +impl Ord for Instance<'_> { + fn cmp(&self, other: &Self) -> Ordering { + self.id().cmp(&other.id()) + } +} + +impl PartialEq for Instance<'_> { + fn eq(&self, other: &Self) -> bool { + self.id().eq(&other.id()) + } +} + +impl Eq for Instance<'_> {} diff --git a/library/alloc/tests/testing/mod.rs b/library/alloc/tests/testing/mod.rs new file mode 100644 index 00000000000..0a3dd191dc8 --- /dev/null +++ b/library/alloc/tests/testing/mod.rs @@ -0,0 +1 @@ +pub mod crash_test; diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs index 0f27fdff3e1..84679827ba1 100644 --- a/library/alloc/tests/vec.rs +++ b/library/alloc/tests/vec.rs @@ -1414,7 +1414,7 @@ fn extract_if_empty() { let mut vec: Vec<i32> = vec![]; { - let mut iter = vec.extract_if(|_| true); + let mut iter = vec.extract_if(.., |_| true); assert_eq!(iter.size_hint(), (0, Some(0))); assert_eq!(iter.next(), None); assert_eq!(iter.size_hint(), (0, Some(0))); @@ -1431,7 +1431,7 @@ fn extract_if_zst() { let initial_len = vec.len(); let mut count = 0; { - let mut iter = vec.extract_if(|_| true); + let mut iter = vec.extract_if(.., |_| true); assert_eq!(iter.size_hint(), (0, Some(initial_len))); while let Some(_) = iter.next() { count += 1; @@ -1454,7 +1454,7 @@ fn extract_if_false() { let initial_len = vec.len(); let mut count = 0; { - let mut iter = vec.extract_if(|_| false); + let mut iter = vec.extract_if(.., |_| false); assert_eq!(iter.size_hint(), (0, Some(initial_len))); for _ in iter.by_ref() { count += 1; @@ -1476,7 +1476,7 @@ fn extract_if_true() { let initial_len = vec.len(); let mut count = 0; { - let mut iter = vec.extract_if(|_| true); + let mut iter = vec.extract_if(.., |_| true); assert_eq!(iter.size_hint(), (0, Some(initial_len))); while let Some(_) = iter.next() { count += 1; @@ -1493,6 +1493,31 @@ fn extract_if_true() { } #[test] +fn extract_if_ranges() { + let mut vec = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + + let mut count = 0; + let it = vec.extract_if(1..=3, |_| { + count += 1; + true + }); + assert_eq!(it.collect::<Vec<_>>(), vec![1, 2, 3]); + assert_eq!(vec, vec![0, 4, 5, 6, 7, 8, 9, 10]); + assert_eq!(count, 3); + + let it = vec.extract_if(1..=3, |_| false); + assert_eq!(it.collect::<Vec<_>>(), vec![]); + assert_eq!(vec, vec![0, 4, 5, 6, 7, 8, 9, 10]); +} + +#[test] +#[should_panic] +fn extract_if_out_of_bounds() { + let mut vec = vec![0, 1]; + let _ = vec.extract_if(5.., |_| true).for_each(drop); +} + +#[test] fn extract_if_complex() { { // [+xxx++++++xxxxx++++x+x++] @@ -1501,7 +1526,7 @@ fn extract_if_complex() { 39, ]; - let removed = vec.extract_if(|x| *x % 2 == 0).collect::<Vec<_>>(); + let removed = vec.extract_if(.., |x| *x % 2 == 0).collect::<Vec<_>>(); assert_eq!(removed.len(), 10); assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]); @@ -1515,7 +1540,7 @@ fn extract_if_complex() { 2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 22, 24, 26, 27, 29, 31, 33, 34, 35, 36, 37, 39, ]; - let removed = vec.extract_if(|x| *x % 2 == 0).collect::<Vec<_>>(); + let removed = vec.extract_if(.., |x| *x % 2 == 0).collect::<Vec<_>>(); assert_eq!(removed.len(), 10); assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]); @@ -1528,7 +1553,7 @@ fn extract_if_complex() { let mut vec = vec![2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 22, 24, 26, 27, 29, 31, 33, 34, 35, 36]; - let removed = vec.extract_if(|x| *x % 2 == 0).collect::<Vec<_>>(); + let removed = vec.extract_if(.., |x| *x % 2 == 0).collect::<Vec<_>>(); assert_eq!(removed.len(), 10); assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]); @@ -1540,7 +1565,7 @@ fn extract_if_complex() { // [xxxxxxxxxx+++++++++++] let mut vec = vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19]; - let removed = vec.extract_if(|x| *x % 2 == 0).collect::<Vec<_>>(); + let removed = vec.extract_if(.., |x| *x % 2 == 0).collect::<Vec<_>>(); assert_eq!(removed.len(), 10); assert_eq!(removed, vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20]); @@ -1552,7 +1577,7 @@ fn extract_if_complex() { // [+++++++++++xxxxxxxxxx] let mut vec = vec![1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20]; - let removed = vec.extract_if(|x| *x % 2 == 0).collect::<Vec<_>>(); + let removed = vec.extract_if(.., |x| *x % 2 == 0).collect::<Vec<_>>(); assert_eq!(removed.len(), 10); assert_eq!(removed, vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20]); @@ -1600,7 +1625,7 @@ fn extract_if_consumed_panic() { } c.index < 6 }; - let drain = data.extract_if(filter); + let drain = data.extract_if(.., filter); // NOTE: The ExtractIf is explicitly consumed drain.for_each(drop); @@ -1653,7 +1678,7 @@ fn extract_if_unconsumed_panic() { } c.index < 6 }; - let _drain = data.extract_if(filter); + let _drain = data.extract_if(.., filter); // NOTE: The ExtractIf is dropped without being consumed }); @@ -1669,7 +1694,7 @@ fn extract_if_unconsumed_panic() { #[test] fn extract_if_unconsumed() { let mut vec = vec![1, 2, 3, 4]; - let drain = vec.extract_if(|&mut x| x % 2 != 0); + let drain = vec.extract_if(.., |&mut x| x % 2 != 0); drop(drain); assert_eq!(vec, [1, 2, 3, 4]); } |
