summaryrefslogtreecommitdiffstats
path: root/library/alloc/tests
diff options
context:
space:
mode:
Diffstat (limited to 'library/alloc/tests')
-rw-r--r--library/alloc/tests/arc.rs212
-rw-r--r--library/alloc/tests/borrow.rs60
-rw-r--r--library/alloc/tests/boxed.rs167
-rw-r--r--library/alloc/tests/btree_set_hash.rs29
-rw-r--r--library/alloc/tests/c_str.rs19
-rw-r--r--library/alloc/tests/const_fns.rs35
-rw-r--r--library/alloc/tests/cow_str.rs144
-rw-r--r--library/alloc/tests/fmt.rs323
-rw-r--r--library/alloc/tests/heap.rs44
-rw-r--r--library/alloc/tests/lib.rs88
-rw-r--r--library/alloc/tests/linked_list.rs21
-rw-r--r--library/alloc/tests/rc.rs208
-rw-r--r--library/alloc/tests/slice.rs2018
-rw-r--r--library/alloc/tests/str.rs2383
-rw-r--r--library/alloc/tests/string.rs876
-rw-r--r--library/alloc/tests/thin_box.rs262
-rw-r--r--library/alloc/tests/vec.rs2436
-rw-r--r--library/alloc/tests/vec_deque.rs1786
18 files changed, 11111 insertions, 0 deletions
diff --git a/library/alloc/tests/arc.rs b/library/alloc/tests/arc.rs
new file mode 100644
index 000000000..ce40b5c9b
--- /dev/null
+++ b/library/alloc/tests/arc.rs
@@ -0,0 +1,212 @@
+use std::any::Any;
+use std::cell::RefCell;
+use std::cmp::PartialEq;
+use std::iter::TrustedLen;
+use std::mem;
+use std::sync::{Arc, Weak};
+
+#[test]
+fn uninhabited() {
+ enum Void {}
+ let mut a = Weak::<Void>::new();
+ a = a.clone();
+ assert!(a.upgrade().is_none());
+
+ let mut a: Weak<dyn Any> = a; // Unsizing
+ a = a.clone();
+ assert!(a.upgrade().is_none());
+}
+
+#[test]
+fn slice() {
+ let a: Arc<[u32; 3]> = Arc::new([3, 2, 1]);
+ let a: Arc<[u32]> = a; // Unsizing
+ let b: Arc<[u32]> = Arc::from(&[3, 2, 1][..]); // Conversion
+ assert_eq!(a, b);
+
+ // Exercise is_dangling() with a DST
+ let mut a = Arc::downgrade(&a);
+ a = a.clone();
+ assert!(a.upgrade().is_some());
+}
+
+#[test]
+fn trait_object() {
+ let a: Arc<u32> = Arc::new(4);
+ let a: Arc<dyn Any> = a; // Unsizing
+
+ // Exercise is_dangling() with a DST
+ let mut a = Arc::downgrade(&a);
+ a = a.clone();
+ assert!(a.upgrade().is_some());
+
+ let mut b = Weak::<u32>::new();
+ b = b.clone();
+ assert!(b.upgrade().is_none());
+ let mut b: Weak<dyn Any> = b; // Unsizing
+ b = b.clone();
+ assert!(b.upgrade().is_none());
+}
+
+#[test]
+fn float_nan_ne() {
+ let x = Arc::new(f32::NAN);
+ assert!(x != x);
+ assert!(!(x == x));
+}
+
+#[test]
+fn partial_eq() {
+ struct TestPEq(RefCell<usize>);
+ impl PartialEq for TestPEq {
+ fn eq(&self, other: &TestPEq) -> bool {
+ *self.0.borrow_mut() += 1;
+ *other.0.borrow_mut() += 1;
+ true
+ }
+ }
+ let x = Arc::new(TestPEq(RefCell::new(0)));
+ assert!(x == x);
+ assert!(!(x != x));
+ assert_eq!(*x.0.borrow(), 4);
+}
+
+#[test]
+fn eq() {
+ #[derive(Eq)]
+ struct TestEq(RefCell<usize>);
+ impl PartialEq for TestEq {
+ fn eq(&self, other: &TestEq) -> bool {
+ *self.0.borrow_mut() += 1;
+ *other.0.borrow_mut() += 1;
+ true
+ }
+ }
+ let x = Arc::new(TestEq(RefCell::new(0)));
+ assert!(x == x);
+ assert!(!(x != x));
+ assert_eq!(*x.0.borrow(), 0);
+}
+
+// The test code below is identical to that in `rc.rs`.
+// For better maintainability we therefore define this type alias.
+type Rc<T> = Arc<T>;
+
+const SHARED_ITER_MAX: u16 = 100;
+
+fn assert_trusted_len<I: TrustedLen>(_: &I) {}
+
+#[test]
+fn shared_from_iter_normal() {
+ // Exercise the base implementation for non-`TrustedLen` iterators.
+ {
+ // `Filter` is never `TrustedLen` since we don't
+ // know statically how many elements will be kept:
+ let iter = (0..SHARED_ITER_MAX).filter(|x| x % 2 == 0).map(Box::new);
+
+ // Collecting into a `Vec<T>` or `Rc<[T]>` should make no difference:
+ let vec = iter.clone().collect::<Vec<_>>();
+ let rc = iter.collect::<Rc<[_]>>();
+ assert_eq!(&*vec, &*rc);
+
+ // Clone a bit and let these get dropped.
+ {
+ let _rc_2 = rc.clone();
+ let _rc_3 = rc.clone();
+ let _rc_4 = Rc::downgrade(&_rc_3);
+ }
+ } // Drop what hasn't been here.
+}
+
+#[test]
+fn shared_from_iter_trustedlen_normal() {
+ // Exercise the `TrustedLen` implementation under normal circumstances
+ // where `size_hint()` matches `(_, Some(exact_len))`.
+ {
+ let iter = (0..SHARED_ITER_MAX).map(Box::new);
+ assert_trusted_len(&iter);
+
+ // Collecting into a `Vec<T>` or `Rc<[T]>` should make no difference:
+ let vec = iter.clone().collect::<Vec<_>>();
+ let rc = iter.collect::<Rc<[_]>>();
+ assert_eq!(&*vec, &*rc);
+ assert_eq!(mem::size_of::<Box<u16>>() * SHARED_ITER_MAX as usize, mem::size_of_val(&*rc));
+
+ // Clone a bit and let these get dropped.
+ {
+ let _rc_2 = rc.clone();
+ let _rc_3 = rc.clone();
+ let _rc_4 = Rc::downgrade(&_rc_3);
+ }
+ } // Drop what hasn't been here.
+
+ // Try a ZST to make sure it is handled well.
+ {
+ let iter = (0..SHARED_ITER_MAX).map(drop);
+ let vec = iter.clone().collect::<Vec<_>>();
+ let rc = iter.collect::<Rc<[_]>>();
+ assert_eq!(&*vec, &*rc);
+ assert_eq!(0, mem::size_of_val(&*rc));
+ {
+ let _rc_2 = rc.clone();
+ let _rc_3 = rc.clone();
+ let _rc_4 = Rc::downgrade(&_rc_3);
+ }
+ }
+}
+
+#[test]
+#[should_panic = "I've almost got 99 problems."]
+fn shared_from_iter_trustedlen_panic() {
+ // Exercise the `TrustedLen` implementation when `size_hint()` matches
+ // `(_, Some(exact_len))` but where `.next()` drops before the last iteration.
+ let iter = (0..SHARED_ITER_MAX).map(|val| match val {
+ 98 => panic!("I've almost got 99 problems."),
+ _ => Box::new(val),
+ });
+ assert_trusted_len(&iter);
+ let _ = iter.collect::<Rc<[_]>>();
+
+ panic!("I am unreachable.");
+}
+
+#[test]
+fn shared_from_iter_trustedlen_no_fuse() {
+ // Exercise the `TrustedLen` implementation when `size_hint()` matches
+ // `(_, Some(exact_len))` but where the iterator does not behave in a fused manner.
+ struct Iter(std::vec::IntoIter<Option<Box<u8>>>);
+
+ unsafe impl TrustedLen for Iter {}
+
+ impl Iterator for Iter {
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (2, Some(2))
+ }
+
+ type Item = Box<u8>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.0.next().flatten()
+ }
+ }
+
+ let vec = vec![Some(Box::new(42)), Some(Box::new(24)), None, Some(Box::new(12))];
+ let iter = Iter(vec.into_iter());
+ assert_trusted_len(&iter);
+ assert_eq!(&[Box::new(42), Box::new(24)], &*iter.collect::<Rc<[_]>>());
+}
+
+#[test]
+fn weak_may_dangle() {
+ fn hmm<'a>(val: &'a mut Weak<&'a str>) -> Weak<&'a str> {
+ val.clone()
+ }
+
+ // Without #[may_dangle] we get:
+ let mut val = Weak::new();
+ hmm(&mut val);
+ // ~~~~~~~~ borrowed value does not live long enough
+ //
+ // `val` dropped here while still borrowed
+ // borrow might be used here, when `val` is dropped and runs the `Drop` code for type `std::sync::Weak`
+}
diff --git a/library/alloc/tests/borrow.rs b/library/alloc/tests/borrow.rs
new file mode 100644
index 000000000..57976aa6c
--- /dev/null
+++ b/library/alloc/tests/borrow.rs
@@ -0,0 +1,60 @@
+use std::borrow::{Cow, ToOwned};
+use std::ffi::{CStr, OsStr};
+use std::path::Path;
+use std::rc::Rc;
+use std::sync::Arc;
+
+macro_rules! test_from_cow {
+ ($value:ident => $($ty:ty),+) => {$(
+ let borrowed = <$ty>::from(Cow::Borrowed($value));
+ let owned = <$ty>::from(Cow::Owned($value.to_owned()));
+ assert_eq!($value, &*borrowed);
+ assert_eq!($value, &*owned);
+ )+};
+ ($value:ident : & $ty:ty) => {
+ test_from_cow!($value => Box<$ty>, Rc<$ty>, Arc<$ty>);
+ }
+}
+
+#[test]
+fn test_from_cow_slice() {
+ let slice: &[i32] = &[1, 2, 3];
+ test_from_cow!(slice: &[i32]);
+}
+
+#[test]
+fn test_from_cow_str() {
+ let string = "hello";
+ test_from_cow!(string: &str);
+}
+
+#[test]
+fn test_from_cow_c_str() {
+ let string = CStr::from_bytes_with_nul(b"hello\0").unwrap();
+ test_from_cow!(string: &CStr);
+}
+
+#[test]
+fn test_from_cow_os_str() {
+ let string = OsStr::new("hello");
+ test_from_cow!(string: &OsStr);
+}
+
+#[test]
+fn test_from_cow_path() {
+ let path = Path::new("hello");
+ test_from_cow!(path: &Path);
+}
+
+#[test]
+fn cow_const() {
+ // test that the methods of `Cow` are usable in a const context
+
+ const COW: Cow<'_, str> = Cow::Borrowed("moo");
+
+ const IS_BORROWED: bool = COW.is_borrowed();
+ assert!(IS_BORROWED);
+
+ const IS_OWNED: bool = COW.is_owned();
+ assert!(!IS_OWNED);
+}
diff --git a/library/alloc/tests/boxed.rs b/library/alloc/tests/boxed.rs
new file mode 100644
index 000000000..9e5123be9
--- /dev/null
+++ b/library/alloc/tests/boxed.rs
@@ -0,0 +1,167 @@
+use core::alloc::{AllocError, Allocator, Layout};
+use core::cell::Cell;
+use core::mem::MaybeUninit;
+use core::ptr::NonNull;
+
+#[test]
+fn uninitialized_zero_size_box() {
+ assert_eq!(
+ &*Box::<()>::new_uninit() as *const _,
+ NonNull::<MaybeUninit<()>>::dangling().as_ptr(),
+ );
+ assert_eq!(
+ Box::<[()]>::new_uninit_slice(4).as_ptr(),
+ NonNull::<MaybeUninit<()>>::dangling().as_ptr(),
+ );
+ assert_eq!(
+ Box::<[String]>::new_uninit_slice(0).as_ptr(),
+ NonNull::<MaybeUninit<String>>::dangling().as_ptr(),
+ );
+}
+
+#[derive(Clone, PartialEq, Eq, Debug)]
+struct Dummy {
+ _data: u8,
+}
+
+#[test]
+fn box_clone_and_clone_from_equivalence() {
+ for size in (0..8).map(|i| 2usize.pow(i)) {
+ let control = vec![Dummy { _data: 42 }; size].into_boxed_slice();
+ let clone = control.clone();
+ let mut copy = vec![Dummy { _data: 84 }; size].into_boxed_slice();
+ copy.clone_from(&control);
+ assert_eq!(control, clone);
+ assert_eq!(control, copy);
+ }
+}
+
+/// This test might give a false positive in case the box reallocates,
+/// but the allocator keeps the original pointer.
+///
+/// On the other hand, it won't give a false negative: If it fails, then the
+/// memory was definitely not reused.
+#[test]
+fn box_clone_from_ptr_stability() {
+ for size in (0..8).map(|i| 2usize.pow(i)) {
+ let control = vec![Dummy { _data: 42 }; size].into_boxed_slice();
+ let mut copy = vec![Dummy { _data: 84 }; size].into_boxed_slice();
+ let copy_raw = copy.as_ptr() as usize;
+ copy.clone_from(&control);
+ assert_eq!(copy.as_ptr() as usize, copy_raw);
+ }
+}
+
+#[test]
+fn box_deref_lval() {
+ let x = Box::new(Cell::new(5));
+ x.set(1000);
+ assert_eq!(x.get(), 1000);
+}
+
+pub struct ConstAllocator;
+
+unsafe impl const Allocator for ConstAllocator {
+ fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
+ match layout.size() {
+ 0 => Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)),
+ _ => unsafe {
+ let ptr = core::intrinsics::const_allocate(layout.size(), layout.align());
+ Ok(NonNull::new_unchecked(ptr as *mut [u8; 0] as *mut [u8]))
+ },
+ }
+ }
+
+ unsafe fn deallocate(&self, _ptr: NonNull<u8>, layout: Layout) {
+ match layout.size() {
+ 0 => { /* do nothing */ }
+ _ => { /* do nothing too */ }
+ }
+ }
+
+ fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
+ let ptr = self.allocate(layout)?;
+ if layout.size() > 0 {
+ unsafe {
+ ptr.as_mut_ptr().write_bytes(0, layout.size());
+ }
+ }
+ Ok(ptr)
+ }
+
+ unsafe fn grow(
+ &self,
+ ptr: NonNull<u8>,
+ old_layout: Layout,
+ new_layout: Layout,
+ ) -> Result<NonNull<[u8]>, AllocError> {
+ debug_assert!(
+ new_layout.size() >= old_layout.size(),
+ "`new_layout.size()` must be greater than or equal to `old_layout.size()`"
+ );
+
+ let new_ptr = self.allocate(new_layout)?;
+ if new_layout.size() > 0 {
+ new_ptr.as_mut_ptr().copy_from_nonoverlapping(ptr.as_ptr(), old_layout.size());
+ self.deallocate(ptr, old_layout);
+ }
+ Ok(new_ptr)
+ }
+
+ unsafe fn grow_zeroed(
+ &self,
+ ptr: NonNull<u8>,
+ old_layout: Layout,
+ new_layout: Layout,
+ ) -> Result<NonNull<[u8]>, AllocError> {
+ let new_ptr = self.grow(ptr, old_layout, new_layout)?;
+ if new_layout.size() > 0 {
+ let old_size = old_layout.size();
+ let new_size = new_layout.size();
+ let raw_ptr = new_ptr.as_mut_ptr();
+ raw_ptr.add(old_size).write_bytes(0, new_size - old_size);
+ }
+ Ok(new_ptr)
+ }
+
+ unsafe fn shrink(
+ &self,
+ ptr: NonNull<u8>,
+ old_layout: Layout,
+ new_layout: Layout,
+ ) -> Result<NonNull<[u8]>, AllocError> {
+ debug_assert!(
+ new_layout.size() <= old_layout.size(),
+ "`new_layout.size()` must be smaller than or equal to `old_layout.size()`"
+ );
+
+ let new_ptr = self.allocate(new_layout)?;
+ if new_layout.size() > 0 {
+ new_ptr.as_mut_ptr().copy_from_nonoverlapping(ptr.as_ptr(), new_layout.size());
+ self.deallocate(ptr, old_layout);
+ }
+ Ok(new_ptr)
+ }
+
+ fn by_ref(&self) -> &Self
+ where
+ Self: Sized,
+ {
+ self
+ }
+}
+
+#[test]
+fn const_box() {
+ const VALUE: u32 = {
+ let mut boxed = Box::new_in(1u32, ConstAllocator);
+ assert!(*boxed == 1);
+
+ *boxed = 42;
+ assert!(*boxed == 42);
+
+ *Box::leak(boxed)
+ };
+
+ assert!(VALUE == 42);
+}
diff --git a/library/alloc/tests/btree_set_hash.rs b/library/alloc/tests/btree_set_hash.rs
new file mode 100644
index 000000000..ab275ac43
--- /dev/null
+++ b/library/alloc/tests/btree_set_hash.rs
@@ -0,0 +1,29 @@
+use crate::hash;
+use std::collections::BTreeSet;
+
+#[test]
+fn test_hash() {
+ let mut x = BTreeSet::new();
+ let mut y = BTreeSet::new();
+
+ x.insert(1);
+ x.insert(2);
+ x.insert(3);
+
+ y.insert(3);
+ y.insert(2);
+ y.insert(1);
+
+ assert_eq!(hash(&x), hash(&y));
+}
+
+#[test]
+fn test_prefix_free() {
+ let x = BTreeSet::from([1, 2, 3]);
+ let y = BTreeSet::<i32>::new();
+
+ // If hashed by iteration alone, `(x, y)` and `(y, x)` would visit the same
+ // order of elements, resulting in the same hash. But now that we also hash
+ // the length, they get distinct sequences of hashed data.
+ assert_ne!(hash(&(&x, &y)), hash(&(&y, &x)));
+}
diff --git a/library/alloc/tests/c_str.rs b/library/alloc/tests/c_str.rs
new file mode 100644
index 000000000..4a5817939
--- /dev/null
+++ b/library/alloc/tests/c_str.rs
@@ -0,0 +1,19 @@
+use std::borrow::Cow::{Borrowed, Owned};
+use std::ffi::CStr;
+use std::os::raw::c_char;
+
+#[test]
+fn to_str() {
+ let data = b"123\xE2\x80\xA6\0";
+ let ptr = data.as_ptr() as *const c_char;
+ unsafe {
+ assert_eq!(CStr::from_ptr(ptr).to_str(), Ok("123…"));
+ assert_eq!(CStr::from_ptr(ptr).to_string_lossy(), Borrowed("123…"));
+ }
+ let data = b"123\xE2\0";
+ let ptr = data.as_ptr() as *const c_char;
+ unsafe {
+ assert!(CStr::from_ptr(ptr).to_str().is_err());
+ assert_eq!(CStr::from_ptr(ptr).to_string_lossy(), Owned::<str>(format!("123\u{FFFD}")));
+ }
+}
diff --git a/library/alloc/tests/const_fns.rs b/library/alloc/tests/const_fns.rs
new file mode 100644
index 000000000..49b837bec
--- /dev/null
+++ b/library/alloc/tests/const_fns.rs
@@ -0,0 +1,35 @@
+// Test const functions in the library
+
+pub const MY_VEC: Vec<usize> = Vec::new();
+pub const MY_VEC2: Vec<usize> = Default::default();
+
+pub const MY_STRING: String = String::new();
+pub const MY_STRING2: String = Default::default();
+
+pub const MY_BOXED_SLICE: Box<[usize]> = Default::default();
+pub const MY_BOXED_STR: Box<str> = Default::default();
+
+use std::collections::{BTreeMap, BTreeSet};
+
+pub const MY_BTREEMAP: BTreeMap<usize, usize> = BTreeMap::new();
+pub const MAP: &'static BTreeMap<usize, usize> = &MY_BTREEMAP;
+pub const MAP_LEN: usize = MAP.len();
+pub const MAP_IS_EMPTY: bool = MAP.is_empty();
+
+pub const MY_BTREESET: BTreeSet<usize> = BTreeSet::new();
+pub const SET: &'static BTreeSet<usize> = &MY_BTREESET;
+pub const SET_LEN: usize = SET.len();
+pub const SET_IS_EMPTY: bool = SET.is_empty();
+
+#[test]
+fn test_const() {
+ assert_eq!(MY_VEC, MY_VEC2);
+ assert_eq!(MY_STRING, MY_STRING2);
+
+ assert_eq!(MY_VEC, *MY_BOXED_SLICE);
+ assert_eq!(MY_STRING, *MY_BOXED_STR);
+
+ assert_eq!(MAP_LEN, 0);
+ assert_eq!(SET_LEN, 0);
+ assert!(MAP_IS_EMPTY && SET_IS_EMPTY);
+}
diff --git a/library/alloc/tests/cow_str.rs b/library/alloc/tests/cow_str.rs
new file mode 100644
index 000000000..62a5c245a
--- /dev/null
+++ b/library/alloc/tests/cow_str.rs
@@ -0,0 +1,144 @@
+use std::borrow::Cow;
+
+// check that Cow<'a, str> implements addition
+#[test]
+fn check_cow_add_cow() {
+ let borrowed1 = Cow::Borrowed("Hello, ");
+ let borrowed2 = Cow::Borrowed("World!");
+ let borrow_empty = Cow::Borrowed("");
+
+ let owned1: Cow<'_, str> = Cow::Owned(String::from("Hi, "));
+ let owned2: Cow<'_, str> = Cow::Owned(String::from("Rustaceans!"));
+ let owned_empty: Cow<'_, str> = Cow::Owned(String::new());
+
+ assert_eq!("Hello, World!", borrowed1.clone() + borrowed2.clone());
+ assert_eq!("Hello, Rustaceans!", borrowed1.clone() + owned2.clone());
+
+ assert_eq!("Hi, World!", owned1.clone() + borrowed2.clone());
+ assert_eq!("Hi, Rustaceans!", owned1.clone() + owned2.clone());
+
+ if let Cow::Owned(_) = borrowed1.clone() + borrow_empty.clone() {
+ panic!("Adding empty strings to a borrow should note allocate");
+ }
+ if let Cow::Owned(_) = borrow_empty.clone() + borrowed1.clone() {
+ panic!("Adding empty strings to a borrow should note allocate");
+ }
+ if let Cow::Owned(_) = borrowed1.clone() + owned_empty.clone() {
+ panic!("Adding empty strings to a borrow should note allocate");
+ }
+ if let Cow::Owned(_) = owned_empty.clone() + borrowed1.clone() {
+ panic!("Adding empty strings to a borrow should note allocate");
+ }
+}
+
+#[test]
+fn check_cow_add_str() {
+ let borrowed = Cow::Borrowed("Hello, ");
+ let borrow_empty = Cow::Borrowed("");
+
+ let owned: Cow<'_, str> = Cow::Owned(String::from("Hi, "));
+ let owned_empty: Cow<'_, str> = Cow::Owned(String::new());
+
+ assert_eq!("Hello, World!", borrowed.clone() + "World!");
+
+ assert_eq!("Hi, World!", owned.clone() + "World!");
+
+ if let Cow::Owned(_) = borrowed.clone() + "" {
+ panic!("Adding empty strings to a borrow should note allocate");
+ }
+ if let Cow::Owned(_) = borrow_empty.clone() + "Hello, " {
+ panic!("Adding empty strings to a borrow should note allocate");
+ }
+ if let Cow::Owned(_) = owned_empty.clone() + "Hello, " {
+ panic!("Adding empty strings to a borrow should note allocate");
+ }
+}
+
+#[test]
+fn check_cow_add_assign_cow() {
+ let mut borrowed1 = Cow::Borrowed("Hello, ");
+ let borrowed2 = Cow::Borrowed("World!");
+ let borrow_empty = Cow::Borrowed("");
+
+ let mut owned1: Cow<'_, str> = Cow::Owned(String::from("Hi, "));
+ let owned2: Cow<'_, str> = Cow::Owned(String::from("Rustaceans!"));
+ let owned_empty: Cow<'_, str> = Cow::Owned(String::new());
+
+ let mut s = borrowed1.clone();
+ s += borrow_empty.clone();
+ assert_eq!("Hello, ", s);
+ if let Cow::Owned(_) = s {
+ panic!("Adding empty strings to a borrow should note allocate");
+ }
+ let mut s = borrow_empty.clone();
+ s += borrowed1.clone();
+ assert_eq!("Hello, ", s);
+ if let Cow::Owned(_) = s {
+ panic!("Adding empty strings to a borrow should note allocate");
+ }
+ let mut s = borrowed1.clone();
+ s += owned_empty.clone();
+ assert_eq!("Hello, ", s);
+ if let Cow::Owned(_) = s {
+ panic!("Adding empty strings to a borrow should note allocate");
+ }
+ let mut s = owned_empty.clone();
+ s += borrowed1.clone();
+ assert_eq!("Hello, ", s);
+ if let Cow::Owned(_) = s {
+ panic!("Adding empty strings to a borrow should note allocate");
+ }
+
+ owned1 += borrowed2;
+ borrowed1 += owned2;
+
+ assert_eq!("Hi, World!", owned1);
+ assert_eq!("Hello, Rustaceans!", borrowed1);
+}
+
+#[test]
+fn check_cow_add_assign_str() {
+ let mut borrowed = Cow::Borrowed("Hello, ");
+ let borrow_empty = Cow::Borrowed("");
+
+ let mut owned: Cow<'_, str> = Cow::Owned(String::from("Hi, "));
+ let owned_empty: Cow<'_, str> = Cow::Owned(String::new());
+
+ let mut s = borrowed.clone();
+ s += "";
+ assert_eq!("Hello, ", s);
+ if let Cow::Owned(_) = s {
+ panic!("Adding empty strings to a borrow should note allocate");
+ }
+ let mut s = borrow_empty.clone();
+ s += "World!";
+ assert_eq!("World!", s);
+ if let Cow::Owned(_) = s {
+ panic!("Adding empty strings to a borrow should note allocate");
+ }
+ let mut s = owned_empty.clone();
+ s += "World!";
+ assert_eq!("World!", s);
+ if let Cow::Owned(_) = s {
+ panic!("Adding empty strings to a borrow should note allocate");
+ }
+
+ owned += "World!";
+ borrowed += "World!";
+
+ assert_eq!("Hi, World!", owned);
+ assert_eq!("Hello, World!", borrowed);
+}
+
+#[test]
+fn check_cow_clone_from() {
+ let mut c1: Cow<'_, str> = Cow::Owned(String::with_capacity(25));
+ let s: String = "hi".to_string();
+ assert!(s.capacity() < 25);
+ let c2: Cow<'_, str> = Cow::Owned(s);
+ c1.clone_from(&c2);
+ assert!(c1.into_owned().capacity() >= 25);
+ let mut c3: Cow<'_, str> = Cow::Borrowed("bye");
+ c3.clone_from(&c2);
+ assert_eq!(c2, c3);
+}
diff --git a/library/alloc/tests/fmt.rs b/library/alloc/tests/fmt.rs
new file mode 100644
index 000000000..5ee6db43f
--- /dev/null
+++ b/library/alloc/tests/fmt.rs
@@ -0,0 +1,323 @@
+#![deny(warnings)]
+
+use std::cell::RefCell;
+use std::fmt::{self, Write};
+
+#[test]
+fn test_format() {
+ let s = fmt::format(format_args!("Hello, {}!", "world"));
+ assert_eq!(s, "Hello, world!");
+}
+
+struct A;
+struct B;
+struct C;
+struct D;
+
+impl fmt::LowerHex for A {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str("aloha")
+ }
+}
+impl fmt::UpperHex for B {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str("adios")
+ }
+}
+impl fmt::Display for C {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.pad_integral(true, "☃", "123")
+ }
+}
+impl fmt::Binary for D {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str("aa")?;
+ f.write_char('☃')?;
+ f.write_str("bb")
+ }
+}
+
+macro_rules! t {
+ ($a:expr, $b:expr) => {
+ assert_eq!($a, $b)
+ };
+}
+
+#[test]
+fn test_format_macro_interface() {
+ // Various edge cases without formats
+ t!(format!(""), "");
+ t!(format!("hello"), "hello");
+ t!(format!("hello {{"), "hello {");
+
+ // default formatters should work
+ t!(format!("{}", 1.0f32), "1");
+ t!(format!("{}", 1.0f64), "1");
+ t!(format!("{}", "a"), "a");
+ t!(format!("{}", "a".to_string()), "a");
+ t!(format!("{}", false), "false");
+ t!(format!("{}", 'a'), "a");
+
+ // At least exercise all the formats
+ t!(format!("{}", true), "true");
+ t!(format!("{}", '☃'), "☃");
+ t!(format!("{}", 10), "10");
+ t!(format!("{}", 10_usize), "10");
+ t!(format!("{:?}", '☃'), "'☃'");
+ t!(format!("{:?}", 10), "10");
+ t!(format!("{:?}", 10_usize), "10");
+ t!(format!("{:?}", "true"), "\"true\"");
+ t!(format!("{:?}", "foo\nbar"), "\"foo\\nbar\"");
+ t!(format!("{:?}", "foo\n\"bar\"\r\n\'baz\'\t\\qux\\"), r#""foo\n\"bar\"\r\n'baz'\t\\qux\\""#);
+ t!(format!("{:?}", "foo\0bar\x01baz\u{7f}q\u{75}x"), r#""foo\0bar\u{1}baz\u{7f}qux""#);
+ t!(format!("{:o}", 10_usize), "12");
+ t!(format!("{:x}", 10_usize), "a");
+ t!(format!("{:X}", 10_usize), "A");
+ t!(format!("{}", "foo"), "foo");
+ t!(format!("{}", "foo".to_string()), "foo");
+ if cfg!(target_pointer_width = "32") {
+ t!(format!("{:#p}", 0x1234 as *const isize), "0x00001234");
+ t!(format!("{:#p}", 0x1234 as *mut isize), "0x00001234");
+ } else {
+ t!(format!("{:#p}", 0x1234 as *const isize), "0x0000000000001234");
+ t!(format!("{:#p}", 0x1234 as *mut isize), "0x0000000000001234");
+ }
+ t!(format!("{:p}", 0x1234 as *const isize), "0x1234");
+ t!(format!("{:p}", 0x1234 as *mut isize), "0x1234");
+ t!(format!("{A:x}"), "aloha");
+ t!(format!("{B:X}"), "adios");
+ t!(format!("foo {} ☃☃☃☃☃☃", "bar"), "foo bar ☃☃☃☃☃☃");
+ t!(format!("{1} {0}", 0, 1), "1 0");
+ t!(format!("{foo} {bar}", foo = 0, bar = 1), "0 1");
+ t!(format!("{foo} {1} {bar} {0}", 0, 1, foo = 2, bar = 3), "2 1 3 0");
+ t!(format!("{} {0}", "a"), "a a");
+ t!(format!("{_foo}", _foo = 6usize), "6");
+ t!(format!("{foo_bar}", foo_bar = 1), "1");
+ t!(format!("{}", 5 + 5), "10");
+ t!(format!("{C:#4}"), "☃123");
+ t!(format!("{D:b}"), "aa☃bb");
+
+ let a: &dyn fmt::Debug = &1;
+ t!(format!("{a:?}"), "1");
+
+ // Formatting strings and their arguments
+ t!(format!("{}", "a"), "a");
+ t!(format!("{:4}", "a"), "a ");
+ t!(format!("{:4}", "☃"), "☃ ");
+ t!(format!("{:>4}", "a"), " a");
+ t!(format!("{:<4}", "a"), "a ");
+ t!(format!("{:^5}", "a"), " a ");
+ t!(format!("{:^5}", "aa"), " aa ");
+ t!(format!("{:^4}", "a"), " a ");
+ t!(format!("{:^4}", "aa"), " aa ");
+ t!(format!("{:.4}", "a"), "a");
+ t!(format!("{:4.4}", "a"), "a ");
+ t!(format!("{:4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa");
+ t!(format!("{:<4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa");
+ t!(format!("{:>4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa");
+ t!(format!("{:^4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa");
+ t!(format!("{:>10.4}", "aaaaaaaaaaaaaaaaaa"), " aaaa");
+ t!(format!("{:2.4}", "aaaaa"), "aaaa");
+ t!(format!("{:2.4}", "aaaa"), "aaaa");
+ t!(format!("{:2.4}", "aaa"), "aaa");
+ t!(format!("{:2.4}", "aa"), "aa");
+ t!(format!("{:2.4}", "a"), "a ");
+ t!(format!("{:0>2}", "a"), "0a");
+ t!(format!("{:.*}", 4, "aaaaaaaaaaaaaaaaaa"), "aaaa");
+ t!(format!("{:.1$}", "aaaaaaaaaaaaaaaaaa", 4), "aaaa");
+ t!(format!("{:.a$}", "aaaaaaaaaaaaaaaaaa", a = 4), "aaaa");
+ t!(format!("{:._a$}", "aaaaaaaaaaaaaaaaaa", _a = 4), "aaaa");
+ t!(format!("{:1$}", "a", 4), "a ");
+ t!(format!("{1:0$}", 4, "a"), "a ");
+ t!(format!("{:a$}", "a", a = 4), "a ");
+ t!(format!("{:-#}", "a"), "a");
+ t!(format!("{:+#}", "a"), "a");
+ t!(format!("{:/^10.8}", "1234567890"), "/12345678/");
+
+ // Some float stuff
+ t!(format!("{:}", 1.0f32), "1");
+ t!(format!("{:}", 1.0f64), "1");
+ t!(format!("{:.3}", 1.0f64), "1.000");
+ t!(format!("{:10.3}", 1.0f64), " 1.000");
+ t!(format!("{:+10.3}", 1.0f64), " +1.000");
+ t!(format!("{:+10.3}", -1.0f64), " -1.000");
+
+ t!(format!("{:e}", 1.2345e6f32), "1.2345e6");
+ t!(format!("{:e}", 1.2345e6f64), "1.2345e6");
+ t!(format!("{:E}", 1.2345e6f64), "1.2345E6");
+ t!(format!("{:.3e}", 1.2345e6f64), "1.234e6");
+ t!(format!("{:10.3e}", 1.2345e6f64), " 1.234e6");
+ t!(format!("{:+10.3e}", 1.2345e6f64), " +1.234e6");
+ t!(format!("{:+10.3e}", -1.2345e6f64), " -1.234e6");
+
+ // Float edge cases
+ t!(format!("{}", -0.0), "-0");
+ t!(format!("{:?}", 0.0), "0.0");
+
+ // sign aware zero padding
+ t!(format!("{:<3}", 1), "1 ");
+ t!(format!("{:>3}", 1), " 1");
+ t!(format!("{:^3}", 1), " 1 ");
+ t!(format!("{:03}", 1), "001");
+ t!(format!("{:<03}", 1), "001");
+ t!(format!("{:>03}", 1), "001");
+ t!(format!("{:^03}", 1), "001");
+ t!(format!("{:+03}", 1), "+01");
+ t!(format!("{:<+03}", 1), "+01");
+ t!(format!("{:>+03}", 1), "+01");
+ t!(format!("{:^+03}", 1), "+01");
+ t!(format!("{:#05x}", 1), "0x001");
+ t!(format!("{:<#05x}", 1), "0x001");
+ t!(format!("{:>#05x}", 1), "0x001");
+ t!(format!("{:^#05x}", 1), "0x001");
+ t!(format!("{:05}", 1.2), "001.2");
+ t!(format!("{:<05}", 1.2), "001.2");
+ t!(format!("{:>05}", 1.2), "001.2");
+ t!(format!("{:^05}", 1.2), "001.2");
+ t!(format!("{:05}", -1.2), "-01.2");
+ t!(format!("{:<05}", -1.2), "-01.2");
+ t!(format!("{:>05}", -1.2), "-01.2");
+ t!(format!("{:^05}", -1.2), "-01.2");
+ t!(format!("{:+05}", 1.2), "+01.2");
+ t!(format!("{:<+05}", 1.2), "+01.2");
+ t!(format!("{:>+05}", 1.2), "+01.2");
+ t!(format!("{:^+05}", 1.2), "+01.2");
+
+ // Ergonomic format_args!
+ t!(format!("{0:x} {0:X}", 15), "f F");
+ t!(format!("{0:x} {0:X} {}", 15), "f F 15");
+ t!(format!("{:x}{0:X}{a:x}{:X}{1:x}{a:X}", 13, 14, a = 15), "dDfEeF");
+ t!(format!("{a:x} {a:X}", a = 15), "f F");
+
+ // And its edge cases
+ t!(
+ format!(
+ "{a:.0$} {b:.0$} {0:.0$}\n{a:.c$} {b:.c$} {c:.c$}",
+ 4,
+ a = "abcdefg",
+ b = "hijklmn",
+ c = 3
+ ),
+ "abcd hijk 4\nabc hij 3"
+ );
+ t!(format!("{a:.*} {0} {:.*}", 4, 3, "efgh", a = "abcdef"), "abcd 4 efg");
+ t!(format!("{:.a$} {a} {a:#x}", "aaaaaa", a = 2), "aa 2 0x2");
+
+ // Test that pointers don't get truncated.
+ {
+ let val = usize::MAX;
+ let exp = format!("{val:#x}");
+ t!(format!("{:p}", std::ptr::invalid::<isize>(val)), exp);
+ }
+
+ // Escaping
+ t!(format!("{{"), "{");
+ t!(format!("}}"), "}");
+
+ // make sure that format! doesn't move out of local variables
+ let a = Box::new(3);
+ format!("{a}");
+ format!("{a}");
+
+ // make sure that format! doesn't cause spurious unused-unsafe warnings when
+ // it's inside of an outer unsafe block
+ unsafe {
+ let a: isize = ::std::mem::transmute(3_usize);
+ format!("{a}");
+ }
+
+ // test that trailing commas are acceptable
+ format!("{}", "test",);
+ format!("{foo}", foo = "test",);
+}
+
+// Basic test to make sure that we can invoke the `write!` macro with an
+// fmt::Write instance.
+#[test]
+fn test_write() {
+ let mut buf = String::new();
+ let _ = write!(&mut buf, "{}", 3);
+ {
+ let w = &mut buf;
+ let _ = write!(w, "{foo}", foo = 4);
+ let _ = write!(w, "{}", "hello");
+ let _ = writeln!(w, "{}", "line");
+ let _ = writeln!(w, "{foo}", foo = "bar");
+ let _ = w.write_char('☃');
+ let _ = w.write_str("str");
+ }
+
+ t!(buf, "34helloline\nbar\n☃str");
+}
+
+// Just make sure that the macros are defined, there's not really a lot that we
+// can do with them just yet (to test the output)
+#[test]
+fn test_print() {
+ print!("hi");
+ print!("{:?}", vec![0u8]);
+ println!("hello");
+ println!("this is a {}", "test");
+ println!("{foo}", foo = "bar");
+}
+
+// Just make sure that the macros are defined, there's not really a lot that we
+// can do with them just yet (to test the output)
+#[test]
+fn test_format_args() {
+ let mut buf = String::new();
+ {
+ let w = &mut buf;
+ let _ = write!(w, "{}", format_args!("{}", 1));
+ let _ = write!(w, "{}", format_args!("test"));
+ let _ = write!(w, "{}", format_args!("{test}", test = 3));
+ }
+ let s = buf;
+ t!(s, "1test3");
+
+ let s = fmt::format(format_args!("hello {}", "world"));
+ t!(s, "hello world");
+ let s = format!("{}: {}", "args were", format_args!("hello {}", "world"));
+ t!(s, "args were: hello world");
+}
+
+#[test]
+fn test_order() {
+ // Make sure format!() arguments are always evaluated in a left-to-right
+ // ordering
+ fn foo() -> isize {
+ static mut FOO: isize = 0;
+ unsafe {
+ FOO += 1;
+ FOO
+ }
+ }
+ assert_eq!(
+ format!("{} {} {a} {b} {} {c}", foo(), foo(), foo(), a = foo(), b = foo(), c = foo()),
+ "1 2 4 5 3 6".to_string()
+ );
+}
+
+#[test]
+fn test_once() {
+ // Make sure each argument are evaluated only once even though it may be
+ // formatted multiple times
+ fn foo() -> isize {
+ static mut FOO: isize = 0;
+ unsafe {
+ FOO += 1;
+ FOO
+ }
+ }
+ assert_eq!(format!("{0} {0} {0} {a} {a} {a}", foo(), a = foo()), "1 1 1 2 2 2".to_string());
+}
+
+#[test]
+fn test_refcell() {
+ let refcell = RefCell::new(5);
+ assert_eq!(format!("{refcell:?}"), "RefCell { value: 5 }");
+ let borrow = refcell.borrow_mut();
+ assert_eq!(format!("{refcell:?}"), "RefCell { value: <borrowed> }");
+ drop(borrow);
+ assert_eq!(format!("{refcell:?}"), "RefCell { value: 5 }");
+}
diff --git a/library/alloc/tests/heap.rs b/library/alloc/tests/heap.rs
new file mode 100644
index 000000000..246b341ee
--- /dev/null
+++ b/library/alloc/tests/heap.rs
@@ -0,0 +1,44 @@
+use std::alloc::{Allocator, Global, Layout, System};
+
+/// Issue #45955 and #62251.
+#[test]
+fn alloc_system_overaligned_request() {
+ check_overalign_requests(System)
+}
+
+#[test]
+fn std_heap_overaligned_request() {
+ check_overalign_requests(Global)
+}
+
+fn check_overalign_requests<T: Allocator>(allocator: T) {
+ for &align in &[4, 8, 16, 32] {
+ // less than and bigger than `MIN_ALIGN`
+ for &size in &[align / 2, align - 1] {
+ // size less than alignment
+ let iterations = 128;
+ unsafe {
+ let pointers: Vec<_> = (0..iterations)
+ .map(|_| {
+ allocator.allocate(Layout::from_size_align(size, align).unwrap()).unwrap()
+ })
+ .collect();
+ for &ptr in &pointers {
+ assert_eq!(
+ (ptr.as_non_null_ptr().as_ptr() as usize) % align,
+ 0,
+ "Got a pointer less aligned than requested"
+ )
+ }
+
+ // Clean up
+ for &ptr in &pointers {
+ allocator.deallocate(
+ ptr.as_non_null_ptr(),
+ Layout::from_size_align(size, align).unwrap(),
+ )
+ }
+ }
+ }
+ }
+}
diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs
new file mode 100644
index 000000000..d83cd29dd
--- /dev/null
+++ b/library/alloc/tests/lib.rs
@@ -0,0 +1,88 @@
+#![feature(allocator_api)]
+#![feature(alloc_layout_extra)]
+#![feature(assert_matches)]
+#![feature(box_syntax)]
+#![feature(cow_is_borrowed)]
+#![feature(const_box)]
+#![feature(const_convert)]
+#![feature(const_cow_is_borrowed)]
+#![feature(const_heap)]
+#![feature(const_mut_refs)]
+#![feature(const_nonnull_slice_from_raw_parts)]
+#![feature(const_ptr_write)]
+#![feature(const_try)]
+#![feature(core_intrinsics)]
+#![feature(drain_filter)]
+#![feature(exact_size_is_empty)]
+#![feature(new_uninit)]
+#![feature(pattern)]
+#![feature(trusted_len)]
+#![feature(try_reserve_kind)]
+#![feature(unboxed_closures)]
+#![feature(associated_type_bounds)]
+#![feature(binary_heap_into_iter_sorted)]
+#![feature(binary_heap_drain_sorted)]
+#![feature(slice_ptr_get)]
+#![feature(binary_heap_retain)]
+#![feature(binary_heap_as_slice)]
+#![feature(inplace_iteration)]
+#![feature(iter_advance_by)]
+#![feature(iter_next_chunk)]
+#![feature(round_char_boundary)]
+#![feature(slice_group_by)]
+#![feature(slice_partition_dedup)]
+#![feature(string_remove_matches)]
+#![feature(const_btree_new)]
+#![feature(const_default_impls)]
+#![feature(const_trait_impl)]
+#![feature(const_str_from_utf8)]
+#![feature(nonnull_slice_from_raw_parts)]
+#![feature(panic_update_hook)]
+#![feature(slice_flatten)]
+#![feature(thin_box)]
+#![feature(bench_black_box)]
+#![feature(strict_provenance)]
+#![feature(once_cell)]
+
+use std::collections::hash_map::DefaultHasher;
+use std::hash::{Hash, Hasher};
+
+mod arc;
+mod borrow;
+mod boxed;
+mod btree_set_hash;
+mod c_str;
+mod const_fns;
+mod cow_str;
+mod fmt;
+mod heap;
+mod linked_list;
+mod rc;
+mod slice;
+mod str;
+mod string;
+mod thin_box;
+mod vec;
+mod vec_deque;
+
+fn hash<T: Hash>(t: &T) -> u64 {
+ let mut s = DefaultHasher::new();
+ t.hash(&mut s);
+ s.finish()
+}
+
+// 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"))]
+#[test]
+fn test_boxed_hasher() {
+ let ordinary_hash = hash(&5u32);
+
+ let mut hasher_1 = Box::new(DefaultHasher::new());
+ 5u32.hash(&mut hasher_1);
+ assert_eq!(ordinary_hash, hasher_1.finish());
+
+ let mut hasher_2 = Box::new(DefaultHasher::new()) as Box<dyn Hasher>;
+ 5u32.hash(&mut hasher_2);
+ assert_eq!(ordinary_hash, hasher_2.finish());
+}
diff --git a/library/alloc/tests/linked_list.rs b/library/alloc/tests/linked_list.rs
new file mode 100644
index 000000000..65b09cb00
--- /dev/null
+++ b/library/alloc/tests/linked_list.rs
@@ -0,0 +1,21 @@
+use std::collections::LinkedList;
+
+#[test]
+fn test_hash() {
+ use crate::hash;
+
+ let mut x = LinkedList::new();
+ let mut y = LinkedList::new();
+
+ assert!(hash(&x) == hash(&y));
+
+ x.push_back(1);
+ x.push_back(2);
+ x.push_back(3);
+
+ y.push_front(3);
+ y.push_front(2);
+ y.push_front(1);
+
+ assert!(hash(&x) == hash(&y));
+}
diff --git a/library/alloc/tests/rc.rs b/library/alloc/tests/rc.rs
new file mode 100644
index 000000000..efb39a609
--- /dev/null
+++ b/library/alloc/tests/rc.rs
@@ -0,0 +1,208 @@
+use std::any::Any;
+use std::cell::RefCell;
+use std::cmp::PartialEq;
+use std::iter::TrustedLen;
+use std::mem;
+use std::rc::{Rc, Weak};
+
+#[test]
+fn uninhabited() {
+ enum Void {}
+ let mut a = Weak::<Void>::new();
+ a = a.clone();
+ assert!(a.upgrade().is_none());
+
+ let mut a: Weak<dyn Any> = a; // Unsizing
+ a = a.clone();
+ assert!(a.upgrade().is_none());
+}
+
+#[test]
+fn slice() {
+ let a: Rc<[u32; 3]> = Rc::new([3, 2, 1]);
+ let a: Rc<[u32]> = a; // Unsizing
+ let b: Rc<[u32]> = Rc::from(&[3, 2, 1][..]); // Conversion
+ assert_eq!(a, b);
+
+ // Exercise is_dangling() with a DST
+ let mut a = Rc::downgrade(&a);
+ a = a.clone();
+ assert!(a.upgrade().is_some());
+}
+
+#[test]
+fn trait_object() {
+ let a: Rc<u32> = Rc::new(4);
+ let a: Rc<dyn Any> = a; // Unsizing
+
+ // Exercise is_dangling() with a DST
+ let mut a = Rc::downgrade(&a);
+ a = a.clone();
+ assert!(a.upgrade().is_some());
+
+ let mut b = Weak::<u32>::new();
+ b = b.clone();
+ assert!(b.upgrade().is_none());
+ let mut b: Weak<dyn Any> = b; // Unsizing
+ b = b.clone();
+ assert!(b.upgrade().is_none());
+}
+
+#[test]
+fn float_nan_ne() {
+ let x = Rc::new(f32::NAN);
+ assert!(x != x);
+ assert!(!(x == x));
+}
+
+#[test]
+fn partial_eq() {
+ struct TestPEq(RefCell<usize>);
+ impl PartialEq for TestPEq {
+ fn eq(&self, other: &TestPEq) -> bool {
+ *self.0.borrow_mut() += 1;
+ *other.0.borrow_mut() += 1;
+ true
+ }
+ }
+ let x = Rc::new(TestPEq(RefCell::new(0)));
+ assert!(x == x);
+ assert!(!(x != x));
+ assert_eq!(*x.0.borrow(), 4);
+}
+
+#[test]
+fn eq() {
+ #[derive(Eq)]
+ struct TestEq(RefCell<usize>);
+ impl PartialEq for TestEq {
+ fn eq(&self, other: &TestEq) -> bool {
+ *self.0.borrow_mut() += 1;
+ *other.0.borrow_mut() += 1;
+ true
+ }
+ }
+ let x = Rc::new(TestEq(RefCell::new(0)));
+ assert!(x == x);
+ assert!(!(x != x));
+ assert_eq!(*x.0.borrow(), 0);
+}
+
+const SHARED_ITER_MAX: u16 = 100;
+
+fn assert_trusted_len<I: TrustedLen>(_: &I) {}
+
+#[test]
+fn shared_from_iter_normal() {
+ // Exercise the base implementation for non-`TrustedLen` iterators.
+ {
+ // `Filter` is never `TrustedLen` since we don't
+ // know statically how many elements will be kept:
+ let iter = (0..SHARED_ITER_MAX).filter(|x| x % 2 == 0).map(Box::new);
+
+ // Collecting into a `Vec<T>` or `Rc<[T]>` should make no difference:
+ let vec = iter.clone().collect::<Vec<_>>();
+ let rc = iter.collect::<Rc<[_]>>();
+ assert_eq!(&*vec, &*rc);
+
+ // Clone a bit and let these get dropped.
+ {
+ let _rc_2 = rc.clone();
+ let _rc_3 = rc.clone();
+ let _rc_4 = Rc::downgrade(&_rc_3);
+ }
+ } // Drop what hasn't been here.
+}
+
+#[test]
+fn shared_from_iter_trustedlen_normal() {
+ // Exercise the `TrustedLen` implementation under normal circumstances
+ // where `size_hint()` matches `(_, Some(exact_len))`.
+ {
+ let iter = (0..SHARED_ITER_MAX).map(Box::new);
+ assert_trusted_len(&iter);
+
+ // Collecting into a `Vec<T>` or `Rc<[T]>` should make no difference:
+ let vec = iter.clone().collect::<Vec<_>>();
+ let rc = iter.collect::<Rc<[_]>>();
+ assert_eq!(&*vec, &*rc);
+ assert_eq!(mem::size_of::<Box<u16>>() * SHARED_ITER_MAX as usize, mem::size_of_val(&*rc));
+
+ // Clone a bit and let these get dropped.
+ {
+ let _rc_2 = rc.clone();
+ let _rc_3 = rc.clone();
+ let _rc_4 = Rc::downgrade(&_rc_3);
+ }
+ } // Drop what hasn't been here.
+
+ // Try a ZST to make sure it is handled well.
+ {
+ let iter = (0..SHARED_ITER_MAX).map(drop);
+ let vec = iter.clone().collect::<Vec<_>>();
+ let rc = iter.collect::<Rc<[_]>>();
+ assert_eq!(&*vec, &*rc);
+ assert_eq!(0, mem::size_of_val(&*rc));
+ {
+ let _rc_2 = rc.clone();
+ let _rc_3 = rc.clone();
+ let _rc_4 = Rc::downgrade(&_rc_3);
+ }
+ }
+}
+
+#[test]
+#[should_panic = "I've almost got 99 problems."]
+fn shared_from_iter_trustedlen_panic() {
+ // Exercise the `TrustedLen` implementation when `size_hint()` matches
+ // `(_, Some(exact_len))` but where `.next()` drops before the last iteration.
+ let iter = (0..SHARED_ITER_MAX).map(|val| match val {
+ 98 => panic!("I've almost got 99 problems."),
+ _ => Box::new(val),
+ });
+ assert_trusted_len(&iter);
+ let _ = iter.collect::<Rc<[_]>>();
+
+ panic!("I am unreachable.");
+}
+
+#[test]
+fn shared_from_iter_trustedlen_no_fuse() {
+ // Exercise the `TrustedLen` implementation when `size_hint()` matches
+ // `(_, Some(exact_len))` but where the iterator does not behave in a fused manner.
+ struct Iter(std::vec::IntoIter<Option<Box<u8>>>);
+
+ unsafe impl TrustedLen for Iter {}
+
+ impl Iterator for Iter {
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (2, Some(2))
+ }
+
+ type Item = Box<u8>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.0.next().flatten()
+ }
+ }
+
+ let vec = vec![Some(Box::new(42)), Some(Box::new(24)), None, Some(Box::new(12))];
+ let iter = Iter(vec.into_iter());
+ assert_trusted_len(&iter);
+ assert_eq!(&[Box::new(42), Box::new(24)], &*iter.collect::<Rc<[_]>>());
+}
+
+#[test]
+fn weak_may_dangle() {
+ fn hmm<'a>(val: &'a mut Weak<&'a str>) -> Weak<&'a str> {
+ val.clone()
+ }
+
+ // Without #[may_dangle] we get:
+ let mut val = Weak::new();
+ hmm(&mut val);
+ // ~~~~~~~~ borrowed value does not live long enough
+ //
+ // `val` dropped here while still borrowed
+ // borrow might be used here, when `val` is dropped and runs the `Drop` code for type `std::rc::Weak`
+}
diff --git a/library/alloc/tests/slice.rs b/library/alloc/tests/slice.rs
new file mode 100644
index 000000000..21f894343
--- /dev/null
+++ b/library/alloc/tests/slice.rs
@@ -0,0 +1,2018 @@
+use std::cell::Cell;
+use std::cmp::Ordering::{self, Equal, Greater, Less};
+use std::convert::identity;
+use std::fmt;
+use std::mem;
+use std::panic;
+use std::rc::Rc;
+use std::sync::atomic::{AtomicUsize, Ordering::Relaxed};
+
+use rand::distributions::Standard;
+use rand::seq::SliceRandom;
+use rand::{thread_rng, Rng, RngCore};
+
+fn square(n: usize) -> usize {
+ n * n
+}
+
+fn is_odd(n: &usize) -> bool {
+ *n % 2 == 1
+}
+
+#[test]
+fn test_from_fn() {
+ // Test on-stack from_fn.
+ let mut v: Vec<_> = (0..3).map(square).collect();
+ {
+ let v = v;
+ assert_eq!(v.len(), 3);
+ assert_eq!(v[0], 0);
+ assert_eq!(v[1], 1);
+ assert_eq!(v[2], 4);
+ }
+
+ // Test on-heap from_fn.
+ v = (0..5).map(square).collect();
+ {
+ let v = v;
+ assert_eq!(v.len(), 5);
+ assert_eq!(v[0], 0);
+ assert_eq!(v[1], 1);
+ assert_eq!(v[2], 4);
+ assert_eq!(v[3], 9);
+ assert_eq!(v[4], 16);
+ }
+}
+
+#[test]
+fn test_from_elem() {
+ // Test on-stack from_elem.
+ let mut v = vec![10, 10];
+ {
+ let v = v;
+ assert_eq!(v.len(), 2);
+ assert_eq!(v[0], 10);
+ assert_eq!(v[1], 10);
+ }
+
+ // Test on-heap from_elem.
+ v = vec![20; 6];
+ {
+ let v = &v[..];
+ assert_eq!(v[0], 20);
+ assert_eq!(v[1], 20);
+ assert_eq!(v[2], 20);
+ assert_eq!(v[3], 20);
+ assert_eq!(v[4], 20);
+ assert_eq!(v[5], 20);
+ }
+}
+
+#[test]
+fn test_is_empty() {
+ let xs: [i32; 0] = [];
+ assert!(xs.is_empty());
+ assert!(![0].is_empty());
+}
+
+#[test]
+fn test_len_divzero() {
+ type Z = [i8; 0];
+ let v0: &[Z] = &[];
+ let v1: &[Z] = &[[]];
+ let v2: &[Z] = &[[], []];
+ assert_eq!(mem::size_of::<Z>(), 0);
+ assert_eq!(v0.len(), 0);
+ assert_eq!(v1.len(), 1);
+ assert_eq!(v2.len(), 2);
+}
+
+#[test]
+fn test_get() {
+ let mut a = vec![11];
+ assert_eq!(a.get(1), None);
+ a = vec![11, 12];
+ assert_eq!(a.get(1).unwrap(), &12);
+ a = vec![11, 12, 13];
+ assert_eq!(a.get(1).unwrap(), &12);
+}
+
+#[test]
+fn test_first() {
+ let mut a = vec![];
+ assert_eq!(a.first(), None);
+ a = vec![11];
+ assert_eq!(a.first().unwrap(), &11);
+ a = vec![11, 12];
+ assert_eq!(a.first().unwrap(), &11);
+}
+
+#[test]
+fn test_first_mut() {
+ let mut a = vec![];
+ assert_eq!(a.first_mut(), None);
+ a = vec![11];
+ assert_eq!(*a.first_mut().unwrap(), 11);
+ a = vec![11, 12];
+ assert_eq!(*a.first_mut().unwrap(), 11);
+}
+
+#[test]
+fn test_split_first() {
+ let mut a = vec![11];
+ let b: &[i32] = &[];
+ assert!(b.split_first().is_none());
+ assert_eq!(a.split_first(), Some((&11, b)));
+ a = vec![11, 12];
+ let b: &[i32] = &[12];
+ assert_eq!(a.split_first(), Some((&11, b)));
+}
+
+#[test]
+fn test_split_first_mut() {
+ let mut a = vec![11];
+ let b: &mut [i32] = &mut [];
+ assert!(b.split_first_mut().is_none());
+ assert!(a.split_first_mut() == Some((&mut 11, b)));
+ a = vec![11, 12];
+ let b: &mut [_] = &mut [12];
+ assert!(a.split_first_mut() == Some((&mut 11, b)));
+}
+
+#[test]
+fn test_split_last() {
+ let mut a = vec![11];
+ let b: &[i32] = &[];
+ assert!(b.split_last().is_none());
+ assert_eq!(a.split_last(), Some((&11, b)));
+ a = vec![11, 12];
+ let b: &[_] = &[11];
+ assert_eq!(a.split_last(), Some((&12, b)));
+}
+
+#[test]
+fn test_split_last_mut() {
+ let mut a = vec![11];
+ let b: &mut [i32] = &mut [];
+ assert!(b.split_last_mut().is_none());
+ assert!(a.split_last_mut() == Some((&mut 11, b)));
+
+ a = vec![11, 12];
+ let b: &mut [_] = &mut [11];
+ assert!(a.split_last_mut() == Some((&mut 12, b)));
+}
+
+#[test]
+fn test_last() {
+ let mut a = vec![];
+ assert_eq!(a.last(), None);
+ a = vec![11];
+ assert_eq!(a.last().unwrap(), &11);
+ a = vec![11, 12];
+ assert_eq!(a.last().unwrap(), &12);
+}
+
+#[test]
+fn test_last_mut() {
+ let mut a = vec![];
+ assert_eq!(a.last_mut(), None);
+ a = vec![11];
+ assert_eq!(*a.last_mut().unwrap(), 11);
+ a = vec![11, 12];
+ assert_eq!(*a.last_mut().unwrap(), 12);
+}
+
+#[test]
+fn test_slice() {
+ // Test fixed length vector.
+ let vec_fixed = [1, 2, 3, 4];
+ let v_a = vec_fixed[1..vec_fixed.len()].to_vec();
+ assert_eq!(v_a.len(), 3);
+
+ assert_eq!(v_a[0], 2);
+ assert_eq!(v_a[1], 3);
+ assert_eq!(v_a[2], 4);
+
+ // Test on stack.
+ let vec_stack: &[_] = &[1, 2, 3];
+ let v_b = vec_stack[1..3].to_vec();
+ assert_eq!(v_b.len(), 2);
+
+ assert_eq!(v_b[0], 2);
+ assert_eq!(v_b[1], 3);
+
+ // Test `Box<[T]>`
+ let vec_unique = vec![1, 2, 3, 4, 5, 6];
+ let v_d = vec_unique[1..6].to_vec();
+ assert_eq!(v_d.len(), 5);
+
+ assert_eq!(v_d[0], 2);
+ assert_eq!(v_d[1], 3);
+ assert_eq!(v_d[2], 4);
+ assert_eq!(v_d[3], 5);
+ assert_eq!(v_d[4], 6);
+}
+
+#[test]
+fn test_slice_from() {
+ let vec: &[_] = &[1, 2, 3, 4];
+ assert_eq!(&vec[..], vec);
+ let b: &[_] = &[3, 4];
+ assert_eq!(&vec[2..], b);
+ let b: &[_] = &[];
+ assert_eq!(&vec[4..], b);
+}
+
+#[test]
+fn test_slice_to() {
+ let vec: &[_] = &[1, 2, 3, 4];
+ assert_eq!(&vec[..4], vec);
+ let b: &[_] = &[1, 2];
+ assert_eq!(&vec[..2], b);
+ let b: &[_] = &[];
+ assert_eq!(&vec[..0], b);
+}
+
+#[test]
+fn test_pop() {
+ let mut v = vec![5];
+ let e = v.pop();
+ assert_eq!(v.len(), 0);
+ assert_eq!(e, Some(5));
+ let f = v.pop();
+ assert_eq!(f, None);
+ let g = v.pop();
+ assert_eq!(g, None);
+}
+
+#[test]
+fn test_swap_remove() {
+ let mut v = vec![1, 2, 3, 4, 5];
+ let mut e = v.swap_remove(0);
+ assert_eq!(e, 1);
+ assert_eq!(v, [5, 2, 3, 4]);
+ e = v.swap_remove(3);
+ assert_eq!(e, 4);
+ assert_eq!(v, [5, 2, 3]);
+}
+
+#[test]
+#[should_panic]
+fn test_swap_remove_fail() {
+ let mut v = vec![1];
+ let _ = v.swap_remove(0);
+ let _ = v.swap_remove(0);
+}
+
+#[test]
+fn test_swap_remove_noncopyable() {
+ // Tests that we don't accidentally run destructors twice.
+ let mut v: Vec<Box<_>> = Vec::new();
+ v.push(Box::new(0));
+ v.push(Box::new(0));
+ v.push(Box::new(0));
+ let mut _e = v.swap_remove(0);
+ assert_eq!(v.len(), 2);
+ _e = v.swap_remove(1);
+ assert_eq!(v.len(), 1);
+ _e = v.swap_remove(0);
+ assert_eq!(v.len(), 0);
+}
+
+#[test]
+fn test_push() {
+ // Test on-stack push().
+ let mut v = vec![];
+ v.push(1);
+ assert_eq!(v.len(), 1);
+ assert_eq!(v[0], 1);
+
+ // Test on-heap push().
+ v.push(2);
+ assert_eq!(v.len(), 2);
+ assert_eq!(v[0], 1);
+ assert_eq!(v[1], 2);
+}
+
+#[test]
+fn test_truncate() {
+ let mut v: Vec<Box<_>> = vec![Box::new(6), Box::new(5), Box::new(4)];
+ v.truncate(1);
+ let v = v;
+ assert_eq!(v.len(), 1);
+ assert_eq!(*(v[0]), 6);
+ // If the unsafe block didn't drop things properly, we blow up here.
+}
+
+#[test]
+fn test_clear() {
+ let mut v: Vec<Box<_>> = vec![Box::new(6), Box::new(5), Box::new(4)];
+ v.clear();
+ assert_eq!(v.len(), 0);
+ // If the unsafe block didn't drop things properly, we blow up here.
+}
+
+#[test]
+fn test_retain() {
+ let mut v = vec![1, 2, 3, 4, 5];
+ v.retain(is_odd);
+ assert_eq!(v, [1, 3, 5]);
+}
+
+#[test]
+fn test_binary_search() {
+ assert_eq!([1, 2, 3, 4, 5].binary_search(&5).ok(), Some(4));
+ assert_eq!([1, 2, 3, 4, 5].binary_search(&4).ok(), Some(3));
+ assert_eq!([1, 2, 3, 4, 5].binary_search(&3).ok(), Some(2));
+ assert_eq!([1, 2, 3, 4, 5].binary_search(&2).ok(), Some(1));
+ assert_eq!([1, 2, 3, 4, 5].binary_search(&1).ok(), Some(0));
+
+ assert_eq!([2, 4, 6, 8, 10].binary_search(&1).ok(), None);
+ assert_eq!([2, 4, 6, 8, 10].binary_search(&5).ok(), None);
+ assert_eq!([2, 4, 6, 8, 10].binary_search(&4).ok(), Some(1));
+ assert_eq!([2, 4, 6, 8, 10].binary_search(&10).ok(), Some(4));
+
+ assert_eq!([2, 4, 6, 8].binary_search(&1).ok(), None);
+ assert_eq!([2, 4, 6, 8].binary_search(&5).ok(), None);
+ assert_eq!([2, 4, 6, 8].binary_search(&4).ok(), Some(1));
+ assert_eq!([2, 4, 6, 8].binary_search(&8).ok(), Some(3));
+
+ assert_eq!([2, 4, 6].binary_search(&1).ok(), None);
+ assert_eq!([2, 4, 6].binary_search(&5).ok(), None);
+ assert_eq!([2, 4, 6].binary_search(&4).ok(), Some(1));
+ assert_eq!([2, 4, 6].binary_search(&6).ok(), Some(2));
+
+ assert_eq!([2, 4].binary_search(&1).ok(), None);
+ assert_eq!([2, 4].binary_search(&5).ok(), None);
+ assert_eq!([2, 4].binary_search(&2).ok(), Some(0));
+ assert_eq!([2, 4].binary_search(&4).ok(), Some(1));
+
+ assert_eq!([2].binary_search(&1).ok(), None);
+ assert_eq!([2].binary_search(&5).ok(), None);
+ assert_eq!([2].binary_search(&2).ok(), Some(0));
+
+ assert_eq!([].binary_search(&1).ok(), None);
+ assert_eq!([].binary_search(&5).ok(), None);
+
+ assert!([1, 1, 1, 1, 1].binary_search(&1).ok() != None);
+ assert!([1, 1, 1, 1, 2].binary_search(&1).ok() != None);
+ assert!([1, 1, 1, 2, 2].binary_search(&1).ok() != None);
+ assert!([1, 1, 2, 2, 2].binary_search(&1).ok() != None);
+ assert_eq!([1, 2, 2, 2, 2].binary_search(&1).ok(), Some(0));
+
+ assert_eq!([1, 2, 3, 4, 5].binary_search(&6).ok(), None);
+ assert_eq!([1, 2, 3, 4, 5].binary_search(&0).ok(), None);
+}
+
+#[test]
+fn test_reverse() {
+ let mut v = vec![10, 20];
+ assert_eq!(v[0], 10);
+ assert_eq!(v[1], 20);
+ v.reverse();
+ assert_eq!(v[0], 20);
+ assert_eq!(v[1], 10);
+
+ let mut v3 = Vec::<i32>::new();
+ v3.reverse();
+ assert!(v3.is_empty());
+
+ // check the 1-byte-types path
+ let mut v = (-50..51i8).collect::<Vec<_>>();
+ v.reverse();
+ assert_eq!(v, (-50..51i8).rev().collect::<Vec<_>>());
+
+ // check the 2-byte-types path
+ let mut v = (-50..51i16).collect::<Vec<_>>();
+ v.reverse();
+ assert_eq!(v, (-50..51i16).rev().collect::<Vec<_>>());
+}
+
+#[test]
+#[cfg_attr(miri, ignore)] // Miri is too slow
+fn test_sort() {
+ let mut rng = thread_rng();
+
+ for len in (2..25).chain(500..510) {
+ for &modulus in &[5, 10, 100, 1000] {
+ for _ in 0..10 {
+ let orig: Vec<_> =
+ rng.sample_iter::<i32, _>(&Standard).map(|x| x % modulus).take(len).collect();
+
+ // Sort in default order.
+ let mut v = orig.clone();
+ v.sort();
+ assert!(v.windows(2).all(|w| w[0] <= w[1]));
+
+ // Sort in ascending order.
+ let mut v = orig.clone();
+ v.sort_by(|a, b| a.cmp(b));
+ assert!(v.windows(2).all(|w| w[0] <= w[1]));
+
+ // Sort in descending order.
+ let mut v = orig.clone();
+ v.sort_by(|a, b| b.cmp(a));
+ assert!(v.windows(2).all(|w| w[0] >= w[1]));
+
+ // Sort in lexicographic order.
+ let mut v1 = orig.clone();
+ let mut v2 = orig.clone();
+ v1.sort_by_key(|x| x.to_string());
+ v2.sort_by_cached_key(|x| x.to_string());
+ assert!(v1.windows(2).all(|w| w[0].to_string() <= w[1].to_string()));
+ assert!(v1 == v2);
+
+ // Sort with many pre-sorted runs.
+ let mut v = orig.clone();
+ v.sort();
+ v.reverse();
+ for _ in 0..5 {
+ let a = rng.gen::<usize>() % len;
+ let b = rng.gen::<usize>() % len;
+ if a < b {
+ v[a..b].reverse();
+ } else {
+ v.swap(a, b);
+ }
+ }
+ v.sort();
+ assert!(v.windows(2).all(|w| w[0] <= w[1]));
+ }
+ }
+ }
+
+ // Sort using a completely random comparison function.
+ // This will reorder the elements *somehow*, but won't panic.
+ let mut v = [0; 500];
+ for i in 0..v.len() {
+ v[i] = i as i32;
+ }
+ v.sort_by(|_, _| *[Less, Equal, Greater].choose(&mut rng).unwrap());
+ v.sort();
+ for i in 0..v.len() {
+ assert_eq!(v[i], i as i32);
+ }
+
+ // Should not panic.
+ [0i32; 0].sort();
+ [(); 10].sort();
+ [(); 100].sort();
+
+ let mut v = [0xDEADBEEFu64];
+ v.sort();
+ assert!(v == [0xDEADBEEF]);
+}
+
+#[test]
+fn test_sort_stability() {
+ // Miri is too slow
+ let large_range = if cfg!(miri) { 0..0 } else { 500..510 };
+ let rounds = if cfg!(miri) { 1 } else { 10 };
+
+ for len in (2..25).chain(large_range) {
+ for _ in 0..rounds {
+ let mut counts = [0; 10];
+
+ // create a vector like [(6, 1), (5, 1), (6, 2), ...],
+ // where the first item of each tuple is random, but
+ // the second item represents which occurrence of that
+ // number this element is, i.e., the second elements
+ // will occur in sorted order.
+ let orig: Vec<_> = (0..len)
+ .map(|_| {
+ let n = thread_rng().gen::<usize>() % 10;
+ counts[n] += 1;
+ (n, counts[n])
+ })
+ .collect();
+
+ let mut v = orig.clone();
+ // Only sort on the first element, so an unstable sort
+ // may mix up the counts.
+ v.sort_by(|&(a, _), &(b, _)| a.cmp(&b));
+
+ // This comparison includes the count (the second item
+ // of the tuple), so elements with equal first items
+ // will need to be ordered with increasing
+ // counts... i.e., exactly asserting that this sort is
+ // stable.
+ assert!(v.windows(2).all(|w| w[0] <= w[1]));
+
+ let mut v = orig.clone();
+ v.sort_by_cached_key(|&(x, _)| x);
+ assert!(v.windows(2).all(|w| w[0] <= w[1]));
+ }
+ }
+}
+
+#[test]
+fn test_rotate_left() {
+ let expected: Vec<_> = (0..13).collect();
+ let mut v = Vec::new();
+
+ // no-ops
+ v.clone_from(&expected);
+ v.rotate_left(0);
+ assert_eq!(v, expected);
+ v.rotate_left(expected.len());
+ assert_eq!(v, expected);
+ let mut zst_array = [(), (), ()];
+ zst_array.rotate_left(2);
+
+ // happy path
+ v = (5..13).chain(0..5).collect();
+ v.rotate_left(8);
+ assert_eq!(v, expected);
+
+ let expected: Vec<_> = (0..1000).collect();
+
+ // small rotations in large slice, uses ptr::copy
+ v = (2..1000).chain(0..2).collect();
+ v.rotate_left(998);
+ assert_eq!(v, expected);
+ v = (998..1000).chain(0..998).collect();
+ v.rotate_left(2);
+ assert_eq!(v, expected);
+
+ // non-small prime rotation, has a few rounds of swapping
+ v = (389..1000).chain(0..389).collect();
+ v.rotate_left(1000 - 389);
+ assert_eq!(v, expected);
+}
+
+#[test]
+fn test_rotate_right() {
+ let expected: Vec<_> = (0..13).collect();
+ let mut v = Vec::new();
+
+ // no-ops
+ v.clone_from(&expected);
+ v.rotate_right(0);
+ assert_eq!(v, expected);
+ v.rotate_right(expected.len());
+ assert_eq!(v, expected);
+ let mut zst_array = [(), (), ()];
+ zst_array.rotate_right(2);
+
+ // happy path
+ v = (5..13).chain(0..5).collect();
+ v.rotate_right(5);
+ assert_eq!(v, expected);
+
+ let expected: Vec<_> = (0..1000).collect();
+
+ // small rotations in large slice, uses ptr::copy
+ v = (2..1000).chain(0..2).collect();
+ v.rotate_right(2);
+ assert_eq!(v, expected);
+ v = (998..1000).chain(0..998).collect();
+ v.rotate_right(998);
+ assert_eq!(v, expected);
+
+ // non-small prime rotation, has a few rounds of swapping
+ v = (389..1000).chain(0..389).collect();
+ v.rotate_right(389);
+ assert_eq!(v, expected);
+}
+
+#[test]
+fn test_concat() {
+ let v: [Vec<i32>; 0] = [];
+ let c = v.concat();
+ assert_eq!(c, []);
+ let d = [vec![1], vec![2, 3]].concat();
+ assert_eq!(d, [1, 2, 3]);
+
+ let v: &[&[_]] = &[&[1], &[2, 3]];
+ assert_eq!(v.join(&0), [1, 0, 2, 3]);
+ let v: &[&[_]] = &[&[1], &[2], &[3]];
+ assert_eq!(v.join(&0), [1, 0, 2, 0, 3]);
+}
+
+#[test]
+fn test_join() {
+ let v: [Vec<i32>; 0] = [];
+ assert_eq!(v.join(&0), []);
+ assert_eq!([vec![1], vec![2, 3]].join(&0), [1, 0, 2, 3]);
+ assert_eq!([vec![1], vec![2], vec![3]].join(&0), [1, 0, 2, 0, 3]);
+
+ let v: [&[_]; 2] = [&[1], &[2, 3]];
+ assert_eq!(v.join(&0), [1, 0, 2, 3]);
+ let v: [&[_]; 3] = [&[1], &[2], &[3]];
+ assert_eq!(v.join(&0), [1, 0, 2, 0, 3]);
+}
+
+#[test]
+fn test_join_nocopy() {
+ let v: [String; 0] = [];
+ assert_eq!(v.join(","), "");
+ assert_eq!(["a".to_string(), "ab".into()].join(","), "a,ab");
+ assert_eq!(["a".to_string(), "ab".into(), "abc".into()].join(","), "a,ab,abc");
+ assert_eq!(["a".to_string(), "ab".into(), "".into()].join(","), "a,ab,");
+}
+
+#[test]
+fn test_insert() {
+ let mut a = vec![1, 2, 4];
+ a.insert(2, 3);
+ assert_eq!(a, [1, 2, 3, 4]);
+
+ let mut a = vec![1, 2, 3];
+ a.insert(0, 0);
+ assert_eq!(a, [0, 1, 2, 3]);
+
+ let mut a = vec![1, 2, 3];
+ a.insert(3, 4);
+ assert_eq!(a, [1, 2, 3, 4]);
+
+ let mut a = vec![];
+ a.insert(0, 1);
+ assert_eq!(a, [1]);
+}
+
+#[test]
+#[should_panic]
+fn test_insert_oob() {
+ let mut a = vec![1, 2, 3];
+ a.insert(4, 5);
+}
+
+#[test]
+fn test_remove() {
+ let mut a = vec![1, 2, 3, 4];
+
+ assert_eq!(a.remove(2), 3);
+ assert_eq!(a, [1, 2, 4]);
+
+ assert_eq!(a.remove(2), 4);
+ assert_eq!(a, [1, 2]);
+
+ assert_eq!(a.remove(0), 1);
+ assert_eq!(a, [2]);
+
+ assert_eq!(a.remove(0), 2);
+ assert_eq!(a, []);
+}
+
+#[test]
+#[should_panic]
+fn test_remove_fail() {
+ let mut a = vec![1];
+ let _ = a.remove(0);
+ let _ = a.remove(0);
+}
+
+#[test]
+fn test_capacity() {
+ let mut v = vec![0];
+ v.reserve_exact(10);
+ assert!(v.capacity() >= 11);
+}
+
+#[test]
+fn test_slice_2() {
+ let v = vec![1, 2, 3, 4, 5];
+ let v = &v[1..3];
+ assert_eq!(v.len(), 2);
+ assert_eq!(v[0], 2);
+ assert_eq!(v[1], 3);
+}
+
+macro_rules! assert_order {
+ (Greater, $a:expr, $b:expr) => {
+ assert_eq!($a.cmp($b), Greater);
+ assert!($a > $b);
+ };
+ (Less, $a:expr, $b:expr) => {
+ assert_eq!($a.cmp($b), Less);
+ assert!($a < $b);
+ };
+ (Equal, $a:expr, $b:expr) => {
+ assert_eq!($a.cmp($b), Equal);
+ assert_eq!($a, $b);
+ };
+}
+
+#[test]
+fn test_total_ord_u8() {
+ let c = &[1u8, 2, 3];
+ assert_order!(Greater, &[1u8, 2, 3, 4][..], &c[..]);
+ let c = &[1u8, 2, 3, 4];
+ assert_order!(Less, &[1u8, 2, 3][..], &c[..]);
+ let c = &[1u8, 2, 3, 6];
+ assert_order!(Equal, &[1u8, 2, 3, 6][..], &c[..]);
+ let c = &[1u8, 2, 3, 4, 5, 6];
+ assert_order!(Less, &[1u8, 2, 3, 4, 5, 5, 5, 5][..], &c[..]);
+ let c = &[1u8, 2, 3, 4];
+ assert_order!(Greater, &[2u8, 2][..], &c[..]);
+}
+
+#[test]
+fn test_total_ord_i32() {
+ let c = &[1, 2, 3];
+ assert_order!(Greater, &[1, 2, 3, 4][..], &c[..]);
+ let c = &[1, 2, 3, 4];
+ assert_order!(Less, &[1, 2, 3][..], &c[..]);
+ let c = &[1, 2, 3, 6];
+ assert_order!(Equal, &[1, 2, 3, 6][..], &c[..]);
+ let c = &[1, 2, 3, 4, 5, 6];
+ assert_order!(Less, &[1, 2, 3, 4, 5, 5, 5, 5][..], &c[..]);
+ let c = &[1, 2, 3, 4];
+ assert_order!(Greater, &[2, 2][..], &c[..]);
+}
+
+#[test]
+fn test_iterator() {
+ let xs = [1, 2, 5, 10, 11];
+ let mut it = xs.iter();
+ assert_eq!(it.size_hint(), (5, Some(5)));
+ assert_eq!(it.next().unwrap(), &1);
+ assert_eq!(it.size_hint(), (4, Some(4)));
+ assert_eq!(it.next().unwrap(), &2);
+ assert_eq!(it.size_hint(), (3, Some(3)));
+ assert_eq!(it.next().unwrap(), &5);
+ assert_eq!(it.size_hint(), (2, Some(2)));
+ assert_eq!(it.next().unwrap(), &10);
+ assert_eq!(it.size_hint(), (1, Some(1)));
+ assert_eq!(it.next().unwrap(), &11);
+ assert_eq!(it.size_hint(), (0, Some(0)));
+ assert!(it.next().is_none());
+}
+
+#[test]
+fn test_iter_size_hints() {
+ let mut xs = [1, 2, 5, 10, 11];
+ assert_eq!(xs.iter().size_hint(), (5, Some(5)));
+ assert_eq!(xs.iter_mut().size_hint(), (5, Some(5)));
+}
+
+#[test]
+fn test_iter_as_slice() {
+ let xs = [1, 2, 5, 10, 11];
+ let mut iter = xs.iter();
+ assert_eq!(iter.as_slice(), &[1, 2, 5, 10, 11]);
+ iter.next();
+ assert_eq!(iter.as_slice(), &[2, 5, 10, 11]);
+}
+
+#[test]
+fn test_iter_as_ref() {
+ let xs = [1, 2, 5, 10, 11];
+ let mut iter = xs.iter();
+ assert_eq!(iter.as_ref(), &[1, 2, 5, 10, 11]);
+ iter.next();
+ assert_eq!(iter.as_ref(), &[2, 5, 10, 11]);
+}
+
+#[test]
+fn test_iter_clone() {
+ let xs = [1, 2, 5];
+ let mut it = xs.iter();
+ it.next();
+ let mut jt = it.clone();
+ assert_eq!(it.next(), jt.next());
+ assert_eq!(it.next(), jt.next());
+ assert_eq!(it.next(), jt.next());
+}
+
+#[test]
+fn test_iter_is_empty() {
+ let xs = [1, 2, 5, 10, 11];
+ for i in 0..xs.len() {
+ for j in i..xs.len() {
+ assert_eq!(xs[i..j].iter().is_empty(), xs[i..j].is_empty());
+ }
+ }
+}
+
+#[test]
+fn test_mut_iterator() {
+ let mut xs = [1, 2, 3, 4, 5];
+ for x in &mut xs {
+ *x += 1;
+ }
+ assert!(xs == [2, 3, 4, 5, 6])
+}
+
+#[test]
+fn test_rev_iterator() {
+ let xs = [1, 2, 5, 10, 11];
+ let ys = [11, 10, 5, 2, 1];
+ let mut i = 0;
+ for &x in xs.iter().rev() {
+ assert_eq!(x, ys[i]);
+ i += 1;
+ }
+ assert_eq!(i, 5);
+}
+
+#[test]
+fn test_mut_rev_iterator() {
+ let mut xs = [1, 2, 3, 4, 5];
+ for (i, x) in xs.iter_mut().rev().enumerate() {
+ *x += i;
+ }
+ assert!(xs == [5, 5, 5, 5, 5])
+}
+
+#[test]
+fn test_move_iterator() {
+ let xs = vec![1, 2, 3, 4, 5];
+ assert_eq!(xs.into_iter().fold(0, |a: usize, b: usize| 10 * a + b), 12345);
+}
+
+#[test]
+fn test_move_rev_iterator() {
+ let xs = vec![1, 2, 3, 4, 5];
+ assert_eq!(xs.into_iter().rev().fold(0, |a: usize, b: usize| 10 * a + b), 54321);
+}
+
+#[test]
+fn test_splitator() {
+ let xs = &[1, 2, 3, 4, 5];
+
+ let splits: &[&[_]] = &[&[1], &[3], &[5]];
+ assert_eq!(xs.split(|x| *x % 2 == 0).collect::<Vec<_>>(), splits);
+ let splits: &[&[_]] = &[&[], &[2, 3, 4, 5]];
+ assert_eq!(xs.split(|x| *x == 1).collect::<Vec<_>>(), splits);
+ let splits: &[&[_]] = &[&[1, 2, 3, 4], &[]];
+ assert_eq!(xs.split(|x| *x == 5).collect::<Vec<_>>(), splits);
+ let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
+ assert_eq!(xs.split(|x| *x == 10).collect::<Vec<_>>(), splits);
+ let splits: &[&[_]] = &[&[], &[], &[], &[], &[], &[]];
+ assert_eq!(xs.split(|_| true).collect::<Vec<&[i32]>>(), splits);
+
+ let xs: &[i32] = &[];
+ let splits: &[&[i32]] = &[&[]];
+ assert_eq!(xs.split(|x| *x == 5).collect::<Vec<&[i32]>>(), splits);
+}
+
+#[test]
+fn test_splitator_inclusive() {
+ let xs = &[1, 2, 3, 4, 5];
+
+ let splits: &[&[_]] = &[&[1, 2], &[3, 4], &[5]];
+ assert_eq!(xs.split_inclusive(|x| *x % 2 == 0).collect::<Vec<_>>(), splits);
+ let splits: &[&[_]] = &[&[1], &[2, 3, 4, 5]];
+ assert_eq!(xs.split_inclusive(|x| *x == 1).collect::<Vec<_>>(), splits);
+ let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
+ assert_eq!(xs.split_inclusive(|x| *x == 5).collect::<Vec<_>>(), splits);
+ let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
+ assert_eq!(xs.split_inclusive(|x| *x == 10).collect::<Vec<_>>(), splits);
+ let splits: &[&[_]] = &[&[1], &[2], &[3], &[4], &[5]];
+ assert_eq!(xs.split_inclusive(|_| true).collect::<Vec<&[i32]>>(), splits);
+
+ let xs: &[i32] = &[];
+ let splits: &[&[i32]] = &[];
+ assert_eq!(xs.split_inclusive(|x| *x == 5).collect::<Vec<&[i32]>>(), splits);
+}
+
+#[test]
+fn test_splitator_inclusive_reverse() {
+ let xs = &[1, 2, 3, 4, 5];
+
+ let splits: &[&[_]] = &[&[5], &[3, 4], &[1, 2]];
+ assert_eq!(xs.split_inclusive(|x| *x % 2 == 0).rev().collect::<Vec<_>>(), splits);
+ let splits: &[&[_]] = &[&[2, 3, 4, 5], &[1]];
+ assert_eq!(xs.split_inclusive(|x| *x == 1).rev().collect::<Vec<_>>(), splits);
+ let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
+ assert_eq!(xs.split_inclusive(|x| *x == 5).rev().collect::<Vec<_>>(), splits);
+ let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
+ assert_eq!(xs.split_inclusive(|x| *x == 10).rev().collect::<Vec<_>>(), splits);
+ let splits: &[&[_]] = &[&[5], &[4], &[3], &[2], &[1]];
+ assert_eq!(xs.split_inclusive(|_| true).rev().collect::<Vec<_>>(), splits);
+
+ let xs: &[i32] = &[];
+ let splits: &[&[i32]] = &[];
+ assert_eq!(xs.split_inclusive(|x| *x == 5).rev().collect::<Vec<_>>(), splits);
+}
+
+#[test]
+fn test_splitator_mut_inclusive() {
+ let xs = &mut [1, 2, 3, 4, 5];
+
+ let splits: &[&[_]] = &[&[1, 2], &[3, 4], &[5]];
+ assert_eq!(xs.split_inclusive_mut(|x| *x % 2 == 0).collect::<Vec<_>>(), splits);
+ let splits: &[&[_]] = &[&[1], &[2, 3, 4, 5]];
+ assert_eq!(xs.split_inclusive_mut(|x| *x == 1).collect::<Vec<_>>(), splits);
+ let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
+ assert_eq!(xs.split_inclusive_mut(|x| *x == 5).collect::<Vec<_>>(), splits);
+ let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
+ assert_eq!(xs.split_inclusive_mut(|x| *x == 10).collect::<Vec<_>>(), splits);
+ let splits: &[&[_]] = &[&[1], &[2], &[3], &[4], &[5]];
+ assert_eq!(xs.split_inclusive_mut(|_| true).collect::<Vec<_>>(), splits);
+
+ let xs: &mut [i32] = &mut [];
+ let splits: &[&[i32]] = &[];
+ assert_eq!(xs.split_inclusive_mut(|x| *x == 5).collect::<Vec<_>>(), splits);
+}
+
+#[test]
+fn test_splitator_mut_inclusive_reverse() {
+ let xs = &mut [1, 2, 3, 4, 5];
+
+ let splits: &[&[_]] = &[&[5], &[3, 4], &[1, 2]];
+ assert_eq!(xs.split_inclusive_mut(|x| *x % 2 == 0).rev().collect::<Vec<_>>(), splits);
+ let splits: &[&[_]] = &[&[2, 3, 4, 5], &[1]];
+ assert_eq!(xs.split_inclusive_mut(|x| *x == 1).rev().collect::<Vec<_>>(), splits);
+ let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
+ assert_eq!(xs.split_inclusive_mut(|x| *x == 5).rev().collect::<Vec<_>>(), splits);
+ let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
+ assert_eq!(xs.split_inclusive_mut(|x| *x == 10).rev().collect::<Vec<_>>(), splits);
+ let splits: &[&[_]] = &[&[5], &[4], &[3], &[2], &[1]];
+ assert_eq!(xs.split_inclusive_mut(|_| true).rev().collect::<Vec<_>>(), splits);
+
+ let xs: &mut [i32] = &mut [];
+ let splits: &[&[i32]] = &[];
+ assert_eq!(xs.split_inclusive_mut(|x| *x == 5).rev().collect::<Vec<_>>(), splits);
+}
+
+#[test]
+fn test_splitnator() {
+ let xs = &[1, 2, 3, 4, 5];
+
+ let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
+ assert_eq!(xs.splitn(1, |x| *x % 2 == 0).collect::<Vec<_>>(), splits);
+ let splits: &[&[_]] = &[&[1], &[3, 4, 5]];
+ assert_eq!(xs.splitn(2, |x| *x % 2 == 0).collect::<Vec<_>>(), splits);
+ let splits: &[&[_]] = &[&[], &[], &[], &[4, 5]];
+ assert_eq!(xs.splitn(4, |_| true).collect::<Vec<_>>(), splits);
+
+ let xs: &[i32] = &[];
+ let splits: &[&[i32]] = &[&[]];
+ assert_eq!(xs.splitn(2, |x| *x == 5).collect::<Vec<_>>(), splits);
+}
+
+#[test]
+fn test_splitnator_mut() {
+ let xs = &mut [1, 2, 3, 4, 5];
+
+ let splits: &[&mut [_]] = &[&mut [1, 2, 3, 4, 5]];
+ assert_eq!(xs.splitn_mut(1, |x| *x % 2 == 0).collect::<Vec<_>>(), splits);
+ let splits: &[&mut [_]] = &[&mut [1], &mut [3, 4, 5]];
+ assert_eq!(xs.splitn_mut(2, |x| *x % 2 == 0).collect::<Vec<_>>(), splits);
+ let splits: &[&mut [_]] = &[&mut [], &mut [], &mut [], &mut [4, 5]];
+ assert_eq!(xs.splitn_mut(4, |_| true).collect::<Vec<_>>(), splits);
+
+ let xs: &mut [i32] = &mut [];
+ let splits: &[&mut [i32]] = &[&mut []];
+ assert_eq!(xs.splitn_mut(2, |x| *x == 5).collect::<Vec<_>>(), splits);
+}
+
+#[test]
+fn test_rsplitator() {
+ let xs = &[1, 2, 3, 4, 5];
+
+ let splits: &[&[_]] = &[&[5], &[3], &[1]];
+ assert_eq!(xs.split(|x| *x % 2 == 0).rev().collect::<Vec<_>>(), splits);
+ let splits: &[&[_]] = &[&[2, 3, 4, 5], &[]];
+ assert_eq!(xs.split(|x| *x == 1).rev().collect::<Vec<_>>(), splits);
+ let splits: &[&[_]] = &[&[], &[1, 2, 3, 4]];
+ assert_eq!(xs.split(|x| *x == 5).rev().collect::<Vec<_>>(), splits);
+ let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
+ assert_eq!(xs.split(|x| *x == 10).rev().collect::<Vec<_>>(), splits);
+
+ let xs: &[i32] = &[];
+ let splits: &[&[i32]] = &[&[]];
+ assert_eq!(xs.split(|x| *x == 5).rev().collect::<Vec<&[i32]>>(), splits);
+}
+
+#[test]
+fn test_rsplitnator() {
+ let xs = &[1, 2, 3, 4, 5];
+
+ let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
+ assert_eq!(xs.rsplitn(1, |x| *x % 2 == 0).collect::<Vec<_>>(), splits);
+ let splits: &[&[_]] = &[&[5], &[1, 2, 3]];
+ assert_eq!(xs.rsplitn(2, |x| *x % 2 == 0).collect::<Vec<_>>(), splits);
+ let splits: &[&[_]] = &[&[], &[], &[], &[1, 2]];
+ assert_eq!(xs.rsplitn(4, |_| true).collect::<Vec<_>>(), splits);
+
+ let xs: &[i32] = &[];
+ let splits: &[&[i32]] = &[&[]];
+ assert_eq!(xs.rsplitn(2, |x| *x == 5).collect::<Vec<&[i32]>>(), splits);
+ assert!(xs.rsplitn(0, |x| *x % 2 == 0).next().is_none());
+}
+
+#[test]
+fn test_split_iterators_size_hint() {
+ #[derive(Copy, Clone)]
+ enum Bounds {
+ Lower,
+ Upper,
+ }
+ fn assert_tight_size_hints(mut it: impl Iterator, which: Bounds, ctx: impl fmt::Display) {
+ match which {
+ Bounds::Lower => {
+ let mut lower_bounds = vec![it.size_hint().0];
+ while let Some(_) = it.next() {
+ lower_bounds.push(it.size_hint().0);
+ }
+ let target: Vec<_> = (0..lower_bounds.len()).rev().collect();
+ assert_eq!(lower_bounds, target, "lower bounds incorrect or not tight: {}", ctx);
+ }
+ Bounds::Upper => {
+ let mut upper_bounds = vec![it.size_hint().1];
+ while let Some(_) = it.next() {
+ upper_bounds.push(it.size_hint().1);
+ }
+ let target: Vec<_> = (0..upper_bounds.len()).map(Some).rev().collect();
+ assert_eq!(upper_bounds, target, "upper bounds incorrect or not tight: {}", ctx);
+ }
+ }
+ }
+
+ for len in 0..=2 {
+ let mut v: Vec<u8> = (0..len).collect();
+
+ // p: predicate, b: bound selection
+ for (p, b) in [
+ // with a predicate always returning false, the split*-iterators
+ // become maximally short, so the size_hint lower bounds are tight
+ ((|_| false) as fn(&_) -> _, Bounds::Lower),
+ // with a predicate always returning true, the split*-iterators
+ // become maximally long, so the size_hint upper bounds are tight
+ ((|_| true) as fn(&_) -> _, Bounds::Upper),
+ ] {
+ use assert_tight_size_hints as a;
+ use format_args as f;
+
+ a(v.split(p), b, "split");
+ a(v.split_mut(p), b, "split_mut");
+ a(v.split_inclusive(p), b, "split_inclusive");
+ a(v.split_inclusive_mut(p), b, "split_inclusive_mut");
+ a(v.rsplit(p), b, "rsplit");
+ a(v.rsplit_mut(p), b, "rsplit_mut");
+
+ for n in 0..=3 {
+ a(v.splitn(n, p), b, f!("splitn, n = {n}"));
+ a(v.splitn_mut(n, p), b, f!("splitn_mut, n = {n}"));
+ a(v.rsplitn(n, p), b, f!("rsplitn, n = {n}"));
+ a(v.rsplitn_mut(n, p), b, f!("rsplitn_mut, n = {n}"));
+ }
+ }
+ }
+}
+
+#[test]
+fn test_windowsator() {
+ let v = &[1, 2, 3, 4];
+
+ let wins: &[&[_]] = &[&[1, 2], &[2, 3], &[3, 4]];
+ assert_eq!(v.windows(2).collect::<Vec<_>>(), wins);
+
+ let wins: &[&[_]] = &[&[1, 2, 3], &[2, 3, 4]];
+ assert_eq!(v.windows(3).collect::<Vec<_>>(), wins);
+ assert!(v.windows(6).next().is_none());
+
+ let wins: &[&[_]] = &[&[3, 4], &[2, 3], &[1, 2]];
+ assert_eq!(v.windows(2).rev().collect::<Vec<&[_]>>(), wins);
+}
+
+#[test]
+#[should_panic]
+fn test_windowsator_0() {
+ let v = &[1, 2, 3, 4];
+ let _it = v.windows(0);
+}
+
+#[test]
+fn test_chunksator() {
+ let v = &[1, 2, 3, 4, 5];
+
+ assert_eq!(v.chunks(2).len(), 3);
+
+ let chunks: &[&[_]] = &[&[1, 2], &[3, 4], &[5]];
+ assert_eq!(v.chunks(2).collect::<Vec<_>>(), chunks);
+ let chunks: &[&[_]] = &[&[1, 2, 3], &[4, 5]];
+ assert_eq!(v.chunks(3).collect::<Vec<_>>(), chunks);
+ let chunks: &[&[_]] = &[&[1, 2, 3, 4, 5]];
+ assert_eq!(v.chunks(6).collect::<Vec<_>>(), chunks);
+
+ let chunks: &[&[_]] = &[&[5], &[3, 4], &[1, 2]];
+ assert_eq!(v.chunks(2).rev().collect::<Vec<_>>(), chunks);
+}
+
+#[test]
+#[should_panic]
+fn test_chunksator_0() {
+ let v = &[1, 2, 3, 4];
+ let _it = v.chunks(0);
+}
+
+#[test]
+fn test_chunks_exactator() {
+ let v = &[1, 2, 3, 4, 5];
+
+ assert_eq!(v.chunks_exact(2).len(), 2);
+
+ let chunks: &[&[_]] = &[&[1, 2], &[3, 4]];
+ assert_eq!(v.chunks_exact(2).collect::<Vec<_>>(), chunks);
+ let chunks: &[&[_]] = &[&[1, 2, 3]];
+ assert_eq!(v.chunks_exact(3).collect::<Vec<_>>(), chunks);
+ let chunks: &[&[_]] = &[];
+ assert_eq!(v.chunks_exact(6).collect::<Vec<_>>(), chunks);
+
+ let chunks: &[&[_]] = &[&[3, 4], &[1, 2]];
+ assert_eq!(v.chunks_exact(2).rev().collect::<Vec<_>>(), chunks);
+}
+
+#[test]
+#[should_panic]
+fn test_chunks_exactator_0() {
+ let v = &[1, 2, 3, 4];
+ let _it = v.chunks_exact(0);
+}
+
+#[test]
+fn test_rchunksator() {
+ let v = &[1, 2, 3, 4, 5];
+
+ assert_eq!(v.rchunks(2).len(), 3);
+
+ let chunks: &[&[_]] = &[&[4, 5], &[2, 3], &[1]];
+ assert_eq!(v.rchunks(2).collect::<Vec<_>>(), chunks);
+ let chunks: &[&[_]] = &[&[3, 4, 5], &[1, 2]];
+ assert_eq!(v.rchunks(3).collect::<Vec<_>>(), chunks);
+ let chunks: &[&[_]] = &[&[1, 2, 3, 4, 5]];
+ assert_eq!(v.rchunks(6).collect::<Vec<_>>(), chunks);
+
+ let chunks: &[&[_]] = &[&[1], &[2, 3], &[4, 5]];
+ assert_eq!(v.rchunks(2).rev().collect::<Vec<_>>(), chunks);
+}
+
+#[test]
+#[should_panic]
+fn test_rchunksator_0() {
+ let v = &[1, 2, 3, 4];
+ let _it = v.rchunks(0);
+}
+
+#[test]
+fn test_rchunks_exactator() {
+ let v = &[1, 2, 3, 4, 5];
+
+ assert_eq!(v.rchunks_exact(2).len(), 2);
+
+ let chunks: &[&[_]] = &[&[4, 5], &[2, 3]];
+ assert_eq!(v.rchunks_exact(2).collect::<Vec<_>>(), chunks);
+ let chunks: &[&[_]] = &[&[3, 4, 5]];
+ assert_eq!(v.rchunks_exact(3).collect::<Vec<_>>(), chunks);
+ let chunks: &[&[_]] = &[];
+ assert_eq!(v.rchunks_exact(6).collect::<Vec<_>>(), chunks);
+
+ let chunks: &[&[_]] = &[&[2, 3], &[4, 5]];
+ assert_eq!(v.rchunks_exact(2).rev().collect::<Vec<_>>(), chunks);
+}
+
+#[test]
+#[should_panic]
+fn test_rchunks_exactator_0() {
+ let v = &[1, 2, 3, 4];
+ let _it = v.rchunks_exact(0);
+}
+
+#[test]
+fn test_reverse_part() {
+ let mut values = [1, 2, 3, 4, 5];
+ values[1..4].reverse();
+ assert!(values == [1, 4, 3, 2, 5]);
+}
+
+#[test]
+fn test_show() {
+ macro_rules! test_show_vec {
+ ($x:expr, $x_str:expr) => {{
+ let (x, x_str) = ($x, $x_str);
+ assert_eq!(format!("{x:?}"), x_str);
+ assert_eq!(format!("{x:?}"), x_str);
+ }};
+ }
+ let empty = Vec::<i32>::new();
+ test_show_vec!(empty, "[]");
+ test_show_vec!(vec![1], "[1]");
+ test_show_vec!(vec![1, 2, 3], "[1, 2, 3]");
+ test_show_vec!(vec![vec![], vec![1], vec![1, 1]], "[[], [1], [1, 1]]");
+
+ let empty_mut: &mut [i32] = &mut [];
+ test_show_vec!(empty_mut, "[]");
+ let v = &mut [1];
+ test_show_vec!(v, "[1]");
+ let v = &mut [1, 2, 3];
+ test_show_vec!(v, "[1, 2, 3]");
+ let v: &mut [&mut [_]] = &mut [&mut [], &mut [1], &mut [1, 1]];
+ test_show_vec!(v, "[[], [1], [1, 1]]");
+}
+
+#[test]
+fn test_vec_default() {
+ macro_rules! t {
+ ($ty:ty) => {{
+ let v: $ty = Default::default();
+ assert!(v.is_empty());
+ }};
+ }
+
+ t!(&[i32]);
+ t!(Vec<i32>);
+}
+
+#[test]
+#[should_panic]
+fn test_overflow_does_not_cause_segfault() {
+ let mut v = vec![];
+ v.reserve_exact(!0);
+ v.push(1);
+ v.push(2);
+}
+
+#[test]
+#[should_panic]
+fn test_overflow_does_not_cause_segfault_managed() {
+ let mut v = vec![Rc::new(1)];
+ v.reserve_exact(!0);
+ v.push(Rc::new(2));
+}
+
+#[test]
+fn test_mut_split_at() {
+ let mut values = [1, 2, 3, 4, 5];
+ {
+ let (left, right) = values.split_at_mut(2);
+ {
+ let left: &[_] = left;
+ assert!(left[..left.len()] == [1, 2]);
+ }
+ for p in left {
+ *p += 1;
+ }
+
+ {
+ let right: &[_] = right;
+ assert!(right[..right.len()] == [3, 4, 5]);
+ }
+ for p in right {
+ *p += 2;
+ }
+ }
+
+ assert!(values == [2, 3, 5, 6, 7]);
+}
+
+#[derive(Clone, PartialEq)]
+struct Foo;
+
+#[test]
+fn test_iter_zero_sized() {
+ let mut v = vec![Foo, Foo, Foo];
+ assert_eq!(v.len(), 3);
+ let mut cnt = 0;
+
+ for f in &v {
+ assert!(*f == Foo);
+ cnt += 1;
+ }
+ assert_eq!(cnt, 3);
+
+ for f in &v[1..3] {
+ assert!(*f == Foo);
+ cnt += 1;
+ }
+ assert_eq!(cnt, 5);
+
+ for f in &mut v {
+ assert!(*f == Foo);
+ cnt += 1;
+ }
+ assert_eq!(cnt, 8);
+
+ for f in v {
+ assert!(f == Foo);
+ cnt += 1;
+ }
+ assert_eq!(cnt, 11);
+
+ let xs: [Foo; 3] = [Foo, Foo, Foo];
+ cnt = 0;
+ for f in &xs {
+ assert!(*f == Foo);
+ cnt += 1;
+ }
+ assert!(cnt == 3);
+}
+
+#[test]
+fn test_shrink_to_fit() {
+ let mut xs = vec![0, 1, 2, 3];
+ for i in 4..100 {
+ xs.push(i)
+ }
+ assert_eq!(xs.capacity(), 128);
+ xs.shrink_to_fit();
+ assert_eq!(xs.capacity(), 100);
+ assert_eq!(xs, (0..100).collect::<Vec<_>>());
+}
+
+#[test]
+fn test_starts_with() {
+ assert!(b"foobar".starts_with(b"foo"));
+ assert!(!b"foobar".starts_with(b"oob"));
+ assert!(!b"foobar".starts_with(b"bar"));
+ assert!(!b"foo".starts_with(b"foobar"));
+ assert!(!b"bar".starts_with(b"foobar"));
+ assert!(b"foobar".starts_with(b"foobar"));
+ let empty: &[u8] = &[];
+ assert!(empty.starts_with(empty));
+ assert!(!empty.starts_with(b"foo"));
+ assert!(b"foobar".starts_with(empty));
+}
+
+#[test]
+fn test_ends_with() {
+ assert!(b"foobar".ends_with(b"bar"));
+ assert!(!b"foobar".ends_with(b"oba"));
+ assert!(!b"foobar".ends_with(b"foo"));
+ assert!(!b"foo".ends_with(b"foobar"));
+ assert!(!b"bar".ends_with(b"foobar"));
+ assert!(b"foobar".ends_with(b"foobar"));
+ let empty: &[u8] = &[];
+ assert!(empty.ends_with(empty));
+ assert!(!empty.ends_with(b"foo"));
+ assert!(b"foobar".ends_with(empty));
+}
+
+#[test]
+fn test_mut_splitator() {
+ let mut xs = [0, 1, 0, 2, 3, 0, 0, 4, 5, 0];
+ assert_eq!(xs.split_mut(|x| *x == 0).count(), 6);
+ for slice in xs.split_mut(|x| *x == 0) {
+ slice.reverse();
+ }
+ assert!(xs == [0, 1, 0, 3, 2, 0, 0, 5, 4, 0]);
+
+ let mut xs = [0, 1, 0, 2, 3, 0, 0, 4, 5, 0, 6, 7];
+ for slice in xs.split_mut(|x| *x == 0).take(5) {
+ slice.reverse();
+ }
+ assert!(xs == [0, 1, 0, 3, 2, 0, 0, 5, 4, 0, 6, 7]);
+}
+
+#[test]
+fn test_mut_splitator_rev() {
+ let mut xs = [1, 2, 0, 3, 4, 0, 0, 5, 6, 0];
+ for slice in xs.split_mut(|x| *x == 0).rev().take(4) {
+ slice.reverse();
+ }
+ assert!(xs == [1, 2, 0, 4, 3, 0, 0, 6, 5, 0]);
+}
+
+#[test]
+fn test_get_mut() {
+ let mut v = [0, 1, 2];
+ assert_eq!(v.get_mut(3), None);
+ v.get_mut(1).map(|e| *e = 7);
+ assert_eq!(v[1], 7);
+ let mut x = 2;
+ assert_eq!(v.get_mut(2), Some(&mut x));
+}
+
+#[test]
+fn test_mut_chunks() {
+ let mut v = [0, 1, 2, 3, 4, 5, 6];
+ assert_eq!(v.chunks_mut(3).len(), 3);
+ for (i, chunk) in v.chunks_mut(3).enumerate() {
+ for x in chunk {
+ *x = i as u8;
+ }
+ }
+ let result = [0, 0, 0, 1, 1, 1, 2];
+ assert_eq!(v, result);
+}
+
+#[test]
+fn test_mut_chunks_rev() {
+ let mut v = [0, 1, 2, 3, 4, 5, 6];
+ for (i, chunk) in v.chunks_mut(3).rev().enumerate() {
+ for x in chunk {
+ *x = i as u8;
+ }
+ }
+ let result = [2, 2, 2, 1, 1, 1, 0];
+ assert_eq!(v, result);
+}
+
+#[test]
+#[should_panic]
+fn test_mut_chunks_0() {
+ let mut v = [1, 2, 3, 4];
+ let _it = v.chunks_mut(0);
+}
+
+#[test]
+fn test_mut_chunks_exact() {
+ let mut v = [0, 1, 2, 3, 4, 5, 6];
+ assert_eq!(v.chunks_exact_mut(3).len(), 2);
+ for (i, chunk) in v.chunks_exact_mut(3).enumerate() {
+ for x in chunk {
+ *x = i as u8;
+ }
+ }
+ let result = [0, 0, 0, 1, 1, 1, 6];
+ assert_eq!(v, result);
+}
+
+#[test]
+fn test_mut_chunks_exact_rev() {
+ let mut v = [0, 1, 2, 3, 4, 5, 6];
+ for (i, chunk) in v.chunks_exact_mut(3).rev().enumerate() {
+ for x in chunk {
+ *x = i as u8;
+ }
+ }
+ let result = [1, 1, 1, 0, 0, 0, 6];
+ assert_eq!(v, result);
+}
+
+#[test]
+#[should_panic]
+fn test_mut_chunks_exact_0() {
+ let mut v = [1, 2, 3, 4];
+ let _it = v.chunks_exact_mut(0);
+}
+
+#[test]
+fn test_mut_rchunks() {
+ let mut v = [0, 1, 2, 3, 4, 5, 6];
+ assert_eq!(v.rchunks_mut(3).len(), 3);
+ for (i, chunk) in v.rchunks_mut(3).enumerate() {
+ for x in chunk {
+ *x = i as u8;
+ }
+ }
+ let result = [2, 1, 1, 1, 0, 0, 0];
+ assert_eq!(v, result);
+}
+
+#[test]
+fn test_mut_rchunks_rev() {
+ let mut v = [0, 1, 2, 3, 4, 5, 6];
+ for (i, chunk) in v.rchunks_mut(3).rev().enumerate() {
+ for x in chunk {
+ *x = i as u8;
+ }
+ }
+ let result = [0, 1, 1, 1, 2, 2, 2];
+ assert_eq!(v, result);
+}
+
+#[test]
+#[should_panic]
+fn test_mut_rchunks_0() {
+ let mut v = [1, 2, 3, 4];
+ let _it = v.rchunks_mut(0);
+}
+
+#[test]
+fn test_mut_rchunks_exact() {
+ let mut v = [0, 1, 2, 3, 4, 5, 6];
+ assert_eq!(v.rchunks_exact_mut(3).len(), 2);
+ for (i, chunk) in v.rchunks_exact_mut(3).enumerate() {
+ for x in chunk {
+ *x = i as u8;
+ }
+ }
+ let result = [0, 1, 1, 1, 0, 0, 0];
+ assert_eq!(v, result);
+}
+
+#[test]
+fn test_mut_rchunks_exact_rev() {
+ let mut v = [0, 1, 2, 3, 4, 5, 6];
+ for (i, chunk) in v.rchunks_exact_mut(3).rev().enumerate() {
+ for x in chunk {
+ *x = i as u8;
+ }
+ }
+ let result = [0, 0, 0, 0, 1, 1, 1];
+ assert_eq!(v, result);
+}
+
+#[test]
+#[should_panic]
+fn test_mut_rchunks_exact_0() {
+ let mut v = [1, 2, 3, 4];
+ let _it = v.rchunks_exact_mut(0);
+}
+
+#[test]
+fn test_mut_last() {
+ let mut x = [1, 2, 3, 4, 5];
+ let h = x.last_mut();
+ assert_eq!(*h.unwrap(), 5);
+
+ let y: &mut [i32] = &mut [];
+ assert!(y.last_mut().is_none());
+}
+
+#[test]
+fn test_to_vec() {
+ let xs: Box<_> = Box::new([1, 2, 3]);
+ let ys = xs.to_vec();
+ assert_eq!(ys, [1, 2, 3]);
+}
+
+#[test]
+fn test_in_place_iterator_specialization() {
+ let src: Box<[usize]> = Box::new([1, 2, 3]);
+ let src_ptr = src.as_ptr();
+ let sink: Box<_> = src.into_vec().into_iter().map(std::convert::identity).collect();
+ let sink_ptr = sink.as_ptr();
+ assert_eq!(src_ptr, sink_ptr);
+}
+
+#[test]
+fn test_box_slice_clone() {
+ let data = vec![vec![0, 1], vec![0], vec![1]];
+ let data2 = data.clone().into_boxed_slice().clone().to_vec();
+
+ assert_eq!(data, data2);
+}
+
+#[test]
+#[allow(unused_must_use)] // here, we care about the side effects of `.clone()`
+#[cfg_attr(target_os = "emscripten", ignore)]
+fn test_box_slice_clone_panics() {
+ use std::sync::atomic::{AtomicUsize, Ordering};
+ use std::sync::Arc;
+
+ struct Canary {
+ count: Arc<AtomicUsize>,
+ panics: bool,
+ }
+
+ impl Drop for Canary {
+ fn drop(&mut self) {
+ self.count.fetch_add(1, Ordering::SeqCst);
+ }
+ }
+
+ impl Clone for Canary {
+ fn clone(&self) -> Self {
+ if self.panics {
+ panic!()
+ }
+
+ Canary { count: self.count.clone(), panics: self.panics }
+ }
+ }
+
+ let drop_count = Arc::new(AtomicUsize::new(0));
+ let canary = Canary { count: drop_count.clone(), panics: false };
+ let panic = Canary { count: drop_count.clone(), panics: true };
+
+ std::panic::catch_unwind(move || {
+ // When xs is dropped, +5.
+ let xs =
+ vec![canary.clone(), canary.clone(), canary.clone(), panic, canary].into_boxed_slice();
+
+ // When panic is cloned, +3.
+ xs.clone();
+ })
+ .unwrap_err();
+
+ // Total = 8
+ assert_eq!(drop_count.load(Ordering::SeqCst), 8);
+}
+
+#[test]
+fn test_copy_from_slice() {
+ let src = [0, 1, 2, 3, 4, 5];
+ let mut dst = [0; 6];
+ dst.copy_from_slice(&src);
+ assert_eq!(src, dst)
+}
+
+#[test]
+#[should_panic(expected = "source slice length (4) does not match destination slice length (5)")]
+fn test_copy_from_slice_dst_longer() {
+ let src = [0, 1, 2, 3];
+ let mut dst = [0; 5];
+ dst.copy_from_slice(&src);
+}
+
+#[test]
+#[should_panic(expected = "source slice length (4) does not match destination slice length (3)")]
+fn test_copy_from_slice_dst_shorter() {
+ let src = [0, 1, 2, 3];
+ let mut dst = [0; 3];
+ dst.copy_from_slice(&src);
+}
+
+const MAX_LEN: usize = 80;
+
+static DROP_COUNTS: [AtomicUsize; MAX_LEN] = [
+ // FIXME(RFC 1109): AtomicUsize is not Copy.
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+ AtomicUsize::new(0),
+];
+
+static VERSIONS: AtomicUsize = AtomicUsize::new(0);
+
+#[derive(Clone, Eq)]
+struct DropCounter {
+ x: u32,
+ id: usize,
+ version: Cell<usize>,
+}
+
+impl PartialEq for DropCounter {
+ fn eq(&self, other: &Self) -> bool {
+ self.partial_cmp(other) == Some(Ordering::Equal)
+ }
+}
+
+impl PartialOrd for DropCounter {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ self.version.set(self.version.get() + 1);
+ other.version.set(other.version.get() + 1);
+ VERSIONS.fetch_add(2, Relaxed);
+ self.x.partial_cmp(&other.x)
+ }
+}
+
+impl Ord for DropCounter {
+ fn cmp(&self, other: &Self) -> Ordering {
+ self.partial_cmp(other).unwrap()
+ }
+}
+
+impl Drop for DropCounter {
+ fn drop(&mut self) {
+ DROP_COUNTS[self.id].fetch_add(1, Relaxed);
+ VERSIONS.fetch_sub(self.version.get(), Relaxed);
+ }
+}
+
+macro_rules! test {
+ ($input:ident, $func:ident) => {
+ let len = $input.len();
+
+ // Work out the total number of comparisons required to sort
+ // this array...
+ let mut count = 0usize;
+ $input.to_owned().$func(|a, b| {
+ count += 1;
+ a.cmp(b)
+ });
+
+ // ... and then panic on each and every single one.
+ for panic_countdown in 0..count {
+ // Refresh the counters.
+ VERSIONS.store(0, Relaxed);
+ for i in 0..len {
+ DROP_COUNTS[i].store(0, Relaxed);
+ }
+
+ let v = $input.to_owned();
+ let _ = std::panic::catch_unwind(move || {
+ let mut v = v;
+ let mut panic_countdown = panic_countdown;
+ v.$func(|a, b| {
+ if panic_countdown == 0 {
+ SILENCE_PANIC.with(|s| s.set(true));
+ panic!();
+ }
+ panic_countdown -= 1;
+ a.cmp(b)
+ })
+ });
+
+ // Check that the number of things dropped is exactly
+ // what we expect (i.e., the contents of `v`).
+ for (i, c) in DROP_COUNTS.iter().enumerate().take(len) {
+ let count = c.load(Relaxed);
+ assert!(count == 1, "found drop count == {} for i == {}, len == {}", count, i, len);
+ }
+
+ // Check that the most recent versions of values were dropped.
+ assert_eq!(VERSIONS.load(Relaxed), 0);
+ }
+ };
+}
+
+thread_local!(static SILENCE_PANIC: Cell<bool> = Cell::new(false));
+
+#[test]
+#[cfg_attr(target_os = "emscripten", ignore)] // no threads
+fn panic_safe() {
+ panic::update_hook(move |prev, info| {
+ if !SILENCE_PANIC.with(|s| s.get()) {
+ prev(info);
+ }
+ });
+
+ let mut rng = thread_rng();
+
+ // Miri is too slow (but still need to `chain` to make the types match)
+ let lens = if cfg!(miri) { (1..10).chain(0..0) } else { (1..20).chain(70..MAX_LEN) };
+ let moduli: &[u32] = if cfg!(miri) { &[5] } else { &[5, 20, 50] };
+
+ for len in lens {
+ for &modulus in moduli {
+ for &has_runs in &[false, true] {
+ let mut input = (0..len)
+ .map(|id| DropCounter {
+ x: rng.next_u32() % modulus,
+ id: id,
+ version: Cell::new(0),
+ })
+ .collect::<Vec<_>>();
+
+ if has_runs {
+ for c in &mut input {
+ c.x = c.id as u32;
+ }
+
+ for _ in 0..5 {
+ let a = rng.gen::<usize>() % len;
+ let b = rng.gen::<usize>() % len;
+ if a < b {
+ input[a..b].reverse();
+ } else {
+ input.swap(a, b);
+ }
+ }
+ }
+
+ test!(input, sort_by);
+ test!(input, sort_unstable_by);
+ }
+ }
+ }
+
+ // Set default panic hook again.
+ drop(panic::take_hook());
+}
+
+#[test]
+fn repeat_generic_slice() {
+ assert_eq!([1, 2].repeat(2), vec![1, 2, 1, 2]);
+ assert_eq!([1, 2, 3, 4].repeat(0), vec![]);
+ assert_eq!([1, 2, 3, 4].repeat(1), vec![1, 2, 3, 4]);
+ assert_eq!([1, 2, 3, 4].repeat(3), vec![1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4]);
+}
+
+#[test]
+#[allow(unreachable_patterns)]
+fn subslice_patterns() {
+ // This test comprehensively checks the passing static and dynamic semantics
+ // of subslice patterns `..`, `x @ ..`, `ref x @ ..`, and `ref mut @ ..`
+ // in slice patterns `[$($pat), $(,)?]` .
+
+ #[derive(PartialEq, Debug, Clone)]
+ struct N(u8);
+
+ macro_rules! n {
+ ($($e:expr),* $(,)?) => {
+ [$(N($e)),*]
+ }
+ }
+
+ macro_rules! c {
+ ($inp:expr, $typ:ty, $out:expr $(,)?) => {
+ assert_eq!($out, identity::<$typ>($inp))
+ };
+ }
+
+ macro_rules! m {
+ ($e:expr, $p:pat => $b:expr) => {
+ match $e {
+ $p => $b,
+ _ => panic!(),
+ }
+ };
+ }
+
+ // == Slices ==
+
+ // Matching slices using `ref` patterns:
+ let mut v = vec![N(0), N(1), N(2), N(3), N(4)];
+ let mut vc = (0..=4).collect::<Vec<u8>>();
+
+ let [..] = v[..]; // Always matches.
+ m!(v[..], [N(0), ref sub @ .., N(4)] => c!(sub, &[N], n![1, 2, 3]));
+ m!(v[..], [N(0), ref sub @ ..] => c!(sub, &[N], n![1, 2, 3, 4]));
+ m!(v[..], [ref sub @ .., N(4)] => c!(sub, &[N], n![0, 1, 2, 3]));
+ m!(v[..], [ref sub @ .., _, _, _, _, _] => c!(sub, &[N], &n![] as &[N]));
+ m!(v[..], [_, _, _, _, _, ref sub @ ..] => c!(sub, &[N], &n![] as &[N]));
+ m!(vc[..], [x, .., y] => c!((x, y), (u8, u8), (0, 4)));
+
+ // Matching slices using `ref mut` patterns:
+ let [..] = v[..]; // Always matches.
+ m!(v[..], [N(0), ref mut sub @ .., N(4)] => c!(sub, &mut [N], n![1, 2, 3]));
+ m!(v[..], [N(0), ref mut sub @ ..] => c!(sub, &mut [N], n![1, 2, 3, 4]));
+ m!(v[..], [ref mut sub @ .., N(4)] => c!(sub, &mut [N], n![0, 1, 2, 3]));
+ m!(v[..], [ref mut sub @ .., _, _, _, _, _] => c!(sub, &mut [N], &mut n![] as &mut [N]));
+ m!(v[..], [_, _, _, _, _, ref mut sub @ ..] => c!(sub, &mut [N], &mut n![] as &mut [N]));
+ m!(vc[..], [x, .., y] => c!((x, y), (u8, u8), (0, 4)));
+
+ // Matching slices using default binding modes (&):
+ let [..] = &v[..]; // Always matches.
+ m!(&v[..], [N(0), sub @ .., N(4)] => c!(sub, &[N], n![1, 2, 3]));
+ m!(&v[..], [N(0), sub @ ..] => c!(sub, &[N], n![1, 2, 3, 4]));
+ m!(&v[..], [sub @ .., N(4)] => c!(sub, &[N], n![0, 1, 2, 3]));
+ m!(&v[..], [sub @ .., _, _, _, _, _] => c!(sub, &[N], &n![] as &[N]));
+ m!(&v[..], [_, _, _, _, _, sub @ ..] => c!(sub, &[N], &n![] as &[N]));
+ m!(&vc[..], [x, .., y] => c!((x, y), (&u8, &u8), (&0, &4)));
+
+ // Matching slices using default binding modes (&mut):
+ let [..] = &mut v[..]; // Always matches.
+ m!(&mut v[..], [N(0), sub @ .., N(4)] => c!(sub, &mut [N], n![1, 2, 3]));
+ m!(&mut v[..], [N(0), sub @ ..] => c!(sub, &mut [N], n![1, 2, 3, 4]));
+ m!(&mut v[..], [sub @ .., N(4)] => c!(sub, &mut [N], n![0, 1, 2, 3]));
+ m!(&mut v[..], [sub @ .., _, _, _, _, _] => c!(sub, &mut [N], &mut n![] as &mut [N]));
+ m!(&mut v[..], [_, _, _, _, _, sub @ ..] => c!(sub, &mut [N], &mut n![] as &mut [N]));
+ m!(&mut vc[..], [x, .., y] => c!((x, y), (&mut u8, &mut u8), (&mut 0, &mut 4)));
+
+ // == Arrays ==
+ let mut v = n![0, 1, 2, 3, 4];
+ let vc = [0, 1, 2, 3, 4];
+
+ // Matching arrays by value:
+ m!(v.clone(), [N(0), sub @ .., N(4)] => c!(sub, [N; 3], n![1, 2, 3]));
+ m!(v.clone(), [N(0), sub @ ..] => c!(sub, [N; 4], n![1, 2, 3, 4]));
+ m!(v.clone(), [sub @ .., N(4)] => c!(sub, [N; 4], n![0, 1, 2, 3]));
+ m!(v.clone(), [sub @ .., _, _, _, _, _] => c!(sub, [N; 0], n![] as [N; 0]));
+ m!(v.clone(), [_, _, _, _, _, sub @ ..] => c!(sub, [N; 0], n![] as [N; 0]));
+ m!(v.clone(), [x, .., y] => c!((x, y), (N, N), (N(0), N(4))));
+ m!(v.clone(), [..] => ());
+
+ // Matching arrays by ref patterns:
+ m!(v, [N(0), ref sub @ .., N(4)] => c!(sub, &[N; 3], &n![1, 2, 3]));
+ m!(v, [N(0), ref sub @ ..] => c!(sub, &[N; 4], &n![1, 2, 3, 4]));
+ m!(v, [ref sub @ .., N(4)] => c!(sub, &[N; 4], &n![0, 1, 2, 3]));
+ m!(v, [ref sub @ .., _, _, _, _, _] => c!(sub, &[N; 0], &n![] as &[N; 0]));
+ m!(v, [_, _, _, _, _, ref sub @ ..] => c!(sub, &[N; 0], &n![] as &[N; 0]));
+ m!(vc, [x, .., y] => c!((x, y), (u8, u8), (0, 4)));
+
+ // Matching arrays by ref mut patterns:
+ m!(v, [N(0), ref mut sub @ .., N(4)] => c!(sub, &mut [N; 3], &mut n![1, 2, 3]));
+ m!(v, [N(0), ref mut sub @ ..] => c!(sub, &mut [N; 4], &mut n![1, 2, 3, 4]));
+ m!(v, [ref mut sub @ .., N(4)] => c!(sub, &mut [N; 4], &mut n![0, 1, 2, 3]));
+ m!(v, [ref mut sub @ .., _, _, _, _, _] => c!(sub, &mut [N; 0], &mut n![] as &mut [N; 0]));
+ m!(v, [_, _, _, _, _, ref mut sub @ ..] => c!(sub, &mut [N; 0], &mut n![] as &mut [N; 0]));
+
+ // Matching arrays by default binding modes (&):
+ m!(&v, [N(0), sub @ .., N(4)] => c!(sub, &[N; 3], &n![1, 2, 3]));
+ m!(&v, [N(0), sub @ ..] => c!(sub, &[N; 4], &n![1, 2, 3, 4]));
+ m!(&v, [sub @ .., N(4)] => c!(sub, &[N; 4], &n![0, 1, 2, 3]));
+ m!(&v, [sub @ .., _, _, _, _, _] => c!(sub, &[N; 0], &n![] as &[N; 0]));
+ m!(&v, [_, _, _, _, _, sub @ ..] => c!(sub, &[N; 0], &n![] as &[N; 0]));
+ m!(&v, [..] => ());
+ m!(&v, [x, .., y] => c!((x, y), (&N, &N), (&N(0), &N(4))));
+
+ // Matching arrays by default binding modes (&mut):
+ m!(&mut v, [N(0), sub @ .., N(4)] => c!(sub, &mut [N; 3], &mut n![1, 2, 3]));
+ m!(&mut v, [N(0), sub @ ..] => c!(sub, &mut [N; 4], &mut n![1, 2, 3, 4]));
+ m!(&mut v, [sub @ .., N(4)] => c!(sub, &mut [N; 4], &mut n![0, 1, 2, 3]));
+ m!(&mut v, [sub @ .., _, _, _, _, _] => c!(sub, &mut [N; 0], &mut n![] as &[N; 0]));
+ m!(&mut v, [_, _, _, _, _, sub @ ..] => c!(sub, &mut [N; 0], &mut n![] as &[N; 0]));
+ m!(&mut v, [..] => ());
+ m!(&mut v, [x, .., y] => c!((x, y), (&mut N, &mut N), (&mut N(0), &mut N(4))));
+}
+
+#[test]
+fn test_group_by() {
+ let slice = &[1, 1, 1, 3, 3, 2, 2, 2, 1, 0];
+
+ let mut iter = slice.group_by(|a, b| a == b);
+ assert_eq!(iter.next(), Some(&[1, 1, 1][..]));
+ assert_eq!(iter.next(), Some(&[3, 3][..]));
+ assert_eq!(iter.next(), Some(&[2, 2, 2][..]));
+ assert_eq!(iter.next(), Some(&[1][..]));
+ assert_eq!(iter.next(), Some(&[0][..]));
+ assert_eq!(iter.next(), None);
+
+ let mut iter = slice.group_by(|a, b| a == b);
+ assert_eq!(iter.next_back(), Some(&[0][..]));
+ assert_eq!(iter.next_back(), Some(&[1][..]));
+ assert_eq!(iter.next_back(), Some(&[2, 2, 2][..]));
+ assert_eq!(iter.next_back(), Some(&[3, 3][..]));
+ assert_eq!(iter.next_back(), Some(&[1, 1, 1][..]));
+ assert_eq!(iter.next_back(), None);
+
+ let mut iter = slice.group_by(|a, b| a == b);
+ assert_eq!(iter.next(), Some(&[1, 1, 1][..]));
+ assert_eq!(iter.next_back(), Some(&[0][..]));
+ assert_eq!(iter.next(), Some(&[3, 3][..]));
+ assert_eq!(iter.next_back(), Some(&[1][..]));
+ assert_eq!(iter.next(), Some(&[2, 2, 2][..]));
+ assert_eq!(iter.next_back(), None);
+}
+
+#[test]
+fn test_group_by_mut() {
+ let slice = &mut [1, 1, 1, 3, 3, 2, 2, 2, 1, 0];
+
+ let mut iter = slice.group_by_mut(|a, b| a == b);
+ assert_eq!(iter.next(), Some(&mut [1, 1, 1][..]));
+ assert_eq!(iter.next(), Some(&mut [3, 3][..]));
+ assert_eq!(iter.next(), Some(&mut [2, 2, 2][..]));
+ assert_eq!(iter.next(), Some(&mut [1][..]));
+ assert_eq!(iter.next(), Some(&mut [0][..]));
+ assert_eq!(iter.next(), None);
+
+ let mut iter = slice.group_by_mut(|a, b| a == b);
+ assert_eq!(iter.next_back(), Some(&mut [0][..]));
+ assert_eq!(iter.next_back(), Some(&mut [1][..]));
+ assert_eq!(iter.next_back(), Some(&mut [2, 2, 2][..]));
+ assert_eq!(iter.next_back(), Some(&mut [3, 3][..]));
+ assert_eq!(iter.next_back(), Some(&mut [1, 1, 1][..]));
+ assert_eq!(iter.next_back(), None);
+
+ let mut iter = slice.group_by_mut(|a, b| a == b);
+ assert_eq!(iter.next(), Some(&mut [1, 1, 1][..]));
+ assert_eq!(iter.next_back(), Some(&mut [0][..]));
+ assert_eq!(iter.next(), Some(&mut [3, 3][..]));
+ assert_eq!(iter.next_back(), Some(&mut [1][..]));
+ assert_eq!(iter.next(), Some(&mut [2, 2, 2][..]));
+ assert_eq!(iter.next_back(), None);
+}
diff --git a/library/alloc/tests/str.rs b/library/alloc/tests/str.rs
new file mode 100644
index 000000000..7379569dd
--- /dev/null
+++ b/library/alloc/tests/str.rs
@@ -0,0 +1,2383 @@
+use std::assert_matches::assert_matches;
+use std::borrow::Cow;
+use std::cmp::Ordering::{Equal, Greater, Less};
+use std::str::{from_utf8, from_utf8_unchecked};
+
+#[test]
+fn test_le() {
+ assert!("" <= "");
+ assert!("" <= "foo");
+ assert!("foo" <= "foo");
+ assert_ne!("foo", "bar");
+}
+
+#[test]
+fn test_find() {
+ assert_eq!("hello".find('l'), Some(2));
+ assert_eq!("hello".find(|c: char| c == 'o'), Some(4));
+ assert!("hello".find('x').is_none());
+ assert!("hello".find(|c: char| c == 'x').is_none());
+ assert_eq!("ประเทศไทย中华Việt Nam".find('华'), Some(30));
+ assert_eq!("ประเทศไทย中华Việt Nam".find(|c: char| c == '华'), Some(30));
+}
+
+#[test]
+fn test_rfind() {
+ assert_eq!("hello".rfind('l'), Some(3));
+ assert_eq!("hello".rfind(|c: char| c == 'o'), Some(4));
+ assert!("hello".rfind('x').is_none());
+ assert!("hello".rfind(|c: char| c == 'x').is_none());
+ assert_eq!("ประเทศไทย中华Việt Nam".rfind('华'), Some(30));
+ assert_eq!("ประเทศไทย中华Việt Nam".rfind(|c: char| c == '华'), Some(30));
+}
+
+#[test]
+fn test_collect() {
+ let empty = "";
+ let s: String = empty.chars().collect();
+ assert_eq!(empty, s);
+ let data = "ประเทศไทย中";
+ let s: String = data.chars().collect();
+ assert_eq!(data, s);
+}
+
+#[test]
+fn test_into_bytes() {
+ let data = String::from("asdf");
+ let buf = data.into_bytes();
+ assert_eq!(buf, b"asdf");
+}
+
+#[test]
+fn test_find_str() {
+ // byte positions
+ assert_eq!("".find(""), Some(0));
+ assert!("banana".find("apple pie").is_none());
+
+ let data = "abcabc";
+ assert_eq!(data[0..6].find("ab"), Some(0));
+ assert_eq!(data[2..6].find("ab"), Some(3 - 2));
+ assert!(data[2..4].find("ab").is_none());
+
+ let string = "ประเทศไทย中华Việt Nam";
+ let mut data = String::from(string);
+ data.push_str(string);
+ assert!(data.find("ไท华").is_none());
+ assert_eq!(data[0..43].find(""), Some(0));
+ assert_eq!(data[6..43].find(""), Some(6 - 6));
+
+ assert_eq!(data[0..43].find("ประ"), Some(0));
+ assert_eq!(data[0..43].find("ทศไ"), Some(12));
+ assert_eq!(data[0..43].find("ย中"), Some(24));
+ assert_eq!(data[0..43].find("iệt"), Some(34));
+ assert_eq!(data[0..43].find("Nam"), Some(40));
+
+ assert_eq!(data[43..86].find("ประ"), Some(43 - 43));
+ assert_eq!(data[43..86].find("ทศไ"), Some(55 - 43));
+ assert_eq!(data[43..86].find("ย中"), Some(67 - 43));
+ assert_eq!(data[43..86].find("iệt"), Some(77 - 43));
+ assert_eq!(data[43..86].find("Nam"), Some(83 - 43));
+
+ // find every substring -- assert that it finds it, or an earlier occurrence.
+ let string = "Việt Namacbaabcaabaaba";
+ for (i, ci) in string.char_indices() {
+ let ip = i + ci.len_utf8();
+ for j in string[ip..].char_indices().map(|(i, _)| i).chain(Some(string.len() - ip)) {
+ let pat = &string[i..ip + j];
+ assert!(match string.find(pat) {
+ None => false,
+ Some(x) => x <= i,
+ });
+ assert!(match string.rfind(pat) {
+ None => false,
+ Some(x) => x >= i,
+ });
+ }
+ }
+}
+
+fn s(x: &str) -> String {
+ x.to_string()
+}
+
+macro_rules! test_concat {
+ ($expected: expr, $string: expr) => {{
+ let s: String = $string.concat();
+ assert_eq!($expected, s);
+ }};
+}
+
+#[test]
+fn test_concat_for_different_types() {
+ test_concat!("ab", vec![s("a"), s("b")]);
+ test_concat!("ab", vec!["a", "b"]);
+}
+
+#[test]
+fn test_concat_for_different_lengths() {
+ let empty: &[&str] = &[];
+ test_concat!("", empty);
+ test_concat!("a", ["a"]);
+ test_concat!("ab", ["a", "b"]);
+ test_concat!("abc", ["", "a", "bc"]);
+}
+
+macro_rules! test_join {
+ ($expected: expr, $string: expr, $delim: expr) => {{
+ let s = $string.join($delim);
+ assert_eq!($expected, s);
+ }};
+}
+
+#[test]
+fn test_join_for_different_types() {
+ test_join!("a-b", ["a", "b"], "-");
+ let hyphen = "-".to_string();
+ test_join!("a-b", [s("a"), s("b")], &*hyphen);
+ test_join!("a-b", vec!["a", "b"], &*hyphen);
+ test_join!("a-b", &*vec!["a", "b"], "-");
+ test_join!("a-b", vec![s("a"), s("b")], "-");
+}
+
+#[test]
+fn test_join_for_different_lengths() {
+ let empty: &[&str] = &[];
+ test_join!("", empty, "-");
+ test_join!("a", ["a"], "-");
+ test_join!("a-b", ["a", "b"], "-");
+ test_join!("-a-bc", ["", "a", "bc"], "-");
+}
+
+// join has fast paths for small separators up to 4 bytes
+// this tests the slow paths.
+#[test]
+fn test_join_for_different_lengths_with_long_separator() {
+ assert_eq!("~~~~~".len(), 15);
+
+ let empty: &[&str] = &[];
+ test_join!("", empty, "~~~~~");
+ test_join!("a", ["a"], "~~~~~");
+ test_join!("a~~~~~b", ["a", "b"], "~~~~~");
+ test_join!("~~~~~a~~~~~bc", ["", "a", "bc"], "~~~~~");
+}
+
+#[test]
+fn test_join_issue_80335() {
+ use core::{borrow::Borrow, cell::Cell};
+
+ struct WeirdBorrow {
+ state: Cell<bool>,
+ }
+
+ impl Default for WeirdBorrow {
+ fn default() -> Self {
+ WeirdBorrow { state: Cell::new(false) }
+ }
+ }
+
+ impl Borrow<str> for WeirdBorrow {
+ fn borrow(&self) -> &str {
+ let state = self.state.get();
+ if state {
+ "0"
+ } else {
+ self.state.set(true);
+ "123456"
+ }
+ }
+ }
+
+ let arr: [WeirdBorrow; 3] = Default::default();
+ test_join!("0-0-0", arr, "-");
+}
+
+#[test]
+#[cfg_attr(miri, ignore)] // Miri is too slow
+fn test_unsafe_slice() {
+ assert_eq!("ab", unsafe { "abc".get_unchecked(0..2) });
+ assert_eq!("bc", unsafe { "abc".get_unchecked(1..3) });
+ assert_eq!("", unsafe { "abc".get_unchecked(1..1) });
+ fn a_million_letter_a() -> String {
+ let mut i = 0;
+ let mut rs = String::new();
+ while i < 100000 {
+ rs.push_str("aaaaaaaaaa");
+ i += 1;
+ }
+ rs
+ }
+ fn half_a_million_letter_a() -> String {
+ let mut i = 0;
+ let mut rs = String::new();
+ while i < 100000 {
+ rs.push_str("aaaaa");
+ i += 1;
+ }
+ rs
+ }
+ let letters = a_million_letter_a();
+ assert_eq!(half_a_million_letter_a(), unsafe { letters.get_unchecked(0..500000) });
+}
+
+#[test]
+fn test_starts_with() {
+ assert!("".starts_with(""));
+ assert!("abc".starts_with(""));
+ assert!("abc".starts_with("a"));
+ assert!(!"a".starts_with("abc"));
+ assert!(!"".starts_with("abc"));
+ assert!(!"ödd".starts_with("-"));
+ assert!("ödd".starts_with("öd"));
+}
+
+#[test]
+fn test_ends_with() {
+ assert!("".ends_with(""));
+ assert!("abc".ends_with(""));
+ assert!("abc".ends_with("c"));
+ assert!(!"a".ends_with("abc"));
+ assert!(!"".ends_with("abc"));
+ assert!(!"ddö".ends_with("-"));
+ assert!("ddö".ends_with("dö"));
+}
+
+#[test]
+fn test_is_empty() {
+ assert!("".is_empty());
+ assert!(!"a".is_empty());
+}
+
+#[test]
+fn test_replacen() {
+ assert_eq!("".replacen('a', "b", 5), "");
+ assert_eq!("acaaa".replacen("a", "b", 3), "bcbba");
+ assert_eq!("aaaa".replacen("a", "b", 0), "aaaa");
+
+ let test = "test";
+ assert_eq!(" test test ".replacen(test, "toast", 3), " toast toast ");
+ assert_eq!(" test test ".replacen(test, "toast", 0), " test test ");
+ assert_eq!(" test test ".replacen(test, "", 5), " ");
+
+ assert_eq!("qwer123zxc789".replacen(char::is_numeric, "", 3), "qwerzxc789");
+}
+
+#[test]
+fn test_replace() {
+ let a = "a";
+ assert_eq!("".replace(a, "b"), "");
+ assert_eq!("a".replace(a, "b"), "b");
+ assert_eq!("ab".replace(a, "b"), "bb");
+ let test = "test";
+ assert_eq!(" test test ".replace(test, "toast"), " toast toast ");
+ assert_eq!(" test test ".replace(test, ""), " ");
+}
+
+#[test]
+fn test_replace_2a() {
+ let data = "ประเทศไทย中华";
+ let repl = "دولة الكويت";
+
+ let a = "ประเ";
+ let a2 = "دولة الكويتทศไทย中华";
+ assert_eq!(data.replace(a, repl), a2);
+}
+
+#[test]
+fn test_replace_2b() {
+ let data = "ประเทศไทย中华";
+ let repl = "دولة الكويت";
+
+ let b = "ะเ";
+ let b2 = "ปรدولة الكويتทศไทย中华";
+ assert_eq!(data.replace(b, repl), b2);
+}
+
+#[test]
+fn test_replace_2c() {
+ let data = "ประเทศไทย中华";
+ let repl = "دولة الكويت";
+
+ let c = "中华";
+ let c2 = "ประเทศไทยدولة الكويت";
+ assert_eq!(data.replace(c, repl), c2);
+}
+
+#[test]
+fn test_replace_2d() {
+ let data = "ประเทศไทย中华";
+ let repl = "دولة الكويت";
+
+ let d = "ไท华";
+ assert_eq!(data.replace(d, repl), data);
+}
+
+#[test]
+fn test_replace_pattern() {
+ let data = "abcdαβγδabcdαβγδ";
+ assert_eq!(data.replace("dαβ", "😺😺😺"), "abc😺😺😺γδabc😺😺😺γδ");
+ assert_eq!(data.replace('γ', "😺😺😺"), "abcdαβ😺😺😺δabcdαβ😺😺😺δ");
+ assert_eq!(data.replace(&['a', 'γ'] as &[_], "😺😺😺"), "😺😺😺bcdαβ😺😺😺δ😺😺😺bcdαβ😺😺😺δ");
+ assert_eq!(data.replace(|c| c == 'γ', "😺😺😺"), "abcdαβ😺😺😺δabcdαβ😺😺😺δ");
+}
+
+// The current implementation of SliceIndex fails to handle methods
+// orthogonally from range types; therefore, it is worth testing
+// all of the indexing operations on each input.
+mod slice_index {
+ // Test a slicing operation **that should succeed,**
+ // testing it on all of the indexing methods.
+ //
+ // This is not suitable for testing failure on invalid inputs.
+ macro_rules! assert_range_eq {
+ ($s:expr, $range:expr, $expected:expr) => {
+ let mut s: String = $s.to_owned();
+ let mut expected: String = $expected.to_owned();
+ {
+ let s: &str = &s;
+ let expected: &str = &expected;
+
+ assert_eq!(&s[$range], expected, "(in assertion for: index)");
+ assert_eq!(s.get($range), Some(expected), "(in assertion for: get)");
+ unsafe {
+ assert_eq!(
+ s.get_unchecked($range),
+ expected,
+ "(in assertion for: get_unchecked)",
+ );
+ }
+ }
+ {
+ let s: &mut str = &mut s;
+ let expected: &mut str = &mut expected;
+
+ assert_eq!(&mut s[$range], expected, "(in assertion for: index_mut)",);
+ assert_eq!(
+ s.get_mut($range),
+ Some(&mut expected[..]),
+ "(in assertion for: get_mut)",
+ );
+ unsafe {
+ assert_eq!(
+ s.get_unchecked_mut($range),
+ expected,
+ "(in assertion for: get_unchecked_mut)",
+ );
+ }
+ }
+ };
+ }
+
+ // Make sure the macro can actually detect bugs,
+ // because if it can't, then what are we even doing here?
+ //
+ // (Be aware this only demonstrates the ability to detect bugs
+ // in the FIRST method that panics, as the macro is not designed
+ // to be used in `should_panic`)
+ #[test]
+ #[should_panic(expected = "out of bounds")]
+ fn assert_range_eq_can_fail_by_panic() {
+ assert_range_eq!("abc", 0..5, "abc");
+ }
+
+ // (Be aware this only demonstrates the ability to detect bugs
+ // in the FIRST method it calls, as the macro is not designed
+ // to be used in `should_panic`)
+ #[test]
+ #[should_panic(expected = "==")]
+ fn assert_range_eq_can_fail_by_inequality() {
+ assert_range_eq!("abc", 0..2, "abc");
+ }
+
+ // Generates test cases for bad index operations.
+ //
+ // This generates `should_panic` test cases for Index/IndexMut
+ // and `None` test cases for get/get_mut.
+ macro_rules! panic_cases {
+ ($(
+ in mod $case_name:ident {
+ data: $data:expr;
+
+ // optional:
+ //
+ // a similar input for which DATA[input] succeeds, and the corresponding
+ // output str. This helps validate "critical points" where an input range
+ // straddles the boundary between valid and invalid.
+ // (such as the input `len..len`, which is just barely valid)
+ $(
+ good: data[$good:expr] == $output:expr;
+ )*
+
+ bad: data[$bad:expr];
+ message: $expect_msg:expr; // must be a literal
+ }
+ )*) => {$(
+ mod $case_name {
+ #[test]
+ fn pass() {
+ let mut v: String = $data.into();
+
+ $( assert_range_eq!(v, $good, $output); )*
+
+ {
+ let v: &str = &v;
+ assert_eq!(v.get($bad), None, "(in None assertion for get)");
+ }
+
+ {
+ let v: &mut str = &mut v;
+ assert_eq!(v.get_mut($bad), None, "(in None assertion for get_mut)");
+ }
+ }
+
+ #[test]
+ #[should_panic(expected = $expect_msg)]
+ fn index_fail() {
+ let v: String = $data.into();
+ let v: &str = &v;
+ let _v = &v[$bad];
+ }
+
+ #[test]
+ #[should_panic(expected = $expect_msg)]
+ fn index_mut_fail() {
+ let mut v: String = $data.into();
+ let v: &mut str = &mut v;
+ let _v = &mut v[$bad];
+ }
+ }
+ )*};
+ }
+
+ #[test]
+ fn simple_ascii() {
+ assert_range_eq!("abc", .., "abc");
+
+ assert_range_eq!("abc", 0..2, "ab");
+ assert_range_eq!("abc", 0..=1, "ab");
+ assert_range_eq!("abc", ..2, "ab");
+ assert_range_eq!("abc", ..=1, "ab");
+
+ assert_range_eq!("abc", 1..3, "bc");
+ assert_range_eq!("abc", 1..=2, "bc");
+ assert_range_eq!("abc", 1..1, "");
+ assert_range_eq!("abc", 1..=0, "");
+ }
+
+ #[test]
+ fn simple_unicode() {
+ // 日本
+ assert_range_eq!("\u{65e5}\u{672c}", .., "\u{65e5}\u{672c}");
+
+ assert_range_eq!("\u{65e5}\u{672c}", 0..3, "\u{65e5}");
+ assert_range_eq!("\u{65e5}\u{672c}", 0..=2, "\u{65e5}");
+ assert_range_eq!("\u{65e5}\u{672c}", ..3, "\u{65e5}");
+ assert_range_eq!("\u{65e5}\u{672c}", ..=2, "\u{65e5}");
+
+ assert_range_eq!("\u{65e5}\u{672c}", 3..6, "\u{672c}");
+ assert_range_eq!("\u{65e5}\u{672c}", 3..=5, "\u{672c}");
+ assert_range_eq!("\u{65e5}\u{672c}", 3.., "\u{672c}");
+
+ let data = "ประเทศไทย中华";
+ assert_range_eq!(data, 0..3, "ป");
+ assert_range_eq!(data, 3..6, "ร");
+ assert_range_eq!(data, 3..3, "");
+ assert_range_eq!(data, 30..33, "华");
+
+ /*0: 中
+ 3: 华
+ 6: V
+ 7: i
+ 8: ệ
+ 11: t
+ 12:
+ 13: N
+ 14: a
+ 15: m */
+ let ss = "中华Việt Nam";
+ assert_range_eq!(ss, 3..6, "华");
+ assert_range_eq!(ss, 6..16, "Việt Nam");
+ assert_range_eq!(ss, 6..=15, "Việt Nam");
+ assert_range_eq!(ss, 6.., "Việt Nam");
+
+ assert_range_eq!(ss, 0..3, "中");
+ assert_range_eq!(ss, 3..7, "华V");
+ assert_range_eq!(ss, 3..=6, "华V");
+ assert_range_eq!(ss, 3..3, "");
+ assert_range_eq!(ss, 3..=2, "");
+ }
+
+ #[test]
+ #[cfg_attr(target_os = "emscripten", ignore)] // hits an OOM
+ #[cfg_attr(miri, ignore)] // Miri is too slow
+ fn simple_big() {
+ fn a_million_letter_x() -> String {
+ let mut i = 0;
+ let mut rs = String::new();
+ while i < 100000 {
+ rs.push_str("华华华华华华华华华华");
+ i += 1;
+ }
+ rs
+ }
+ fn half_a_million_letter_x() -> String {
+ let mut i = 0;
+ let mut rs = String::new();
+ while i < 100000 {
+ rs.push_str("华华华华华");
+ i += 1;
+ }
+ rs
+ }
+ let letters = a_million_letter_x();
+ assert_range_eq!(letters, 0..3 * 500000, half_a_million_letter_x());
+ }
+
+ #[test]
+ #[should_panic]
+ fn test_slice_fail() {
+ let _ = &"中华Việt Nam"[0..2];
+ }
+
+ panic_cases! {
+ in mod rangefrom_len {
+ data: "abcdef";
+ good: data[6..] == "";
+ bad: data[7..];
+ message: "out of bounds";
+ }
+
+ in mod rangeto_len {
+ data: "abcdef";
+ good: data[..6] == "abcdef";
+ bad: data[..7];
+ message: "out of bounds";
+ }
+
+ in mod rangetoinclusive_len {
+ data: "abcdef";
+ good: data[..=5] == "abcdef";
+ bad: data[..=6];
+ message: "out of bounds";
+ }
+
+ in mod rangeinclusive_len {
+ data: "abcdef";
+ good: data[0..=5] == "abcdef";
+ bad: data[0..=6];
+ message: "out of bounds";
+ }
+
+ in mod range_len_len {
+ data: "abcdef";
+ good: data[6..6] == "";
+ bad: data[7..7];
+ message: "out of bounds";
+ }
+
+ in mod rangeinclusive_len_len {
+ data: "abcdef";
+ good: data[6..=5] == "";
+ bad: data[7..=6];
+ message: "out of bounds";
+ }
+ }
+
+ panic_cases! {
+ in mod rangeinclusive_exhausted {
+ data: "abcdef";
+
+ good: data[0..=5] == "abcdef";
+ good: data[{
+ let mut iter = 0..=5;
+ iter.by_ref().count(); // exhaust it
+ iter
+ }] == "";
+
+ // 0..=6 is out of bounds before exhaustion, so it
+ // stands to reason that it still would be after.
+ bad: data[{
+ let mut iter = 0..=6;
+ iter.by_ref().count(); // exhaust it
+ iter
+ }];
+ message: "out of bounds";
+ }
+ }
+
+ panic_cases! {
+ in mod range_neg_width {
+ data: "abcdef";
+ good: data[4..4] == "";
+ bad: data[4..3];
+ message: "begin <= end (4 <= 3)";
+ }
+
+ in mod rangeinclusive_neg_width {
+ data: "abcdef";
+ good: data[4..=3] == "";
+ bad: data[4..=2];
+ message: "begin <= end (4 <= 3)";
+ }
+ }
+
+ mod overflow {
+ panic_cases! {
+ in mod rangeinclusive {
+ data: "hello";
+ // note: using 0 specifically ensures that the result of overflowing is 0..0,
+ // so that `get` doesn't simply return None for the wrong reason.
+ bad: data[0..=usize::MAX];
+ message: "maximum usize";
+ }
+
+ in mod rangetoinclusive {
+ data: "hello";
+ bad: data[..=usize::MAX];
+ message: "maximum usize";
+ }
+ }
+ }
+
+ mod boundary {
+ const DATA: &str = "abcαβγ";
+
+ const BAD_START: usize = 4;
+ const GOOD_START: usize = 3;
+ const BAD_END: usize = 6;
+ const GOOD_END: usize = 7;
+ const BAD_END_INCL: usize = BAD_END - 1;
+ const GOOD_END_INCL: usize = GOOD_END - 1;
+
+ // it is especially important to test all of the different range types here
+ // because some of the logic may be duplicated as part of micro-optimizations
+ // to dodge unicode boundary checks on half-ranges.
+ panic_cases! {
+ in mod range_1 {
+ data: super::DATA;
+ bad: data[super::BAD_START..super::GOOD_END];
+ message:
+ "byte index 4 is not a char boundary; it is inside 'α' (bytes 3..5) of";
+ }
+
+ in mod range_2 {
+ data: super::DATA;
+ bad: data[super::GOOD_START..super::BAD_END];
+ message:
+ "byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of";
+ }
+
+ in mod rangefrom {
+ data: super::DATA;
+ bad: data[super::BAD_START..];
+ message:
+ "byte index 4 is not a char boundary; it is inside 'α' (bytes 3..5) of";
+ }
+
+ in mod rangeto {
+ data: super::DATA;
+ bad: data[..super::BAD_END];
+ message:
+ "byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of";
+ }
+
+ in mod rangeinclusive_1 {
+ data: super::DATA;
+ bad: data[super::BAD_START..=super::GOOD_END_INCL];
+ message:
+ "byte index 4 is not a char boundary; it is inside 'α' (bytes 3..5) of";
+ }
+
+ in mod rangeinclusive_2 {
+ data: super::DATA;
+ bad: data[super::GOOD_START..=super::BAD_END_INCL];
+ message:
+ "byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of";
+ }
+
+ in mod rangetoinclusive {
+ data: super::DATA;
+ bad: data[..=super::BAD_END_INCL];
+ message:
+ "byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of";
+ }
+ }
+ }
+
+ const LOREM_PARAGRAPH: &str = "\
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse quis lorem \
+ sit amet dolor ultricies condimentum. Praesent iaculis purus elit, ac malesuada \
+ quam malesuada in. Duis sed orci eros. Suspendisse sit amet magna mollis, mollis \
+ nunc luctus, imperdiet mi. Integer fringilla non sem ut lacinia. Fusce varius \
+ tortor a risus porttitor hendrerit. Morbi mauris dui, ultricies nec tempus vel, \
+ gravida nec quam.";
+
+ // check the panic includes the prefix of the sliced string
+ #[test]
+ #[should_panic(expected = "byte index 1024 is out of bounds of `Lorem ipsum dolor sit amet")]
+ fn test_slice_fail_truncated_1() {
+ let _ = &LOREM_PARAGRAPH[..1024];
+ }
+ // check the truncation in the panic message
+ #[test]
+ #[should_panic(expected = "luctus, im`[...]")]
+ fn test_slice_fail_truncated_2() {
+ let _ = &LOREM_PARAGRAPH[..1024];
+ }
+}
+
+#[test]
+fn test_str_slice_rangetoinclusive_ok() {
+ let s = "abcαβγ";
+ assert_eq!(&s[..=2], "abc");
+ assert_eq!(&s[..=4], "abcα");
+}
+
+#[test]
+#[should_panic]
+fn test_str_slice_rangetoinclusive_notok() {
+ let s = "abcαβγ";
+ let _ = &s[..=3];
+}
+
+#[test]
+fn test_str_slicemut_rangetoinclusive_ok() {
+ let mut s = "abcαβγ".to_owned();
+ let s: &mut str = &mut s;
+ assert_eq!(&mut s[..=2], "abc");
+ assert_eq!(&mut s[..=4], "abcα");
+}
+
+#[test]
+#[should_panic]
+fn test_str_slicemut_rangetoinclusive_notok() {
+ let mut s = "abcαβγ".to_owned();
+ let s: &mut str = &mut s;
+ let _ = &mut s[..=3];
+}
+
+#[test]
+fn test_is_char_boundary() {
+ let s = "ศไทย中华Việt Nam β-release 🐱123";
+ assert!(s.is_char_boundary(0));
+ assert!(s.is_char_boundary(s.len()));
+ assert!(!s.is_char_boundary(s.len() + 1));
+ for (i, ch) in s.char_indices() {
+ // ensure character locations are boundaries and continuation bytes are not
+ assert!(s.is_char_boundary(i), "{} is a char boundary in {:?}", i, s);
+ for j in 1..ch.len_utf8() {
+ assert!(
+ !s.is_char_boundary(i + j),
+ "{} should not be a char boundary in {:?}",
+ i + j,
+ s
+ );
+ }
+ }
+}
+
+#[test]
+fn test_trim_start_matches() {
+ let v: &[char] = &[];
+ assert_eq!(" *** foo *** ".trim_start_matches(v), " *** foo *** ");
+ let chars: &[char] = &['*', ' '];
+ assert_eq!(" *** foo *** ".trim_start_matches(chars), "foo *** ");
+ assert_eq!(" *** *** ".trim_start_matches(chars), "");
+ assert_eq!("foo *** ".trim_start_matches(chars), "foo *** ");
+
+ assert_eq!("11foo1bar11".trim_start_matches('1'), "foo1bar11");
+ let chars: &[char] = &['1', '2'];
+ assert_eq!("12foo1bar12".trim_start_matches(chars), "foo1bar12");
+ assert_eq!("123foo1bar123".trim_start_matches(|c: char| c.is_numeric()), "foo1bar123");
+}
+
+#[test]
+fn test_trim_end_matches() {
+ let v: &[char] = &[];
+ assert_eq!(" *** foo *** ".trim_end_matches(v), " *** foo *** ");
+ let chars: &[char] = &['*', ' '];
+ assert_eq!(" *** foo *** ".trim_end_matches(chars), " *** foo");
+ assert_eq!(" *** *** ".trim_end_matches(chars), "");
+ assert_eq!(" *** foo".trim_end_matches(chars), " *** foo");
+
+ assert_eq!("11foo1bar11".trim_end_matches('1'), "11foo1bar");
+ let chars: &[char] = &['1', '2'];
+ assert_eq!("12foo1bar12".trim_end_matches(chars), "12foo1bar");
+ assert_eq!("123foo1bar123".trim_end_matches(|c: char| c.is_numeric()), "123foo1bar");
+}
+
+#[test]
+fn test_trim_matches() {
+ let v: &[char] = &[];
+ assert_eq!(" *** foo *** ".trim_matches(v), " *** foo *** ");
+ let chars: &[char] = &['*', ' '];
+ assert_eq!(" *** foo *** ".trim_matches(chars), "foo");
+ assert_eq!(" *** *** ".trim_matches(chars), "");
+ assert_eq!("foo".trim_matches(chars), "foo");
+
+ assert_eq!("11foo1bar11".trim_matches('1'), "foo1bar");
+ let chars: &[char] = &['1', '2'];
+ assert_eq!("12foo1bar12".trim_matches(chars), "foo1bar");
+ assert_eq!("123foo1bar123".trim_matches(|c: char| c.is_numeric()), "foo1bar");
+}
+
+#[test]
+fn test_trim_start() {
+ assert_eq!("".trim_start(), "");
+ assert_eq!("a".trim_start(), "a");
+ assert_eq!(" ".trim_start(), "");
+ assert_eq!(" blah".trim_start(), "blah");
+ assert_eq!(" \u{3000} wut".trim_start(), "wut");
+ assert_eq!("hey ".trim_start(), "hey ");
+}
+
+#[test]
+fn test_trim_end() {
+ assert_eq!("".trim_end(), "");
+ assert_eq!("a".trim_end(), "a");
+ assert_eq!(" ".trim_end(), "");
+ assert_eq!("blah ".trim_end(), "blah");
+ assert_eq!("wut \u{3000} ".trim_end(), "wut");
+ assert_eq!(" hey".trim_end(), " hey");
+}
+
+#[test]
+fn test_trim() {
+ assert_eq!("".trim(), "");
+ assert_eq!("a".trim(), "a");
+ assert_eq!(" ".trim(), "");
+ assert_eq!(" blah ".trim(), "blah");
+ assert_eq!("\nwut \u{3000} ".trim(), "wut");
+ assert_eq!(" hey dude ".trim(), "hey dude");
+}
+
+#[test]
+fn test_is_whitespace() {
+ assert!("".chars().all(|c| c.is_whitespace()));
+ assert!(" ".chars().all(|c| c.is_whitespace()));
+ assert!("\u{2009}".chars().all(|c| c.is_whitespace())); // Thin space
+ assert!(" \n\t ".chars().all(|c| c.is_whitespace()));
+ assert!(!" _ ".chars().all(|c| c.is_whitespace()));
+}
+
+#[test]
+fn test_is_utf8() {
+ // deny overlong encodings
+ assert!(from_utf8(&[0xc0, 0x80]).is_err());
+ assert!(from_utf8(&[0xc0, 0xae]).is_err());
+ assert!(from_utf8(&[0xe0, 0x80, 0x80]).is_err());
+ assert!(from_utf8(&[0xe0, 0x80, 0xaf]).is_err());
+ assert!(from_utf8(&[0xe0, 0x81, 0x81]).is_err());
+ assert!(from_utf8(&[0xf0, 0x82, 0x82, 0xac]).is_err());
+ assert!(from_utf8(&[0xf4, 0x90, 0x80, 0x80]).is_err());
+
+ // deny surrogates
+ assert!(from_utf8(&[0xED, 0xA0, 0x80]).is_err());
+ assert!(from_utf8(&[0xED, 0xBF, 0xBF]).is_err());
+
+ assert!(from_utf8(&[0xC2, 0x80]).is_ok());
+ assert!(from_utf8(&[0xDF, 0xBF]).is_ok());
+ assert!(from_utf8(&[0xE0, 0xA0, 0x80]).is_ok());
+ assert!(from_utf8(&[0xED, 0x9F, 0xBF]).is_ok());
+ assert!(from_utf8(&[0xEE, 0x80, 0x80]).is_ok());
+ assert!(from_utf8(&[0xEF, 0xBF, 0xBF]).is_ok());
+ assert!(from_utf8(&[0xF0, 0x90, 0x80, 0x80]).is_ok());
+ assert!(from_utf8(&[0xF4, 0x8F, 0xBF, 0xBF]).is_ok());
+}
+
+#[test]
+fn test_const_is_utf8() {
+ const _: () = {
+ // deny overlong encodings
+ assert!(from_utf8(&[0xc0, 0x80]).is_err());
+ assert!(from_utf8(&[0xc0, 0xae]).is_err());
+ assert!(from_utf8(&[0xe0, 0x80, 0x80]).is_err());
+ assert!(from_utf8(&[0xe0, 0x80, 0xaf]).is_err());
+ assert!(from_utf8(&[0xe0, 0x81, 0x81]).is_err());
+ assert!(from_utf8(&[0xf0, 0x82, 0x82, 0xac]).is_err());
+ assert!(from_utf8(&[0xf4, 0x90, 0x80, 0x80]).is_err());
+
+ // deny surrogates
+ assert!(from_utf8(&[0xED, 0xA0, 0x80]).is_err());
+ assert!(from_utf8(&[0xED, 0xBF, 0xBF]).is_err());
+
+ assert!(from_utf8(&[0xC2, 0x80]).is_ok());
+ assert!(from_utf8(&[0xDF, 0xBF]).is_ok());
+ assert!(from_utf8(&[0xE0, 0xA0, 0x80]).is_ok());
+ assert!(from_utf8(&[0xED, 0x9F, 0xBF]).is_ok());
+ assert!(from_utf8(&[0xEE, 0x80, 0x80]).is_ok());
+ assert!(from_utf8(&[0xEF, 0xBF, 0xBF]).is_ok());
+ assert!(from_utf8(&[0xF0, 0x90, 0x80, 0x80]).is_ok());
+ assert!(from_utf8(&[0xF4, 0x8F, 0xBF, 0xBF]).is_ok());
+ };
+}
+
+#[test]
+fn from_utf8_mostly_ascii() {
+ // deny invalid bytes embedded in long stretches of ascii
+ for i in 32..64 {
+ let mut data = [0; 128];
+ data[i] = 0xC0;
+ assert!(from_utf8(&data).is_err());
+ data[i] = 0xC2;
+ assert!(from_utf8(&data).is_err());
+ }
+}
+
+#[test]
+fn const_from_utf8_mostly_ascii() {
+ const _: () = {
+ // deny invalid bytes embedded in long stretches of ascii
+ let mut i = 32;
+ while i < 64 {
+ let mut data = [0; 128];
+ data[i] = 0xC0;
+ assert!(from_utf8(&data).is_err());
+ data[i] = 0xC2;
+ assert!(from_utf8(&data).is_err());
+
+ i = i + 1;
+ }
+ };
+}
+
+#[test]
+fn from_utf8_error() {
+ macro_rules! test {
+ ($input: expr, $expected_valid_up_to:pat, $expected_error_len:pat) => {
+ let error = from_utf8($input).unwrap_err();
+ assert_matches!(error.valid_up_to(), $expected_valid_up_to);
+ assert_matches!(error.error_len(), $expected_error_len);
+
+ const _: () = {
+ match from_utf8($input) {
+ Err(error) => {
+ let valid_up_to = error.valid_up_to();
+ let error_len = error.error_len();
+
+ assert!(matches!(valid_up_to, $expected_valid_up_to));
+ assert!(matches!(error_len, $expected_error_len));
+ }
+ Ok(_) => unreachable!(),
+ }
+ };
+ };
+ }
+ test!(b"A\xC3\xA9 \xFF ", 4, Some(1));
+ test!(b"A\xC3\xA9 \x80 ", 4, Some(1));
+ test!(b"A\xC3\xA9 \xC1 ", 4, Some(1));
+ test!(b"A\xC3\xA9 \xC1", 4, Some(1));
+ test!(b"A\xC3\xA9 \xC2", 4, None);
+ test!(b"A\xC3\xA9 \xC2 ", 4, Some(1));
+ test!(b"A\xC3\xA9 \xC2\xC0", 4, Some(1));
+ test!(b"A\xC3\xA9 \xE0", 4, None);
+ test!(b"A\xC3\xA9 \xE0\x9F", 4, Some(1));
+ test!(b"A\xC3\xA9 \xE0\xA0", 4, None);
+ test!(b"A\xC3\xA9 \xE0\xA0\xC0", 4, Some(2));
+ test!(b"A\xC3\xA9 \xE0\xA0 ", 4, Some(2));
+ test!(b"A\xC3\xA9 \xED\xA0\x80 ", 4, Some(1));
+ test!(b"A\xC3\xA9 \xF1", 4, None);
+ test!(b"A\xC3\xA9 \xF1\x80", 4, None);
+ test!(b"A\xC3\xA9 \xF1\x80\x80", 4, None);
+ test!(b"A\xC3\xA9 \xF1 ", 4, Some(1));
+ test!(b"A\xC3\xA9 \xF1\x80 ", 4, Some(2));
+ test!(b"A\xC3\xA9 \xF1\x80\x80 ", 4, Some(3));
+}
+
+#[test]
+fn test_as_bytes() {
+ // no null
+ let v = [
+ 224, 184, 168, 224, 185, 132, 224, 184, 151, 224, 184, 162, 228, 184, 173, 229, 141, 142,
+ 86, 105, 225, 187, 135, 116, 32, 78, 97, 109,
+ ];
+ let b: &[u8] = &[];
+ assert_eq!("".as_bytes(), b);
+ assert_eq!("abc".as_bytes(), b"abc");
+ assert_eq!("ศไทย中华Việt Nam".as_bytes(), v);
+}
+
+#[test]
+#[should_panic]
+fn test_as_bytes_fail() {
+ // Don't double free. (I'm not sure if this exercises the
+ // original problem code path anymore.)
+ let s = String::from("");
+ let _bytes = s.as_bytes();
+ panic!();
+}
+
+#[test]
+fn test_as_ptr() {
+ let buf = "hello".as_ptr();
+ unsafe {
+ assert_eq!(*buf.offset(0), b'h');
+ assert_eq!(*buf.offset(1), b'e');
+ assert_eq!(*buf.offset(2), b'l');
+ assert_eq!(*buf.offset(3), b'l');
+ assert_eq!(*buf.offset(4), b'o');
+ }
+}
+
+#[test]
+fn vec_str_conversions() {
+ let s1: String = String::from("All mimsy were the borogoves");
+
+ let v: Vec<u8> = s1.as_bytes().to_vec();
+ let s2: String = String::from(from_utf8(&v).unwrap());
+ let mut i = 0;
+ let n1 = s1.len();
+ let n2 = v.len();
+ assert_eq!(n1, n2);
+ while i < n1 {
+ let a: u8 = s1.as_bytes()[i];
+ let b: u8 = s2.as_bytes()[i];
+ assert_eq!(a, b);
+ i += 1;
+ }
+}
+
+#[test]
+fn test_contains() {
+ assert!("abcde".contains("bcd"));
+ assert!("abcde".contains("abcd"));
+ assert!("abcde".contains("bcde"));
+ assert!("abcde".contains(""));
+ assert!("".contains(""));
+ assert!(!"abcde".contains("def"));
+ assert!(!"".contains("a"));
+
+ let data = "ประเทศไทย中华Việt Nam";
+ assert!(data.contains("ประเ"));
+ assert!(data.contains("ะเ"));
+ assert!(data.contains("中华"));
+ assert!(!data.contains("ไท华"));
+}
+
+#[test]
+fn test_contains_char() {
+ assert!("abc".contains('b'));
+ assert!("a".contains('a'));
+ assert!(!"abc".contains('d'));
+ assert!(!"".contains('a'));
+}
+
+#[test]
+fn test_split_at() {
+ let s = "ศไทย中华Việt Nam";
+ for (index, _) in s.char_indices() {
+ let (a, b) = s.split_at(index);
+ assert_eq!(&s[..a.len()], a);
+ assert_eq!(&s[a.len()..], b);
+ }
+ let (a, b) = s.split_at(s.len());
+ assert_eq!(a, s);
+ assert_eq!(b, "");
+}
+
+#[test]
+fn test_split_at_mut() {
+ let mut s = "Hello World".to_string();
+ {
+ let (a, b) = s.split_at_mut(5);
+ a.make_ascii_uppercase();
+ b.make_ascii_lowercase();
+ }
+ assert_eq!(s, "HELLO world");
+}
+
+#[test]
+#[should_panic]
+fn test_split_at_boundscheck() {
+ let s = "ศไทย中华Việt Nam";
+ let _ = s.split_at(1);
+}
+
+#[test]
+fn test_escape_unicode() {
+ assert_eq!("abc".escape_unicode().to_string(), "\\u{61}\\u{62}\\u{63}");
+ assert_eq!("a c".escape_unicode().to_string(), "\\u{61}\\u{20}\\u{63}");
+ assert_eq!("\r\n\t".escape_unicode().to_string(), "\\u{d}\\u{a}\\u{9}");
+ assert_eq!("'\"\\".escape_unicode().to_string(), "\\u{27}\\u{22}\\u{5c}");
+ assert_eq!("\x00\x01\u{fe}\u{ff}".escape_unicode().to_string(), "\\u{0}\\u{1}\\u{fe}\\u{ff}");
+ assert_eq!("\u{100}\u{ffff}".escape_unicode().to_string(), "\\u{100}\\u{ffff}");
+ assert_eq!("\u{10000}\u{10ffff}".escape_unicode().to_string(), "\\u{10000}\\u{10ffff}");
+ assert_eq!("ab\u{fb00}".escape_unicode().to_string(), "\\u{61}\\u{62}\\u{fb00}");
+ assert_eq!("\u{1d4ea}\r".escape_unicode().to_string(), "\\u{1d4ea}\\u{d}");
+}
+
+#[test]
+fn test_escape_debug() {
+ // Note that there are subtleties with the number of backslashes
+ // on the left- and right-hand sides. In particular, Unicode code points
+ // are usually escaped with two backslashes on the right-hand side, as
+ // they are escaped. However, when the character is unescaped (e.g., for
+ // printable characters), only a single backslash appears (as the character
+ // itself appears in the debug string).
+ assert_eq!("abc".escape_debug().to_string(), "abc");
+ assert_eq!("a c".escape_debug().to_string(), "a c");
+ assert_eq!("éèê".escape_debug().to_string(), "éèê");
+ assert_eq!("\0\r\n\t".escape_debug().to_string(), "\\0\\r\\n\\t");
+ assert_eq!("'\"\\".escape_debug().to_string(), "\\'\\\"\\\\");
+ assert_eq!("\u{7f}\u{ff}".escape_debug().to_string(), "\\u{7f}\u{ff}");
+ assert_eq!("\u{100}\u{ffff}".escape_debug().to_string(), "\u{100}\\u{ffff}");
+ assert_eq!("\u{10000}\u{10ffff}".escape_debug().to_string(), "\u{10000}\\u{10ffff}");
+ assert_eq!("ab\u{200b}".escape_debug().to_string(), "ab\\u{200b}");
+ assert_eq!("\u{10d4ea}\r".escape_debug().to_string(), "\\u{10d4ea}\\r");
+ assert_eq!(
+ "\u{301}a\u{301}bé\u{e000}".escape_debug().to_string(),
+ "\\u{301}a\u{301}bé\\u{e000}"
+ );
+}
+
+#[test]
+fn test_escape_default() {
+ assert_eq!("abc".escape_default().to_string(), "abc");
+ assert_eq!("a c".escape_default().to_string(), "a c");
+ assert_eq!("éèê".escape_default().to_string(), "\\u{e9}\\u{e8}\\u{ea}");
+ assert_eq!("\r\n\t".escape_default().to_string(), "\\r\\n\\t");
+ assert_eq!("'\"\\".escape_default().to_string(), "\\'\\\"\\\\");
+ assert_eq!("\u{7f}\u{ff}".escape_default().to_string(), "\\u{7f}\\u{ff}");
+ assert_eq!("\u{100}\u{ffff}".escape_default().to_string(), "\\u{100}\\u{ffff}");
+ assert_eq!("\u{10000}\u{10ffff}".escape_default().to_string(), "\\u{10000}\\u{10ffff}");
+ assert_eq!("ab\u{200b}".escape_default().to_string(), "ab\\u{200b}");
+ assert_eq!("\u{10d4ea}\r".escape_default().to_string(), "\\u{10d4ea}\\r");
+}
+
+#[test]
+fn test_total_ord() {
+ assert_eq!("1234".cmp("123"), Greater);
+ assert_eq!("123".cmp("1234"), Less);
+ assert_eq!("1234".cmp("1234"), Equal);
+ assert_eq!("12345555".cmp("123456"), Less);
+ assert_eq!("22".cmp("1234"), Greater);
+}
+
+#[test]
+fn test_iterator() {
+ let s = "ศไทย中华Việt Nam";
+ let v = ['ศ', 'ไ', 'ท', 'ย', '中', '华', 'V', 'i', 'ệ', 't', ' ', 'N', 'a', 'm'];
+
+ let mut pos = 0;
+ let it = s.chars();
+
+ for c in it {
+ assert_eq!(c, v[pos]);
+ pos += 1;
+ }
+ assert_eq!(pos, v.len());
+ assert_eq!(s.chars().count(), v.len());
+}
+
+#[test]
+fn test_rev_iterator() {
+ let s = "ศไทย中华Việt Nam";
+ let v = ['m', 'a', 'N', ' ', 't', 'ệ', 'i', 'V', '华', '中', 'ย', 'ท', 'ไ', 'ศ'];
+
+ let mut pos = 0;
+ let it = s.chars().rev();
+
+ for c in it {
+ assert_eq!(c, v[pos]);
+ pos += 1;
+ }
+ assert_eq!(pos, v.len());
+}
+
+#[test]
+fn test_to_lowercase_rev_iterator() {
+ let s = "AÖßÜ💩ΣΤΙΓΜΑΣDžfiİ";
+ let v = ['\u{307}', 'i', 'fi', 'dž', 'σ', 'α', 'μ', 'γ', 'ι', 'τ', 'σ', '💩', 'ü', 'ß', 'ö', 'a'];
+
+ let mut pos = 0;
+ let it = s.chars().flat_map(|c| c.to_lowercase()).rev();
+
+ for c in it {
+ assert_eq!(c, v[pos]);
+ pos += 1;
+ }
+ assert_eq!(pos, v.len());
+}
+
+#[test]
+fn test_to_uppercase_rev_iterator() {
+ let s = "aößü💩στιγμαςDžfiᾀ";
+ let v =
+ ['Ι', 'Ἀ', 'I', 'F', 'DŽ', 'Σ', 'Α', 'Μ', 'Γ', 'Ι', 'Τ', 'Σ', '💩', 'Ü', 'S', 'S', 'Ö', 'A'];
+
+ let mut pos = 0;
+ let it = s.chars().flat_map(|c| c.to_uppercase()).rev();
+
+ for c in it {
+ assert_eq!(c, v[pos]);
+ pos += 1;
+ }
+ assert_eq!(pos, v.len());
+}
+
+#[test]
+#[cfg_attr(miri, ignore)] // Miri is too slow
+fn test_chars_decoding() {
+ let mut bytes = [0; 4];
+ for c in (0..0x110000).filter_map(std::char::from_u32) {
+ let s = c.encode_utf8(&mut bytes);
+ if Some(c) != s.chars().next() {
+ panic!("character {:x}={} does not decode correctly", c as u32, c);
+ }
+ }
+}
+
+#[test]
+#[cfg_attr(miri, ignore)] // Miri is too slow
+fn test_chars_rev_decoding() {
+ let mut bytes = [0; 4];
+ for c in (0..0x110000).filter_map(std::char::from_u32) {
+ let s = c.encode_utf8(&mut bytes);
+ if Some(c) != s.chars().rev().next() {
+ panic!("character {:x}={} does not decode correctly", c as u32, c);
+ }
+ }
+}
+
+#[test]
+fn test_iterator_clone() {
+ let s = "ศไทย中华Việt Nam";
+ let mut it = s.chars();
+ it.next();
+ assert!(it.clone().zip(it).all(|(x, y)| x == y));
+}
+
+#[test]
+fn test_iterator_last() {
+ let s = "ศไทย中华Việt Nam";
+ let mut it = s.chars();
+ it.next();
+ assert_eq!(it.last(), Some('m'));
+}
+
+#[test]
+fn test_chars_debug() {
+ let s = "ศไทย中华Việt Nam";
+ let c = s.chars();
+ assert_eq!(
+ format!("{c:?}"),
+ r#"Chars(['ศ', 'ไ', 'ท', 'ย', '中', '华', 'V', 'i', 'ệ', 't', ' ', 'N', 'a', 'm'])"#
+ );
+}
+
+#[test]
+fn test_bytesator() {
+ let s = "ศไทย中华Việt Nam";
+ let v = [
+ 224, 184, 168, 224, 185, 132, 224, 184, 151, 224, 184, 162, 228, 184, 173, 229, 141, 142,
+ 86, 105, 225, 187, 135, 116, 32, 78, 97, 109,
+ ];
+ let mut pos = 0;
+
+ for b in s.bytes() {
+ assert_eq!(b, v[pos]);
+ pos += 1;
+ }
+}
+
+#[test]
+fn test_bytes_revator() {
+ let s = "ศไทย中华Việt Nam";
+ let v = [
+ 224, 184, 168, 224, 185, 132, 224, 184, 151, 224, 184, 162, 228, 184, 173, 229, 141, 142,
+ 86, 105, 225, 187, 135, 116, 32, 78, 97, 109,
+ ];
+ let mut pos = v.len();
+
+ for b in s.bytes().rev() {
+ pos -= 1;
+ assert_eq!(b, v[pos]);
+ }
+}
+
+#[test]
+fn test_bytesator_nth() {
+ let s = "ศไทย中华Việt Nam";
+ let v = [
+ 224, 184, 168, 224, 185, 132, 224, 184, 151, 224, 184, 162, 228, 184, 173, 229, 141, 142,
+ 86, 105, 225, 187, 135, 116, 32, 78, 97, 109,
+ ];
+
+ let mut b = s.bytes();
+ assert_eq!(b.nth(2).unwrap(), v[2]);
+ assert_eq!(b.nth(10).unwrap(), v[10]);
+ assert_eq!(b.nth(200), None);
+}
+
+#[test]
+fn test_bytesator_count() {
+ let s = "ศไทย中华Việt Nam";
+
+ let b = s.bytes();
+ assert_eq!(b.count(), 28)
+}
+
+#[test]
+fn test_bytesator_last() {
+ let s = "ศไทย中华Việt Nam";
+
+ let b = s.bytes();
+ assert_eq!(b.last().unwrap(), 109)
+}
+
+#[test]
+fn test_char_indicesator() {
+ let s = "ศไทย中华Việt Nam";
+ let p = [0, 3, 6, 9, 12, 15, 18, 19, 20, 23, 24, 25, 26, 27];
+ let v = ['ศ', 'ไ', 'ท', 'ย', '中', '华', 'V', 'i', 'ệ', 't', ' ', 'N', 'a', 'm'];
+
+ let mut pos = 0;
+ let it = s.char_indices();
+
+ for c in it {
+ assert_eq!(c, (p[pos], v[pos]));
+ pos += 1;
+ }
+ assert_eq!(pos, v.len());
+ assert_eq!(pos, p.len());
+}
+
+#[test]
+fn test_char_indices_revator() {
+ let s = "ศไทย中华Việt Nam";
+ let p = [27, 26, 25, 24, 23, 20, 19, 18, 15, 12, 9, 6, 3, 0];
+ let v = ['m', 'a', 'N', ' ', 't', 'ệ', 'i', 'V', '华', '中', 'ย', 'ท', 'ไ', 'ศ'];
+
+ let mut pos = 0;
+ let it = s.char_indices().rev();
+
+ for c in it {
+ assert_eq!(c, (p[pos], v[pos]));
+ pos += 1;
+ }
+ assert_eq!(pos, v.len());
+ assert_eq!(pos, p.len());
+}
+
+#[test]
+fn test_char_indices_last() {
+ let s = "ศไทย中华Việt Nam";
+ let mut it = s.char_indices();
+ it.next();
+ assert_eq!(it.last(), Some((27, 'm')));
+}
+
+#[test]
+fn test_splitn_char_iterator() {
+ let data = "\nMäry häd ä little lämb\nLittle lämb\n";
+
+ let split: Vec<&str> = data.splitn(4, ' ').collect();
+ assert_eq!(split, ["\nMäry", "häd", "ä", "little lämb\nLittle lämb\n"]);
+
+ let split: Vec<&str> = data.splitn(4, |c: char| c == ' ').collect();
+ assert_eq!(split, ["\nMäry", "häd", "ä", "little lämb\nLittle lämb\n"]);
+
+ // Unicode
+ let split: Vec<&str> = data.splitn(4, 'ä').collect();
+ assert_eq!(split, ["\nM", "ry h", "d ", " little lämb\nLittle lämb\n"]);
+
+ let split: Vec<&str> = data.splitn(4, |c: char| c == 'ä').collect();
+ assert_eq!(split, ["\nM", "ry h", "d ", " little lämb\nLittle lämb\n"]);
+}
+
+#[test]
+fn test_split_char_iterator_no_trailing() {
+ let data = "\nMäry häd ä little lämb\nLittle lämb\n";
+
+ let split: Vec<&str> = data.split('\n').collect();
+ assert_eq!(split, ["", "Märy häd ä little lämb", "Little lämb", ""]);
+
+ let split: Vec<&str> = data.split_terminator('\n').collect();
+ assert_eq!(split, ["", "Märy häd ä little lämb", "Little lämb"]);
+}
+
+#[test]
+fn test_split_char_iterator_inclusive() {
+ let data = "\nMäry häd ä little lämb\nLittle lämb\n";
+
+ let split: Vec<&str> = data.split_inclusive('\n').collect();
+ assert_eq!(split, ["\n", "Märy häd ä little lämb\n", "Little lämb\n"]);
+
+ let uppercase_separated = "SheePSharKTurtlECaT";
+ let mut first_char = true;
+ let split: Vec<&str> = uppercase_separated
+ .split_inclusive(|c: char| {
+ let split = !first_char && c.is_uppercase();
+ first_char = split;
+ split
+ })
+ .collect();
+ assert_eq!(split, ["SheeP", "SharK", "TurtlE", "CaT"]);
+}
+
+#[test]
+fn test_split_char_iterator_inclusive_rev() {
+ let data = "\nMäry häd ä little lämb\nLittle lämb\n";
+
+ let split: Vec<&str> = data.split_inclusive('\n').rev().collect();
+ assert_eq!(split, ["Little lämb\n", "Märy häd ä little lämb\n", "\n"]);
+
+ // Note that the predicate is stateful and thus dependent
+ // on the iteration order.
+ // (A different predicate is needed for reverse iterator vs normal iterator.)
+ // Not sure if anything can be done though.
+ let uppercase_separated = "SheePSharKTurtlECaT";
+ let mut term_char = true;
+ let split: Vec<&str> = uppercase_separated
+ .split_inclusive(|c: char| {
+ let split = term_char && c.is_uppercase();
+ term_char = c.is_uppercase();
+ split
+ })
+ .rev()
+ .collect();
+ assert_eq!(split, ["CaT", "TurtlE", "SharK", "SheeP"]);
+}
+
+#[test]
+fn test_rsplit() {
+ let data = "\nMäry häd ä little lämb\nLittle lämb\n";
+
+ let split: Vec<&str> = data.rsplit(' ').collect();
+ assert_eq!(split, ["lämb\n", "lämb\nLittle", "little", "ä", "häd", "\nMäry"]);
+
+ let split: Vec<&str> = data.rsplit("lämb").collect();
+ assert_eq!(split, ["\n", "\nLittle ", "\nMäry häd ä little "]);
+
+ let split: Vec<&str> = data.rsplit(|c: char| c == 'ä').collect();
+ assert_eq!(split, ["mb\n", "mb\nLittle l", " little l", "d ", "ry h", "\nM"]);
+}
+
+#[test]
+fn test_rsplitn() {
+ let data = "\nMäry häd ä little lämb\nLittle lämb\n";
+
+ let split: Vec<&str> = data.rsplitn(2, ' ').collect();
+ assert_eq!(split, ["lämb\n", "\nMäry häd ä little lämb\nLittle"]);
+
+ let split: Vec<&str> = data.rsplitn(2, "lämb").collect();
+ assert_eq!(split, ["\n", "\nMäry häd ä little lämb\nLittle "]);
+
+ let split: Vec<&str> = data.rsplitn(2, |c: char| c == 'ä').collect();
+ assert_eq!(split, ["mb\n", "\nMäry häd ä little lämb\nLittle l"]);
+}
+
+#[test]
+fn test_split_once() {
+ assert_eq!("".split_once("->"), None);
+ assert_eq!("-".split_once("->"), None);
+ assert_eq!("->".split_once("->"), Some(("", "")));
+ assert_eq!("a->".split_once("->"), Some(("a", "")));
+ assert_eq!("->b".split_once("->"), Some(("", "b")));
+ assert_eq!("a->b".split_once("->"), Some(("a", "b")));
+ assert_eq!("a->b->c".split_once("->"), Some(("a", "b->c")));
+ assert_eq!("---".split_once("--"), Some(("", "-")));
+}
+
+#[test]
+fn test_rsplit_once() {
+ assert_eq!("".rsplit_once("->"), None);
+ assert_eq!("-".rsplit_once("->"), None);
+ assert_eq!("->".rsplit_once("->"), Some(("", "")));
+ assert_eq!("a->".rsplit_once("->"), Some(("a", "")));
+ assert_eq!("->b".rsplit_once("->"), Some(("", "b")));
+ assert_eq!("a->b".rsplit_once("->"), Some(("a", "b")));
+ assert_eq!("a->b->c".rsplit_once("->"), Some(("a->b", "c")));
+ assert_eq!("---".rsplit_once("--"), Some(("-", "")));
+}
+
+#[test]
+fn test_split_whitespace() {
+ let data = "\n \tMäry häd\tä little lämb\nLittle lämb\n";
+ let words: Vec<&str> = data.split_whitespace().collect();
+ assert_eq!(words, ["Märy", "häd", "ä", "little", "lämb", "Little", "lämb"])
+}
+
+#[test]
+fn test_lines() {
+ let data = "\nMäry häd ä little lämb\n\r\nLittle lämb\n";
+ let lines: Vec<&str> = data.lines().collect();
+ assert_eq!(lines, ["", "Märy häd ä little lämb", "", "Little lämb"]);
+
+ let data = "\r\nMäry häd ä little lämb\n\nLittle lämb"; // no trailing \n
+ let lines: Vec<&str> = data.lines().collect();
+ assert_eq!(lines, ["", "Märy häd ä little lämb", "", "Little lämb"]);
+}
+
+#[test]
+fn test_splitator() {
+ fn t(s: &str, sep: &str, u: &[&str]) {
+ let v: Vec<&str> = s.split(sep).collect();
+ assert_eq!(v, u);
+ }
+ t("--1233345--", "12345", &["--1233345--"]);
+ t("abc::hello::there", "::", &["abc", "hello", "there"]);
+ t("::hello::there", "::", &["", "hello", "there"]);
+ t("hello::there::", "::", &["hello", "there", ""]);
+ t("::hello::there::", "::", &["", "hello", "there", ""]);
+ t("ประเทศไทย中华Việt Nam", "中华", &["ประเทศไทย", "Việt Nam"]);
+ t("zzXXXzzYYYzz", "zz", &["", "XXX", "YYY", ""]);
+ t("zzXXXzYYYz", "XXX", &["zz", "zYYYz"]);
+ t(".XXX.YYY.", ".", &["", "XXX", "YYY", ""]);
+ t("", ".", &[""]);
+ t("zz", "zz", &["", ""]);
+ t("ok", "z", &["ok"]);
+ t("zzz", "zz", &["", "z"]);
+ t("zzzzz", "zz", &["", "", "z"]);
+}
+
+#[test]
+fn test_str_default() {
+ use std::default::Default;
+
+ fn t<S: Default + AsRef<str>>() {
+ let s: S = Default::default();
+ assert_eq!(s.as_ref(), "");
+ }
+
+ t::<&str>();
+ t::<String>();
+ t::<&mut str>();
+}
+
+#[test]
+fn test_str_container() {
+ fn sum_len(v: &[&str]) -> usize {
+ v.iter().map(|x| x.len()).sum()
+ }
+
+ let s = "01234";
+ assert_eq!(5, sum_len(&["012", "", "34"]));
+ assert_eq!(5, sum_len(&["01", "2", "34", ""]));
+ assert_eq!(5, sum_len(&[s]));
+}
+
+#[test]
+fn test_str_from_utf8() {
+ let xs = b"hello";
+ assert_eq!(from_utf8(xs), Ok("hello"));
+
+ let xs = "ศไทย中华Việt Nam".as_bytes();
+ assert_eq!(from_utf8(xs), Ok("ศไทย中华Việt Nam"));
+
+ let xs = b"hello\xFF";
+ assert!(from_utf8(xs).is_err());
+}
+
+#[test]
+fn test_pattern_deref_forward() {
+ let data = "aabcdaa";
+ assert!(data.contains("bcd"));
+ assert!(data.contains(&"bcd"));
+ assert!(data.contains(&"bcd".to_string()));
+}
+
+#[test]
+fn test_empty_match_indices() {
+ let data = "aä中!";
+ let vec: Vec<_> = data.match_indices("").collect();
+ assert_eq!(vec, [(0, ""), (1, ""), (3, ""), (6, ""), (7, "")]);
+}
+
+#[test]
+fn test_bool_from_str() {
+ assert_eq!("true".parse().ok(), Some(true));
+ assert_eq!("false".parse().ok(), Some(false));
+ assert_eq!("not even a boolean".parse::<bool>().ok(), None);
+}
+
+fn check_contains_all_substrings(s: &str) {
+ assert!(s.contains(""));
+ for i in 0..s.len() {
+ for j in i + 1..=s.len() {
+ assert!(s.contains(&s[i..j]));
+ }
+ }
+}
+
+#[test]
+#[cfg_attr(miri, ignore)] // Miri is too slow
+fn strslice_issue_16589() {
+ assert!("bananas".contains("nana"));
+
+ // prior to the fix for #16589, x.contains("abcdabcd") returned false
+ // test all substrings for good measure
+ check_contains_all_substrings("012345678901234567890123456789bcdabcdabcd");
+}
+
+#[test]
+fn strslice_issue_16878() {
+ assert!(!"1234567ah012345678901ah".contains("hah"));
+ assert!(!"00abc01234567890123456789abc".contains("bcabc"));
+}
+
+#[test]
+#[cfg_attr(miri, ignore)] // Miri is too slow
+fn test_strslice_contains() {
+ let x = "There are moments, Jeeves, when one asks oneself, 'Do trousers matter?'";
+ check_contains_all_substrings(x);
+}
+
+#[test]
+fn test_rsplitn_char_iterator() {
+ let data = "\nMäry häd ä little lämb\nLittle lämb\n";
+
+ let mut split: Vec<&str> = data.rsplitn(4, ' ').collect();
+ split.reverse();
+ assert_eq!(split, ["\nMäry häd ä", "little", "lämb\nLittle", "lämb\n"]);
+
+ let mut split: Vec<&str> = data.rsplitn(4, |c: char| c == ' ').collect();
+ split.reverse();
+ assert_eq!(split, ["\nMäry häd ä", "little", "lämb\nLittle", "lämb\n"]);
+
+ // Unicode
+ let mut split: Vec<&str> = data.rsplitn(4, 'ä').collect();
+ split.reverse();
+ assert_eq!(split, ["\nMäry häd ", " little l", "mb\nLittle l", "mb\n"]);
+
+ let mut split: Vec<&str> = data.rsplitn(4, |c: char| c == 'ä').collect();
+ split.reverse();
+ assert_eq!(split, ["\nMäry häd ", " little l", "mb\nLittle l", "mb\n"]);
+}
+
+#[test]
+fn test_split_char_iterator() {
+ let data = "\nMäry häd ä little lämb\nLittle lämb\n";
+
+ let split: Vec<&str> = data.split(' ').collect();
+ assert_eq!(split, ["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]);
+
+ let mut rsplit: Vec<&str> = data.split(' ').rev().collect();
+ rsplit.reverse();
+ assert_eq!(rsplit, ["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]);
+
+ let split: Vec<&str> = data.split(|c: char| c == ' ').collect();
+ assert_eq!(split, ["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]);
+
+ let mut rsplit: Vec<&str> = data.split(|c: char| c == ' ').rev().collect();
+ rsplit.reverse();
+ assert_eq!(rsplit, ["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]);
+
+ // Unicode
+ let split: Vec<&str> = data.split('ä').collect();
+ assert_eq!(split, ["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]);
+
+ let mut rsplit: Vec<&str> = data.split('ä').rev().collect();
+ rsplit.reverse();
+ assert_eq!(rsplit, ["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]);
+
+ let split: Vec<&str> = data.split(|c: char| c == 'ä').collect();
+ assert_eq!(split, ["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]);
+
+ let mut rsplit: Vec<&str> = data.split(|c: char| c == 'ä').rev().collect();
+ rsplit.reverse();
+ assert_eq!(rsplit, ["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]);
+}
+
+#[test]
+fn test_rev_split_char_iterator_no_trailing() {
+ let data = "\nMäry häd ä little lämb\nLittle lämb\n";
+
+ let mut split: Vec<&str> = data.split('\n').rev().collect();
+ split.reverse();
+ assert_eq!(split, ["", "Märy häd ä little lämb", "Little lämb", ""]);
+
+ let mut split: Vec<&str> = data.split_terminator('\n').rev().collect();
+ split.reverse();
+ assert_eq!(split, ["", "Märy häd ä little lämb", "Little lämb"]);
+}
+
+#[test]
+fn test_utf16_code_units() {
+ assert_eq!("é\u{1F4A9}".encode_utf16().collect::<Vec<u16>>(), [0xE9, 0xD83D, 0xDCA9])
+}
+
+#[test]
+fn starts_with_in_unicode() {
+ assert!(!"├── Cargo.toml".starts_with("# "));
+}
+
+#[test]
+fn starts_short_long() {
+ assert!(!"".starts_with("##"));
+ assert!(!"##".starts_with("####"));
+ assert!("####".starts_with("##"));
+ assert!(!"##ä".starts_with("####"));
+ assert!("####ä".starts_with("##"));
+ assert!(!"##".starts_with("####ä"));
+ assert!("##ä##".starts_with("##ä"));
+
+ assert!("".starts_with(""));
+ assert!("ä".starts_with(""));
+ assert!("#ä".starts_with(""));
+ assert!("##ä".starts_with(""));
+ assert!("ä###".starts_with(""));
+ assert!("#ä##".starts_with(""));
+ assert!("##ä#".starts_with(""));
+}
+
+#[test]
+fn contains_weird_cases() {
+ assert!("* \t".contains(' '));
+ assert!(!"* \t".contains('?'));
+ assert!(!"* \t".contains('\u{1F4A9}'));
+}
+
+#[test]
+fn trim_ws() {
+ assert_eq!(" \t a \t ".trim_start_matches(|c: char| c.is_whitespace()), "a \t ");
+ assert_eq!(" \t a \t ".trim_end_matches(|c: char| c.is_whitespace()), " \t a");
+ assert_eq!(" \t a \t ".trim_start_matches(|c: char| c.is_whitespace()), "a \t ");
+ assert_eq!(" \t a \t ".trim_end_matches(|c: char| c.is_whitespace()), " \t a");
+ assert_eq!(" \t a \t ".trim_matches(|c: char| c.is_whitespace()), "a");
+ assert_eq!(" \t \t ".trim_start_matches(|c: char| c.is_whitespace()), "");
+ assert_eq!(" \t \t ".trim_end_matches(|c: char| c.is_whitespace()), "");
+ assert_eq!(" \t \t ".trim_start_matches(|c: char| c.is_whitespace()), "");
+ assert_eq!(" \t \t ".trim_end_matches(|c: char| c.is_whitespace()), "");
+ assert_eq!(" \t \t ".trim_matches(|c: char| c.is_whitespace()), "");
+}
+
+#[test]
+fn to_lowercase() {
+ assert_eq!("".to_lowercase(), "");
+ assert_eq!("AÉDžaé ".to_lowercase(), "aédžaé ");
+
+ // https://github.com/rust-lang/rust/issues/26035
+ assert_eq!("ΑΣ".to_lowercase(), "ας");
+ assert_eq!("Α'Σ".to_lowercase(), "α'ς");
+ assert_eq!("Α''Σ".to_lowercase(), "α''ς");
+
+ assert_eq!("ΑΣ Α".to_lowercase(), "ας α");
+ assert_eq!("Α'Σ Α".to_lowercase(), "α'ς α");
+ assert_eq!("Α''Σ Α".to_lowercase(), "α''ς α");
+
+ assert_eq!("ΑΣ' Α".to_lowercase(), "ας' α");
+ assert_eq!("ΑΣ'' Α".to_lowercase(), "ας'' α");
+
+ assert_eq!("Α'Σ' Α".to_lowercase(), "α'ς' α");
+ assert_eq!("Α''Σ'' Α".to_lowercase(), "α''ς'' α");
+
+ assert_eq!("Α Σ".to_lowercase(), "α σ");
+ assert_eq!("Α 'Σ".to_lowercase(), "α 'σ");
+ assert_eq!("Α ''Σ".to_lowercase(), "α ''σ");
+
+ assert_eq!("Σ".to_lowercase(), "σ");
+ assert_eq!("'Σ".to_lowercase(), "'σ");
+ assert_eq!("''Σ".to_lowercase(), "''σ");
+
+ assert_eq!("ΑΣΑ".to_lowercase(), "ασα");
+ assert_eq!("ΑΣ'Α".to_lowercase(), "ασ'α");
+ assert_eq!("ΑΣ''Α".to_lowercase(), "ασ''α");
+
+ // a really long string that has it's lowercase form
+ // even longer. this tests that implementations don't assume
+ // an incorrect upper bound on allocations
+ let upper = str::repeat("İ", 512);
+ let lower = str::repeat("i̇", 512);
+ assert_eq!(upper.to_lowercase(), lower);
+
+ // a really long ascii-only string.
+ // This test that the ascii hot-path
+ // functions correctly
+ let upper = str::repeat("A", 511);
+ let lower = str::repeat("a", 511);
+ assert_eq!(upper.to_lowercase(), lower);
+}
+
+#[test]
+fn to_uppercase() {
+ assert_eq!("".to_uppercase(), "");
+ assert_eq!("aéDžßfiᾀ".to_uppercase(), "AÉDŽSSFIἈΙ");
+}
+
+#[test]
+fn test_into_string() {
+ // The only way to acquire a Box<str> in the first place is through a String, so just
+ // test that we can round-trip between Box<str> and String.
+ let string = String::from("Some text goes here");
+ assert_eq!(string.clone().into_boxed_str().into_string(), string);
+}
+
+#[test]
+fn test_box_slice_clone() {
+ let data = String::from("hello HELLO hello HELLO yes YES 5 中ä华!!!");
+ let data2 = data.clone().into_boxed_str().clone().into_string();
+
+ assert_eq!(data, data2);
+}
+
+#[test]
+fn test_cow_from() {
+ let borrowed = "borrowed";
+ let owned = String::from("owned");
+ match (Cow::from(owned.clone()), Cow::from(borrowed)) {
+ (Cow::Owned(o), Cow::Borrowed(b)) => assert!(o == owned && b == borrowed),
+ _ => panic!("invalid `Cow::from`"),
+ }
+}
+
+#[test]
+fn test_repeat() {
+ assert_eq!("".repeat(3), "");
+ assert_eq!("abc".repeat(0), "");
+ assert_eq!("α".repeat(3), "ααα");
+}
+
+mod pattern {
+ use std::str::pattern::SearchStep::{self, Done, Match, Reject};
+ use std::str::pattern::{Pattern, ReverseSearcher, Searcher};
+
+ macro_rules! make_test {
+ ($name:ident, $p:expr, $h:expr, [$($e:expr,)*]) => {
+ #[allow(unused_imports)]
+ mod $name {
+ use std::str::pattern::SearchStep::{Match, Reject};
+ use super::{cmp_search_to_vec};
+ #[test]
+ fn fwd() {
+ cmp_search_to_vec(false, $p, $h, vec![$($e),*]);
+ }
+ #[test]
+ fn bwd() {
+ cmp_search_to_vec(true, $p, $h, vec![$($e),*]);
+ }
+ }
+ }
+ }
+
+ fn cmp_search_to_vec<'a>(
+ rev: bool,
+ pat: impl Pattern<'a, Searcher: ReverseSearcher<'a>>,
+ haystack: &'a str,
+ right: Vec<SearchStep>,
+ ) {
+ let mut searcher = pat.into_searcher(haystack);
+ let mut v = vec![];
+ loop {
+ match if !rev { searcher.next() } else { searcher.next_back() } {
+ Match(a, b) => v.push(Match(a, b)),
+ Reject(a, b) => v.push(Reject(a, b)),
+ Done => break,
+ }
+ }
+ if rev {
+ v.reverse();
+ }
+
+ let mut first_index = 0;
+ let mut err = None;
+
+ for (i, e) in right.iter().enumerate() {
+ match *e {
+ Match(a, b) | Reject(a, b) if a <= b && a == first_index => {
+ first_index = b;
+ }
+ _ => {
+ err = Some(i);
+ break;
+ }
+ }
+ }
+
+ if let Some(err) = err {
+ panic!("Input skipped range at {err}");
+ }
+
+ if first_index != haystack.len() {
+ panic!("Did not cover whole input");
+ }
+
+ assert_eq!(v, right);
+ }
+
+ make_test!(
+ str_searcher_ascii_haystack,
+ "bb",
+ "abbcbbd",
+ [Reject(0, 1), Match(1, 3), Reject(3, 4), Match(4, 6), Reject(6, 7),]
+ );
+ make_test!(
+ str_searcher_ascii_haystack_seq,
+ "bb",
+ "abbcbbbbd",
+ [Reject(0, 1), Match(1, 3), Reject(3, 4), Match(4, 6), Match(6, 8), Reject(8, 9),]
+ );
+ make_test!(
+ str_searcher_empty_needle_ascii_haystack,
+ "",
+ "abbcbbd",
+ [
+ Match(0, 0),
+ Reject(0, 1),
+ Match(1, 1),
+ Reject(1, 2),
+ Match(2, 2),
+ Reject(2, 3),
+ Match(3, 3),
+ Reject(3, 4),
+ Match(4, 4),
+ Reject(4, 5),
+ Match(5, 5),
+ Reject(5, 6),
+ Match(6, 6),
+ Reject(6, 7),
+ Match(7, 7),
+ ]
+ );
+ make_test!(
+ str_searcher_multibyte_haystack,
+ " ",
+ "├──",
+ [Reject(0, 3), Reject(3, 6), Reject(6, 9),]
+ );
+ make_test!(
+ str_searcher_empty_needle_multibyte_haystack,
+ "",
+ "├──",
+ [
+ Match(0, 0),
+ Reject(0, 3),
+ Match(3, 3),
+ Reject(3, 6),
+ Match(6, 6),
+ Reject(6, 9),
+ Match(9, 9),
+ ]
+ );
+ make_test!(str_searcher_empty_needle_empty_haystack, "", "", [Match(0, 0),]);
+ make_test!(str_searcher_nonempty_needle_empty_haystack, "├", "", []);
+ make_test!(
+ char_searcher_ascii_haystack,
+ 'b',
+ "abbcbbd",
+ [
+ Reject(0, 1),
+ Match(1, 2),
+ Match(2, 3),
+ Reject(3, 4),
+ Match(4, 5),
+ Match(5, 6),
+ Reject(6, 7),
+ ]
+ );
+ make_test!(
+ char_searcher_multibyte_haystack,
+ ' ',
+ "├──",
+ [Reject(0, 3), Reject(3, 6), Reject(6, 9),]
+ );
+ make_test!(
+ char_searcher_short_haystack,
+ '\u{1F4A9}',
+ "* \t",
+ [Reject(0, 1), Reject(1, 2), Reject(2, 3),]
+ );
+
+ // See #85462
+ #[test]
+ fn str_searcher_empty_needle_after_done() {
+ // Empty needle and haystack
+ {
+ let mut searcher = "".into_searcher("");
+
+ assert_eq!(searcher.next(), SearchStep::Match(0, 0));
+ assert_eq!(searcher.next(), SearchStep::Done);
+ assert_eq!(searcher.next(), SearchStep::Done);
+ assert_eq!(searcher.next(), SearchStep::Done);
+
+ let mut searcher = "".into_searcher("");
+
+ assert_eq!(searcher.next_back(), SearchStep::Match(0, 0));
+ assert_eq!(searcher.next_back(), SearchStep::Done);
+ assert_eq!(searcher.next_back(), SearchStep::Done);
+ assert_eq!(searcher.next_back(), SearchStep::Done);
+ }
+ // Empty needle and non-empty haystack
+ {
+ let mut searcher = "".into_searcher("a");
+
+ assert_eq!(searcher.next(), SearchStep::Match(0, 0));
+ assert_eq!(searcher.next(), SearchStep::Reject(0, 1));
+ assert_eq!(searcher.next(), SearchStep::Match(1, 1));
+ assert_eq!(searcher.next(), SearchStep::Done);
+ assert_eq!(searcher.next(), SearchStep::Done);
+ assert_eq!(searcher.next(), SearchStep::Done);
+
+ let mut searcher = "".into_searcher("a");
+
+ assert_eq!(searcher.next_back(), SearchStep::Match(1, 1));
+ assert_eq!(searcher.next_back(), SearchStep::Reject(0, 1));
+ assert_eq!(searcher.next_back(), SearchStep::Match(0, 0));
+ assert_eq!(searcher.next_back(), SearchStep::Done);
+ assert_eq!(searcher.next_back(), SearchStep::Done);
+ assert_eq!(searcher.next_back(), SearchStep::Done);
+ }
+ }
+}
+
+macro_rules! generate_iterator_test {
+ {
+ $name:ident {
+ $(
+ ($($arg:expr),*) -> [$($t:tt)*];
+ )*
+ }
+ with $fwd:expr, $bwd:expr;
+ } => {
+ #[test]
+ fn $name() {
+ $(
+ {
+ let res = vec![$($t)*];
+
+ let fwd_vec: Vec<_> = ($fwd)($($arg),*).collect();
+ assert_eq!(fwd_vec, res);
+
+ let mut bwd_vec: Vec<_> = ($bwd)($($arg),*).collect();
+ bwd_vec.reverse();
+ assert_eq!(bwd_vec, res);
+ }
+ )*
+ }
+ };
+ {
+ $name:ident {
+ $(
+ ($($arg:expr),*) -> [$($t:tt)*];
+ )*
+ }
+ with $fwd:expr;
+ } => {
+ #[test]
+ fn $name() {
+ $(
+ {
+ let res = vec![$($t)*];
+
+ let fwd_vec: Vec<_> = ($fwd)($($arg),*).collect();
+ assert_eq!(fwd_vec, res);
+ }
+ )*
+ }
+ }
+}
+
+generate_iterator_test! {
+ double_ended_split {
+ ("foo.bar.baz", '.') -> ["foo", "bar", "baz"];
+ ("foo::bar::baz", "::") -> ["foo", "bar", "baz"];
+ }
+ with str::split, str::rsplit;
+}
+
+generate_iterator_test! {
+ double_ended_split_terminator {
+ ("foo;bar;baz;", ';') -> ["foo", "bar", "baz"];
+ }
+ with str::split_terminator, str::rsplit_terminator;
+}
+
+generate_iterator_test! {
+ double_ended_matches {
+ ("a1b2c3", char::is_numeric) -> ["1", "2", "3"];
+ }
+ with str::matches, str::rmatches;
+}
+
+generate_iterator_test! {
+ double_ended_match_indices {
+ ("a1b2c3", char::is_numeric) -> [(1, "1"), (3, "2"), (5, "3")];
+ }
+ with str::match_indices, str::rmatch_indices;
+}
+
+generate_iterator_test! {
+ not_double_ended_splitn {
+ ("foo::bar::baz", 2, "::") -> ["foo", "bar::baz"];
+ }
+ with str::splitn;
+}
+
+generate_iterator_test! {
+ not_double_ended_rsplitn {
+ ("foo::bar::baz", 2, "::") -> ["baz", "foo::bar"];
+ }
+ with str::rsplitn;
+}
+
+#[test]
+fn different_str_pattern_forwarding_lifetimes() {
+ use std::str::pattern::Pattern;
+
+ fn foo<'a, P>(p: P)
+ where
+ for<'b> &'b P: Pattern<'a>,
+ {
+ for _ in 0..3 {
+ "asdf".find(&p);
+ }
+ }
+
+ foo::<&str>("x");
+}
+
+#[test]
+fn test_str_multiline() {
+ let a: String = "this \
+is a test"
+ .to_string();
+ let b: String = "this \
+ is \
+ another \
+ test"
+ .to_string();
+ assert_eq!(a, "this is a test".to_string());
+ assert_eq!(b, "this is another test".to_string());
+}
+
+#[test]
+fn test_str_escapes() {
+ let x = "\\\\\
+ ";
+ assert_eq!(x, r"\\"); // extraneous whitespace stripped
+}
+
+#[test]
+fn const_str_ptr() {
+ const A: [u8; 2] = ['h' as u8, 'i' as u8];
+ const B: &'static [u8; 2] = &A;
+ const C: *const u8 = B as *const u8;
+
+ // Miri does not deduplicate consts (https://github.com/rust-lang/miri/issues/131)
+ #[cfg(not(miri))]
+ {
+ let foo = &A as *const u8;
+ assert_eq!(foo, C);
+ }
+
+ unsafe {
+ assert_eq!(from_utf8_unchecked(&A), "hi");
+ assert_eq!(*C, A[0]);
+ assert_eq!(*(&B[0] as *const u8), A[0]);
+ }
+}
+
+#[test]
+fn utf8() {
+ let yen: char = '¥'; // 0xa5
+ let c_cedilla: char = 'ç'; // 0xe7
+ let thorn: char = 'þ'; // 0xfe
+ let y_diaeresis: char = 'ÿ'; // 0xff
+ let pi: char = 'Π'; // 0x3a0
+
+ assert_eq!(yen as isize, 0xa5);
+ assert_eq!(c_cedilla as isize, 0xe7);
+ assert_eq!(thorn as isize, 0xfe);
+ assert_eq!(y_diaeresis as isize, 0xff);
+ assert_eq!(pi as isize, 0x3a0);
+
+ assert_eq!(pi as isize, '\u{3a0}' as isize);
+ assert_eq!('\x0a' as isize, '\n' as isize);
+
+ let bhutan: String = "འབྲུག་ཡུལ།".to_string();
+ let japan: String = "日本".to_string();
+ let uzbekistan: String = "Ўзбекистон".to_string();
+ let austria: String = "Österreich".to_string();
+
+ let bhutan_e: String =
+ "\u{f60}\u{f56}\u{fb2}\u{f74}\u{f42}\u{f0b}\u{f61}\u{f74}\u{f63}\u{f0d}".to_string();
+ let japan_e: String = "\u{65e5}\u{672c}".to_string();
+ let uzbekistan_e: String =
+ "\u{40e}\u{437}\u{431}\u{435}\u{43a}\u{438}\u{441}\u{442}\u{43e}\u{43d}".to_string();
+ let austria_e: String = "\u{d6}sterreich".to_string();
+
+ let oo: char = 'Ö';
+ assert_eq!(oo as isize, 0xd6);
+
+ fn check_str_eq(a: String, b: String) {
+ let mut i: isize = 0;
+ for ab in a.bytes() {
+ println!("{i}");
+ println!("{ab}");
+ let bb: u8 = b.as_bytes()[i as usize];
+ println!("{bb}");
+ assert_eq!(ab, bb);
+ i += 1;
+ }
+ }
+
+ check_str_eq(bhutan, bhutan_e);
+ check_str_eq(japan, japan_e);
+ check_str_eq(uzbekistan, uzbekistan_e);
+ check_str_eq(austria, austria_e);
+}
+
+#[test]
+fn utf8_chars() {
+ // Chars of 1, 2, 3, and 4 bytes
+ let chs: Vec<char> = vec!['e', 'é', '€', '\u{10000}'];
+ let s: String = chs.iter().cloned().collect();
+ let schs: Vec<char> = s.chars().collect();
+
+ assert_eq!(s.len(), 10);
+ assert_eq!(s.chars().count(), 4);
+ assert_eq!(schs.len(), 4);
+ assert_eq!(schs.iter().cloned().collect::<String>(), s);
+
+ assert!((from_utf8(s.as_bytes()).is_ok()));
+ // invalid prefix
+ assert!((!from_utf8(&[0x80]).is_ok()));
+ // invalid 2 byte prefix
+ assert!((!from_utf8(&[0xc0]).is_ok()));
+ assert!((!from_utf8(&[0xc0, 0x10]).is_ok()));
+ // invalid 3 byte prefix
+ assert!((!from_utf8(&[0xe0]).is_ok()));
+ assert!((!from_utf8(&[0xe0, 0x10]).is_ok()));
+ assert!((!from_utf8(&[0xe0, 0xff, 0x10]).is_ok()));
+ // invalid 4 byte prefix
+ assert!((!from_utf8(&[0xf0]).is_ok()));
+ assert!((!from_utf8(&[0xf0, 0x10]).is_ok()));
+ assert!((!from_utf8(&[0xf0, 0xff, 0x10]).is_ok()));
+ assert!((!from_utf8(&[0xf0, 0xff, 0xff, 0x10]).is_ok()));
+}
+
+#[test]
+fn utf8_char_counts() {
+ let strs = [("e", 1), ("é", 1), ("€", 1), ("\u{10000}", 1), ("eé€\u{10000}", 4)];
+ let spread = if cfg!(miri) { 4 } else { 8 };
+ let mut reps = [8, 64, 256, 512]
+ .iter()
+ .copied()
+ .flat_map(|n| n - spread..=n + spread)
+ .collect::<Vec<usize>>();
+ if cfg!(not(miri)) {
+ reps.extend([1024, 1 << 16].iter().copied().flat_map(|n| n - spread..=n + spread));
+ }
+ let counts = if cfg!(miri) { 0..1 } else { 0..8 };
+ let padding = counts.map(|len| " ".repeat(len)).collect::<Vec<String>>();
+
+ for repeat in reps {
+ for (tmpl_str, tmpl_char_count) in strs {
+ for pad_start in &padding {
+ for pad_end in &padding {
+ // Create a string with padding...
+ let with_padding =
+ format!("{}{}{}", pad_start, tmpl_str.repeat(repeat), pad_end);
+ // ...and then skip past that padding. This should ensure
+ // that we test several different alignments for both head
+ // and tail.
+ let si = pad_start.len();
+ let ei = with_padding.len() - pad_end.len();
+ let target = &with_padding[si..ei];
+
+ assert!(!target.starts_with(" ") && !target.ends_with(" "));
+ let expected_count = tmpl_char_count * repeat;
+ assert_eq!(
+ expected_count,
+ target.chars().count(),
+ "wrong count for `{:?}.repeat({})` (padding: `{:?}`)",
+ tmpl_str,
+ repeat,
+ (pad_start.len(), pad_end.len()),
+ );
+ }
+ }
+ }
+ }
+}
+
+#[test]
+fn floor_char_boundary() {
+ fn check_many(s: &str, arg: impl IntoIterator<Item = usize>, ret: usize) {
+ for idx in arg {
+ assert_eq!(
+ s.floor_char_boundary(idx),
+ ret,
+ "{:?}.floor_char_boundary({:?}) != {:?}",
+ s,
+ idx,
+ ret
+ );
+ }
+ }
+
+ // edge case
+ check_many("", [0, 1, isize::MAX as usize, usize::MAX], 0);
+
+ // basic check
+ check_many("x", [0], 0);
+ check_many("x", [1, isize::MAX as usize, usize::MAX], 1);
+
+ // 1-byte chars
+ check_many("jp", [0], 0);
+ check_many("jp", [1], 1);
+ check_many("jp", 2..4, 2);
+
+ // 2-byte chars
+ check_many("ĵƥ", 0..2, 0);
+ check_many("ĵƥ", 2..4, 2);
+ check_many("ĵƥ", 4..6, 4);
+
+ // 3-byte chars
+ check_many("日本", 0..3, 0);
+ check_many("日本", 3..6, 3);
+ check_many("日本", 6..8, 6);
+
+ // 4-byte chars
+ check_many("🇯🇵", 0..4, 0);
+ check_many("🇯🇵", 4..8, 4);
+ check_many("🇯🇵", 8..10, 8);
+}
+
+#[test]
+fn ceil_char_boundary() {
+ fn check_many(s: &str, arg: impl IntoIterator<Item = usize>, ret: usize) {
+ for idx in arg {
+ assert_eq!(
+ s.ceil_char_boundary(idx),
+ ret,
+ "{:?}.ceil_char_boundary({:?}) != {:?}",
+ s,
+ idx,
+ ret
+ );
+ }
+ }
+
+ // edge case
+ check_many("", [0], 0);
+
+ // basic check
+ check_many("x", [0], 0);
+ check_many("x", [1], 1);
+
+ // 1-byte chars
+ check_many("jp", [0], 0);
+ check_many("jp", [1], 1);
+ check_many("jp", [2], 2);
+
+ // 2-byte chars
+ check_many("ĵƥ", 0..=0, 0);
+ check_many("ĵƥ", 1..=2, 2);
+ check_many("ĵƥ", 3..=4, 4);
+
+ // 3-byte chars
+ check_many("日本", 0..=0, 0);
+ check_many("日本", 1..=3, 3);
+ check_many("日本", 4..=6, 6);
+
+ // 4-byte chars
+ check_many("🇯🇵", 0..=0, 0);
+ check_many("🇯🇵", 1..=4, 4);
+ check_many("🇯🇵", 5..=8, 8);
+}
+
+#[test]
+#[should_panic]
+fn ceil_char_boundary_above_len_panic() {
+ let _ = "x".ceil_char_boundary(2);
+}
diff --git a/library/alloc/tests/string.rs b/library/alloc/tests/string.rs
new file mode 100644
index 000000000..b6836fdc8
--- /dev/null
+++ b/library/alloc/tests/string.rs
@@ -0,0 +1,876 @@
+use std::assert_matches::assert_matches;
+use std::borrow::Cow;
+use std::cell::Cell;
+use std::collections::TryReserveErrorKind::*;
+use std::ops::Bound;
+use std::ops::Bound::*;
+use std::ops::RangeBounds;
+use std::panic;
+use std::str;
+
+pub trait IntoCow<'a, B: ?Sized>
+where
+ B: ToOwned,
+{
+ fn into_cow(self) -> Cow<'a, B>;
+}
+
+impl<'a> IntoCow<'a, str> for String {
+ fn into_cow(self) -> Cow<'a, str> {
+ Cow::Owned(self)
+ }
+}
+
+impl<'a> IntoCow<'a, str> for &'a str {
+ fn into_cow(self) -> Cow<'a, str> {
+ Cow::Borrowed(self)
+ }
+}
+
+#[test]
+fn test_from_str() {
+ let owned: Option<std::string::String> = "string".parse().ok();
+ assert_eq!(owned.as_ref().map(|s| &**s), Some("string"));
+}
+
+#[test]
+fn test_from_cow_str() {
+ assert_eq!(String::from(Cow::Borrowed("string")), "string");
+ assert_eq!(String::from(Cow::Owned(String::from("string"))), "string");
+}
+
+#[test]
+fn test_unsized_to_string() {
+ let s: &str = "abc";
+ let _: String = (*s).to_string();
+}
+
+#[test]
+fn test_from_utf8() {
+ let xs = b"hello".to_vec();
+ assert_eq!(String::from_utf8(xs).unwrap(), String::from("hello"));
+
+ let xs = "ศไทย中华Việt Nam".as_bytes().to_vec();
+ assert_eq!(String::from_utf8(xs).unwrap(), String::from("ศไทย中华Việt Nam"));
+
+ let xs = b"hello\xFF".to_vec();
+ let err = String::from_utf8(xs).unwrap_err();
+ assert_eq!(err.as_bytes(), b"hello\xff");
+ let err_clone = err.clone();
+ assert_eq!(err, err_clone);
+ assert_eq!(err.into_bytes(), b"hello\xff".to_vec());
+ assert_eq!(err_clone.utf8_error().valid_up_to(), 5);
+}
+
+#[test]
+fn test_from_utf8_lossy() {
+ let xs = b"hello";
+ let ys: Cow<'_, str> = "hello".into_cow();
+ assert_eq!(String::from_utf8_lossy(xs), ys);
+
+ let xs = "ศไทย中华Việt Nam".as_bytes();
+ let ys: Cow<'_, str> = "ศไทย中华Việt Nam".into_cow();
+ assert_eq!(String::from_utf8_lossy(xs), ys);
+
+ let xs = b"Hello\xC2 There\xFF Goodbye";
+ assert_eq!(
+ String::from_utf8_lossy(xs),
+ String::from("Hello\u{FFFD} There\u{FFFD} Goodbye").into_cow()
+ );
+
+ let xs = b"Hello\xC0\x80 There\xE6\x83 Goodbye";
+ assert_eq!(
+ String::from_utf8_lossy(xs),
+ String::from("Hello\u{FFFD}\u{FFFD} There\u{FFFD} Goodbye").into_cow()
+ );
+
+ let xs = b"\xF5foo\xF5\x80bar";
+ assert_eq!(
+ String::from_utf8_lossy(xs),
+ String::from("\u{FFFD}foo\u{FFFD}\u{FFFD}bar").into_cow()
+ );
+
+ let xs = b"\xF1foo\xF1\x80bar\xF1\x80\x80baz";
+ assert_eq!(
+ String::from_utf8_lossy(xs),
+ String::from("\u{FFFD}foo\u{FFFD}bar\u{FFFD}baz").into_cow()
+ );
+
+ let xs = b"\xF4foo\xF4\x80bar\xF4\xBFbaz";
+ assert_eq!(
+ String::from_utf8_lossy(xs),
+ String::from("\u{FFFD}foo\u{FFFD}bar\u{FFFD}\u{FFFD}baz").into_cow()
+ );
+
+ let xs = b"\xF0\x80\x80\x80foo\xF0\x90\x80\x80bar";
+ assert_eq!(
+ String::from_utf8_lossy(xs),
+ String::from("\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}foo\u{10000}bar").into_cow()
+ );
+
+ // surrogates
+ let xs = b"\xED\xA0\x80foo\xED\xBF\xBFbar";
+ assert_eq!(
+ String::from_utf8_lossy(xs),
+ String::from("\u{FFFD}\u{FFFD}\u{FFFD}foo\u{FFFD}\u{FFFD}\u{FFFD}bar").into_cow()
+ );
+}
+
+#[test]
+fn test_from_utf16() {
+ let pairs = [
+ (
+ String::from("𐍅𐌿𐌻𐍆𐌹𐌻𐌰\n"),
+ vec![
+ 0xd800, 0xdf45, 0xd800, 0xdf3f, 0xd800, 0xdf3b, 0xd800, 0xdf46, 0xd800, 0xdf39,
+ 0xd800, 0xdf3b, 0xd800, 0xdf30, 0x000a,
+ ],
+ ),
+ (
+ String::from("𐐒𐑉𐐮𐑀𐐲𐑋 𐐏𐐲𐑍\n"),
+ vec![
+ 0xd801, 0xdc12, 0xd801, 0xdc49, 0xd801, 0xdc2e, 0xd801, 0xdc40, 0xd801, 0xdc32,
+ 0xd801, 0xdc4b, 0x0020, 0xd801, 0xdc0f, 0xd801, 0xdc32, 0xd801, 0xdc4d, 0x000a,
+ ],
+ ),
+ (
+ String::from("𐌀𐌖𐌋𐌄𐌑𐌉·𐌌𐌄𐌕𐌄𐌋𐌉𐌑\n"),
+ vec![
+ 0xd800, 0xdf00, 0xd800, 0xdf16, 0xd800, 0xdf0b, 0xd800, 0xdf04, 0xd800, 0xdf11,
+ 0xd800, 0xdf09, 0x00b7, 0xd800, 0xdf0c, 0xd800, 0xdf04, 0xd800, 0xdf15, 0xd800,
+ 0xdf04, 0xd800, 0xdf0b, 0xd800, 0xdf09, 0xd800, 0xdf11, 0x000a,
+ ],
+ ),
+ (
+ String::from("𐒋𐒘𐒈𐒑𐒛𐒒 𐒕𐒓 𐒈𐒚𐒍 𐒏𐒜𐒒𐒖𐒆 𐒕𐒆\n"),
+ vec![
+ 0xd801, 0xdc8b, 0xd801, 0xdc98, 0xd801, 0xdc88, 0xd801, 0xdc91, 0xd801, 0xdc9b,
+ 0xd801, 0xdc92, 0x0020, 0xd801, 0xdc95, 0xd801, 0xdc93, 0x0020, 0xd801, 0xdc88,
+ 0xd801, 0xdc9a, 0xd801, 0xdc8d, 0x0020, 0xd801, 0xdc8f, 0xd801, 0xdc9c, 0xd801,
+ 0xdc92, 0xd801, 0xdc96, 0xd801, 0xdc86, 0x0020, 0xd801, 0xdc95, 0xd801, 0xdc86,
+ 0x000a,
+ ],
+ ),
+ // Issue #12318, even-numbered non-BMP planes
+ (String::from("\u{20000}"), vec![0xD840, 0xDC00]),
+ ];
+
+ for p in &pairs {
+ let (s, u) = (*p).clone();
+ let s_as_utf16 = s.encode_utf16().collect::<Vec<u16>>();
+ let u_as_string = String::from_utf16(&u).unwrap();
+
+ assert!(core::char::decode_utf16(u.iter().cloned()).all(|r| r.is_ok()));
+ assert_eq!(s_as_utf16, u);
+
+ assert_eq!(u_as_string, s);
+ assert_eq!(String::from_utf16_lossy(&u), s);
+
+ assert_eq!(String::from_utf16(&s_as_utf16).unwrap(), s);
+ assert_eq!(u_as_string.encode_utf16().collect::<Vec<u16>>(), u);
+ }
+}
+
+#[test]
+fn test_utf16_invalid() {
+ // completely positive cases tested above.
+ // lead + eof
+ assert!(String::from_utf16(&[0xD800]).is_err());
+ // lead + lead
+ assert!(String::from_utf16(&[0xD800, 0xD800]).is_err());
+
+ // isolated trail
+ assert!(String::from_utf16(&[0x0061, 0xDC00]).is_err());
+
+ // general
+ assert!(String::from_utf16(&[0xD800, 0xd801, 0xdc8b, 0xD800]).is_err());
+}
+
+#[test]
+fn test_from_utf16_lossy() {
+ // completely positive cases tested above.
+ // lead + eof
+ assert_eq!(String::from_utf16_lossy(&[0xD800]), String::from("\u{FFFD}"));
+ // lead + lead
+ assert_eq!(String::from_utf16_lossy(&[0xD800, 0xD800]), String::from("\u{FFFD}\u{FFFD}"));
+
+ // isolated trail
+ assert_eq!(String::from_utf16_lossy(&[0x0061, 0xDC00]), String::from("a\u{FFFD}"));
+
+ // general
+ assert_eq!(
+ String::from_utf16_lossy(&[0xD800, 0xd801, 0xdc8b, 0xD800]),
+ String::from("\u{FFFD}𐒋\u{FFFD}")
+ );
+}
+
+#[test]
+fn test_push_bytes() {
+ let mut s = String::from("ABC");
+ unsafe {
+ let mv = s.as_mut_vec();
+ mv.extend_from_slice(&[b'D']);
+ }
+ assert_eq!(s, "ABCD");
+}
+
+#[test]
+fn test_push_str() {
+ let mut s = String::new();
+ s.push_str("");
+ assert_eq!(&s[0..], "");
+ s.push_str("abc");
+ assert_eq!(&s[0..], "abc");
+ s.push_str("ประเทศไทย中华Việt Nam");
+ assert_eq!(&s[0..], "abcประเทศไทย中华Việt Nam");
+}
+
+#[test]
+fn test_add_assign() {
+ let mut s = String::new();
+ s += "";
+ assert_eq!(s.as_str(), "");
+ s += "abc";
+ assert_eq!(s.as_str(), "abc");
+ s += "ประเทศไทย中华Việt Nam";
+ assert_eq!(s.as_str(), "abcประเทศไทย中华Việt Nam");
+}
+
+#[test]
+fn test_push() {
+ let mut data = String::from("ประเทศไทย中");
+ data.push('华');
+ data.push('b'); // 1 byte
+ data.push('¢'); // 2 byte
+ data.push('€'); // 3 byte
+ data.push('𤭢'); // 4 byte
+ assert_eq!(data, "ประเทศไทย中华b¢€𤭢");
+}
+
+#[test]
+fn test_pop() {
+ let mut data = String::from("ประเทศไทย中华b¢€𤭢");
+ assert_eq!(data.pop().unwrap(), '𤭢'); // 4 bytes
+ assert_eq!(data.pop().unwrap(), '€'); // 3 bytes
+ assert_eq!(data.pop().unwrap(), '¢'); // 2 bytes
+ assert_eq!(data.pop().unwrap(), 'b'); // 1 bytes
+ assert_eq!(data.pop().unwrap(), '华');
+ assert_eq!(data, "ประเทศไทย中");
+}
+
+#[test]
+fn test_split_off_empty() {
+ let orig = "Hello, world!";
+ let mut split = String::from(orig);
+ let empty: String = split.split_off(orig.len());
+ assert!(empty.is_empty());
+}
+
+#[test]
+#[should_panic]
+fn test_split_off_past_end() {
+ let orig = "Hello, world!";
+ let mut split = String::from(orig);
+ let _ = split.split_off(orig.len() + 1);
+}
+
+#[test]
+#[should_panic]
+fn test_split_off_mid_char() {
+ let mut shan = String::from("山");
+ let _broken_mountain = shan.split_off(1);
+}
+
+#[test]
+fn test_split_off_ascii() {
+ let mut ab = String::from("ABCD");
+ let orig_capacity = ab.capacity();
+ let cd = ab.split_off(2);
+ assert_eq!(ab, "AB");
+ assert_eq!(cd, "CD");
+ assert_eq!(ab.capacity(), orig_capacity);
+}
+
+#[test]
+fn test_split_off_unicode() {
+ let mut nihon = String::from("日本語");
+ let orig_capacity = nihon.capacity();
+ let go = nihon.split_off("日本".len());
+ assert_eq!(nihon, "日本");
+ assert_eq!(go, "語");
+ assert_eq!(nihon.capacity(), orig_capacity);
+}
+
+#[test]
+fn test_str_truncate() {
+ let mut s = String::from("12345");
+ s.truncate(5);
+ assert_eq!(s, "12345");
+ s.truncate(3);
+ assert_eq!(s, "123");
+ s.truncate(0);
+ assert_eq!(s, "");
+
+ let mut s = String::from("12345");
+ let p = s.as_ptr();
+ s.truncate(3);
+ s.push_str("6");
+ let p_ = s.as_ptr();
+ assert_eq!(p_, p);
+}
+
+#[test]
+fn test_str_truncate_invalid_len() {
+ let mut s = String::from("12345");
+ s.truncate(6);
+ assert_eq!(s, "12345");
+}
+
+#[test]
+#[should_panic]
+fn test_str_truncate_split_codepoint() {
+ let mut s = String::from("\u{FC}"); // ü
+ s.truncate(1);
+}
+
+#[test]
+fn test_str_clear() {
+ let mut s = String::from("12345");
+ s.clear();
+ assert_eq!(s.len(), 0);
+ assert_eq!(s, "");
+}
+
+#[test]
+fn test_str_add() {
+ let a = String::from("12345");
+ let b = a + "2";
+ let b = b + "2";
+ assert_eq!(b.len(), 7);
+ assert_eq!(b, "1234522");
+}
+
+#[test]
+fn remove() {
+ let mut s = "ศไทย中华Việt Nam; foobar".to_string();
+ assert_eq!(s.remove(0), 'ศ');
+ assert_eq!(s.len(), 33);
+ assert_eq!(s, "ไทย中华Việt Nam; foobar");
+ assert_eq!(s.remove(17), 'ệ');
+ assert_eq!(s, "ไทย中华Vit Nam; foobar");
+}
+
+#[test]
+#[should_panic]
+fn remove_bad() {
+ "ศ".to_string().remove(1);
+}
+
+#[test]
+fn test_remove_matches() {
+ let mut s = "abc".to_string();
+
+ s.remove_matches('b');
+ assert_eq!(s, "ac");
+ s.remove_matches('b');
+ assert_eq!(s, "ac");
+
+ let mut s = "abcb".to_string();
+
+ s.remove_matches('b');
+ assert_eq!(s, "ac");
+
+ let mut s = "ศไทย中华Việt Nam; foobarศ".to_string();
+ s.remove_matches('ศ');
+ assert_eq!(s, "ไทย中华Việt Nam; foobar");
+
+ let mut s = "".to_string();
+ s.remove_matches("");
+ assert_eq!(s, "");
+
+ let mut s = "aaaaa".to_string();
+ s.remove_matches('a');
+ assert_eq!(s, "");
+}
+
+#[test]
+fn test_retain() {
+ let mut s = String::from("α_β_γ");
+
+ s.retain(|_| true);
+ assert_eq!(s, "α_β_γ");
+
+ s.retain(|c| c != '_');
+ assert_eq!(s, "αβγ");
+
+ s.retain(|c| c != 'β');
+ assert_eq!(s, "αγ");
+
+ s.retain(|c| c == 'α');
+ assert_eq!(s, "α");
+
+ s.retain(|_| false);
+ assert_eq!(s, "");
+
+ let mut s = String::from("0è0");
+ let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| {
+ let mut count = 0;
+ s.retain(|_| {
+ count += 1;
+ match count {
+ 1 => false,
+ 2 => true,
+ _ => panic!(),
+ }
+ });
+ }));
+ assert!(std::str::from_utf8(s.as_bytes()).is_ok());
+}
+
+#[test]
+fn insert() {
+ let mut s = "foobar".to_string();
+ s.insert(0, 'ệ');
+ assert_eq!(s, "ệfoobar");
+ s.insert(6, 'ย');
+ assert_eq!(s, "ệfooยbar");
+}
+
+#[test]
+#[should_panic]
+fn insert_bad1() {
+ "".to_string().insert(1, 't');
+}
+#[test]
+#[should_panic]
+fn insert_bad2() {
+ "ệ".to_string().insert(1, 't');
+}
+
+#[test]
+fn test_slicing() {
+ let s = "foobar".to_string();
+ assert_eq!("foobar", &s[..]);
+ assert_eq!("foo", &s[..3]);
+ assert_eq!("bar", &s[3..]);
+ assert_eq!("oob", &s[1..4]);
+}
+
+#[test]
+fn test_simple_types() {
+ assert_eq!(1.to_string(), "1");
+ assert_eq!((-1).to_string(), "-1");
+ assert_eq!(200.to_string(), "200");
+ assert_eq!(2.to_string(), "2");
+ assert_eq!(true.to_string(), "true");
+ assert_eq!(false.to_string(), "false");
+ assert_eq!(("hi".to_string()).to_string(), "hi");
+}
+
+#[test]
+fn test_vectors() {
+ let x: Vec<i32> = vec![];
+ assert_eq!(format!("{x:?}"), "[]");
+ assert_eq!(format!("{:?}", vec![1]), "[1]");
+ assert_eq!(format!("{:?}", vec![1, 2, 3]), "[1, 2, 3]");
+ assert!(format!("{:?}", vec![vec![], vec![1], vec![1, 1]]) == "[[], [1], [1, 1]]");
+}
+
+#[test]
+fn test_from_iterator() {
+ let s = "ศไทย中华Việt Nam".to_string();
+ let t = "ศไทย中华";
+ let u = "Việt Nam";
+
+ let a: String = s.chars().collect();
+ assert_eq!(s, a);
+
+ let mut b = t.to_string();
+ b.extend(u.chars());
+ assert_eq!(s, b);
+
+ let c: String = [t, u].into_iter().collect();
+ assert_eq!(s, c);
+
+ let mut d = t.to_string();
+ d.extend(vec![u]);
+ assert_eq!(s, d);
+}
+
+#[test]
+fn test_drain() {
+ let mut s = String::from("αβγ");
+ assert_eq!(s.drain(2..4).collect::<String>(), "β");
+ assert_eq!(s, "αγ");
+
+ let mut t = String::from("abcd");
+ t.drain(..0);
+ assert_eq!(t, "abcd");
+ t.drain(..1);
+ assert_eq!(t, "bcd");
+ t.drain(3..);
+ assert_eq!(t, "bcd");
+ t.drain(..);
+ assert_eq!(t, "");
+}
+
+#[test]
+#[should_panic]
+fn test_drain_start_overflow() {
+ let mut s = String::from("abc");
+ s.drain((Excluded(usize::MAX), Included(0)));
+}
+
+#[test]
+#[should_panic]
+fn test_drain_end_overflow() {
+ let mut s = String::from("abc");
+ s.drain((Included(0), Included(usize::MAX)));
+}
+
+#[test]
+fn test_replace_range() {
+ let mut s = "Hello, world!".to_owned();
+ s.replace_range(7..12, "世界");
+ assert_eq!(s, "Hello, 世界!");
+}
+
+#[test]
+#[should_panic]
+fn test_replace_range_char_boundary() {
+ let mut s = "Hello, 世界!".to_owned();
+ s.replace_range(..8, "");
+}
+
+#[test]
+fn test_replace_range_inclusive_range() {
+ let mut v = String::from("12345");
+ v.replace_range(2..=3, "789");
+ assert_eq!(v, "127895");
+ v.replace_range(1..=2, "A");
+ assert_eq!(v, "1A895");
+}
+
+#[test]
+#[should_panic]
+fn test_replace_range_out_of_bounds() {
+ let mut s = String::from("12345");
+ s.replace_range(5..6, "789");
+}
+
+#[test]
+#[should_panic]
+fn test_replace_range_inclusive_out_of_bounds() {
+ let mut s = String::from("12345");
+ s.replace_range(5..=5, "789");
+}
+
+#[test]
+#[should_panic]
+fn test_replace_range_start_overflow() {
+ let mut s = String::from("123");
+ s.replace_range((Excluded(usize::MAX), Included(0)), "");
+}
+
+#[test]
+#[should_panic]
+fn test_replace_range_end_overflow() {
+ let mut s = String::from("456");
+ s.replace_range((Included(0), Included(usize::MAX)), "");
+}
+
+#[test]
+fn test_replace_range_empty() {
+ let mut s = String::from("12345");
+ s.replace_range(1..2, "");
+ assert_eq!(s, "1345");
+}
+
+#[test]
+fn test_replace_range_unbounded() {
+ let mut s = String::from("12345");
+ s.replace_range(.., "");
+ assert_eq!(s, "");
+}
+
+#[test]
+fn test_replace_range_evil_start_bound() {
+ struct EvilRange(Cell<bool>);
+
+ impl RangeBounds<usize> for EvilRange {
+ fn start_bound(&self) -> Bound<&usize> {
+ Bound::Included(if self.0.get() {
+ &1
+ } else {
+ self.0.set(true);
+ &0
+ })
+ }
+ fn end_bound(&self) -> Bound<&usize> {
+ Bound::Unbounded
+ }
+ }
+
+ let mut s = String::from("🦀");
+ s.replace_range(EvilRange(Cell::new(false)), "");
+ assert_eq!(Ok(""), str::from_utf8(s.as_bytes()));
+}
+
+#[test]
+fn test_replace_range_evil_end_bound() {
+ struct EvilRange(Cell<bool>);
+
+ impl RangeBounds<usize> for EvilRange {
+ fn start_bound(&self) -> Bound<&usize> {
+ Bound::Included(&0)
+ }
+ fn end_bound(&self) -> Bound<&usize> {
+ Bound::Excluded(if self.0.get() {
+ &3
+ } else {
+ self.0.set(true);
+ &4
+ })
+ }
+ }
+
+ let mut s = String::from("🦀");
+ s.replace_range(EvilRange(Cell::new(false)), "");
+ assert_eq!(Ok(""), str::from_utf8(s.as_bytes()));
+}
+
+#[test]
+fn test_extend_ref() {
+ let mut a = "foo".to_string();
+ a.extend(&['b', 'a', 'r']);
+
+ assert_eq!(&a, "foobar");
+}
+
+#[test]
+fn test_into_boxed_str() {
+ let xs = String::from("hello my name is bob");
+ let ys = xs.into_boxed_str();
+ assert_eq!(&*ys, "hello my name is bob");
+}
+
+#[test]
+fn test_reserve_exact() {
+ // This is all the same as test_reserve
+
+ let mut s = String::new();
+ assert_eq!(s.capacity(), 0);
+
+ s.reserve_exact(2);
+ assert!(s.capacity() >= 2);
+
+ for _i in 0..16 {
+ s.push('0');
+ }
+
+ assert!(s.capacity() >= 16);
+ s.reserve_exact(16);
+ assert!(s.capacity() >= 32);
+
+ s.push('0');
+
+ s.reserve_exact(16);
+ assert!(s.capacity() >= 33)
+}
+
+#[test]
+#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM
+#[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc
+fn test_try_reserve() {
+ // These are the interesting cases:
+ // * exactly isize::MAX should never trigger a CapacityOverflow (can be OOM)
+ // * > isize::MAX should always fail
+ // * On 16/32-bit should CapacityOverflow
+ // * On 64-bit should OOM
+ // * overflow may trigger when adding `len` to `cap` (in number of elements)
+ // * overflow may trigger when multiplying `new_cap` by size_of::<T> (to get bytes)
+
+ const MAX_CAP: usize = isize::MAX as usize;
+ const MAX_USIZE: usize = usize::MAX;
+
+ // On 16/32-bit, we check that allocations don't exceed isize::MAX,
+ // on 64-bit, we assume the OS will give an OOM for such a ridiculous size.
+ // Any platform that succeeds for these requests is technically broken with
+ // ptr::offset because LLVM is the worst.
+ let guards_against_isize = usize::BITS < 64;
+
+ {
+ // Note: basic stuff is checked by test_reserve
+ let mut empty_string: String = String::new();
+
+ // Check isize::MAX doesn't count as an overflow
+ if let Err(CapacityOverflow) = empty_string.try_reserve(MAX_CAP).map_err(|e| e.kind()) {
+ panic!("isize::MAX shouldn't trigger an overflow!");
+ }
+ // Play it again, frank! (just to be sure)
+ if let Err(CapacityOverflow) = empty_string.try_reserve(MAX_CAP).map_err(|e| e.kind()) {
+ panic!("isize::MAX shouldn't trigger an overflow!");
+ }
+
+ if guards_against_isize {
+ // Check isize::MAX + 1 does count as overflow
+ assert_matches!(
+ empty_string.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()),
+ Err(CapacityOverflow),
+ "isize::MAX + 1 should trigger an overflow!"
+ );
+
+ // Check usize::MAX does count as overflow
+ assert_matches!(
+ empty_string.try_reserve(MAX_USIZE).map_err(|e| e.kind()),
+ Err(CapacityOverflow),
+ "usize::MAX should trigger an overflow!"
+ );
+ } else {
+ // Check isize::MAX + 1 is an OOM
+ assert_matches!(
+ empty_string.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()),
+ Err(AllocError { .. }),
+ "isize::MAX + 1 should trigger an OOM!"
+ );
+
+ // Check usize::MAX is an OOM
+ assert_matches!(
+ empty_string.try_reserve(MAX_USIZE).map_err(|e| e.kind()),
+ Err(AllocError { .. }),
+ "usize::MAX should trigger an OOM!"
+ );
+ }
+ }
+
+ {
+ // Same basic idea, but with non-zero len
+ let mut ten_bytes: String = String::from("0123456789");
+
+ if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) {
+ panic!("isize::MAX shouldn't trigger an overflow!");
+ }
+ if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) {
+ panic!("isize::MAX shouldn't trigger an overflow!");
+ }
+ if guards_against_isize {
+ assert_matches!(
+ ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()),
+ Err(CapacityOverflow),
+ "isize::MAX + 1 should trigger an overflow!"
+ );
+ } else {
+ assert_matches!(
+ ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()),
+ Err(AllocError { .. }),
+ "isize::MAX + 1 should trigger an OOM!"
+ );
+ }
+ // Should always overflow in the add-to-len
+ assert_matches!(
+ ten_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()),
+ Err(CapacityOverflow),
+ "usize::MAX should trigger an overflow!"
+ );
+ }
+}
+
+#[test]
+#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM
+#[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc
+fn test_try_reserve_exact() {
+ // This is exactly the same as test_try_reserve with the method changed.
+ // See that test for comments.
+
+ const MAX_CAP: usize = isize::MAX as usize;
+ const MAX_USIZE: usize = usize::MAX;
+
+ let guards_against_isize = usize::BITS < 64;
+
+ {
+ let mut empty_string: String = String::new();
+
+ if let Err(CapacityOverflow) = empty_string.try_reserve_exact(MAX_CAP).map_err(|e| e.kind())
+ {
+ panic!("isize::MAX shouldn't trigger an overflow!");
+ }
+ if let Err(CapacityOverflow) = empty_string.try_reserve_exact(MAX_CAP).map_err(|e| e.kind())
+ {
+ panic!("isize::MAX shouldn't trigger an overflow!");
+ }
+
+ if guards_against_isize {
+ assert_matches!(
+ empty_string.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()),
+ Err(CapacityOverflow),
+ "isize::MAX + 1 should trigger an overflow!"
+ );
+
+ assert_matches!(
+ empty_string.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()),
+ Err(CapacityOverflow),
+ "usize::MAX should trigger an overflow!"
+ );
+ } else {
+ assert_matches!(
+ empty_string.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()),
+ Err(AllocError { .. }),
+ "isize::MAX + 1 should trigger an OOM!"
+ );
+
+ assert_matches!(
+ empty_string.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()),
+ Err(AllocError { .. }),
+ "usize::MAX should trigger an OOM!"
+ );
+ }
+ }
+
+ {
+ let mut ten_bytes: String = String::from("0123456789");
+
+ 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!");
+ }
+ 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!");
+ }
+ if guards_against_isize {
+ assert_matches!(
+ ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()),
+ Err(CapacityOverflow),
+ "isize::MAX + 1 should trigger an overflow!"
+ );
+ } else {
+ assert_matches!(
+ ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()),
+ Err(AllocError { .. }),
+ "isize::MAX + 1 should trigger an OOM!"
+ );
+ }
+ assert_matches!(
+ ten_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()),
+ Err(CapacityOverflow),
+ "usize::MAX should trigger an overflow!"
+ );
+ }
+}
+
+#[test]
+fn test_from_char() {
+ assert_eq!(String::from('a'), 'a'.to_string());
+ let s: String = 'x'.into();
+ assert_eq!(s, 'x'.to_string());
+}
+
+#[test]
+fn test_str_concat() {
+ let a: String = "hello".to_string();
+ let b: String = "world".to_string();
+ let s: String = format!("{a}{b}");
+ assert_eq!(s.as_bytes()[9], 'd' as u8);
+}
diff --git a/library/alloc/tests/thin_box.rs b/library/alloc/tests/thin_box.rs
new file mode 100644
index 000000000..368aa564f
--- /dev/null
+++ b/library/alloc/tests/thin_box.rs
@@ -0,0 +1,262 @@
+use core::fmt::Debug;
+use core::mem::size_of;
+use std::boxed::ThinBox;
+
+#[test]
+fn want_niche_optimization() {
+ fn uses_niche<T: ?Sized>() -> bool {
+ size_of::<*const ()>() == size_of::<Option<ThinBox<T>>>()
+ }
+
+ trait Tr {}
+ assert!(uses_niche::<dyn Tr>());
+ assert!(uses_niche::<[i32]>());
+ assert!(uses_niche::<i32>());
+}
+
+#[test]
+fn want_thin() {
+ fn is_thin<T: ?Sized>() -> bool {
+ size_of::<*const ()>() == size_of::<ThinBox<T>>()
+ }
+
+ trait Tr {}
+ assert!(is_thin::<dyn Tr>());
+ assert!(is_thin::<[i32]>());
+ assert!(is_thin::<i32>());
+}
+
+#[allow(dead_code)]
+fn assert_covariance() {
+ fn thin_box<'new>(b: ThinBox<[&'static str]>) -> ThinBox<[&'new str]> {
+ b
+ }
+}
+
+#[track_caller]
+fn verify_aligned<T>(ptr: *const T) {
+ // Use `black_box` to attempt to obscure the fact that we're calling this
+ // function on pointers that come from box/references, which the compiler
+ // would otherwise realize is impossible (because it would mean we've
+ // already executed UB).
+ //
+ // That is, we'd *like* it to be possible for the asserts in this function
+ // to detect brokenness in the ThinBox impl.
+ //
+ // It would probably be better if we instead had these as debug_asserts
+ // inside `ThinBox`, prior to the point where we do the UB. Anyway, in
+ // practice these checks are mostly just smoke-detectors for an extremely
+ // broken `ThinBox` impl, since it's an extremely subtle piece of code.
+ let ptr = core::hint::black_box(ptr);
+ let align = core::mem::align_of::<T>();
+ assert!(
+ (ptr.addr() & (align - 1)) == 0 && !ptr.is_null(),
+ "misaligned ThinBox data; valid pointers to `{}` should be aligned to {align}: {ptr:p}",
+ core::any::type_name::<T>(),
+ );
+}
+
+#[track_caller]
+fn check_thin_sized<T: Debug + PartialEq + Clone>(make: impl FnOnce() -> T) {
+ let value = make();
+ let boxed = ThinBox::new(value.clone());
+ let val = &*boxed;
+ verify_aligned(val as *const T);
+ assert_eq!(val, &value);
+}
+
+#[track_caller]
+fn check_thin_dyn<T: Debug + PartialEq + Clone>(make: impl FnOnce() -> T) {
+ let value = make();
+ let wanted_debug = format!("{value:?}");
+ let boxed: ThinBox<dyn Debug> = ThinBox::new_unsize(value.clone());
+ let val = &*boxed;
+ // wide reference -> wide pointer -> thin pointer
+ verify_aligned(val as *const dyn Debug as *const T);
+ let got_debug = format!("{val:?}");
+ assert_eq!(wanted_debug, got_debug);
+}
+
+macro_rules! define_test {
+ (
+ @test_name: $testname:ident;
+
+ $(#[$m:meta])*
+ struct $Type:ident($inner:ty);
+
+ $($test_stmts:tt)*
+ ) => {
+ #[test]
+ fn $testname() {
+ use core::sync::atomic::{AtomicIsize, Ordering};
+ // Define the type, and implement new/clone/drop in such a way that
+ // the number of live instances will be counted.
+ $(#[$m])*
+ #[derive(Debug, PartialEq)]
+ struct $Type {
+ _priv: $inner,
+ }
+
+ impl Clone for $Type {
+ fn clone(&self) -> Self {
+ verify_aligned(self);
+ Self::new(self._priv.clone())
+ }
+ }
+
+ impl Drop for $Type {
+ fn drop(&mut self) {
+ verify_aligned(self);
+ Self::modify_live(-1);
+ }
+ }
+
+ impl $Type {
+ fn new(i: $inner) -> Self {
+ Self::modify_live(1);
+ Self { _priv: i }
+ }
+
+ fn modify_live(n: isize) -> isize {
+ static COUNTER: AtomicIsize = AtomicIsize::new(0);
+ COUNTER.fetch_add(n, Ordering::Relaxed) + n
+ }
+
+ fn live_objects() -> isize {
+ Self::modify_live(0)
+ }
+ }
+ // Run the test statements
+ let _: () = { $($test_stmts)* };
+ // Check that we didn't leak anything, or call drop too many times.
+ assert_eq!(
+ $Type::live_objects(), 0,
+ "Wrong number of drops of {}, `initializations - drops` should be 0.",
+ stringify!($Type),
+ );
+ }
+ };
+}
+
+define_test! {
+ @test_name: align1zst;
+ struct Align1Zst(());
+
+ check_thin_sized(|| Align1Zst::new(()));
+ check_thin_dyn(|| Align1Zst::new(()));
+}
+
+define_test! {
+ @test_name: align1small;
+ struct Align1Small(u8);
+
+ check_thin_sized(|| Align1Small::new(50));
+ check_thin_dyn(|| Align1Small::new(50));
+}
+
+define_test! {
+ @test_name: align1_size_not_pow2;
+ struct Align64NotPow2Size([u8; 79]);
+
+ check_thin_sized(|| Align64NotPow2Size::new([100; 79]));
+ check_thin_dyn(|| Align64NotPow2Size::new([100; 79]));
+}
+
+define_test! {
+ @test_name: align1big;
+ struct Align1Big([u8; 256]);
+
+ check_thin_sized(|| Align1Big::new([5u8; 256]));
+ check_thin_dyn(|| Align1Big::new([5u8; 256]));
+}
+
+// Note: `#[repr(align(2))]` is worth testing because
+// - can have pointers which are misaligned, unlike align(1)
+// - is still expected to have an alignment less than the alignment of a vtable.
+define_test! {
+ @test_name: align2zst;
+ #[repr(align(2))]
+ struct Align2Zst(());
+
+ check_thin_sized(|| Align2Zst::new(()));
+ check_thin_dyn(|| Align2Zst::new(()));
+}
+
+define_test! {
+ @test_name: align2small;
+ #[repr(align(2))]
+ struct Align2Small(u8);
+
+ check_thin_sized(|| Align2Small::new(60));
+ check_thin_dyn(|| Align2Small::new(60));
+}
+
+define_test! {
+ @test_name: align2full;
+ #[repr(align(2))]
+ struct Align2Full([u8; 2]);
+ check_thin_sized(|| Align2Full::new([3u8; 2]));
+ check_thin_dyn(|| Align2Full::new([3u8; 2]));
+}
+
+define_test! {
+ @test_name: align2_size_not_pow2;
+ #[repr(align(2))]
+ struct Align2NotPower2Size([u8; 6]);
+
+ check_thin_sized(|| Align2NotPower2Size::new([3; 6]));
+ check_thin_dyn(|| Align2NotPower2Size::new([3; 6]));
+}
+
+define_test! {
+ @test_name: align2big;
+ #[repr(align(2))]
+ struct Align2Big([u8; 256]);
+
+ check_thin_sized(|| Align2Big::new([5u8; 256]));
+ check_thin_dyn(|| Align2Big::new([5u8; 256]));
+}
+
+define_test! {
+ @test_name: align64zst;
+ #[repr(align(64))]
+ struct Align64Zst(());
+
+ check_thin_sized(|| Align64Zst::new(()));
+ check_thin_dyn(|| Align64Zst::new(()));
+}
+
+define_test! {
+ @test_name: align64small;
+ #[repr(align(64))]
+ struct Align64Small(u8);
+
+ check_thin_sized(|| Align64Small::new(50));
+ check_thin_dyn(|| Align64Small::new(50));
+}
+
+define_test! {
+ @test_name: align64med;
+ #[repr(align(64))]
+ struct Align64Med([u8; 64]);
+ check_thin_sized(|| Align64Med::new([10; 64]));
+ check_thin_dyn(|| Align64Med::new([10; 64]));
+}
+
+define_test! {
+ @test_name: align64_size_not_pow2;
+ #[repr(align(64))]
+ struct Align64NotPow2Size([u8; 192]);
+
+ check_thin_sized(|| Align64NotPow2Size::new([10; 192]));
+ check_thin_dyn(|| Align64NotPow2Size::new([10; 192]));
+}
+
+define_test! {
+ @test_name: align64big;
+ #[repr(align(64))]
+ struct Align64Big([u8; 256]);
+
+ check_thin_sized(|| Align64Big::new([10; 256]));
+ check_thin_dyn(|| Align64Big::new([10; 256]));
+}
diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs
new file mode 100644
index 000000000..b797e2375
--- /dev/null
+++ b/library/alloc/tests/vec.rs
@@ -0,0 +1,2436 @@
+use core::alloc::{Allocator, Layout};
+use core::iter::IntoIterator;
+use core::ptr::NonNull;
+use std::alloc::System;
+use std::assert_matches::assert_matches;
+use std::borrow::Cow;
+use std::cell::Cell;
+use std::collections::TryReserveErrorKind::*;
+use std::fmt::Debug;
+use std::iter::InPlaceIterable;
+use std::mem::{size_of, swap};
+use std::ops::Bound::*;
+use std::panic::{catch_unwind, AssertUnwindSafe};
+use std::rc::Rc;
+use std::sync::atomic::{AtomicU32, Ordering};
+use std::vec::{Drain, IntoIter};
+
+struct DropCounter<'a> {
+ count: &'a mut u32,
+}
+
+impl Drop for DropCounter<'_> {
+ fn drop(&mut self) {
+ *self.count += 1;
+ }
+}
+
+#[test]
+fn test_small_vec_struct() {
+ assert_eq!(size_of::<Vec<u8>>(), size_of::<usize>() * 3);
+}
+
+#[test]
+fn test_double_drop() {
+ struct TwoVec<T> {
+ x: Vec<T>,
+ y: Vec<T>,
+ }
+
+ let (mut count_x, mut count_y) = (0, 0);
+ {
+ let mut tv = TwoVec { x: Vec::new(), y: Vec::new() };
+ tv.x.push(DropCounter { count: &mut count_x });
+ tv.y.push(DropCounter { count: &mut count_y });
+
+ // If Vec had a drop flag, here is where it would be zeroed.
+ // Instead, it should rely on its internal state to prevent
+ // doing anything significant when dropped multiple times.
+ drop(tv.x);
+
+ // Here tv goes out of scope, tv.y should be dropped, but not tv.x.
+ }
+
+ assert_eq!(count_x, 1);
+ assert_eq!(count_y, 1);
+}
+
+#[test]
+fn test_reserve() {
+ let mut v = Vec::new();
+ assert_eq!(v.capacity(), 0);
+
+ v.reserve(2);
+ assert!(v.capacity() >= 2);
+
+ for i in 0..16 {
+ v.push(i);
+ }
+
+ assert!(v.capacity() >= 16);
+ v.reserve(16);
+ assert!(v.capacity() >= 32);
+
+ v.push(16);
+
+ v.reserve(16);
+ assert!(v.capacity() >= 33)
+}
+
+#[test]
+fn test_zst_capacity() {
+ assert_eq!(Vec::<()>::new().capacity(), usize::MAX);
+}
+
+#[test]
+fn test_indexing() {
+ let v: Vec<isize> = vec![10, 20];
+ assert_eq!(v[0], 10);
+ assert_eq!(v[1], 20);
+ let mut x: usize = 0;
+ assert_eq!(v[x], 10);
+ assert_eq!(v[x + 1], 20);
+ x = x + 1;
+ assert_eq!(v[x], 20);
+ assert_eq!(v[x - 1], 10);
+}
+
+#[test]
+fn test_debug_fmt() {
+ let vec1: Vec<isize> = vec![];
+ assert_eq!("[]", format!("{:?}", vec1));
+
+ let vec2 = vec![0, 1];
+ assert_eq!("[0, 1]", format!("{:?}", vec2));
+
+ let slice: &[isize] = &[4, 5];
+ assert_eq!("[4, 5]", format!("{slice:?}"));
+}
+
+#[test]
+fn test_push() {
+ let mut v = vec![];
+ v.push(1);
+ assert_eq!(v, [1]);
+ v.push(2);
+ assert_eq!(v, [1, 2]);
+ v.push(3);
+ assert_eq!(v, [1, 2, 3]);
+}
+
+#[test]
+fn test_extend() {
+ let mut v = Vec::new();
+ let mut w = Vec::new();
+
+ v.extend(w.clone());
+ assert_eq!(v, &[]);
+
+ v.extend(0..3);
+ for i in 0..3 {
+ w.push(i)
+ }
+
+ assert_eq!(v, w);
+
+ v.extend(3..10);
+ for i in 3..10 {
+ w.push(i)
+ }
+
+ assert_eq!(v, w);
+
+ v.extend(w.clone()); // specializes to `append`
+ assert!(v.iter().eq(w.iter().chain(w.iter())));
+
+ // Zero sized types
+ #[derive(PartialEq, Debug)]
+ struct Foo;
+
+ let mut a = Vec::new();
+ let b = vec![Foo, Foo];
+
+ a.extend(b);
+ assert_eq!(a, &[Foo, Foo]);
+
+ // Double drop
+ let mut count_x = 0;
+ {
+ let mut x = Vec::new();
+ let y = vec![DropCounter { count: &mut count_x }];
+ x.extend(y);
+ }
+ assert_eq!(count_x, 1);
+}
+
+#[test]
+fn test_extend_from_slice() {
+ let a: Vec<isize> = vec![1, 2, 3, 4, 5];
+ let b: Vec<isize> = vec![6, 7, 8, 9, 0];
+
+ let mut v: Vec<isize> = a;
+
+ v.extend_from_slice(&b);
+
+ assert_eq!(v, [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]);
+}
+
+#[test]
+fn test_extend_ref() {
+ let mut v = vec![1, 2];
+ v.extend(&[3, 4, 5]);
+
+ assert_eq!(v.len(), 5);
+ assert_eq!(v, [1, 2, 3, 4, 5]);
+
+ let w = vec![6, 7];
+ v.extend(&w);
+
+ assert_eq!(v.len(), 7);
+ assert_eq!(v, [1, 2, 3, 4, 5, 6, 7]);
+}
+
+#[test]
+fn test_slice_from_ref() {
+ let values = vec![1, 2, 3, 4, 5];
+ let slice = &values[1..3];
+
+ assert_eq!(slice, [2, 3]);
+}
+
+#[test]
+fn test_slice_from_mut() {
+ let mut values = vec![1, 2, 3, 4, 5];
+ {
+ let slice = &mut values[2..];
+ assert!(slice == [3, 4, 5]);
+ for p in slice {
+ *p += 2;
+ }
+ }
+
+ assert!(values == [1, 2, 5, 6, 7]);
+}
+
+#[test]
+fn test_slice_to_mut() {
+ let mut values = vec![1, 2, 3, 4, 5];
+ {
+ let slice = &mut values[..2];
+ assert!(slice == [1, 2]);
+ for p in slice {
+ *p += 1;
+ }
+ }
+
+ assert!(values == [2, 3, 3, 4, 5]);
+}
+
+#[test]
+fn test_split_at_mut() {
+ let mut values = vec![1, 2, 3, 4, 5];
+ {
+ let (left, right) = values.split_at_mut(2);
+ {
+ let left: &[_] = left;
+ assert!(&left[..left.len()] == &[1, 2]);
+ }
+ for p in left {
+ *p += 1;
+ }
+
+ {
+ let right: &[_] = right;
+ assert!(&right[..right.len()] == &[3, 4, 5]);
+ }
+ for p in right {
+ *p += 2;
+ }
+ }
+
+ assert_eq!(values, [2, 3, 5, 6, 7]);
+}
+
+#[test]
+fn test_clone() {
+ let v: Vec<i32> = vec![];
+ let w = vec![1, 2, 3];
+
+ assert_eq!(v, v.clone());
+
+ let z = w.clone();
+ assert_eq!(w, z);
+ // they should be disjoint in memory.
+ assert!(w.as_ptr() != z.as_ptr())
+}
+
+#[test]
+fn test_clone_from() {
+ let mut v = vec![];
+ let three: Vec<Box<_>> = vec![Box::new(1), Box::new(2), Box::new(3)];
+ let two: Vec<Box<_>> = vec![Box::new(4), Box::new(5)];
+ // zero, long
+ v.clone_from(&three);
+ assert_eq!(v, three);
+
+ // equal
+ v.clone_from(&three);
+ assert_eq!(v, three);
+
+ // long, short
+ v.clone_from(&two);
+ assert_eq!(v, two);
+
+ // short, long
+ v.clone_from(&three);
+ assert_eq!(v, three)
+}
+
+#[test]
+fn test_retain() {
+ let mut vec = vec![1, 2, 3, 4];
+ vec.retain(|&x| x % 2 == 0);
+ assert_eq!(vec, [2, 4]);
+}
+
+#[test]
+fn test_retain_pred_panic_with_hole() {
+ let v = (0..5).map(Rc::new).collect::<Vec<_>>();
+ catch_unwind(AssertUnwindSafe(|| {
+ let mut v = v.clone();
+ v.retain(|r| match **r {
+ 0 => true,
+ 1 => false,
+ 2 => true,
+ _ => panic!(),
+ });
+ }))
+ .unwrap_err();
+ // Everything is dropped when predicate panicked.
+ assert!(v.iter().all(|r| Rc::strong_count(r) == 1));
+}
+
+#[test]
+fn test_retain_pred_panic_no_hole() {
+ let v = (0..5).map(Rc::new).collect::<Vec<_>>();
+ catch_unwind(AssertUnwindSafe(|| {
+ let mut v = v.clone();
+ v.retain(|r| match **r {
+ 0 | 1 | 2 => true,
+ _ => panic!(),
+ });
+ }))
+ .unwrap_err();
+ // Everything is dropped when predicate panicked.
+ assert!(v.iter().all(|r| Rc::strong_count(r) == 1));
+}
+
+#[test]
+fn test_retain_drop_panic() {
+ struct Wrap(Rc<i32>);
+
+ impl Drop for Wrap {
+ fn drop(&mut self) {
+ if *self.0 == 3 {
+ panic!();
+ }
+ }
+ }
+
+ let v = (0..5).map(|x| Rc::new(x)).collect::<Vec<_>>();
+ catch_unwind(AssertUnwindSafe(|| {
+ let mut v = v.iter().map(|r| Wrap(r.clone())).collect::<Vec<_>>();
+ v.retain(|w| match *w.0 {
+ 0 => true,
+ 1 => false,
+ 2 => true,
+ 3 => false, // Drop panic.
+ _ => true,
+ });
+ }))
+ .unwrap_err();
+ // Other elements are dropped when `drop` of one element panicked.
+ // The panicked wrapper also has its Rc dropped.
+ assert!(v.iter().all(|r| Rc::strong_count(r) == 1));
+}
+
+#[test]
+fn test_dedup() {
+ fn case(a: Vec<i32>, b: Vec<i32>) {
+ let mut v = a;
+ v.dedup();
+ assert_eq!(v, b);
+ }
+ case(vec![], vec![]);
+ case(vec![1], vec![1]);
+ case(vec![1, 1], vec![1]);
+ case(vec![1, 2, 3], vec![1, 2, 3]);
+ case(vec![1, 1, 2, 3], vec![1, 2, 3]);
+ case(vec![1, 2, 2, 3], vec![1, 2, 3]);
+ case(vec![1, 2, 3, 3], vec![1, 2, 3]);
+ case(vec![1, 1, 2, 2, 2, 3, 3], vec![1, 2, 3]);
+}
+
+#[test]
+fn test_dedup_by_key() {
+ fn case(a: Vec<i32>, b: Vec<i32>) {
+ let mut v = a;
+ v.dedup_by_key(|i| *i / 10);
+ assert_eq!(v, b);
+ }
+ case(vec![], vec![]);
+ case(vec![10], vec![10]);
+ case(vec![10, 11], vec![10]);
+ case(vec![10, 20, 30], vec![10, 20, 30]);
+ case(vec![10, 11, 20, 30], vec![10, 20, 30]);
+ case(vec![10, 20, 21, 30], vec![10, 20, 30]);
+ case(vec![10, 20, 30, 31], vec![10, 20, 30]);
+ case(vec![10, 11, 20, 21, 22, 30, 31], vec![10, 20, 30]);
+}
+
+#[test]
+fn test_dedup_by() {
+ let mut vec = vec!["foo", "bar", "Bar", "baz", "bar"];
+ vec.dedup_by(|a, b| a.eq_ignore_ascii_case(b));
+
+ assert_eq!(vec, ["foo", "bar", "baz", "bar"]);
+
+ let mut vec = vec![("foo", 1), ("foo", 2), ("bar", 3), ("bar", 4), ("bar", 5)];
+ vec.dedup_by(|a, b| {
+ a.0 == b.0 && {
+ b.1 += a.1;
+ true
+ }
+ });
+
+ assert_eq!(vec, [("foo", 3), ("bar", 12)]);
+}
+
+#[test]
+fn test_dedup_unique() {
+ let mut v0: Vec<Box<_>> = vec![Box::new(1), Box::new(1), Box::new(2), Box::new(3)];
+ v0.dedup();
+ let mut v1: Vec<Box<_>> = vec![Box::new(1), Box::new(2), Box::new(2), Box::new(3)];
+ v1.dedup();
+ let mut v2: Vec<Box<_>> = vec![Box::new(1), Box::new(2), Box::new(3), Box::new(3)];
+ v2.dedup();
+ // If the boxed pointers were leaked or otherwise misused, valgrind
+ // and/or rt should raise errors.
+}
+
+#[test]
+fn zero_sized_values() {
+ let mut v = Vec::new();
+ assert_eq!(v.len(), 0);
+ v.push(());
+ assert_eq!(v.len(), 1);
+ v.push(());
+ assert_eq!(v.len(), 2);
+ assert_eq!(v.pop(), Some(()));
+ assert_eq!(v.pop(), Some(()));
+ assert_eq!(v.pop(), None);
+
+ assert_eq!(v.iter().count(), 0);
+ v.push(());
+ assert_eq!(v.iter().count(), 1);
+ v.push(());
+ assert_eq!(v.iter().count(), 2);
+
+ for &() in &v {}
+
+ assert_eq!(v.iter_mut().count(), 2);
+ v.push(());
+ assert_eq!(v.iter_mut().count(), 3);
+ v.push(());
+ assert_eq!(v.iter_mut().count(), 4);
+
+ for &mut () in &mut v {}
+ unsafe {
+ v.set_len(0);
+ }
+ assert_eq!(v.iter_mut().count(), 0);
+}
+
+#[test]
+fn test_partition() {
+ assert_eq!([].into_iter().partition(|x: &i32| *x < 3), (vec![], vec![]));
+ assert_eq!([1, 2, 3].into_iter().partition(|x| *x < 4), (vec![1, 2, 3], vec![]));
+ assert_eq!([1, 2, 3].into_iter().partition(|x| *x < 2), (vec![1], vec![2, 3]));
+ assert_eq!([1, 2, 3].into_iter().partition(|x| *x < 0), (vec![], vec![1, 2, 3]));
+}
+
+#[test]
+fn test_zip_unzip() {
+ let z1 = vec![(1, 4), (2, 5), (3, 6)];
+
+ let (left, right): (Vec<_>, Vec<_>) = z1.iter().cloned().unzip();
+
+ assert_eq!((1, 4), (left[0], right[0]));
+ assert_eq!((2, 5), (left[1], right[1]));
+ assert_eq!((3, 6), (left[2], right[2]));
+}
+
+#[test]
+fn test_cmp() {
+ let x: &[isize] = &[1, 2, 3, 4, 5];
+ let cmp: &[isize] = &[1, 2, 3, 4, 5];
+ assert_eq!(&x[..], cmp);
+ let cmp: &[isize] = &[3, 4, 5];
+ assert_eq!(&x[2..], cmp);
+ let cmp: &[isize] = &[1, 2, 3];
+ assert_eq!(&x[..3], cmp);
+ let cmp: &[isize] = &[2, 3, 4];
+ assert_eq!(&x[1..4], cmp);
+
+ let x: Vec<isize> = vec![1, 2, 3, 4, 5];
+ let cmp: &[isize] = &[1, 2, 3, 4, 5];
+ assert_eq!(&x[..], cmp);
+ let cmp: &[isize] = &[3, 4, 5];
+ assert_eq!(&x[2..], cmp);
+ let cmp: &[isize] = &[1, 2, 3];
+ assert_eq!(&x[..3], cmp);
+ let cmp: &[isize] = &[2, 3, 4];
+ assert_eq!(&x[1..4], cmp);
+}
+
+#[test]
+fn test_vec_truncate_drop() {
+ static mut DROPS: u32 = 0;
+ struct Elem(i32);
+ impl Drop for Elem {
+ fn drop(&mut self) {
+ unsafe {
+ DROPS += 1;
+ }
+ }
+ }
+
+ let mut v = vec![Elem(1), Elem(2), Elem(3), Elem(4), Elem(5)];
+ assert_eq!(unsafe { DROPS }, 0);
+ v.truncate(3);
+ assert_eq!(unsafe { DROPS }, 2);
+ v.truncate(0);
+ assert_eq!(unsafe { DROPS }, 5);
+}
+
+#[test]
+#[should_panic]
+fn test_vec_truncate_fail() {
+ struct BadElem(i32);
+ impl Drop for BadElem {
+ fn drop(&mut self) {
+ let BadElem(ref mut x) = *self;
+ if *x == 0xbadbeef {
+ panic!("BadElem panic: 0xbadbeef")
+ }
+ }
+ }
+
+ let mut v = vec![BadElem(1), BadElem(2), BadElem(0xbadbeef), BadElem(4)];
+ v.truncate(0);
+}
+
+#[test]
+fn test_index() {
+ let vec = vec![1, 2, 3];
+ assert!(vec[1] == 2);
+}
+
+#[test]
+#[should_panic]
+fn test_index_out_of_bounds() {
+ let vec = vec![1, 2, 3];
+ let _ = vec[3];
+}
+
+#[test]
+#[should_panic]
+fn test_slice_out_of_bounds_1() {
+ let x = vec![1, 2, 3, 4, 5];
+ let _ = &x[!0..];
+}
+
+#[test]
+#[should_panic]
+fn test_slice_out_of_bounds_2() {
+ let x = vec![1, 2, 3, 4, 5];
+ let _ = &x[..6];
+}
+
+#[test]
+#[should_panic]
+fn test_slice_out_of_bounds_3() {
+ let x = vec![1, 2, 3, 4, 5];
+ let _ = &x[!0..4];
+}
+
+#[test]
+#[should_panic]
+fn test_slice_out_of_bounds_4() {
+ let x = vec![1, 2, 3, 4, 5];
+ let _ = &x[1..6];
+}
+
+#[test]
+#[should_panic]
+fn test_slice_out_of_bounds_5() {
+ let x = vec![1, 2, 3, 4, 5];
+ let _ = &x[3..2];
+}
+
+#[test]
+#[should_panic]
+fn test_swap_remove_empty() {
+ let mut vec = Vec::<i32>::new();
+ vec.swap_remove(0);
+}
+
+#[test]
+fn test_move_items() {
+ let vec = vec![1, 2, 3];
+ let mut vec2 = vec![];
+ for i in vec {
+ vec2.push(i);
+ }
+ assert_eq!(vec2, [1, 2, 3]);
+}
+
+#[test]
+fn test_move_items_reverse() {
+ let vec = vec![1, 2, 3];
+ let mut vec2 = vec![];
+ for i in vec.into_iter().rev() {
+ vec2.push(i);
+ }
+ assert_eq!(vec2, [3, 2, 1]);
+}
+
+#[test]
+fn test_move_items_zero_sized() {
+ let vec = vec![(), (), ()];
+ let mut vec2 = vec![];
+ for i in vec {
+ vec2.push(i);
+ }
+ assert_eq!(vec2, [(), (), ()]);
+}
+
+#[test]
+fn test_drain_empty_vec() {
+ let mut vec: Vec<i32> = vec![];
+ let mut vec2: Vec<i32> = vec![];
+ for i in vec.drain(..) {
+ vec2.push(i);
+ }
+ assert!(vec.is_empty());
+ assert!(vec2.is_empty());
+}
+
+#[test]
+fn test_drain_items() {
+ let mut vec = vec![1, 2, 3];
+ let mut vec2 = vec![];
+ for i in vec.drain(..) {
+ vec2.push(i);
+ }
+ assert_eq!(vec, []);
+ assert_eq!(vec2, [1, 2, 3]);
+}
+
+#[test]
+fn test_drain_items_reverse() {
+ let mut vec = vec![1, 2, 3];
+ let mut vec2 = vec![];
+ for i in vec.drain(..).rev() {
+ vec2.push(i);
+ }
+ assert_eq!(vec, []);
+ assert_eq!(vec2, [3, 2, 1]);
+}
+
+#[test]
+fn test_drain_items_zero_sized() {
+ let mut vec = vec![(), (), ()];
+ let mut vec2 = vec![];
+ for i in vec.drain(..) {
+ vec2.push(i);
+ }
+ assert_eq!(vec, []);
+ assert_eq!(vec2, [(), (), ()]);
+}
+
+#[test]
+#[should_panic]
+fn test_drain_out_of_bounds() {
+ let mut v = vec![1, 2, 3, 4, 5];
+ v.drain(5..6);
+}
+
+#[test]
+fn test_drain_range() {
+ let mut v = vec![1, 2, 3, 4, 5];
+ for _ in v.drain(4..) {}
+ assert_eq!(v, &[1, 2, 3, 4]);
+
+ let mut v: Vec<_> = (1..6).map(|x| x.to_string()).collect();
+ for _ in v.drain(1..4) {}
+ assert_eq!(v, &[1.to_string(), 5.to_string()]);
+
+ let mut v: Vec<_> = (1..6).map(|x| x.to_string()).collect();
+ for _ in v.drain(1..4).rev() {}
+ assert_eq!(v, &[1.to_string(), 5.to_string()]);
+
+ let mut v: Vec<_> = vec![(); 5];
+ for _ in v.drain(1..4).rev() {}
+ assert_eq!(v, &[(), ()]);
+}
+
+#[test]
+fn test_drain_inclusive_range() {
+ let mut v = vec!['a', 'b', 'c', 'd', 'e'];
+ for _ in v.drain(1..=3) {}
+ assert_eq!(v, &['a', 'e']);
+
+ let mut v: Vec<_> = (0..=5).map(|x| x.to_string()).collect();
+ for _ in v.drain(1..=5) {}
+ assert_eq!(v, &["0".to_string()]);
+
+ let mut v: Vec<String> = (0..=5).map(|x| x.to_string()).collect();
+ for _ in v.drain(0..=5) {}
+ assert_eq!(v, Vec::<String>::new());
+
+ let mut v: Vec<_> = (0..=5).map(|x| x.to_string()).collect();
+ for _ in v.drain(0..=3) {}
+ assert_eq!(v, &["4".to_string(), "5".to_string()]);
+
+ let mut v: Vec<_> = (0..=1).map(|x| x.to_string()).collect();
+ for _ in v.drain(..=0) {}
+ assert_eq!(v, &["1".to_string()]);
+}
+
+#[test]
+fn test_drain_max_vec_size() {
+ let mut v = Vec::<()>::with_capacity(usize::MAX);
+ unsafe {
+ v.set_len(usize::MAX);
+ }
+ for _ in v.drain(usize::MAX - 1..) {}
+ assert_eq!(v.len(), usize::MAX - 1);
+
+ let mut v = Vec::<()>::with_capacity(usize::MAX);
+ unsafe {
+ v.set_len(usize::MAX);
+ }
+ for _ in v.drain(usize::MAX - 1..=usize::MAX - 1) {}
+ assert_eq!(v.len(), usize::MAX - 1);
+}
+
+#[test]
+#[should_panic]
+fn test_drain_index_overflow() {
+ let mut v = Vec::<()>::with_capacity(usize::MAX);
+ unsafe {
+ v.set_len(usize::MAX);
+ }
+ v.drain(0..=usize::MAX);
+}
+
+#[test]
+#[should_panic]
+fn test_drain_inclusive_out_of_bounds() {
+ let mut v = vec![1, 2, 3, 4, 5];
+ v.drain(5..=5);
+}
+
+#[test]
+#[should_panic]
+fn test_drain_start_overflow() {
+ let mut v = vec![1, 2, 3];
+ v.drain((Excluded(usize::MAX), Included(0)));
+}
+
+#[test]
+#[should_panic]
+fn test_drain_end_overflow() {
+ let mut v = vec![1, 2, 3];
+ v.drain((Included(0), Included(usize::MAX)));
+}
+
+#[test]
+fn test_drain_leak() {
+ static mut DROPS: i32 = 0;
+
+ #[derive(Debug, PartialEq)]
+ struct D(u32, bool);
+
+ impl Drop for D {
+ fn drop(&mut self) {
+ unsafe {
+ DROPS += 1;
+ }
+
+ if self.1 {
+ panic!("panic in `drop`");
+ }
+ }
+ }
+
+ let mut v = vec![
+ D(0, false),
+ D(1, false),
+ D(2, false),
+ D(3, false),
+ D(4, true),
+ D(5, false),
+ D(6, false),
+ ];
+
+ catch_unwind(AssertUnwindSafe(|| {
+ v.drain(2..=5);
+ }))
+ .ok();
+
+ assert_eq!(unsafe { DROPS }, 4);
+ assert_eq!(v, vec![D(0, false), D(1, false), D(6, false),]);
+}
+
+#[test]
+fn test_splice() {
+ let mut v = vec![1, 2, 3, 4, 5];
+ let a = [10, 11, 12];
+ v.splice(2..4, a);
+ assert_eq!(v, &[1, 2, 10, 11, 12, 5]);
+ v.splice(1..3, Some(20));
+ assert_eq!(v, &[1, 20, 11, 12, 5]);
+}
+
+#[test]
+fn test_splice_inclusive_range() {
+ let mut v = vec![1, 2, 3, 4, 5];
+ let a = [10, 11, 12];
+ let t1: Vec<_> = v.splice(2..=3, a).collect();
+ assert_eq!(v, &[1, 2, 10, 11, 12, 5]);
+ assert_eq!(t1, &[3, 4]);
+ let t2: Vec<_> = v.splice(1..=2, Some(20)).collect();
+ assert_eq!(v, &[1, 20, 11, 12, 5]);
+ assert_eq!(t2, &[2, 10]);
+}
+
+#[test]
+#[should_panic]
+fn test_splice_out_of_bounds() {
+ let mut v = vec![1, 2, 3, 4, 5];
+ let a = [10, 11, 12];
+ v.splice(5..6, a);
+}
+
+#[test]
+#[should_panic]
+fn test_splice_inclusive_out_of_bounds() {
+ let mut v = vec![1, 2, 3, 4, 5];
+ let a = [10, 11, 12];
+ v.splice(5..=5, a);
+}
+
+#[test]
+fn test_splice_items_zero_sized() {
+ let mut vec = vec![(), (), ()];
+ let vec2 = vec![];
+ let t: Vec<_> = vec.splice(1..2, vec2.iter().cloned()).collect();
+ assert_eq!(vec, &[(), ()]);
+ assert_eq!(t, &[()]);
+}
+
+#[test]
+fn test_splice_unbounded() {
+ let mut vec = vec![1, 2, 3, 4, 5];
+ let t: Vec<_> = vec.splice(.., None).collect();
+ assert_eq!(vec, &[]);
+ assert_eq!(t, &[1, 2, 3, 4, 5]);
+}
+
+#[test]
+fn test_splice_forget() {
+ let mut v = vec![1, 2, 3, 4, 5];
+ let a = [10, 11, 12];
+ std::mem::forget(v.splice(2..4, a));
+ assert_eq!(v, &[1, 2]);
+}
+
+#[test]
+fn test_into_boxed_slice() {
+ let xs = vec![1, 2, 3];
+ let ys = xs.into_boxed_slice();
+ assert_eq!(&*ys, [1, 2, 3]);
+}
+
+#[test]
+fn test_append() {
+ let mut vec = vec![1, 2, 3];
+ let mut vec2 = vec![4, 5, 6];
+ vec.append(&mut vec2);
+ assert_eq!(vec, [1, 2, 3, 4, 5, 6]);
+ assert_eq!(vec2, []);
+}
+
+#[test]
+fn test_split_off() {
+ let mut vec = vec![1, 2, 3, 4, 5, 6];
+ let orig_capacity = vec.capacity();
+ let vec2 = vec.split_off(4);
+ assert_eq!(vec, [1, 2, 3, 4]);
+ assert_eq!(vec2, [5, 6]);
+ assert_eq!(vec.capacity(), orig_capacity);
+}
+
+#[test]
+fn test_split_off_take_all() {
+ let mut vec = vec![1, 2, 3, 4, 5, 6];
+ let orig_ptr = vec.as_ptr();
+ let orig_capacity = vec.capacity();
+ let vec2 = vec.split_off(0);
+ assert_eq!(vec, []);
+ assert_eq!(vec2, [1, 2, 3, 4, 5, 6]);
+ assert_eq!(vec.capacity(), orig_capacity);
+ assert_eq!(vec2.as_ptr(), orig_ptr);
+}
+
+#[test]
+fn test_into_iter_as_slice() {
+ let vec = vec!['a', 'b', 'c'];
+ let mut into_iter = vec.into_iter();
+ assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']);
+ let _ = into_iter.next().unwrap();
+ assert_eq!(into_iter.as_slice(), &['b', 'c']);
+ let _ = into_iter.next().unwrap();
+ let _ = into_iter.next().unwrap();
+ assert_eq!(into_iter.as_slice(), &[]);
+}
+
+#[test]
+fn test_into_iter_as_mut_slice() {
+ let vec = vec!['a', 'b', 'c'];
+ let mut into_iter = vec.into_iter();
+ assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']);
+ into_iter.as_mut_slice()[0] = 'x';
+ into_iter.as_mut_slice()[1] = 'y';
+ assert_eq!(into_iter.next().unwrap(), 'x');
+ assert_eq!(into_iter.as_slice(), &['y', 'c']);
+}
+
+#[test]
+fn test_into_iter_debug() {
+ let vec = vec!['a', 'b', 'c'];
+ let into_iter = vec.into_iter();
+ let debug = format!("{into_iter:?}");
+ assert_eq!(debug, "IntoIter(['a', 'b', 'c'])");
+}
+
+#[test]
+fn test_into_iter_count() {
+ assert_eq!([1, 2, 3].into_iter().count(), 3);
+}
+
+#[test]
+fn test_into_iter_next_chunk() {
+ let mut iter = b"lorem".to_vec().into_iter();
+
+ assert_eq!(iter.next_chunk().unwrap(), [b'l', b'o']); // N is inferred as 2
+ assert_eq!(iter.next_chunk().unwrap(), [b'r', b'e', b'm']); // N is inferred as 3
+ assert_eq!(iter.next_chunk::<4>().unwrap_err().as_slice(), &[]); // N is explicitly 4
+}
+
+#[test]
+fn test_into_iter_clone() {
+ fn iter_equal<I: Iterator<Item = i32>>(it: I, slice: &[i32]) {
+ let v: Vec<i32> = it.collect();
+ assert_eq!(&v[..], slice);
+ }
+ let mut it = [1, 2, 3].into_iter();
+ iter_equal(it.clone(), &[1, 2, 3]);
+ assert_eq!(it.next(), Some(1));
+ let mut it = it.rev();
+ iter_equal(it.clone(), &[3, 2]);
+ assert_eq!(it.next(), Some(3));
+ iter_equal(it.clone(), &[2]);
+ assert_eq!(it.next(), Some(2));
+ iter_equal(it.clone(), &[]);
+ assert_eq!(it.next(), None);
+}
+
+#[test]
+fn test_into_iter_leak() {
+ static mut DROPS: i32 = 0;
+
+ struct D(bool);
+
+ impl Drop for D {
+ fn drop(&mut self) {
+ unsafe {
+ DROPS += 1;
+ }
+
+ if self.0 {
+ panic!("panic in `drop`");
+ }
+ }
+ }
+
+ let v = vec![D(false), D(true), D(false)];
+
+ catch_unwind(move || drop(v.into_iter())).ok();
+
+ assert_eq!(unsafe { DROPS }, 3);
+}
+
+#[test]
+fn test_into_iter_advance_by() {
+ let mut i = [1, 2, 3, 4, 5].into_iter();
+ i.advance_by(0).unwrap();
+ i.advance_back_by(0).unwrap();
+ assert_eq!(i.as_slice(), [1, 2, 3, 4, 5]);
+
+ i.advance_by(1).unwrap();
+ i.advance_back_by(1).unwrap();
+ assert_eq!(i.as_slice(), [2, 3, 4]);
+
+ assert_eq!(i.advance_back_by(usize::MAX), Err(3));
+
+ assert_eq!(i.advance_by(usize::MAX), Err(0));
+
+ i.advance_by(0).unwrap();
+ i.advance_back_by(0).unwrap();
+
+ assert_eq!(i.len(), 0);
+}
+
+#[test]
+fn test_into_iter_drop_allocator() {
+ struct ReferenceCountedAllocator<'a>(DropCounter<'a>);
+
+ unsafe impl Allocator for ReferenceCountedAllocator<'_> {
+ fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, core::alloc::AllocError> {
+ System.allocate(layout)
+ }
+
+ unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
+ System.deallocate(ptr, layout)
+ }
+ }
+
+ let mut drop_count = 0;
+
+ let allocator = ReferenceCountedAllocator(DropCounter { count: &mut drop_count });
+ let _ = Vec::<u32, _>::new_in(allocator);
+ assert_eq!(drop_count, 1);
+
+ let allocator = ReferenceCountedAllocator(DropCounter { count: &mut drop_count });
+ let _ = Vec::<u32, _>::new_in(allocator).into_iter();
+ assert_eq!(drop_count, 2);
+}
+
+#[test]
+fn test_from_iter_specialization() {
+ let src: Vec<usize> = vec![0usize; 1];
+ let srcptr = src.as_ptr();
+ let sink = src.into_iter().collect::<Vec<_>>();
+ let sinkptr = sink.as_ptr();
+ assert_eq!(srcptr, sinkptr);
+}
+
+#[test]
+fn test_from_iter_partially_drained_in_place_specialization() {
+ let src: Vec<usize> = vec![0usize; 10];
+ let srcptr = src.as_ptr();
+ let mut iter = src.into_iter();
+ iter.next();
+ iter.next();
+ let sink = iter.collect::<Vec<_>>();
+ let sinkptr = sink.as_ptr();
+ assert_eq!(srcptr, sinkptr);
+}
+
+#[test]
+fn test_from_iter_specialization_with_iterator_adapters() {
+ fn assert_in_place_trait<T: InPlaceIterable>(_: &T) {}
+ let src: Vec<usize> = vec![0usize; 256];
+ let srcptr = src.as_ptr();
+ let iter = src
+ .into_iter()
+ .enumerate()
+ .map(|i| i.0 + i.1)
+ .zip(std::iter::repeat(1usize))
+ .map(|(a, b)| a + b)
+ .map_while(Option::Some)
+ .skip(1)
+ .map(|e| if e != usize::MAX { Ok(std::num::NonZeroUsize::new(e)) } else { Err(()) });
+ assert_in_place_trait(&iter);
+ let sink = iter.collect::<Result<Vec<_>, _>>().unwrap();
+ let sinkptr = sink.as_ptr();
+ assert_eq!(srcptr, sinkptr as *const usize);
+}
+
+#[test]
+fn test_from_iter_specialization_head_tail_drop() {
+ let drop_count: Vec<_> = (0..=2).map(|_| Rc::new(())).collect();
+ let src: Vec<_> = drop_count.iter().cloned().collect();
+ let srcptr = src.as_ptr();
+ let iter = src.into_iter();
+ let sink: Vec<_> = iter.skip(1).take(1).collect();
+ let sinkptr = sink.as_ptr();
+ assert_eq!(srcptr, sinkptr, "specialization was applied");
+ assert_eq!(Rc::strong_count(&drop_count[0]), 1, "front was dropped");
+ assert_eq!(Rc::strong_count(&drop_count[1]), 2, "one element was collected");
+ assert_eq!(Rc::strong_count(&drop_count[2]), 1, "tail was dropped");
+ assert_eq!(sink.len(), 1);
+}
+
+#[test]
+fn test_from_iter_specialization_panic_during_iteration_drops() {
+ let drop_count: Vec<_> = (0..=2).map(|_| Rc::new(())).collect();
+ let src: Vec<_> = drop_count.iter().cloned().collect();
+ let iter = src.into_iter();
+
+ let _ = std::panic::catch_unwind(AssertUnwindSafe(|| {
+ let _ = iter
+ .enumerate()
+ .filter_map(|(i, e)| {
+ if i == 1 {
+ std::panic!("aborting iteration");
+ }
+ Some(e)
+ })
+ .collect::<Vec<_>>();
+ }));
+
+ assert!(
+ drop_count.iter().map(Rc::strong_count).all(|count| count == 1),
+ "all items were dropped once"
+ );
+}
+
+#[test]
+fn test_from_iter_specialization_panic_during_drop_leaks() {
+ static mut DROP_COUNTER: usize = 0;
+
+ #[derive(Debug)]
+ enum Droppable {
+ DroppedTwice(Box<i32>),
+ PanicOnDrop,
+ }
+
+ impl Drop for Droppable {
+ fn drop(&mut self) {
+ match self {
+ Droppable::DroppedTwice(_) => {
+ unsafe {
+ DROP_COUNTER += 1;
+ }
+ println!("Dropping!")
+ }
+ Droppable::PanicOnDrop => {
+ if !std::thread::panicking() {
+ panic!();
+ }
+ }
+ }
+ }
+ }
+
+ let mut to_free: *mut Droppable = core::ptr::null_mut();
+ let mut cap = 0;
+
+ let _ = std::panic::catch_unwind(AssertUnwindSafe(|| {
+ let mut v = vec![Droppable::DroppedTwice(Box::new(123)), Droppable::PanicOnDrop];
+ to_free = v.as_mut_ptr();
+ cap = v.capacity();
+ let _ = v.into_iter().take(0).collect::<Vec<_>>();
+ }));
+
+ assert_eq!(unsafe { DROP_COUNTER }, 1);
+ // clean up the leak to keep miri happy
+ unsafe {
+ drop(Vec::from_raw_parts(to_free, 0, cap));
+ }
+}
+
+// regression test for issue #85322. Peekable previously implemented InPlaceIterable,
+// but due to an interaction with IntoIter's current Clone implementation it failed to uphold
+// the contract.
+#[test]
+fn test_collect_after_iterator_clone() {
+ let v = vec![0; 5];
+ let mut i = v.into_iter().map(|i| i + 1).peekable();
+ i.peek();
+ let v = i.clone().collect::<Vec<_>>();
+ assert_eq!(v, [1, 1, 1, 1, 1]);
+ assert!(v.len() <= v.capacity());
+}
+#[test]
+fn test_cow_from() {
+ let borrowed: &[_] = &["borrowed", "(slice)"];
+ let owned = vec!["owned", "(vec)"];
+ match (Cow::from(owned.clone()), Cow::from(borrowed)) {
+ (Cow::Owned(o), Cow::Borrowed(b)) => assert!(o == owned && b == borrowed),
+ _ => panic!("invalid `Cow::from`"),
+ }
+}
+
+#[test]
+fn test_from_cow() {
+ let borrowed: &[_] = &["borrowed", "(slice)"];
+ let owned = vec!["owned", "(vec)"];
+ assert_eq!(Vec::from(Cow::Borrowed(borrowed)), vec!["borrowed", "(slice)"]);
+ assert_eq!(Vec::from(Cow::Owned(owned)), vec!["owned", "(vec)"]);
+}
+
+#[allow(dead_code)]
+fn assert_covariance() {
+ fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> {
+ d
+ }
+ fn into_iter<'new>(i: IntoIter<&'static str>) -> IntoIter<&'new str> {
+ i
+ }
+}
+
+#[test]
+fn from_into_inner() {
+ let vec = vec![1, 2, 3];
+ let ptr = vec.as_ptr();
+ let vec = vec.into_iter().collect::<Vec<_>>();
+ assert_eq!(vec, [1, 2, 3]);
+ assert_eq!(vec.as_ptr(), ptr);
+
+ let ptr = &vec[1] as *const _;
+ let mut it = vec.into_iter();
+ it.next().unwrap();
+ let vec = it.collect::<Vec<_>>();
+ assert_eq!(vec, [2, 3]);
+ assert!(ptr != vec.as_ptr());
+}
+
+#[test]
+fn overaligned_allocations() {
+ #[repr(align(256))]
+ struct Foo(usize);
+ let mut v = vec![Foo(273)];
+ for i in 0..0x1000 {
+ v.reserve_exact(i);
+ assert!(v[0].0 == 273);
+ assert!(v.as_ptr() as usize & 0xff == 0);
+ v.shrink_to_fit();
+ assert!(v[0].0 == 273);
+ assert!(v.as_ptr() as usize & 0xff == 0);
+ }
+}
+
+#[test]
+fn drain_filter_empty() {
+ let mut vec: Vec<i32> = vec![];
+
+ {
+ let mut iter = vec.drain_filter(|_| true);
+ assert_eq!(iter.size_hint(), (0, Some(0)));
+ assert_eq!(iter.next(), None);
+ assert_eq!(iter.size_hint(), (0, Some(0)));
+ assert_eq!(iter.next(), None);
+ assert_eq!(iter.size_hint(), (0, Some(0)));
+ }
+ assert_eq!(vec.len(), 0);
+ assert_eq!(vec, vec![]);
+}
+
+#[test]
+fn drain_filter_zst() {
+ let mut vec = vec![(), (), (), (), ()];
+ let initial_len = vec.len();
+ let mut count = 0;
+ {
+ let mut iter = vec.drain_filter(|_| true);
+ assert_eq!(iter.size_hint(), (0, Some(initial_len)));
+ while let Some(_) = iter.next() {
+ count += 1;
+ assert_eq!(iter.size_hint(), (0, Some(initial_len - count)));
+ }
+ assert_eq!(iter.size_hint(), (0, Some(0)));
+ assert_eq!(iter.next(), None);
+ assert_eq!(iter.size_hint(), (0, Some(0)));
+ }
+
+ assert_eq!(count, initial_len);
+ assert_eq!(vec.len(), 0);
+ assert_eq!(vec, vec![]);
+}
+
+#[test]
+fn drain_filter_false() {
+ let mut vec = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+
+ let initial_len = vec.len();
+ let mut count = 0;
+ {
+ let mut iter = vec.drain_filter(|_| false);
+ assert_eq!(iter.size_hint(), (0, Some(initial_len)));
+ for _ in iter.by_ref() {
+ count += 1;
+ }
+ assert_eq!(iter.size_hint(), (0, Some(0)));
+ assert_eq!(iter.next(), None);
+ assert_eq!(iter.size_hint(), (0, Some(0)));
+ }
+
+ assert_eq!(count, 0);
+ assert_eq!(vec.len(), initial_len);
+ assert_eq!(vec, vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
+}
+
+#[test]
+fn drain_filter_true() {
+ let mut vec = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+
+ let initial_len = vec.len();
+ let mut count = 0;
+ {
+ let mut iter = vec.drain_filter(|_| true);
+ assert_eq!(iter.size_hint(), (0, Some(initial_len)));
+ while let Some(_) = iter.next() {
+ count += 1;
+ assert_eq!(iter.size_hint(), (0, Some(initial_len - count)));
+ }
+ assert_eq!(iter.size_hint(), (0, Some(0)));
+ assert_eq!(iter.next(), None);
+ assert_eq!(iter.size_hint(), (0, Some(0)));
+ }
+
+ assert_eq!(count, initial_len);
+ assert_eq!(vec.len(), 0);
+ assert_eq!(vec, vec![]);
+}
+
+#[test]
+fn drain_filter_complex() {
+ {
+ // [+xxx++++++xxxxx++++x+x++]
+ let mut vec = vec![
+ 1, 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.drain_filter(|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]);
+
+ assert_eq!(vec.len(), 14);
+ assert_eq!(vec, vec![1, 7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35, 37, 39]);
+ }
+
+ {
+ // [xxx++++++xxxxx++++x+x++]
+ 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, 37, 39,
+ ];
+
+ let removed = vec.drain_filter(|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]);
+
+ assert_eq!(vec.len(), 13);
+ assert_eq!(vec, vec![7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35, 37, 39]);
+ }
+
+ {
+ // [xxx++++++xxxxx++++x+x]
+ 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.drain_filter(|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]);
+
+ assert_eq!(vec.len(), 11);
+ assert_eq!(vec, vec![7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35]);
+ }
+
+ {
+ // [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.drain_filter(|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]);
+
+ assert_eq!(vec.len(), 10);
+ assert_eq!(vec, vec![1, 3, 5, 7, 9, 11, 13, 15, 17, 19]);
+ }
+
+ {
+ // [+++++++++++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.drain_filter(|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]);
+
+ assert_eq!(vec.len(), 10);
+ assert_eq!(vec, vec![1, 3, 5, 7, 9, 11, 13, 15, 17, 19]);
+ }
+}
+
+// FIXME: re-enable emscripten once it can unwind again
+#[test]
+#[cfg(not(target_os = "emscripten"))]
+fn drain_filter_consumed_panic() {
+ use std::rc::Rc;
+ use std::sync::Mutex;
+
+ struct Check {
+ index: usize,
+ drop_counts: Rc<Mutex<Vec<usize>>>,
+ }
+
+ impl Drop for Check {
+ fn drop(&mut self) {
+ self.drop_counts.lock().unwrap()[self.index] += 1;
+ println!("drop: {}", self.index);
+ }
+ }
+
+ let check_count = 10;
+ let drop_counts = Rc::new(Mutex::new(vec![0_usize; check_count]));
+ let mut data: Vec<Check> = (0..check_count)
+ .map(|index| Check { index, drop_counts: Rc::clone(&drop_counts) })
+ .collect();
+
+ let _ = std::panic::catch_unwind(move || {
+ let filter = |c: &mut Check| {
+ if c.index == 2 {
+ panic!("panic at index: {}", c.index);
+ }
+ // Verify that if the filter could panic again on another element
+ // that it would not cause a double panic and all elements of the
+ // vec would still be dropped exactly once.
+ if c.index == 4 {
+ panic!("panic at index: {}", c.index);
+ }
+ c.index < 6
+ };
+ let drain = data.drain_filter(filter);
+
+ // NOTE: The DrainFilter is explicitly consumed
+ drain.for_each(drop);
+ });
+
+ let drop_counts = drop_counts.lock().unwrap();
+ assert_eq!(check_count, drop_counts.len());
+
+ for (index, count) in drop_counts.iter().cloned().enumerate() {
+ assert_eq!(1, count, "unexpected drop count at index: {} (count: {})", index, count);
+ }
+}
+
+// FIXME: Re-enable emscripten once it can catch panics
+#[test]
+#[cfg(not(target_os = "emscripten"))]
+fn drain_filter_unconsumed_panic() {
+ use std::rc::Rc;
+ use std::sync::Mutex;
+
+ struct Check {
+ index: usize,
+ drop_counts: Rc<Mutex<Vec<usize>>>,
+ }
+
+ impl Drop for Check {
+ fn drop(&mut self) {
+ self.drop_counts.lock().unwrap()[self.index] += 1;
+ println!("drop: {}", self.index);
+ }
+ }
+
+ let check_count = 10;
+ let drop_counts = Rc::new(Mutex::new(vec![0_usize; check_count]));
+ let mut data: Vec<Check> = (0..check_count)
+ .map(|index| Check { index, drop_counts: Rc::clone(&drop_counts) })
+ .collect();
+
+ let _ = std::panic::catch_unwind(move || {
+ let filter = |c: &mut Check| {
+ if c.index == 2 {
+ panic!("panic at index: {}", c.index);
+ }
+ // Verify that if the filter could panic again on another element
+ // that it would not cause a double panic and all elements of the
+ // vec would still be dropped exactly once.
+ if c.index == 4 {
+ panic!("panic at index: {}", c.index);
+ }
+ c.index < 6
+ };
+ let _drain = data.drain_filter(filter);
+
+ // NOTE: The DrainFilter is dropped without being consumed
+ });
+
+ let drop_counts = drop_counts.lock().unwrap();
+ assert_eq!(check_count, drop_counts.len());
+
+ for (index, count) in drop_counts.iter().cloned().enumerate() {
+ assert_eq!(1, count, "unexpected drop count at index: {} (count: {})", index, count);
+ }
+}
+
+#[test]
+fn drain_filter_unconsumed() {
+ let mut vec = vec![1, 2, 3, 4];
+ let drain = vec.drain_filter(|&mut x| x % 2 != 0);
+ drop(drain);
+ assert_eq!(vec, [2, 4]);
+}
+
+#[test]
+fn test_reserve_exact() {
+ // This is all the same as test_reserve
+
+ let mut v = Vec::new();
+ assert_eq!(v.capacity(), 0);
+
+ v.reserve_exact(2);
+ assert!(v.capacity() >= 2);
+
+ for i in 0..16 {
+ v.push(i);
+ }
+
+ assert!(v.capacity() >= 16);
+ v.reserve_exact(16);
+ assert!(v.capacity() >= 32);
+
+ v.push(16);
+
+ v.reserve_exact(16);
+ assert!(v.capacity() >= 33)
+}
+
+#[test]
+#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM
+#[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc
+fn test_try_reserve() {
+ // These are the interesting cases:
+ // * exactly isize::MAX should never trigger a CapacityOverflow (can be OOM)
+ // * > isize::MAX should always fail
+ // * On 16/32-bit should CapacityOverflow
+ // * On 64-bit should OOM
+ // * overflow may trigger when adding `len` to `cap` (in number of elements)
+ // * overflow may trigger when multiplying `new_cap` by size_of::<T> (to get bytes)
+
+ const MAX_CAP: usize = isize::MAX as usize;
+ const MAX_USIZE: usize = usize::MAX;
+
+ // On 16/32-bit, we check that allocations don't exceed isize::MAX,
+ // on 64-bit, we assume the OS will give an OOM for such a ridiculous size.
+ // Any platform that succeeds for these requests is technically broken with
+ // ptr::offset because LLVM is the worst.
+ let guards_against_isize = usize::BITS < 64;
+
+ {
+ // Note: basic stuff is checked by test_reserve
+ let mut empty_bytes: Vec<u8> = Vec::new();
+
+ // Check isize::MAX doesn't count as an overflow
+ if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP).map_err(|e| e.kind()) {
+ panic!("isize::MAX shouldn't trigger an overflow!");
+ }
+ // Play it again, frank! (just to be sure)
+ if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP).map_err(|e| e.kind()) {
+ panic!("isize::MAX shouldn't trigger an overflow!");
+ }
+
+ if guards_against_isize {
+ // Check isize::MAX + 1 does count as overflow
+ assert_matches!(
+ empty_bytes.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()),
+ Err(CapacityOverflow),
+ "isize::MAX + 1 should trigger an overflow!"
+ );
+
+ // Check usize::MAX does count as overflow
+ assert_matches!(
+ empty_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()),
+ Err(CapacityOverflow),
+ "usize::MAX should trigger an overflow!"
+ );
+ } else {
+ // Check isize::MAX + 1 is an OOM
+ assert_matches!(
+ empty_bytes.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()),
+ Err(AllocError { .. }),
+ "isize::MAX + 1 should trigger an OOM!"
+ );
+
+ // Check usize::MAX is an OOM
+ assert_matches!(
+ empty_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()),
+ Err(AllocError { .. }),
+ "usize::MAX should trigger an OOM!"
+ );
+ }
+ }
+
+ {
+ // 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];
+
+ if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) {
+ panic!("isize::MAX shouldn't trigger an overflow!");
+ }
+ if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) {
+ panic!("isize::MAX shouldn't trigger an overflow!");
+ }
+ if guards_against_isize {
+ assert_matches!(
+ ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()),
+ Err(CapacityOverflow),
+ "isize::MAX + 1 should trigger an overflow!"
+ );
+ } else {
+ assert_matches!(
+ ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()),
+ Err(AllocError { .. }),
+ "isize::MAX + 1 should trigger an OOM!"
+ );
+ }
+ // Should always overflow in the add-to-len
+ assert_matches!(
+ ten_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()),
+ Err(CapacityOverflow),
+ "usize::MAX should trigger an overflow!"
+ );
+ }
+
+ {
+ // 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];
+
+ 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!");
+ }
+ 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!");
+ }
+ if guards_against_isize {
+ assert_matches!(
+ ten_u32s.try_reserve(MAX_CAP / 4 - 9).map_err(|e| e.kind()),
+ Err(CapacityOverflow),
+ "isize::MAX + 1 should trigger an overflow!"
+ );
+ } else {
+ assert_matches!(
+ ten_u32s.try_reserve(MAX_CAP / 4 - 9).map_err(|e| e.kind()),
+ Err(AllocError { .. }),
+ "isize::MAX + 1 should trigger an OOM!"
+ );
+ }
+ // Should fail in the mul-by-size
+ assert_matches!(
+ ten_u32s.try_reserve(MAX_USIZE - 20).map_err(|e| e.kind()),
+ Err(CapacityOverflow),
+ "usize::MAX should trigger an overflow!"
+ );
+ }
+}
+
+#[test]
+#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM
+#[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc
+fn test_try_reserve_exact() {
+ // This is exactly the same as test_try_reserve with the method changed.
+ // See that test for comments.
+
+ const MAX_CAP: usize = isize::MAX as usize;
+ const MAX_USIZE: usize = usize::MAX;
+
+ let guards_against_isize = size_of::<usize>() < 8;
+
+ {
+ let mut empty_bytes: Vec<u8> = Vec::new();
+
+ if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP).map_err(|e| e.kind())
+ {
+ panic!("isize::MAX shouldn't trigger an overflow!");
+ }
+ if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP).map_err(|e| e.kind())
+ {
+ panic!("isize::MAX shouldn't trigger an overflow!");
+ }
+
+ if guards_against_isize {
+ assert_matches!(
+ empty_bytes.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()),
+ Err(CapacityOverflow),
+ "isize::MAX + 1 should trigger an overflow!"
+ );
+
+ assert_matches!(
+ empty_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()),
+ Err(CapacityOverflow),
+ "usize::MAX should trigger an overflow!"
+ );
+ } else {
+ assert_matches!(
+ empty_bytes.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()),
+ Err(AllocError { .. }),
+ "isize::MAX + 1 should trigger an OOM!"
+ );
+
+ assert_matches!(
+ empty_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()),
+ Err(AllocError { .. }),
+ "usize::MAX should trigger an OOM!"
+ );
+ }
+ }
+
+ {
+ 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).map_err(|e| e.kind())
+ {
+ panic!("isize::MAX shouldn't trigger an overflow!");
+ }
+ 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!");
+ }
+ if guards_against_isize {
+ assert_matches!(
+ ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()),
+ Err(CapacityOverflow),
+ "isize::MAX + 1 should trigger an overflow!"
+ );
+ } else {
+ assert_matches!(
+ ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()),
+ Err(AllocError { .. }),
+ "isize::MAX + 1 should trigger an OOM!"
+ );
+ }
+ assert_matches!(
+ ten_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()),
+ Err(CapacityOverflow),
+ "usize::MAX should trigger an overflow!"
+ );
+ }
+
+ {
+ 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).map_err(|e| e.kind())
+ {
+ panic!("isize::MAX shouldn't trigger an overflow!");
+ }
+ 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!");
+ }
+ if guards_against_isize {
+ assert_matches!(
+ ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9).map_err(|e| e.kind()),
+ Err(CapacityOverflow),
+ "isize::MAX + 1 should trigger an overflow!"
+ );
+ } else {
+ assert_matches!(
+ ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9).map_err(|e| e.kind()),
+ Err(AllocError { .. }),
+ "isize::MAX + 1 should trigger an OOM!"
+ );
+ }
+ assert_matches!(
+ ten_u32s.try_reserve_exact(MAX_USIZE - 20).map_err(|e| e.kind()),
+ Err(CapacityOverflow),
+ "usize::MAX should trigger an overflow!"
+ );
+ }
+}
+
+#[test]
+fn test_stable_pointers() {
+ /// Pull an element from the iterator, then drop it.
+ /// Useful to cover both the `next` and `drop` paths of an iterator.
+ fn next_then_drop<I: Iterator>(mut i: I) {
+ i.next().unwrap();
+ drop(i);
+ }
+
+ // Test that, if we reserved enough space, adding and removing elements does not
+ // invalidate references into the vector (such as `v0`). This test also
+ // runs in Miri, which would detect such problems.
+ // Note that this test does *not* constitute a stable guarantee that all these functions do not
+ // reallocate! Only what is explicitly documented at
+ // <https://doc.rust-lang.org/nightly/std/vec/struct.Vec.html#guarantees> is stably guaranteed.
+ let mut v = Vec::with_capacity(128);
+ v.push(13);
+
+ // Laundering the lifetime -- we take care that `v` does not reallocate, so that's okay.
+ let v0 = &mut v[0];
+ let v0 = unsafe { &mut *(v0 as *mut _) };
+ // Now do a bunch of things and occasionally use `v0` again to assert it is still valid.
+
+ // Pushing/inserting and popping/removing
+ v.push(1);
+ v.push(2);
+ v.insert(1, 1);
+ assert_eq!(*v0, 13);
+ v.remove(1);
+ v.pop().unwrap();
+ assert_eq!(*v0, 13);
+ v.push(1);
+ v.swap_remove(1);
+ assert_eq!(v.len(), 2);
+ v.swap_remove(1); // swap_remove the last element
+ assert_eq!(*v0, 13);
+
+ // Appending
+ v.append(&mut vec![27, 19]);
+ assert_eq!(*v0, 13);
+
+ // Extending
+ v.extend_from_slice(&[1, 2]);
+ v.extend(&[1, 2]); // `slice::Iter` (with `T: Copy`) specialization
+ v.extend(vec![2, 3]); // `vec::IntoIter` specialization
+ v.extend(std::iter::once(3)); // `TrustedLen` specialization
+ v.extend(std::iter::empty::<i32>()); // `TrustedLen` specialization with empty iterator
+ v.extend(std::iter::once(3).filter(|_| true)); // base case
+ v.extend(std::iter::once(&3)); // `cloned` specialization
+ assert_eq!(*v0, 13);
+
+ // Truncation
+ v.truncate(2);
+ assert_eq!(*v0, 13);
+
+ // Resizing
+ v.resize_with(v.len() + 10, || 42);
+ assert_eq!(*v0, 13);
+ v.resize_with(2, || panic!());
+ assert_eq!(*v0, 13);
+
+ // No-op reservation
+ v.reserve(32);
+ v.reserve_exact(32);
+ assert_eq!(*v0, 13);
+
+ // Partial draining
+ v.resize_with(10, || 42);
+ next_then_drop(v.drain(5..));
+ assert_eq!(*v0, 13);
+
+ // Splicing
+ v.resize_with(10, || 42);
+ next_then_drop(v.splice(5.., vec![1, 2, 3, 4, 5])); // empty tail after range
+ assert_eq!(*v0, 13);
+ next_then_drop(v.splice(5..8, vec![1])); // replacement is smaller than original range
+ assert_eq!(*v0, 13);
+ next_then_drop(v.splice(5..6, [1; 10].into_iter().filter(|_| true))); // lower bound not exact
+ assert_eq!(*v0, 13);
+
+ // spare_capacity_mut
+ v.spare_capacity_mut();
+ assert_eq!(*v0, 13);
+
+ // Smoke test that would fire even outside Miri if an actual relocation happened.
+ *v0 -= 13;
+ assert_eq!(v[0], 0);
+}
+
+// https://github.com/rust-lang/rust/pull/49496 introduced specialization based on:
+//
+// ```
+// unsafe impl<T: ?Sized> IsZero for *mut T {
+// fn is_zero(&self) -> bool {
+// (*self).is_null()
+// }
+// }
+// ```
+//
+// … to call `RawVec::with_capacity_zeroed` for creating `Vec<*mut T>`,
+// which is incorrect for fat pointers since `<*mut T>::is_null` only looks at the data component.
+// That is, a fat pointer can be “null” without being made entirely of zero bits.
+#[test]
+fn vec_macro_repeating_null_raw_fat_pointer() {
+ let raw_dyn = &mut (|| ()) as &mut dyn Fn() as *mut dyn Fn();
+ let vtable = dbg!(ptr_metadata(raw_dyn));
+ let null_raw_dyn = ptr_from_raw_parts(std::ptr::null_mut(), vtable);
+ assert!(null_raw_dyn.is_null());
+
+ let vec = vec![null_raw_dyn; 1];
+ dbg!(ptr_metadata(vec[0]));
+ assert!(vec[0] == null_raw_dyn);
+
+ // Polyfill for https://github.com/rust-lang/rfcs/pull/2580
+
+ fn ptr_metadata(ptr: *mut dyn Fn()) -> *mut () {
+ unsafe { std::mem::transmute::<*mut dyn Fn(), DynRepr>(ptr).vtable }
+ }
+
+ fn ptr_from_raw_parts(data: *mut (), vtable: *mut ()) -> *mut dyn Fn() {
+ unsafe { std::mem::transmute::<DynRepr, *mut dyn Fn()>(DynRepr { data, vtable }) }
+ }
+
+ #[repr(C)]
+ struct DynRepr {
+ data: *mut (),
+ vtable: *mut (),
+ }
+}
+
+// This test will likely fail if you change the capacities used in
+// `RawVec::grow_amortized`.
+#[test]
+fn test_push_growth_strategy() {
+ // If the element size is 1, we jump from 0 to 8, then double.
+ {
+ let mut v1: Vec<u8> = vec![];
+ assert_eq!(v1.capacity(), 0);
+
+ for _ in 0..8 {
+ v1.push(0);
+ assert_eq!(v1.capacity(), 8);
+ }
+
+ for _ in 8..16 {
+ v1.push(0);
+ assert_eq!(v1.capacity(), 16);
+ }
+
+ for _ in 16..32 {
+ v1.push(0);
+ assert_eq!(v1.capacity(), 32);
+ }
+
+ for _ in 32..64 {
+ v1.push(0);
+ assert_eq!(v1.capacity(), 64);
+ }
+ }
+
+ // If the element size is 2..=1024, we jump from 0 to 4, then double.
+ {
+ let mut v2: Vec<u16> = vec![];
+ let mut v1024: Vec<[u8; 1024]> = vec![];
+ assert_eq!(v2.capacity(), 0);
+ assert_eq!(v1024.capacity(), 0);
+
+ for _ in 0..4 {
+ v2.push(0);
+ v1024.push([0; 1024]);
+ assert_eq!(v2.capacity(), 4);
+ assert_eq!(v1024.capacity(), 4);
+ }
+
+ for _ in 4..8 {
+ v2.push(0);
+ v1024.push([0; 1024]);
+ assert_eq!(v2.capacity(), 8);
+ assert_eq!(v1024.capacity(), 8);
+ }
+
+ for _ in 8..16 {
+ v2.push(0);
+ v1024.push([0; 1024]);
+ assert_eq!(v2.capacity(), 16);
+ assert_eq!(v1024.capacity(), 16);
+ }
+
+ for _ in 16..32 {
+ v2.push(0);
+ v1024.push([0; 1024]);
+ assert_eq!(v2.capacity(), 32);
+ assert_eq!(v1024.capacity(), 32);
+ }
+
+ for _ in 32..64 {
+ v2.push(0);
+ v1024.push([0; 1024]);
+ assert_eq!(v2.capacity(), 64);
+ assert_eq!(v1024.capacity(), 64);
+ }
+ }
+
+ // If the element size is > 1024, we jump from 0 to 1, then double.
+ {
+ let mut v1025: Vec<[u8; 1025]> = vec![];
+ assert_eq!(v1025.capacity(), 0);
+
+ for _ in 0..1 {
+ v1025.push([0; 1025]);
+ assert_eq!(v1025.capacity(), 1);
+ }
+
+ for _ in 1..2 {
+ v1025.push([0; 1025]);
+ assert_eq!(v1025.capacity(), 2);
+ }
+
+ for _ in 2..4 {
+ v1025.push([0; 1025]);
+ assert_eq!(v1025.capacity(), 4);
+ }
+
+ for _ in 4..8 {
+ v1025.push([0; 1025]);
+ assert_eq!(v1025.capacity(), 8);
+ }
+
+ for _ in 8..16 {
+ v1025.push([0; 1025]);
+ assert_eq!(v1025.capacity(), 16);
+ }
+
+ for _ in 16..32 {
+ v1025.push([0; 1025]);
+ assert_eq!(v1025.capacity(), 32);
+ }
+
+ for _ in 32..64 {
+ v1025.push([0; 1025]);
+ assert_eq!(v1025.capacity(), 64);
+ }
+ }
+}
+
+macro_rules! generate_assert_eq_vec_and_prim {
+ ($name:ident<$B:ident>($type:ty)) => {
+ fn $name<A: PartialEq<$B> + Debug, $B: Debug>(a: Vec<A>, b: $type) {
+ assert!(a == b);
+ assert_eq!(a, b);
+ }
+ };
+}
+
+generate_assert_eq_vec_and_prim! { assert_eq_vec_and_slice <B>(&[B]) }
+generate_assert_eq_vec_and_prim! { assert_eq_vec_and_array_3<B>([B; 3]) }
+
+#[test]
+fn partialeq_vec_and_prim() {
+ assert_eq_vec_and_slice(vec![1, 2, 3], &[1, 2, 3]);
+ assert_eq_vec_and_array_3(vec![1, 2, 3], [1, 2, 3]);
+}
+
+macro_rules! assert_partial_eq_valid {
+ ($a2:expr, $a3:expr; $b2:expr, $b3: expr) => {
+ assert!($a2 == $b2);
+ assert!($a2 != $b3);
+ assert!($a3 != $b2);
+ assert!($a3 == $b3);
+ assert_eq!($a2, $b2);
+ assert_ne!($a2, $b3);
+ assert_ne!($a3, $b2);
+ assert_eq!($a3, $b3);
+ };
+}
+
+#[test]
+fn partialeq_vec_full() {
+ let vec2: Vec<_> = vec![1, 2];
+ let vec3: Vec<_> = vec![1, 2, 3];
+ let slice2: &[_] = &[1, 2];
+ let slice3: &[_] = &[1, 2, 3];
+ let slicemut2: &[_] = &mut [1, 2];
+ let slicemut3: &[_] = &mut [1, 2, 3];
+ let array2: [_; 2] = [1, 2];
+ let array3: [_; 3] = [1, 2, 3];
+ let arrayref2: &[_; 2] = &[1, 2];
+ let arrayref3: &[_; 3] = &[1, 2, 3];
+
+ assert_partial_eq_valid!(vec2,vec3; vec2,vec3);
+ assert_partial_eq_valid!(vec2,vec3; slice2,slice3);
+ assert_partial_eq_valid!(vec2,vec3; slicemut2,slicemut3);
+ assert_partial_eq_valid!(slice2,slice3; vec2,vec3);
+ assert_partial_eq_valid!(slicemut2,slicemut3; vec2,vec3);
+ assert_partial_eq_valid!(vec2,vec3; array2,array3);
+ assert_partial_eq_valid!(vec2,vec3; arrayref2,arrayref3);
+ assert_partial_eq_valid!(vec2,vec3; arrayref2[..],arrayref3[..]);
+}
+
+#[test]
+fn test_vec_cycle() {
+ #[derive(Debug)]
+ struct C<'a> {
+ v: Vec<Cell<Option<&'a C<'a>>>>,
+ }
+
+ impl<'a> C<'a> {
+ fn new() -> C<'a> {
+ C { v: Vec::new() }
+ }
+ }
+
+ let mut c1 = C::new();
+ let mut c2 = C::new();
+ let mut c3 = C::new();
+
+ // Push
+ c1.v.push(Cell::new(None));
+ c1.v.push(Cell::new(None));
+
+ c2.v.push(Cell::new(None));
+ c2.v.push(Cell::new(None));
+
+ c3.v.push(Cell::new(None));
+ c3.v.push(Cell::new(None));
+
+ // Set
+ c1.v[0].set(Some(&c2));
+ c1.v[1].set(Some(&c3));
+
+ c2.v[0].set(Some(&c2));
+ c2.v[1].set(Some(&c3));
+
+ c3.v[0].set(Some(&c1));
+ c3.v[1].set(Some(&c2));
+}
+
+#[test]
+fn test_vec_cycle_wrapped() {
+ struct Refs<'a> {
+ v: Vec<Cell<Option<&'a C<'a>>>>,
+ }
+
+ struct C<'a> {
+ refs: Refs<'a>,
+ }
+
+ impl<'a> Refs<'a> {
+ fn new() -> Refs<'a> {
+ Refs { v: Vec::new() }
+ }
+ }
+
+ impl<'a> C<'a> {
+ fn new() -> C<'a> {
+ C { refs: Refs::new() }
+ }
+ }
+
+ let mut c1 = C::new();
+ let mut c2 = C::new();
+ let mut c3 = C::new();
+
+ c1.refs.v.push(Cell::new(None));
+ c1.refs.v.push(Cell::new(None));
+ c2.refs.v.push(Cell::new(None));
+ c2.refs.v.push(Cell::new(None));
+ c3.refs.v.push(Cell::new(None));
+ c3.refs.v.push(Cell::new(None));
+
+ c1.refs.v[0].set(Some(&c2));
+ c1.refs.v[1].set(Some(&c3));
+ c2.refs.v[0].set(Some(&c2));
+ c2.refs.v[1].set(Some(&c3));
+ c3.refs.v[0].set(Some(&c1));
+ c3.refs.v[1].set(Some(&c2));
+}
+
+#[test]
+fn test_zero_sized_capacity() {
+ for len in [0, 1, 2, 4, 8, 16, 32, 64, 128, 256] {
+ let v = Vec::<()>::with_capacity(len);
+ assert_eq!(v.len(), 0);
+ assert_eq!(v.capacity(), usize::MAX);
+ }
+}
+
+#[test]
+fn test_zero_sized_vec_push() {
+ const N: usize = 8;
+
+ for len in 0..N {
+ let mut tester = Vec::with_capacity(len);
+ assert_eq!(tester.len(), 0);
+ assert!(tester.capacity() >= len);
+ for _ in 0..len {
+ tester.push(());
+ }
+ assert_eq!(tester.len(), len);
+ assert_eq!(tester.iter().count(), len);
+ tester.clear();
+ }
+}
+
+#[test]
+fn test_vec_macro_repeat() {
+ assert_eq!(vec![1; 3], vec![1, 1, 1]);
+ assert_eq!(vec![1; 2], vec![1, 1]);
+ assert_eq!(vec![1; 1], vec![1]);
+ assert_eq!(vec![1; 0], vec![]);
+
+ // from_elem syntax (see RFC 832)
+ let el = Box::new(1);
+ let n = 3;
+ assert_eq!(vec![el; n], vec![Box::new(1), Box::new(1), Box::new(1)]);
+}
+
+#[test]
+fn test_vec_swap() {
+ let mut a: Vec<isize> = vec![0, 1, 2, 3, 4, 5, 6];
+ a.swap(2, 4);
+ assert_eq!(a[2], 4);
+ assert_eq!(a[4], 2);
+ let mut n = 42;
+ swap(&mut n, &mut a[0]);
+ assert_eq!(a[0], 42);
+ assert_eq!(n, 0);
+}
+
+#[test]
+fn test_extend_from_within_spec() {
+ #[derive(Copy)]
+ struct CopyOnly;
+
+ impl Clone for CopyOnly {
+ fn clone(&self) -> Self {
+ panic!("extend_from_within must use specialization on copy");
+ }
+ }
+
+ vec![CopyOnly, CopyOnly].extend_from_within(..);
+}
+
+#[test]
+fn test_extend_from_within_clone() {
+ let mut v = vec![String::from("sssss"), String::from("12334567890"), String::from("c")];
+ v.extend_from_within(1..);
+
+ assert_eq!(v, ["sssss", "12334567890", "c", "12334567890", "c"]);
+}
+
+#[test]
+fn test_extend_from_within_complete_rande() {
+ let mut v = vec![0, 1, 2, 3];
+ v.extend_from_within(..);
+
+ assert_eq!(v, [0, 1, 2, 3, 0, 1, 2, 3]);
+}
+
+#[test]
+fn test_extend_from_within_empty_rande() {
+ let mut v = vec![0, 1, 2, 3];
+ v.extend_from_within(1..1);
+
+ assert_eq!(v, [0, 1, 2, 3]);
+}
+
+#[test]
+#[should_panic]
+fn test_extend_from_within_out_of_rande() {
+ let mut v = vec![0, 1];
+ v.extend_from_within(..3);
+}
+
+#[test]
+fn test_extend_from_within_zst() {
+ let mut v = vec![(); 8];
+ v.extend_from_within(3..7);
+
+ assert_eq!(v, [(); 12]);
+}
+
+#[test]
+fn test_extend_from_within_empty_vec() {
+ let mut v = Vec::<i32>::new();
+ v.extend_from_within(..);
+
+ assert_eq!(v, []);
+}
+
+#[test]
+fn test_extend_from_within() {
+ let mut v = vec![String::from("a"), String::from("b"), String::from("c")];
+ v.extend_from_within(1..=2);
+ v.extend_from_within(..=1);
+
+ assert_eq!(v, ["a", "b", "c", "b", "c", "a", "b"]);
+}
+
+#[test]
+fn test_vec_dedup_by() {
+ let mut vec: Vec<i32> = vec![1, -1, 2, 3, 1, -5, 5, -2, 2];
+
+ vec.dedup_by(|a, b| a.abs() == b.abs());
+
+ assert_eq!(vec, [1, 2, 3, 1, -5, -2]);
+}
+
+#[test]
+fn test_vec_dedup_empty() {
+ let mut vec: Vec<i32> = Vec::new();
+
+ vec.dedup();
+
+ assert_eq!(vec, []);
+}
+
+#[test]
+fn test_vec_dedup_one() {
+ let mut vec = vec![12i32];
+
+ vec.dedup();
+
+ assert_eq!(vec, [12]);
+}
+
+#[test]
+fn test_vec_dedup_multiple_ident() {
+ let mut vec = vec![12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11];
+
+ vec.dedup();
+
+ assert_eq!(vec, [12, 11]);
+}
+
+#[test]
+fn test_vec_dedup_partialeq() {
+ #[derive(Debug)]
+ struct Foo(i32, i32);
+
+ impl PartialEq for Foo {
+ fn eq(&self, other: &Foo) -> bool {
+ self.0 == other.0
+ }
+ }
+
+ let mut vec = vec![Foo(0, 1), Foo(0, 5), Foo(1, 7), Foo(1, 9)];
+
+ vec.dedup();
+ assert_eq!(vec, [Foo(0, 1), Foo(1, 7)]);
+}
+
+#[test]
+fn test_vec_dedup() {
+ let mut vec: Vec<bool> = Vec::with_capacity(8);
+ let mut template = vec.clone();
+
+ for x in 0u8..255u8 {
+ vec.clear();
+ template.clear();
+
+ let iter = (0..8).map(move |bit| (x >> bit) & 1 == 1);
+ vec.extend(iter);
+ template.extend_from_slice(&vec);
+
+ let (dedup, _) = template.partition_dedup();
+ vec.dedup();
+
+ assert_eq!(vec, dedup);
+ }
+}
+
+#[test]
+fn test_vec_dedup_panicking() {
+ #[derive(Debug)]
+ struct Panic<'a> {
+ drop_counter: &'a Cell<u32>,
+ value: bool,
+ index: usize,
+ }
+
+ impl<'a> PartialEq for Panic<'a> {
+ fn eq(&self, other: &Self) -> bool {
+ self.value == other.value
+ }
+ }
+
+ impl<'a> Drop for Panic<'a> {
+ fn drop(&mut self) {
+ self.drop_counter.set(self.drop_counter.get() + 1);
+ if !std::thread::panicking() {
+ assert!(self.index != 4);
+ }
+ }
+ }
+
+ let drop_counter = &Cell::new(0);
+ let expected = [
+ Panic { drop_counter, value: false, index: 0 },
+ Panic { drop_counter, value: false, index: 5 },
+ Panic { drop_counter, value: true, index: 6 },
+ Panic { drop_counter, value: true, index: 7 },
+ ];
+ let mut vec = vec![
+ Panic { drop_counter, value: false, index: 0 },
+ // these elements get deduplicated
+ Panic { drop_counter, value: false, index: 1 },
+ Panic { drop_counter, value: false, index: 2 },
+ Panic { drop_counter, value: false, index: 3 },
+ Panic { drop_counter, value: false, index: 4 },
+ // here it panics while dropping the item with index==4
+ Panic { drop_counter, value: false, index: 5 },
+ Panic { drop_counter, value: true, index: 6 },
+ Panic { drop_counter, value: true, index: 7 },
+ ];
+
+ let _ = catch_unwind(AssertUnwindSafe(|| vec.dedup())).unwrap_err();
+
+ assert_eq!(drop_counter.get(), 4);
+
+ let ok = vec.iter().zip(expected.iter()).all(|(x, y)| x.index == y.index);
+
+ if !ok {
+ panic!("expected: {expected:?}\ngot: {vec:?}\n");
+ }
+}
+
+// Regression test for issue #82533
+#[test]
+fn test_extend_from_within_panicing_clone() {
+ struct Panic<'dc> {
+ drop_count: &'dc AtomicU32,
+ aaaaa: bool,
+ }
+
+ impl Clone for Panic<'_> {
+ fn clone(&self) -> Self {
+ if self.aaaaa {
+ panic!("panic! at the clone");
+ }
+
+ Self { ..*self }
+ }
+ }
+
+ impl Drop for Panic<'_> {
+ fn drop(&mut self) {
+ self.drop_count.fetch_add(1, Ordering::SeqCst);
+ }
+ }
+
+ let count = core::sync::atomic::AtomicU32::new(0);
+ let mut vec = vec![
+ Panic { drop_count: &count, aaaaa: false },
+ Panic { drop_count: &count, aaaaa: true },
+ Panic { drop_count: &count, aaaaa: false },
+ ];
+
+ // This should clone&append one Panic{..} at the end, and then panic while
+ // cloning second Panic{..}. This means that `Panic::drop` should be called
+ // 4 times (3 for items already in vector, 1 for just appended).
+ //
+ // Previously just appended item was leaked, making drop_count = 3, instead of 4.
+ std::panic::catch_unwind(move || vec.extend_from_within(..)).unwrap_err();
+
+ assert_eq!(count.load(Ordering::SeqCst), 4);
+}
+
+#[test]
+#[should_panic = "vec len overflow"]
+fn test_into_flattened_size_overflow() {
+ let v = vec![[(); usize::MAX]; 2];
+ let _ = v.into_flattened();
+}
diff --git a/library/alloc/tests/vec_deque.rs b/library/alloc/tests/vec_deque.rs
new file mode 100644
index 000000000..89cc7f905
--- /dev/null
+++ b/library/alloc/tests/vec_deque.rs
@@ -0,0 +1,1786 @@
+use std::assert_matches::assert_matches;
+use std::collections::TryReserveErrorKind::*;
+use std::collections::{vec_deque::Drain, VecDeque};
+use std::fmt::Debug;
+use std::mem::size_of;
+use std::ops::Bound::*;
+use std::panic::{catch_unwind, AssertUnwindSafe};
+
+use crate::hash;
+
+use Taggy::*;
+use Taggypar::*;
+
+#[test]
+fn test_simple() {
+ let mut d = VecDeque::new();
+ assert_eq!(d.len(), 0);
+ d.push_front(17);
+ d.push_front(42);
+ d.push_back(137);
+ assert_eq!(d.len(), 3);
+ d.push_back(137);
+ assert_eq!(d.len(), 4);
+ assert_eq!(*d.front().unwrap(), 42);
+ assert_eq!(*d.back().unwrap(), 137);
+ let mut i = d.pop_front();
+ assert_eq!(i, Some(42));
+ i = d.pop_back();
+ assert_eq!(i, Some(137));
+ i = d.pop_back();
+ assert_eq!(i, Some(137));
+ i = d.pop_back();
+ assert_eq!(i, Some(17));
+ assert_eq!(d.len(), 0);
+ d.push_back(3);
+ assert_eq!(d.len(), 1);
+ d.push_front(2);
+ assert_eq!(d.len(), 2);
+ d.push_back(4);
+ assert_eq!(d.len(), 3);
+ d.push_front(1);
+ assert_eq!(d.len(), 4);
+ assert_eq!(d[0], 1);
+ assert_eq!(d[1], 2);
+ assert_eq!(d[2], 3);
+ assert_eq!(d[3], 4);
+}
+
+fn test_parameterized<T: Clone + PartialEq + Debug>(a: T, b: T, c: T, d: T) {
+ let mut deq = VecDeque::new();
+ assert_eq!(deq.len(), 0);
+ deq.push_front(a.clone());
+ deq.push_front(b.clone());
+ deq.push_back(c.clone());
+ assert_eq!(deq.len(), 3);
+ deq.push_back(d.clone());
+ assert_eq!(deq.len(), 4);
+ assert_eq!((*deq.front().unwrap()).clone(), b.clone());
+ assert_eq!((*deq.back().unwrap()).clone(), d.clone());
+ assert_eq!(deq.pop_front().unwrap(), b.clone());
+ assert_eq!(deq.pop_back().unwrap(), d.clone());
+ assert_eq!(deq.pop_back().unwrap(), c.clone());
+ assert_eq!(deq.pop_back().unwrap(), a.clone());
+ assert_eq!(deq.len(), 0);
+ deq.push_back(c.clone());
+ assert_eq!(deq.len(), 1);
+ deq.push_front(b.clone());
+ assert_eq!(deq.len(), 2);
+ deq.push_back(d.clone());
+ assert_eq!(deq.len(), 3);
+ deq.push_front(a.clone());
+ assert_eq!(deq.len(), 4);
+ assert_eq!(deq[0].clone(), a.clone());
+ assert_eq!(deq[1].clone(), b.clone());
+ assert_eq!(deq[2].clone(), c.clone());
+ assert_eq!(deq[3].clone(), d.clone());
+}
+
+#[test]
+fn test_push_front_grow() {
+ let mut deq = VecDeque::new();
+ for i in 0..66 {
+ deq.push_front(i);
+ }
+ assert_eq!(deq.len(), 66);
+
+ for i in 0..66 {
+ assert_eq!(deq[i], 65 - i);
+ }
+
+ let mut deq = VecDeque::new();
+ for i in 0..66 {
+ deq.push_back(i);
+ }
+
+ for i in 0..66 {
+ assert_eq!(deq[i], i);
+ }
+}
+
+#[test]
+fn test_index() {
+ let mut deq = VecDeque::new();
+ for i in 1..4 {
+ deq.push_front(i);
+ }
+ assert_eq!(deq[1], 2);
+}
+
+#[test]
+#[should_panic]
+fn test_index_out_of_bounds() {
+ let mut deq = VecDeque::new();
+ for i in 1..4 {
+ deq.push_front(i);
+ }
+ deq[3];
+}
+
+#[test]
+#[should_panic]
+fn test_range_start_overflow() {
+ let deq = VecDeque::from(vec![1, 2, 3]);
+ deq.range((Included(0), Included(usize::MAX)));
+}
+
+#[test]
+#[should_panic]
+fn test_range_end_overflow() {
+ let deq = VecDeque::from(vec![1, 2, 3]);
+ deq.range((Excluded(usize::MAX), Included(0)));
+}
+
+#[derive(Clone, PartialEq, Debug)]
+enum Taggy {
+ One(i32),
+ Two(i32, i32),
+ Three(i32, i32, i32),
+}
+
+#[derive(Clone, PartialEq, Debug)]
+enum Taggypar<T> {
+ Onepar(T),
+ Twopar(T, T),
+ Threepar(T, T, T),
+}
+
+#[derive(Clone, PartialEq, Debug)]
+struct RecCy {
+ x: i32,
+ y: i32,
+ t: Taggy,
+}
+
+#[test]
+fn test_param_int() {
+ test_parameterized::<i32>(5, 72, 64, 175);
+}
+
+#[test]
+fn test_param_taggy() {
+ test_parameterized::<Taggy>(One(1), Two(1, 2), Three(1, 2, 3), Two(17, 42));
+}
+
+#[test]
+fn test_param_taggypar() {
+ test_parameterized::<Taggypar<i32>>(
+ Onepar::<i32>(1),
+ Twopar::<i32>(1, 2),
+ Threepar::<i32>(1, 2, 3),
+ Twopar::<i32>(17, 42),
+ );
+}
+
+#[test]
+fn test_param_reccy() {
+ let reccy1 = RecCy { x: 1, y: 2, t: One(1) };
+ let reccy2 = RecCy { x: 345, y: 2, t: Two(1, 2) };
+ let reccy3 = RecCy { x: 1, y: 777, t: Three(1, 2, 3) };
+ let reccy4 = RecCy { x: 19, y: 252, t: Two(17, 42) };
+ test_parameterized::<RecCy>(reccy1, reccy2, reccy3, reccy4);
+}
+
+#[test]
+fn test_with_capacity() {
+ let mut d = VecDeque::with_capacity(0);
+ d.push_back(1);
+ assert_eq!(d.len(), 1);
+ let mut d = VecDeque::with_capacity(50);
+ d.push_back(1);
+ assert_eq!(d.len(), 1);
+}
+
+#[test]
+fn test_with_capacity_non_power_two() {
+ let mut d3 = VecDeque::with_capacity(3);
+ d3.push_back(1);
+
+ // X = None, | = lo
+ // [|1, X, X]
+ assert_eq!(d3.pop_front(), Some(1));
+ // [X, |X, X]
+ assert_eq!(d3.front(), None);
+
+ // [X, |3, X]
+ d3.push_back(3);
+ // [X, |3, 6]
+ d3.push_back(6);
+ // [X, X, |6]
+ assert_eq!(d3.pop_front(), Some(3));
+
+ // Pushing the lo past half way point to trigger
+ // the 'B' scenario for growth
+ // [9, X, |6]
+ d3.push_back(9);
+ // [9, 12, |6]
+ d3.push_back(12);
+
+ d3.push_back(15);
+ // There used to be a bug here about how the
+ // VecDeque made growth assumptions about the
+ // underlying Vec which didn't hold and lead
+ // to corruption.
+ // (Vec grows to next power of two)
+ // good- [9, 12, 15, X, X, X, X, |6]
+ // bug- [15, 12, X, X, X, |6, X, X]
+ assert_eq!(d3.pop_front(), Some(6));
+
+ // Which leads us to the following state which
+ // would be a failure case.
+ // bug- [15, 12, X, X, X, X, |X, X]
+ assert_eq!(d3.front(), Some(&9));
+}
+
+#[test]
+fn test_reserve_exact() {
+ let mut d = VecDeque::new();
+ d.push_back(0);
+ d.reserve_exact(50);
+ assert!(d.capacity() >= 51);
+}
+
+#[test]
+fn test_reserve() {
+ let mut d = VecDeque::new();
+ d.push_back(0);
+ d.reserve(50);
+ assert!(d.capacity() >= 51);
+}
+
+#[test]
+fn test_swap() {
+ let mut d: VecDeque<_> = (0..5).collect();
+ d.pop_front();
+ d.swap(0, 3);
+ assert_eq!(d.iter().cloned().collect::<Vec<_>>(), [4, 2, 3, 1]);
+}
+
+#[test]
+fn test_iter() {
+ let mut d = VecDeque::new();
+ assert_eq!(d.iter().next(), None);
+ assert_eq!(d.iter().size_hint(), (0, Some(0)));
+
+ for i in 0..5 {
+ d.push_back(i);
+ }
+ {
+ let b: &[_] = &[&0, &1, &2, &3, &4];
+ assert_eq!(d.iter().collect::<Vec<_>>(), b);
+ }
+
+ for i in 6..9 {
+ d.push_front(i);
+ }
+ {
+ let b: &[_] = &[&8, &7, &6, &0, &1, &2, &3, &4];
+ assert_eq!(d.iter().collect::<Vec<_>>(), b);
+ }
+
+ let mut it = d.iter();
+ let mut len = d.len();
+ loop {
+ match it.next() {
+ None => break,
+ _ => {
+ len -= 1;
+ assert_eq!(it.size_hint(), (len, Some(len)))
+ }
+ }
+ }
+}
+
+#[test]
+fn test_rev_iter() {
+ let mut d = VecDeque::new();
+ assert_eq!(d.iter().rev().next(), None);
+
+ for i in 0..5 {
+ d.push_back(i);
+ }
+ {
+ let b: &[_] = &[&4, &3, &2, &1, &0];
+ assert_eq!(d.iter().rev().collect::<Vec<_>>(), b);
+ }
+
+ for i in 6..9 {
+ d.push_front(i);
+ }
+ let b: &[_] = &[&4, &3, &2, &1, &0, &6, &7, &8];
+ assert_eq!(d.iter().rev().collect::<Vec<_>>(), b);
+}
+
+#[test]
+fn test_mut_rev_iter_wrap() {
+ let mut d = VecDeque::with_capacity(3);
+ assert!(d.iter_mut().rev().next().is_none());
+
+ d.push_back(1);
+ d.push_back(2);
+ d.push_back(3);
+ assert_eq!(d.pop_front(), Some(1));
+ d.push_back(4);
+
+ assert_eq!(d.iter_mut().rev().map(|x| *x).collect::<Vec<_>>(), vec![4, 3, 2]);
+}
+
+#[test]
+fn test_mut_iter() {
+ let mut d = VecDeque::new();
+ assert!(d.iter_mut().next().is_none());
+
+ for i in 0..3 {
+ d.push_front(i);
+ }
+
+ for (i, elt) in d.iter_mut().enumerate() {
+ assert_eq!(*elt, 2 - i);
+ *elt = i;
+ }
+
+ {
+ let mut it = d.iter_mut();
+ assert_eq!(*it.next().unwrap(), 0);
+ assert_eq!(*it.next().unwrap(), 1);
+ assert_eq!(*it.next().unwrap(), 2);
+ assert!(it.next().is_none());
+ }
+}
+
+#[test]
+fn test_mut_rev_iter() {
+ let mut d = VecDeque::new();
+ assert!(d.iter_mut().rev().next().is_none());
+
+ for i in 0..3 {
+ d.push_front(i);
+ }
+
+ for (i, elt) in d.iter_mut().rev().enumerate() {
+ assert_eq!(*elt, i);
+ *elt = i;
+ }
+
+ {
+ let mut it = d.iter_mut().rev();
+ assert_eq!(*it.next().unwrap(), 0);
+ assert_eq!(*it.next().unwrap(), 1);
+ assert_eq!(*it.next().unwrap(), 2);
+ assert!(it.next().is_none());
+ }
+}
+
+#[test]
+fn test_into_iter() {
+ // Empty iter
+ {
+ let d: VecDeque<i32> = VecDeque::new();
+ let mut iter = d.into_iter();
+
+ assert_eq!(iter.size_hint(), (0, Some(0)));
+ assert_eq!(iter.next(), None);
+ assert_eq!(iter.size_hint(), (0, Some(0)));
+ }
+
+ // simple iter
+ {
+ let mut d = VecDeque::new();
+ for i in 0..5 {
+ d.push_back(i);
+ }
+
+ let b = vec![0, 1, 2, 3, 4];
+ assert_eq!(d.into_iter().collect::<Vec<_>>(), b);
+ }
+
+ // wrapped iter
+ {
+ let mut d = VecDeque::new();
+ for i in 0..5 {
+ d.push_back(i);
+ }
+ for i in 6..9 {
+ d.push_front(i);
+ }
+
+ let b = vec![8, 7, 6, 0, 1, 2, 3, 4];
+ assert_eq!(d.into_iter().collect::<Vec<_>>(), b);
+ }
+
+ // partially used
+ {
+ let mut d = VecDeque::new();
+ for i in 0..5 {
+ d.push_back(i);
+ }
+ for i in 6..9 {
+ d.push_front(i);
+ }
+
+ let mut it = d.into_iter();
+ assert_eq!(it.size_hint(), (8, Some(8)));
+ assert_eq!(it.next(), Some(8));
+ assert_eq!(it.size_hint(), (7, Some(7)));
+ assert_eq!(it.next_back(), Some(4));
+ assert_eq!(it.size_hint(), (6, Some(6)));
+ assert_eq!(it.next(), Some(7));
+ assert_eq!(it.size_hint(), (5, Some(5)));
+ }
+}
+
+#[test]
+fn test_drain() {
+ // Empty iter
+ {
+ let mut d: VecDeque<i32> = VecDeque::new();
+
+ {
+ let mut iter = d.drain(..);
+
+ assert_eq!(iter.size_hint(), (0, Some(0)));
+ assert_eq!(iter.next(), None);
+ assert_eq!(iter.size_hint(), (0, Some(0)));
+ }
+
+ assert!(d.is_empty());
+ }
+
+ // simple iter
+ {
+ let mut d = VecDeque::new();
+ for i in 0..5 {
+ d.push_back(i);
+ }
+
+ assert_eq!(d.drain(..).collect::<Vec<_>>(), [0, 1, 2, 3, 4]);
+ assert!(d.is_empty());
+ }
+
+ // wrapped iter
+ {
+ let mut d = VecDeque::new();
+ for i in 0..5 {
+ d.push_back(i);
+ }
+ for i in 6..9 {
+ d.push_front(i);
+ }
+
+ assert_eq!(d.drain(..).collect::<Vec<_>>(), [8, 7, 6, 0, 1, 2, 3, 4]);
+ assert!(d.is_empty());
+ }
+
+ // partially used
+ {
+ let mut d: VecDeque<_> = VecDeque::new();
+ for i in 0..5 {
+ d.push_back(i);
+ }
+ for i in 6..9 {
+ d.push_front(i);
+ }
+
+ {
+ let mut it = d.drain(..);
+ assert_eq!(it.size_hint(), (8, Some(8)));
+ assert_eq!(it.next(), Some(8));
+ assert_eq!(it.size_hint(), (7, Some(7)));
+ assert_eq!(it.next_back(), Some(4));
+ assert_eq!(it.size_hint(), (6, Some(6)));
+ assert_eq!(it.next(), Some(7));
+ assert_eq!(it.size_hint(), (5, Some(5)));
+ }
+ assert!(d.is_empty());
+ }
+}
+
+#[test]
+fn test_from_iter() {
+ let v = vec![1, 2, 3, 4, 5, 6, 7];
+ let deq: VecDeque<_> = v.iter().cloned().collect();
+ let u: Vec<_> = deq.iter().cloned().collect();
+ assert_eq!(u, v);
+
+ let seq = (0..).step_by(2).take(256);
+ let deq: VecDeque<_> = seq.collect();
+ for (i, &x) in deq.iter().enumerate() {
+ assert_eq!(2 * i, x);
+ }
+ assert_eq!(deq.len(), 256);
+}
+
+#[test]
+fn test_clone() {
+ let mut d = VecDeque::new();
+ d.push_front(17);
+ d.push_front(42);
+ d.push_back(137);
+ d.push_back(137);
+ assert_eq!(d.len(), 4);
+ let mut e = d.clone();
+ assert_eq!(e.len(), 4);
+ while !d.is_empty() {
+ assert_eq!(d.pop_back(), e.pop_back());
+ }
+ assert_eq!(d.len(), 0);
+ assert_eq!(e.len(), 0);
+}
+
+#[test]
+fn test_eq() {
+ let mut d = VecDeque::new();
+ assert!(d == VecDeque::with_capacity(0));
+ d.push_front(137);
+ d.push_front(17);
+ d.push_front(42);
+ d.push_back(137);
+ let mut e = VecDeque::with_capacity(0);
+ e.push_back(42);
+ e.push_back(17);
+ e.push_back(137);
+ e.push_back(137);
+ assert!(&e == &d);
+ e.pop_back();
+ e.push_back(0);
+ assert!(e != d);
+ e.clear();
+ assert!(e == VecDeque::new());
+}
+
+#[test]
+fn test_partial_eq_array() {
+ let d = VecDeque::<char>::new();
+ assert!(d == []);
+
+ let mut d = VecDeque::new();
+ d.push_front('a');
+ assert!(d == ['a']);
+
+ let mut d = VecDeque::new();
+ d.push_back('a');
+ assert!(d == ['a']);
+
+ let mut d = VecDeque::new();
+ d.push_back('a');
+ d.push_back('b');
+ assert!(d == ['a', 'b']);
+}
+
+#[test]
+fn test_hash() {
+ let mut x = VecDeque::new();
+ let mut y = VecDeque::new();
+
+ x.push_back(1);
+ x.push_back(2);
+ x.push_back(3);
+
+ y.push_back(0);
+ y.push_back(1);
+ y.pop_front();
+ y.push_back(2);
+ y.push_back(3);
+
+ assert!(hash(&x) == hash(&y));
+}
+
+#[test]
+fn test_hash_after_rotation() {
+ // test that two deques hash equal even if elements are laid out differently
+ let len = 28;
+ let mut ring: VecDeque<i32> = (0..len as i32).collect();
+ let orig = ring.clone();
+ for _ in 0..ring.capacity() {
+ // shift values 1 step to the right by pop, sub one, push
+ ring.pop_front();
+ for elt in &mut ring {
+ *elt -= 1;
+ }
+ ring.push_back(len - 1);
+ assert_eq!(hash(&orig), hash(&ring));
+ assert_eq!(orig, ring);
+ assert_eq!(ring, orig);
+ }
+}
+
+#[test]
+fn test_eq_after_rotation() {
+ // test that two deques are equal even if elements are laid out differently
+ let len = 28;
+ let mut ring: VecDeque<i32> = (0..len as i32).collect();
+ let mut shifted = ring.clone();
+ for _ in 0..10 {
+ // shift values 1 step to the right by pop, sub one, push
+ ring.pop_front();
+ for elt in &mut ring {
+ *elt -= 1;
+ }
+ ring.push_back(len - 1);
+ }
+
+ // try every shift
+ for _ in 0..shifted.capacity() {
+ shifted.pop_front();
+ for elt in &mut shifted {
+ *elt -= 1;
+ }
+ shifted.push_back(len - 1);
+ assert_eq!(shifted, ring);
+ assert_eq!(ring, shifted);
+ }
+}
+
+#[test]
+fn test_ord() {
+ let x = VecDeque::new();
+ let mut y = VecDeque::new();
+ y.push_back(1);
+ y.push_back(2);
+ y.push_back(3);
+ assert!(x < y);
+ assert!(y > x);
+ assert!(x <= x);
+ assert!(x >= x);
+}
+
+#[test]
+fn test_show() {
+ let ringbuf: VecDeque<_> = (0..10).collect();
+ assert_eq!(format!("{ringbuf:?}"), "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]");
+
+ let ringbuf: VecDeque<_> = vec!["just", "one", "test", "more"].iter().cloned().collect();
+ assert_eq!(format!("{ringbuf:?}"), "[\"just\", \"one\", \"test\", \"more\"]");
+}
+
+#[test]
+fn test_drop() {
+ static mut DROPS: i32 = 0;
+ struct Elem;
+ impl Drop for Elem {
+ fn drop(&mut self) {
+ unsafe {
+ DROPS += 1;
+ }
+ }
+ }
+
+ let mut ring = VecDeque::new();
+ ring.push_back(Elem);
+ ring.push_front(Elem);
+ ring.push_back(Elem);
+ ring.push_front(Elem);
+ drop(ring);
+
+ assert_eq!(unsafe { DROPS }, 4);
+}
+
+#[test]
+fn test_drop_with_pop() {
+ static mut DROPS: i32 = 0;
+ struct Elem;
+ impl Drop for Elem {
+ fn drop(&mut self) {
+ unsafe {
+ DROPS += 1;
+ }
+ }
+ }
+
+ let mut ring = VecDeque::new();
+ ring.push_back(Elem);
+ ring.push_front(Elem);
+ ring.push_back(Elem);
+ ring.push_front(Elem);
+
+ drop(ring.pop_back());
+ drop(ring.pop_front());
+ assert_eq!(unsafe { DROPS }, 2);
+
+ drop(ring);
+ assert_eq!(unsafe { DROPS }, 4);
+}
+
+#[test]
+fn test_drop_clear() {
+ static mut DROPS: i32 = 0;
+ struct Elem;
+ impl Drop for Elem {
+ fn drop(&mut self) {
+ unsafe {
+ DROPS += 1;
+ }
+ }
+ }
+
+ let mut ring = VecDeque::new();
+ ring.push_back(Elem);
+ ring.push_front(Elem);
+ ring.push_back(Elem);
+ ring.push_front(Elem);
+ ring.clear();
+ assert_eq!(unsafe { DROPS }, 4);
+
+ drop(ring);
+ assert_eq!(unsafe { DROPS }, 4);
+}
+
+#[test]
+fn test_drop_panic() {
+ static mut DROPS: i32 = 0;
+
+ struct D(bool);
+
+ impl Drop for D {
+ fn drop(&mut self) {
+ unsafe {
+ DROPS += 1;
+ }
+
+ if self.0 {
+ panic!("panic in `drop`");
+ }
+ }
+ }
+
+ let mut q = VecDeque::new();
+ q.push_back(D(false));
+ q.push_back(D(false));
+ q.push_back(D(false));
+ q.push_back(D(false));
+ q.push_back(D(false));
+ q.push_front(D(false));
+ q.push_front(D(false));
+ q.push_front(D(true));
+
+ catch_unwind(move || drop(q)).ok();
+
+ assert_eq!(unsafe { DROPS }, 8);
+}
+
+#[test]
+fn test_reserve_grow() {
+ // test growth path A
+ // [T o o H] -> [T o o H . . . . ]
+ let mut ring = VecDeque::with_capacity(4);
+ for i in 0..3 {
+ ring.push_back(i);
+ }
+ ring.reserve(7);
+ for i in 0..3 {
+ assert_eq!(ring.pop_front(), Some(i));
+ }
+
+ // test growth path B
+ // [H T o o] -> [. T o o H . . . ]
+ let mut ring = VecDeque::with_capacity(4);
+ for i in 0..1 {
+ ring.push_back(i);
+ assert_eq!(ring.pop_front(), Some(i));
+ }
+ for i in 0..3 {
+ ring.push_back(i);
+ }
+ ring.reserve(7);
+ for i in 0..3 {
+ assert_eq!(ring.pop_front(), Some(i));
+ }
+
+ // test growth path C
+ // [o o H T] -> [o o H . . . . T ]
+ let mut ring = VecDeque::with_capacity(4);
+ for i in 0..3 {
+ ring.push_back(i);
+ assert_eq!(ring.pop_front(), Some(i));
+ }
+ for i in 0..3 {
+ ring.push_back(i);
+ }
+ ring.reserve(7);
+ for i in 0..3 {
+ assert_eq!(ring.pop_front(), Some(i));
+ }
+}
+
+#[test]
+fn test_get() {
+ let mut ring = VecDeque::new();
+ ring.push_back(0);
+ assert_eq!(ring.get(0), Some(&0));
+ assert_eq!(ring.get(1), None);
+
+ ring.push_back(1);
+ assert_eq!(ring.get(0), Some(&0));
+ assert_eq!(ring.get(1), Some(&1));
+ assert_eq!(ring.get(2), None);
+
+ ring.push_back(2);
+ assert_eq!(ring.get(0), Some(&0));
+ assert_eq!(ring.get(1), Some(&1));
+ assert_eq!(ring.get(2), Some(&2));
+ assert_eq!(ring.get(3), None);
+
+ assert_eq!(ring.pop_front(), Some(0));
+ assert_eq!(ring.get(0), Some(&1));
+ assert_eq!(ring.get(1), Some(&2));
+ assert_eq!(ring.get(2), None);
+
+ assert_eq!(ring.pop_front(), Some(1));
+ assert_eq!(ring.get(0), Some(&2));
+ assert_eq!(ring.get(1), None);
+
+ assert_eq!(ring.pop_front(), Some(2));
+ assert_eq!(ring.get(0), None);
+ assert_eq!(ring.get(1), None);
+}
+
+#[test]
+fn test_get_mut() {
+ let mut ring = VecDeque::new();
+ for i in 0..3 {
+ ring.push_back(i);
+ }
+
+ match ring.get_mut(1) {
+ Some(x) => *x = -1,
+ None => (),
+ };
+
+ assert_eq!(ring.get_mut(0), Some(&mut 0));
+ assert_eq!(ring.get_mut(1), Some(&mut -1));
+ assert_eq!(ring.get_mut(2), Some(&mut 2));
+ assert_eq!(ring.get_mut(3), None);
+
+ assert_eq!(ring.pop_front(), Some(0));
+ assert_eq!(ring.get_mut(0), Some(&mut -1));
+ assert_eq!(ring.get_mut(1), Some(&mut 2));
+ assert_eq!(ring.get_mut(2), None);
+}
+
+#[test]
+fn test_front() {
+ let mut ring = VecDeque::new();
+ ring.push_back(10);
+ ring.push_back(20);
+ assert_eq!(ring.front(), Some(&10));
+ ring.pop_front();
+ assert_eq!(ring.front(), Some(&20));
+ ring.pop_front();
+ assert_eq!(ring.front(), None);
+}
+
+#[test]
+fn test_as_slices() {
+ let mut ring: VecDeque<i32> = VecDeque::with_capacity(127);
+ let cap = ring.capacity() as i32;
+ let first = cap / 2;
+ let last = cap - first;
+ for i in 0..first {
+ ring.push_back(i);
+
+ let (left, right) = ring.as_slices();
+ let expected: Vec<_> = (0..=i).collect();
+ assert_eq!(left, &expected[..]);
+ assert_eq!(right, []);
+ }
+
+ for j in -last..0 {
+ ring.push_front(j);
+ let (left, right) = ring.as_slices();
+ let expected_left: Vec<_> = (-last..=j).rev().collect();
+ let expected_right: Vec<_> = (0..first).collect();
+ assert_eq!(left, &expected_left[..]);
+ assert_eq!(right, &expected_right[..]);
+ }
+
+ assert_eq!(ring.len() as i32, cap);
+ assert_eq!(ring.capacity() as i32, cap);
+}
+
+#[test]
+fn test_as_mut_slices() {
+ let mut ring: VecDeque<i32> = VecDeque::with_capacity(127);
+ let cap = ring.capacity() as i32;
+ let first = cap / 2;
+ let last = cap - first;
+ for i in 0..first {
+ ring.push_back(i);
+
+ let (left, right) = ring.as_mut_slices();
+ let expected: Vec<_> = (0..=i).collect();
+ assert_eq!(left, &expected[..]);
+ assert_eq!(right, []);
+ }
+
+ for j in -last..0 {
+ ring.push_front(j);
+ let (left, right) = ring.as_mut_slices();
+ let expected_left: Vec<_> = (-last..=j).rev().collect();
+ let expected_right: Vec<_> = (0..first).collect();
+ assert_eq!(left, &expected_left[..]);
+ assert_eq!(right, &expected_right[..]);
+ }
+
+ assert_eq!(ring.len() as i32, cap);
+ assert_eq!(ring.capacity() as i32, cap);
+}
+
+#[test]
+fn test_append() {
+ let mut a: VecDeque<_> = [1, 2, 3].into_iter().collect();
+ let mut b: VecDeque<_> = [4, 5, 6].into_iter().collect();
+
+ // normal append
+ a.append(&mut b);
+ assert_eq!(a.iter().cloned().collect::<Vec<_>>(), [1, 2, 3, 4, 5, 6]);
+ assert_eq!(b.iter().cloned().collect::<Vec<_>>(), []);
+
+ // append nothing to something
+ a.append(&mut b);
+ assert_eq!(a.iter().cloned().collect::<Vec<_>>(), [1, 2, 3, 4, 5, 6]);
+ assert_eq!(b.iter().cloned().collect::<Vec<_>>(), []);
+
+ // append something to nothing
+ b.append(&mut a);
+ assert_eq!(b.iter().cloned().collect::<Vec<_>>(), [1, 2, 3, 4, 5, 6]);
+ assert_eq!(a.iter().cloned().collect::<Vec<_>>(), []);
+}
+
+#[test]
+fn test_append_permutations() {
+ fn construct_vec_deque(
+ push_back: usize,
+ pop_back: usize,
+ push_front: usize,
+ pop_front: usize,
+ ) -> VecDeque<usize> {
+ let mut out = VecDeque::new();
+ for a in 0..push_back {
+ out.push_back(a);
+ }
+ for b in 0..push_front {
+ out.push_front(push_back + b);
+ }
+ for _ in 0..pop_back {
+ out.pop_back();
+ }
+ for _ in 0..pop_front {
+ out.pop_front();
+ }
+ out
+ }
+
+ // Miri is too slow
+ let max = if cfg!(miri) { 3 } else { 5 };
+
+ // Many different permutations of both the `VecDeque` getting appended to
+ // and the one getting appended are generated to check `append`.
+ // This ensures all 6 code paths of `append` are tested.
+ for src_push_back in 0..max {
+ for src_push_front in 0..max {
+ // doesn't pop more values than are pushed
+ for src_pop_back in 0..(src_push_back + src_push_front) {
+ for src_pop_front in 0..(src_push_back + src_push_front - src_pop_back) {
+ let src = construct_vec_deque(
+ src_push_back,
+ src_pop_back,
+ src_push_front,
+ src_pop_front,
+ );
+
+ for dst_push_back in 0..max {
+ for dst_push_front in 0..max {
+ for dst_pop_back in 0..(dst_push_back + dst_push_front) {
+ for dst_pop_front in
+ 0..(dst_push_back + dst_push_front - dst_pop_back)
+ {
+ let mut dst = construct_vec_deque(
+ dst_push_back,
+ dst_pop_back,
+ dst_push_front,
+ dst_pop_front,
+ );
+ let mut src = src.clone();
+
+ // Assert that appending `src` to `dst` gives the same order
+ // of values as iterating over both in sequence.
+ let correct = dst
+ .iter()
+ .chain(src.iter())
+ .cloned()
+ .collect::<Vec<usize>>();
+ dst.append(&mut src);
+ assert_eq!(dst, correct);
+ assert!(src.is_empty());
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+struct DropCounter<'a> {
+ count: &'a mut u32,
+}
+
+impl Drop for DropCounter<'_> {
+ fn drop(&mut self) {
+ *self.count += 1;
+ }
+}
+
+#[test]
+fn test_append_double_drop() {
+ let (mut count_a, mut count_b) = (0, 0);
+ {
+ let mut a = VecDeque::new();
+ let mut b = VecDeque::new();
+ a.push_back(DropCounter { count: &mut count_a });
+ b.push_back(DropCounter { count: &mut count_b });
+
+ a.append(&mut b);
+ }
+ assert_eq!(count_a, 1);
+ assert_eq!(count_b, 1);
+}
+
+#[test]
+fn test_retain() {
+ let mut buf = VecDeque::new();
+ buf.extend(1..5);
+ buf.retain(|&x| x % 2 == 0);
+ let v: Vec<_> = buf.into_iter().collect();
+ assert_eq!(&v[..], &[2, 4]);
+}
+
+#[test]
+fn test_extend_ref() {
+ let mut v = VecDeque::new();
+ v.push_back(1);
+ v.extend(&[2, 3, 4]);
+
+ assert_eq!(v.len(), 4);
+ assert_eq!(v[0], 1);
+ assert_eq!(v[1], 2);
+ assert_eq!(v[2], 3);
+ assert_eq!(v[3], 4);
+
+ let mut w = VecDeque::new();
+ w.push_back(5);
+ w.push_back(6);
+ v.extend(&w);
+
+ assert_eq!(v.len(), 6);
+ assert_eq!(v[0], 1);
+ assert_eq!(v[1], 2);
+ assert_eq!(v[2], 3);
+ assert_eq!(v[3], 4);
+ assert_eq!(v[4], 5);
+ assert_eq!(v[5], 6);
+}
+
+#[test]
+fn test_contains() {
+ let mut v = VecDeque::new();
+ v.extend(&[2, 3, 4]);
+
+ assert!(v.contains(&3));
+ assert!(!v.contains(&1));
+
+ v.clear();
+
+ assert!(!v.contains(&3));
+}
+
+#[allow(dead_code)]
+fn assert_covariance() {
+ fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> {
+ d
+ }
+}
+
+#[test]
+fn test_is_empty() {
+ let mut v = VecDeque::<i32>::new();
+ assert!(v.is_empty());
+ assert!(v.iter().is_empty());
+ assert!(v.iter_mut().is_empty());
+ v.extend(&[2, 3, 4]);
+ assert!(!v.is_empty());
+ assert!(!v.iter().is_empty());
+ assert!(!v.iter_mut().is_empty());
+ while let Some(_) = v.pop_front() {
+ assert_eq!(v.is_empty(), v.len() == 0);
+ assert_eq!(v.iter().is_empty(), v.iter().len() == 0);
+ assert_eq!(v.iter_mut().is_empty(), v.iter_mut().len() == 0);
+ }
+ assert!(v.is_empty());
+ assert!(v.iter().is_empty());
+ assert!(v.iter_mut().is_empty());
+ assert!(v.into_iter().is_empty());
+}
+
+#[test]
+fn test_reserve_exact_2() {
+ // This is all the same as test_reserve
+
+ let mut v = VecDeque::new();
+
+ v.reserve_exact(2);
+ assert!(v.capacity() >= 2);
+
+ for i in 0..16 {
+ v.push_back(i);
+ }
+
+ assert!(v.capacity() >= 16);
+ v.reserve_exact(16);
+ assert!(v.capacity() >= 32);
+
+ v.push_back(16);
+
+ v.reserve_exact(16);
+ assert!(v.capacity() >= 48)
+}
+
+#[test]
+#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM
+#[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc
+fn test_try_reserve() {
+ // These are the interesting cases:
+ // * exactly isize::MAX should never trigger a CapacityOverflow (can be OOM)
+ // * > isize::MAX should always fail
+ // * On 16/32-bit should CapacityOverflow
+ // * On 64-bit should OOM
+ // * overflow may trigger when adding `len` to `cap` (in number of elements)
+ // * overflow may trigger when multiplying `new_cap` by size_of::<T> (to get bytes)
+
+ const MAX_CAP: usize = (isize::MAX as usize + 1) / 2 - 1;
+ const MAX_USIZE: usize = usize::MAX;
+
+ // On 16/32-bit, we check that allocations don't exceed isize::MAX,
+ // on 64-bit, we assume the OS will give an OOM for such a ridiculous size.
+ // Any platform that succeeds for these requests is technically broken with
+ // ptr::offset because LLVM is the worst.
+ let guards_against_isize = size_of::<usize>() < 8;
+
+ {
+ // Note: basic stuff is checked by test_reserve
+ let mut empty_bytes: VecDeque<u8> = VecDeque::new();
+
+ // Check isize::MAX doesn't count as an overflow
+ if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP).map_err(|e| e.kind()) {
+ panic!("isize::MAX shouldn't trigger an overflow!");
+ }
+ // Play it again, frank! (just to be sure)
+ if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_CAP).map_err(|e| e.kind()) {
+ panic!("isize::MAX shouldn't trigger an overflow!");
+ }
+
+ if guards_against_isize {
+ // Check isize::MAX + 1 does count as overflow
+ assert_matches!(
+ empty_bytes.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()),
+ Err(CapacityOverflow),
+ "isize::MAX + 1 should trigger an overflow!"
+ );
+
+ // Check usize::MAX does count as overflow
+ assert_matches!(
+ empty_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()),
+ Err(CapacityOverflow),
+ "usize::MAX should trigger an overflow!"
+ );
+ } else {
+ // Check isize::MAX is an OOM
+ // 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
+ // furthest we can go without triggering CapacityOverflow
+ assert_matches!(
+ empty_bytes.try_reserve(MAX_CAP).map_err(|e| e.kind()),
+ Err(AllocError { .. }),
+ "isize::MAX + 1 should trigger an OOM!"
+ );
+ }
+ }
+
+ {
+ // Same basic idea, but with non-zero len
+ let mut ten_bytes: VecDeque<u8> = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
+
+ if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) {
+ panic!("isize::MAX shouldn't trigger an overflow!");
+ }
+ if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) {
+ panic!("isize::MAX shouldn't trigger an overflow!");
+ }
+ if guards_against_isize {
+ assert_matches!(
+ ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()),
+ Err(CapacityOverflow),
+ "isize::MAX + 1 should trigger an overflow!"
+ );
+ } else {
+ assert_matches!(
+ ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()),
+ Err(AllocError { .. }),
+ "isize::MAX + 1 should trigger an OOM!"
+ );
+ }
+ // Should always overflow in the add-to-len
+ assert_matches!(
+ ten_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()),
+ Err(CapacityOverflow),
+ "usize::MAX should trigger an overflow!"
+ );
+ }
+
+ {
+ // Same basic idea, but with interesting type size
+ let mut ten_u32s: VecDeque<u32> = [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).map_err(|e| e.kind())
+ {
+ panic!("isize::MAX shouldn't trigger an overflow!");
+ }
+ 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!");
+ }
+ if guards_against_isize {
+ assert_matches!(
+ ten_u32s.try_reserve(MAX_CAP / 4 - 9).map_err(|e| e.kind()),
+ Err(CapacityOverflow),
+ "isize::MAX + 1 should trigger an overflow!"
+ );
+ } else {
+ assert_matches!(
+ ten_u32s.try_reserve(MAX_CAP / 4 - 9).map_err(|e| e.kind()),
+ Err(AllocError { .. }),
+ "isize::MAX + 1 should trigger an OOM!"
+ );
+ }
+ // Should fail in the mul-by-size
+ assert_matches!(
+ ten_u32s.try_reserve(MAX_USIZE - 20).map_err(|e| e.kind()),
+ Err(CapacityOverflow),
+ "usize::MAX should trigger an overflow!"
+ );
+ }
+}
+
+#[test]
+#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM
+#[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc
+fn test_try_reserve_exact() {
+ // This is exactly the same as test_try_reserve with the method changed.
+ // See that test for comments.
+
+ const MAX_CAP: usize = (isize::MAX as usize + 1) / 2 - 1;
+ const MAX_USIZE: usize = usize::MAX;
+
+ let guards_against_isize = size_of::<usize>() < 8;
+
+ {
+ let mut empty_bytes: VecDeque<u8> = VecDeque::new();
+
+ if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP).map_err(|e| e.kind())
+ {
+ panic!("isize::MAX shouldn't trigger an overflow!");
+ }
+ if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_CAP).map_err(|e| e.kind())
+ {
+ panic!("isize::MAX shouldn't trigger an overflow!");
+ }
+
+ if guards_against_isize {
+ assert_matches!(
+ empty_bytes.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()),
+ Err(CapacityOverflow),
+ "isize::MAX + 1 should trigger an overflow!"
+ );
+
+ assert_matches!(
+ empty_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()),
+ Err(CapacityOverflow),
+ "usize::MAX should trigger an overflow!"
+ );
+ } else {
+ // Check isize::MAX is an OOM
+ // 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
+ // furthest we can go without triggering CapacityOverflow
+ assert_matches!(
+ empty_bytes.try_reserve_exact(MAX_CAP).map_err(|e| e.kind()),
+ Err(AllocError { .. }),
+ "isize::MAX + 1 should trigger an OOM!"
+ );
+ }
+ }
+
+ {
+ let mut ten_bytes: VecDeque<u8> = [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).map_err(|e| e.kind())
+ {
+ panic!("isize::MAX shouldn't trigger an overflow!");
+ }
+ 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!");
+ }
+ if guards_against_isize {
+ assert_matches!(
+ ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()),
+ Err(CapacityOverflow),
+ "isize::MAX + 1 should trigger an overflow!"
+ );
+ } else {
+ assert_matches!(
+ ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()),
+ Err(AllocError { .. }),
+ "isize::MAX + 1 should trigger an OOM!"
+ );
+ }
+ assert_matches!(
+ ten_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()),
+ Err(CapacityOverflow),
+ "usize::MAX should trigger an overflow!"
+ );
+ }
+
+ {
+ let mut ten_u32s: VecDeque<u32> = [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).map_err(|e| e.kind())
+ {
+ panic!("isize::MAX shouldn't trigger an overflow!");
+ }
+ 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!");
+ }
+ if guards_against_isize {
+ assert_matches!(
+ ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9).map_err(|e| e.kind()),
+ Err(CapacityOverflow),
+ "isize::MAX + 1 should trigger an overflow!"
+ );
+ } else {
+ assert_matches!(
+ ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9).map_err(|e| e.kind()),
+ Err(AllocError { .. }),
+ "isize::MAX + 1 should trigger an OOM!"
+ );
+ }
+ assert_matches!(
+ ten_u32s.try_reserve_exact(MAX_USIZE - 20).map_err(|e| e.kind()),
+ Err(CapacityOverflow),
+ "usize::MAX should trigger an overflow!"
+ );
+ }
+}
+
+#[test]
+fn test_rotate_nop() {
+ let mut v: VecDeque<_> = (0..10).collect();
+ assert_unchanged(&v);
+
+ v.rotate_left(0);
+ assert_unchanged(&v);
+
+ v.rotate_left(10);
+ assert_unchanged(&v);
+
+ v.rotate_right(0);
+ assert_unchanged(&v);
+
+ v.rotate_right(10);
+ assert_unchanged(&v);
+
+ v.rotate_left(3);
+ v.rotate_right(3);
+ assert_unchanged(&v);
+
+ v.rotate_right(3);
+ v.rotate_left(3);
+ assert_unchanged(&v);
+
+ v.rotate_left(6);
+ v.rotate_right(6);
+ assert_unchanged(&v);
+
+ v.rotate_right(6);
+ v.rotate_left(6);
+ assert_unchanged(&v);
+
+ v.rotate_left(3);
+ v.rotate_left(7);
+ assert_unchanged(&v);
+
+ v.rotate_right(4);
+ v.rotate_right(6);
+ assert_unchanged(&v);
+
+ v.rotate_left(1);
+ v.rotate_left(2);
+ v.rotate_left(3);
+ v.rotate_left(4);
+ assert_unchanged(&v);
+
+ v.rotate_right(1);
+ v.rotate_right(2);
+ v.rotate_right(3);
+ v.rotate_right(4);
+ assert_unchanged(&v);
+
+ fn assert_unchanged(v: &VecDeque<i32>) {
+ assert_eq!(v, &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
+ }
+}
+
+#[test]
+fn test_rotate_left_parts() {
+ let mut v: VecDeque<_> = (1..=7).collect();
+ v.rotate_left(2);
+ assert_eq!(v.as_slices(), (&[3, 4, 5, 6, 7, 1][..], &[2][..]));
+ v.rotate_left(2);
+ assert_eq!(v.as_slices(), (&[5, 6, 7, 1][..], &[2, 3, 4][..]));
+ v.rotate_left(2);
+ assert_eq!(v.as_slices(), (&[7, 1][..], &[2, 3, 4, 5, 6][..]));
+ v.rotate_left(2);
+ assert_eq!(v.as_slices(), (&[2, 3, 4, 5, 6, 7, 1][..], &[][..]));
+ v.rotate_left(2);
+ assert_eq!(v.as_slices(), (&[4, 5, 6, 7, 1, 2][..], &[3][..]));
+ v.rotate_left(2);
+ assert_eq!(v.as_slices(), (&[6, 7, 1, 2][..], &[3, 4, 5][..]));
+ v.rotate_left(2);
+ assert_eq!(v.as_slices(), (&[1, 2][..], &[3, 4, 5, 6, 7][..]));
+}
+
+#[test]
+fn test_rotate_right_parts() {
+ let mut v: VecDeque<_> = (1..=7).collect();
+ v.rotate_right(2);
+ assert_eq!(v.as_slices(), (&[6, 7][..], &[1, 2, 3, 4, 5][..]));
+ v.rotate_right(2);
+ assert_eq!(v.as_slices(), (&[4, 5, 6, 7][..], &[1, 2, 3][..]));
+ v.rotate_right(2);
+ assert_eq!(v.as_slices(), (&[2, 3, 4, 5, 6, 7][..], &[1][..]));
+ v.rotate_right(2);
+ assert_eq!(v.as_slices(), (&[7, 1, 2, 3, 4, 5, 6][..], &[][..]));
+ v.rotate_right(2);
+ assert_eq!(v.as_slices(), (&[5, 6][..], &[7, 1, 2, 3, 4][..]));
+ v.rotate_right(2);
+ assert_eq!(v.as_slices(), (&[3, 4, 5, 6][..], &[7, 1, 2][..]));
+ v.rotate_right(2);
+ assert_eq!(v.as_slices(), (&[1, 2, 3, 4, 5, 6][..], &[7][..]));
+}
+
+#[test]
+fn test_rotate_left_random() {
+ let shifts = [
+ 6, 1, 0, 11, 12, 1, 11, 7, 9, 3, 6, 1, 4, 0, 5, 1, 3, 1, 12, 8, 3, 1, 11, 11, 9, 4, 12, 3,
+ 12, 9, 11, 1, 7, 9, 7, 2,
+ ];
+ let n = 12;
+ let mut v: VecDeque<_> = (0..n).collect();
+ let mut total_shift = 0;
+ for shift in shifts.iter().cloned() {
+ v.rotate_left(shift);
+ total_shift += shift;
+ for i in 0..n {
+ assert_eq!(v[i], (i + total_shift) % n);
+ }
+ }
+}
+
+#[test]
+fn test_rotate_right_random() {
+ let shifts = [
+ 6, 1, 0, 11, 12, 1, 11, 7, 9, 3, 6, 1, 4, 0, 5, 1, 3, 1, 12, 8, 3, 1, 11, 11, 9, 4, 12, 3,
+ 12, 9, 11, 1, 7, 9, 7, 2,
+ ];
+ let n = 12;
+ let mut v: VecDeque<_> = (0..n).collect();
+ let mut total_shift = 0;
+ for shift in shifts.iter().cloned() {
+ v.rotate_right(shift);
+ total_shift += shift;
+ for i in 0..n {
+ assert_eq!(v[(i + total_shift) % n], i);
+ }
+ }
+}
+
+#[test]
+fn test_try_fold_empty() {
+ assert_eq!(Some(0), VecDeque::<u32>::new().iter().try_fold(0, |_, _| None));
+}
+
+#[test]
+fn test_try_fold_none() {
+ let v: VecDeque<u32> = (0..12).collect();
+ assert_eq!(None, v.into_iter().try_fold(0, |a, b| if b < 11 { Some(a + b) } else { None }));
+}
+
+#[test]
+fn test_try_fold_ok() {
+ let v: VecDeque<u32> = (0..12).collect();
+ assert_eq!(Ok::<_, ()>(66), v.into_iter().try_fold(0, |a, b| Ok(a + b)));
+}
+
+#[test]
+fn test_try_fold_unit() {
+ let v: VecDeque<()> = std::iter::repeat(()).take(42).collect();
+ assert_eq!(Some(()), v.into_iter().try_fold((), |(), ()| Some(())));
+}
+
+#[test]
+fn test_try_fold_unit_none() {
+ let v: std::collections::VecDeque<()> = [(); 10].iter().cloned().collect();
+ let mut iter = v.into_iter();
+ assert!(iter.try_fold((), |_, _| None).is_none());
+ assert_eq!(iter.len(), 9);
+}
+
+#[test]
+fn test_try_fold_rotated() {
+ let mut v: VecDeque<_> = (0..12).collect();
+ for n in 0..10 {
+ if n & 1 == 0 {
+ v.rotate_left(n);
+ } else {
+ v.rotate_right(n);
+ }
+ assert_eq!(Ok::<_, ()>(66), v.iter().try_fold(0, |a, b| Ok(a + b)));
+ }
+}
+
+#[test]
+fn test_try_fold_moves_iter() {
+ let v: VecDeque<_> = [10, 20, 30, 40, 100, 60, 70, 80, 90].iter().collect();
+ let mut iter = v.into_iter();
+ assert_eq!(iter.try_fold(0_i8, |acc, &x| acc.checked_add(x)), None);
+ assert_eq!(iter.next(), Some(&60));
+}
+
+#[test]
+fn test_try_fold_exhaust_wrap() {
+ let mut v = VecDeque::with_capacity(7);
+ v.push_back(1);
+ v.push_back(1);
+ v.push_back(1);
+ v.pop_front();
+ v.pop_front();
+ let mut iter = v.iter();
+ let _ = iter.try_fold(0, |_, _| Some(1));
+ assert!(iter.is_empty());
+}
+
+#[test]
+fn test_try_fold_wraparound() {
+ let mut v = VecDeque::with_capacity(8);
+ v.push_back(7);
+ v.push_back(8);
+ v.push_back(9);
+ v.push_front(2);
+ v.push_front(1);
+ let mut iter = v.iter();
+ let _ = iter.find(|&&x| x == 2);
+ assert_eq!(Some(&7), iter.next());
+}
+
+#[test]
+fn test_try_rfold_rotated() {
+ let mut v: VecDeque<_> = (0..12).collect();
+ for n in 0..10 {
+ if n & 1 == 0 {
+ v.rotate_left(n);
+ } else {
+ v.rotate_right(n);
+ }
+ assert_eq!(Ok::<_, ()>(66), v.iter().try_rfold(0, |a, b| Ok(a + b)));
+ }
+}
+
+#[test]
+fn test_try_rfold_moves_iter() {
+ let v: VecDeque<_> = [10, 20, 30, 40, 100, 60, 70, 80, 90].iter().collect();
+ let mut iter = v.into_iter();
+ assert_eq!(iter.try_rfold(0_i8, |acc, &x| acc.checked_add(x)), None);
+ assert_eq!(iter.next_back(), Some(&70));
+}
+
+#[test]
+fn truncate_leak() {
+ static mut DROPS: i32 = 0;
+
+ struct D(bool);
+
+ impl Drop for D {
+ fn drop(&mut self) {
+ unsafe {
+ DROPS += 1;
+ }
+
+ if self.0 {
+ panic!("panic in `drop`");
+ }
+ }
+ }
+
+ let mut q = VecDeque::new();
+ q.push_back(D(false));
+ q.push_back(D(false));
+ q.push_back(D(false));
+ q.push_back(D(false));
+ q.push_back(D(false));
+ q.push_front(D(true));
+ q.push_front(D(false));
+ q.push_front(D(false));
+
+ catch_unwind(AssertUnwindSafe(|| q.truncate(1))).ok();
+
+ assert_eq!(unsafe { DROPS }, 7);
+}
+
+#[test]
+fn test_drain_leak() {
+ static mut DROPS: i32 = 0;
+
+ #[derive(Debug, PartialEq)]
+ struct D(u32, bool);
+
+ impl Drop for D {
+ fn drop(&mut self) {
+ unsafe {
+ DROPS += 1;
+ }
+
+ if self.1 {
+ panic!("panic in `drop`");
+ }
+ }
+ }
+
+ let mut v = VecDeque::new();
+ v.push_back(D(4, false));
+ v.push_back(D(5, false));
+ v.push_back(D(6, false));
+ v.push_front(D(3, false));
+ v.push_front(D(2, true));
+ v.push_front(D(1, false));
+ v.push_front(D(0, false));
+
+ catch_unwind(AssertUnwindSafe(|| {
+ v.drain(1..=4);
+ }))
+ .ok();
+
+ assert_eq!(unsafe { DROPS }, 4);
+ assert_eq!(v.len(), 3);
+ drop(v);
+ assert_eq!(unsafe { DROPS }, 7);
+}
+
+#[test]
+fn test_binary_search() {
+ // Contiguous (front only) search:
+ let deque: VecDeque<_> = vec![1, 2, 3, 5, 6].into();
+ assert!(deque.as_slices().1.is_empty());
+ assert_eq!(deque.binary_search(&3), Ok(2));
+ assert_eq!(deque.binary_search(&4), Err(3));
+
+ // Split search (both front & back non-empty):
+ let mut deque: VecDeque<_> = vec![5, 6].into();
+ deque.push_front(3);
+ deque.push_front(2);
+ deque.push_front(1);
+ deque.push_back(10);
+ assert!(!deque.as_slices().0.is_empty());
+ assert!(!deque.as_slices().1.is_empty());
+ assert_eq!(deque.binary_search(&0), Err(0));
+ assert_eq!(deque.binary_search(&1), Ok(0));
+ assert_eq!(deque.binary_search(&5), Ok(3));
+ assert_eq!(deque.binary_search(&7), Err(5));
+ assert_eq!(deque.binary_search(&20), Err(6));
+}
+
+#[test]
+fn test_binary_search_by() {
+ let deque: VecDeque<_> = vec![(1,), (2,), (3,), (5,), (6,)].into();
+
+ assert_eq!(deque.binary_search_by(|&(v,)| v.cmp(&3)), Ok(2));
+ assert_eq!(deque.binary_search_by(|&(v,)| v.cmp(&4)), Err(3));
+}
+
+#[test]
+fn test_binary_search_by_key() {
+ let deque: VecDeque<_> = vec![(1,), (2,), (3,), (5,), (6,)].into();
+
+ assert_eq!(deque.binary_search_by_key(&3, |&(v,)| v), Ok(2));
+ assert_eq!(deque.binary_search_by_key(&4, |&(v,)| v), Err(3));
+}
+
+#[test]
+fn test_partition_point() {
+ // Contiguous (front only) search:
+ let deque: VecDeque<_> = vec![1, 2, 3, 5, 6].into();
+ assert!(deque.as_slices().1.is_empty());
+ assert_eq!(deque.partition_point(|&v| v <= 3), 3);
+
+ // Split search (both front & back non-empty):
+ let mut deque: VecDeque<_> = vec![5, 6].into();
+ deque.push_front(3);
+ deque.push_front(2);
+ deque.push_front(1);
+ deque.push_back(10);
+ assert!(!deque.as_slices().0.is_empty());
+ assert!(!deque.as_slices().1.is_empty());
+ assert_eq!(deque.partition_point(|&v| v <= 5), 4);
+}
+
+#[test]
+fn test_zero_sized_push() {
+ const N: usize = 8;
+
+ // Zero sized type
+ struct Zst;
+
+ // Test that for all possible sequences of push_front / push_back,
+ // we end up with a deque of the correct size
+
+ for len in 0..N {
+ let mut tester = VecDeque::with_capacity(len);
+ assert_eq!(tester.len(), 0);
+ assert!(tester.capacity() >= len);
+ for case in 0..(1 << len) {
+ assert_eq!(tester.len(), 0);
+ for bit in 0..len {
+ if case & (1 << bit) != 0 {
+ tester.push_front(Zst);
+ } else {
+ tester.push_back(Zst);
+ }
+ }
+ assert_eq!(tester.len(), len);
+ assert_eq!(tester.iter().count(), len);
+ tester.clear();
+ }
+ }
+}
+
+#[test]
+fn test_from_zero_sized_vec() {
+ let v = vec![(); 100];
+ let queue = VecDeque::from(v);
+ assert_eq!(queue.len(), 100);
+}