summaryrefslogtreecommitdiffstats
path: root/library/core/tests
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:02:58 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:02:58 +0000
commit698f8c2f01ea549d77d7dc3338a12e04c11057b9 (patch)
tree173a775858bd501c378080a10dca74132f05bc50 /library/core/tests
parentInitial commit. (diff)
downloadrustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.tar.xz
rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.zip
Adding upstream version 1.64.0+dfsg1.upstream/1.64.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--library/core/tests/alloc.rs31
-rw-r--r--library/core/tests/any.rs194
-rw-r--r--library/core/tests/array.rs702
-rw-r--r--library/core/tests/ascii.rs463
-rw-r--r--library/core/tests/asserting.rs37
-rw-r--r--library/core/tests/atomic.rs314
-rw-r--r--library/core/tests/bool.rs105
-rw-r--r--library/core/tests/cell.rs479
-rw-r--r--library/core/tests/char.rs415
-rw-r--r--library/core/tests/clone.rs15
-rw-r--r--library/core/tests/cmp.rs250
-rw-r--r--library/core/tests/const_ptr.rs101
-rw-r--r--library/core/tests/convert.rs16
-rw-r--r--library/core/tests/fmt/builders.rs726
-rw-r--r--library/core/tests/fmt/float.rs55
-rw-r--r--library/core/tests/fmt/mod.rs45
-rw-r--r--library/core/tests/fmt/num.rs225
-rw-r--r--library/core/tests/future.rs128
-rw-r--r--library/core/tests/hash/mod.rs161
-rw-r--r--library/core/tests/hash/sip.rs309
-rw-r--r--library/core/tests/intrinsics.rs101
-rw-r--r--library/core/tests/iter/adapters/chain.rs280
-rw-r--r--library/core/tests/iter/adapters/cloned.rs52
-rw-r--r--library/core/tests/iter/adapters/copied.rs18
-rw-r--r--library/core/tests/iter/adapters/cycle.rs31
-rw-r--r--library/core/tests/iter/adapters/enumerate.rs107
-rw-r--r--library/core/tests/iter/adapters/filter.rs52
-rw-r--r--library/core/tests/iter/adapters/filter_map.rs50
-rw-r--r--library/core/tests/iter/adapters/flat_map.rs74
-rw-r--r--library/core/tests/iter/adapters/flatten.rs170
-rw-r--r--library/core/tests/iter/adapters/fuse.rs75
-rw-r--r--library/core/tests/iter/adapters/inspect.rs38
-rw-r--r--library/core/tests/iter/adapters/intersperse.rs154
-rw-r--r--library/core/tests/iter/adapters/map.rs27
-rw-r--r--library/core/tests/iter/adapters/mod.rs185
-rw-r--r--library/core/tests/iter/adapters/peekable.rs272
-rw-r--r--library/core/tests/iter/adapters/scan.rs20
-rw-r--r--library/core/tests/iter/adapters/skip.rs203
-rw-r--r--library/core/tests/iter/adapters/skip_while.rs50
-rw-r--r--library/core/tests/iter/adapters/step_by.rs246
-rw-r--r--library/core/tests/iter/adapters/take.rs148
-rw-r--r--library/core/tests/iter/adapters/take_while.rs29
-rw-r--r--library/core/tests/iter/adapters/zip.rs315
-rw-r--r--library/core/tests/iter/mod.rs102
-rw-r--r--library/core/tests/iter/range.rs472
-rw-r--r--library/core/tests/iter/sources.rs108
-rw-r--r--library/core/tests/iter/traits/accum.rs66
-rw-r--r--library/core/tests/iter/traits/double_ended.rs91
-rw-r--r--library/core/tests/iter/traits/iterator.rs593
-rw-r--r--library/core/tests/iter/traits/mod.rs4
-rw-r--r--library/core/tests/iter/traits/step.rs89
-rw-r--r--library/core/tests/lazy.rs138
-rw-r--r--library/core/tests/lib.rs142
-rw-r--r--library/core/tests/macros.rs20
-rw-r--r--library/core/tests/manually_drop.rs27
-rw-r--r--library/core/tests/mem.rs343
-rw-r--r--library/core/tests/nonzero.rs336
-rw-r--r--library/core/tests/num/bignum.rs276
-rw-r--r--library/core/tests/num/const_from.rs25
-rw-r--r--library/core/tests/num/dec2flt/float.rs33
-rw-r--r--library/core/tests/num/dec2flt/lemire.rs53
-rw-r--r--library/core/tests/num/dec2flt/mod.rs140
-rw-r--r--library/core/tests/num/dec2flt/parse.rs177
-rw-r--r--library/core/tests/num/flt2dec/estimator.rs62
-rw-r--r--library/core/tests/num/flt2dec/mod.rs1172
-rw-r--r--library/core/tests/num/flt2dec/random.rs202
-rw-r--r--library/core/tests/num/flt2dec/strategy/dragon.rs63
-rw-r--r--library/core/tests/num/flt2dec/strategy/grisu.rs72
-rw-r--r--library/core/tests/num/i128.rs1
-rw-r--r--library/core/tests/num/i16.rs1
-rw-r--r--library/core/tests/num/i32.rs30
-rw-r--r--library/core/tests/num/i64.rs1
-rw-r--r--library/core/tests/num/i8.rs1
-rw-r--r--library/core/tests/num/ieee754.rs158
-rw-r--r--library/core/tests/num/int_log.rs166
-rw-r--r--library/core/tests/num/int_macros.rs343
-rw-r--r--library/core/tests/num/mod.rs871
-rw-r--r--library/core/tests/num/nan.rs7
-rw-r--r--library/core/tests/num/ops.rs232
-rw-r--r--library/core/tests/num/u128.rs1
-rw-r--r--library/core/tests/num/u16.rs1
-rw-r--r--library/core/tests/num/u32.rs1
-rw-r--r--library/core/tests/num/u64.rs1
-rw-r--r--library/core/tests/num/u8.rs1
-rw-r--r--library/core/tests/num/uint_macros.rs235
-rw-r--r--library/core/tests/num/wrapping.rs320
-rw-r--r--library/core/tests/ops.rs240
-rw-r--r--library/core/tests/ops/control_flow.rs18
-rw-r--r--library/core/tests/option.rs555
-rw-r--r--library/core/tests/pattern.rs503
-rw-r--r--library/core/tests/pin.rs31
-rw-r--r--library/core/tests/pin_macro.rs33
-rw-r--r--library/core/tests/ptr.rs855
-rw-r--r--library/core/tests/result.rs427
-rw-r--r--library/core/tests/simd.rs14
-rw-r--r--library/core/tests/slice.rs2597
-rw-r--r--library/core/tests/str.rs1
-rw-r--r--library/core/tests/str_lossy.rs85
-rw-r--r--library/core/tests/task.rs14
-rw-r--r--library/core/tests/time.rs447
-rw-r--r--library/core/tests/tuple.rs61
-rw-r--r--library/core/tests/unicode.rs5
-rw-r--r--library/core/tests/waker.rs22
103 files changed, 20553 insertions, 0 deletions
diff --git a/library/core/tests/alloc.rs b/library/core/tests/alloc.rs
new file mode 100644
index 000000000..8a5a06b34
--- /dev/null
+++ b/library/core/tests/alloc.rs
@@ -0,0 +1,31 @@
+use core::alloc::Layout;
+use core::ptr::{self, NonNull};
+
+#[test]
+fn const_unchecked_layout() {
+ const SIZE: usize = 0x2000;
+ const ALIGN: usize = 0x1000;
+ const LAYOUT: Layout = unsafe { Layout::from_size_align_unchecked(SIZE, ALIGN) };
+ const DANGLING: NonNull<u8> = LAYOUT.dangling();
+ assert_eq!(LAYOUT.size(), SIZE);
+ assert_eq!(LAYOUT.align(), ALIGN);
+ assert_eq!(Some(DANGLING), NonNull::new(ptr::invalid_mut(ALIGN)));
+}
+
+#[test]
+fn layout_debug_shows_log2_of_alignment() {
+ // `Debug` is not stable, but here's what it does right now
+ let layout = Layout::from_size_align(24576, 8192).unwrap();
+ let s = format!("{:?}", layout);
+ assert_eq!(s, "Layout { size: 24576, align: 8192 (1 << 13) }");
+}
+
+// Running this normally doesn't do much, but it's also run in Miri, which
+// will double-check that these are allowed by the validity invariants.
+#[test]
+fn layout_accepts_all_valid_alignments() {
+ for align in 0..usize::BITS {
+ let layout = Layout::from_size_align(0, 1_usize << align).unwrap();
+ assert_eq!(layout.align(), 1_usize << align);
+ }
+}
diff --git a/library/core/tests/any.rs b/library/core/tests/any.rs
new file mode 100644
index 000000000..8ed0c8880
--- /dev/null
+++ b/library/core/tests/any.rs
@@ -0,0 +1,194 @@
+use core::any::*;
+
+#[derive(PartialEq, Debug)]
+struct Test;
+
+static TEST: &'static str = "Test";
+
+#[test]
+fn any_referenced() {
+ let (a, b, c) = (&5 as &dyn Any, &TEST as &dyn Any, &Test as &dyn Any);
+
+ assert!(a.is::<i32>());
+ assert!(!b.is::<i32>());
+ assert!(!c.is::<i32>());
+
+ assert!(!a.is::<&'static str>());
+ assert!(b.is::<&'static str>());
+ assert!(!c.is::<&'static str>());
+
+ assert!(!a.is::<Test>());
+ assert!(!b.is::<Test>());
+ assert!(c.is::<Test>());
+}
+
+#[test]
+fn any_owning() {
+ let (a, b, c) = (
+ Box::new(5_usize) as Box<dyn Any>,
+ Box::new(TEST) as Box<dyn Any>,
+ Box::new(Test) as Box<dyn Any>,
+ );
+
+ assert!(a.is::<usize>());
+ assert!(!b.is::<usize>());
+ assert!(!c.is::<usize>());
+
+ assert!(!a.is::<&'static str>());
+ assert!(b.is::<&'static str>());
+ assert!(!c.is::<&'static str>());
+
+ assert!(!a.is::<Test>());
+ assert!(!b.is::<Test>());
+ assert!(c.is::<Test>());
+}
+
+#[test]
+fn any_downcast_ref() {
+ let a = &5_usize as &dyn Any;
+
+ match a.downcast_ref::<usize>() {
+ Some(&5) => {}
+ x => panic!("Unexpected value {x:?}"),
+ }
+
+ match a.downcast_ref::<Test>() {
+ None => {}
+ x => panic!("Unexpected value {x:?}"),
+ }
+}
+
+#[test]
+fn any_downcast_mut() {
+ let mut a = 5_usize;
+ let mut b: Box<_> = Box::new(7_usize);
+
+ let a_r = &mut a as &mut dyn Any;
+ let tmp: &mut usize = &mut *b;
+ let b_r = tmp as &mut dyn Any;
+
+ match a_r.downcast_mut::<usize>() {
+ Some(x) => {
+ assert_eq!(*x, 5);
+ *x = 612;
+ }
+ x => panic!("Unexpected value {x:?}"),
+ }
+
+ match b_r.downcast_mut::<usize>() {
+ Some(x) => {
+ assert_eq!(*x, 7);
+ *x = 413;
+ }
+ x => panic!("Unexpected value {x:?}"),
+ }
+
+ match a_r.downcast_mut::<Test>() {
+ None => (),
+ x => panic!("Unexpected value {x:?}"),
+ }
+
+ match b_r.downcast_mut::<Test>() {
+ None => (),
+ x => panic!("Unexpected value {x:?}"),
+ }
+
+ match a_r.downcast_mut::<usize>() {
+ Some(&mut 612) => {}
+ x => panic!("Unexpected value {x:?}"),
+ }
+
+ match b_r.downcast_mut::<usize>() {
+ Some(&mut 413) => {}
+ x => panic!("Unexpected value {x:?}"),
+ }
+}
+
+#[test]
+fn any_fixed_vec() {
+ let test = [0_usize; 8];
+ let test = &test as &dyn Any;
+ assert!(test.is::<[usize; 8]>());
+ assert!(!test.is::<[usize; 10]>());
+}
+
+#[test]
+fn any_unsized() {
+ fn is_any<T: Any + ?Sized>() {}
+ is_any::<[i32]>();
+}
+
+#[test]
+fn distinct_type_names() {
+ // https://github.com/rust-lang/rust/issues/84666
+
+ struct Velocity(f32, f32);
+
+ fn type_name_of_val<T>(_: T) -> &'static str {
+ type_name::<T>()
+ }
+
+ assert_ne!(type_name_of_val(Velocity), type_name_of_val(Velocity(0.0, -9.8)),);
+}
+
+// Test the `Provider` API.
+
+struct SomeConcreteType {
+ some_string: String,
+}
+
+impl Provider for SomeConcreteType {
+ fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
+ demand
+ .provide_ref::<String>(&self.some_string)
+ .provide_ref::<str>(&self.some_string)
+ .provide_value::<String>(|| "bye".to_owned());
+ }
+}
+
+// Test the provide and request mechanisms with a by-reference trait object.
+#[test]
+fn test_provider() {
+ let obj: &dyn Provider = &SomeConcreteType { some_string: "hello".to_owned() };
+
+ assert_eq!(&**request_ref::<String>(obj).unwrap(), "hello");
+ assert_eq!(&*request_value::<String>(obj).unwrap(), "bye");
+ assert_eq!(request_value::<u8>(obj), None);
+}
+
+// Test the provide and request mechanisms with a boxed trait object.
+#[test]
+fn test_provider_boxed() {
+ let obj: Box<dyn Provider> = Box::new(SomeConcreteType { some_string: "hello".to_owned() });
+
+ assert_eq!(&**request_ref::<String>(&*obj).unwrap(), "hello");
+ assert_eq!(&*request_value::<String>(&*obj).unwrap(), "bye");
+ assert_eq!(request_value::<u8>(&*obj), None);
+}
+
+// Test the provide and request mechanisms with a concrete object.
+#[test]
+fn test_provider_concrete() {
+ let obj = SomeConcreteType { some_string: "hello".to_owned() };
+
+ assert_eq!(&**request_ref::<String>(&obj).unwrap(), "hello");
+ assert_eq!(&*request_value::<String>(&obj).unwrap(), "bye");
+ assert_eq!(request_value::<u8>(&obj), None);
+}
+
+trait OtherTrait: Provider {}
+
+impl OtherTrait for SomeConcreteType {}
+
+impl dyn OtherTrait {
+ fn get_ref<T: 'static + ?Sized>(&self) -> Option<&T> {
+ request_ref::<T>(self)
+ }
+}
+
+// Test the provide and request mechanisms via an intermediate trait.
+#[test]
+fn test_provider_intermediate() {
+ let obj: &dyn OtherTrait = &SomeConcreteType { some_string: "hello".to_owned() };
+ assert_eq!(obj.get_ref::<str>().unwrap(), "hello");
+}
diff --git a/library/core/tests/array.rs b/library/core/tests/array.rs
new file mode 100644
index 000000000..f268fe3ae
--- /dev/null
+++ b/library/core/tests/array.rs
@@ -0,0 +1,702 @@
+use core::array;
+use core::convert::TryFrom;
+use core::sync::atomic::{AtomicUsize, Ordering};
+
+#[test]
+fn array_from_ref() {
+ let value: String = "Hello World!".into();
+ let arr: &[String; 1] = array::from_ref(&value);
+ assert_eq!(&[value.clone()], arr);
+
+ const VALUE: &&str = &"Hello World!";
+ const ARR: &[&str; 1] = array::from_ref(VALUE);
+ assert_eq!(&[*VALUE], ARR);
+ assert!(core::ptr::eq(VALUE, &ARR[0]));
+}
+
+#[test]
+fn array_from_mut() {
+ let mut value: String = "Hello World".into();
+ let arr: &mut [String; 1] = array::from_mut(&mut value);
+ arr[0].push_str("!");
+ assert_eq!(&value, "Hello World!");
+}
+
+#[test]
+fn array_try_from() {
+ macro_rules! test {
+ ($($N:expr)+) => {
+ $({
+ type Array = [u8; $N];
+ let mut array: Array = [0; $N];
+ let slice: &[u8] = &array[..];
+
+ let result = <&Array>::try_from(slice);
+ assert_eq!(&array, result.unwrap());
+
+ let result = <Array>::try_from(slice);
+ assert_eq!(&array, &result.unwrap());
+
+ let mut_slice: &mut [u8] = &mut array[..];
+ let result = <&mut Array>::try_from(mut_slice);
+ assert_eq!(&[0; $N], result.unwrap());
+
+ let mut_slice: &mut [u8] = &mut array[..];
+ let result = <Array>::try_from(mut_slice);
+ assert_eq!(&array, &result.unwrap());
+ })+
+ }
+ }
+ test! {
+ 0 1 2 3 4 5 6 7 8 9
+ 10 11 12 13 14 15 16 17 18 19
+ 20 21 22 23 24 25 26 27 28 29
+ 30 31 32
+ }
+}
+
+#[test]
+fn iterator_collect() {
+ let arr = [0, 1, 2, 5, 9];
+ let v: Vec<_> = IntoIterator::into_iter(arr.clone()).collect();
+ assert_eq!(&arr[..], &v[..]);
+}
+
+#[test]
+fn iterator_rev_collect() {
+ let arr = [0, 1, 2, 5, 9];
+ let v: Vec<_> = IntoIterator::into_iter(arr.clone()).rev().collect();
+ assert_eq!(&v[..], &[9, 5, 2, 1, 0]);
+}
+
+#[test]
+fn iterator_nth() {
+ let v = [0, 1, 2, 3, 4];
+ for i in 0..v.len() {
+ assert_eq!(IntoIterator::into_iter(v.clone()).nth(i).unwrap(), v[i]);
+ }
+ assert_eq!(IntoIterator::into_iter(v.clone()).nth(v.len()), None);
+
+ let mut iter = IntoIterator::into_iter(v);
+ assert_eq!(iter.nth(2).unwrap(), v[2]);
+ assert_eq!(iter.nth(1).unwrap(), v[4]);
+}
+
+#[test]
+fn iterator_last() {
+ let v = [0, 1, 2, 3, 4];
+ assert_eq!(IntoIterator::into_iter(v).last().unwrap(), 4);
+ assert_eq!(IntoIterator::into_iter([0]).last().unwrap(), 0);
+
+ let mut it = IntoIterator::into_iter([0, 9, 2, 4]);
+ assert_eq!(it.next_back(), Some(4));
+ assert_eq!(it.last(), Some(2));
+}
+
+#[test]
+fn iterator_clone() {
+ let mut it = IntoIterator::into_iter([0, 2, 4, 6, 8]);
+ assert_eq!(it.next(), Some(0));
+ assert_eq!(it.next_back(), Some(8));
+ let mut clone = it.clone();
+ assert_eq!(it.next_back(), Some(6));
+ assert_eq!(clone.next_back(), Some(6));
+ assert_eq!(it.next_back(), Some(4));
+ assert_eq!(clone.next_back(), Some(4));
+ assert_eq!(it.next(), Some(2));
+ assert_eq!(clone.next(), Some(2));
+}
+
+#[test]
+fn iterator_fused() {
+ let mut it = IntoIterator::into_iter([0, 9, 2]);
+ assert_eq!(it.next(), Some(0));
+ assert_eq!(it.next(), Some(9));
+ assert_eq!(it.next(), Some(2));
+ assert_eq!(it.next(), None);
+ assert_eq!(it.next(), None);
+ assert_eq!(it.next(), None);
+ assert_eq!(it.next(), None);
+ assert_eq!(it.next(), None);
+}
+
+#[test]
+fn iterator_len() {
+ let mut it = IntoIterator::into_iter([0, 1, 2, 5, 9]);
+ assert_eq!(it.size_hint(), (5, Some(5)));
+ assert_eq!(it.len(), 5);
+ assert_eq!(it.is_empty(), false);
+
+ assert_eq!(it.next(), Some(0));
+ assert_eq!(it.size_hint(), (4, Some(4)));
+ assert_eq!(it.len(), 4);
+ assert_eq!(it.is_empty(), false);
+
+ assert_eq!(it.next_back(), Some(9));
+ assert_eq!(it.size_hint(), (3, Some(3)));
+ assert_eq!(it.len(), 3);
+ assert_eq!(it.is_empty(), false);
+
+ // Empty
+ let it = IntoIterator::into_iter([] as [String; 0]);
+ assert_eq!(it.size_hint(), (0, Some(0)));
+ assert_eq!(it.len(), 0);
+ assert_eq!(it.is_empty(), true);
+}
+
+#[test]
+fn iterator_count() {
+ let v = [0, 1, 2, 3, 4];
+ assert_eq!(IntoIterator::into_iter(v.clone()).count(), 5);
+
+ let mut iter2 = IntoIterator::into_iter(v);
+ iter2.next();
+ iter2.next();
+ assert_eq!(iter2.count(), 3);
+}
+
+#[test]
+fn iterator_flat_map() {
+ assert!((0..5).flat_map(|i| IntoIterator::into_iter([2 * i, 2 * i + 1])).eq(0..10));
+}
+
+#[test]
+fn iterator_debug() {
+ let arr = [0, 1, 2, 5, 9];
+ assert_eq!(format!("{:?}", IntoIterator::into_iter(arr)), "IntoIter([0, 1, 2, 5, 9])",);
+}
+
+#[test]
+fn iterator_drops() {
+ use core::cell::Cell;
+
+ // This test makes sure the correct number of elements are dropped. The `R`
+ // type is just a reference to a `Cell` that is incremented when an `R` is
+ // dropped.
+
+ #[derive(Clone)]
+ struct Foo<'a>(&'a Cell<usize>);
+
+ impl Drop for Foo<'_> {
+ fn drop(&mut self) {
+ self.0.set(self.0.get() + 1);
+ }
+ }
+
+ fn five(i: &Cell<usize>) -> [Foo<'_>; 5] {
+ // This is somewhat verbose because `Foo` does not implement `Copy`
+ // since it implements `Drop`. Consequently, we cannot write
+ // `[Foo(i); 5]`.
+ [Foo(i), Foo(i), Foo(i), Foo(i), Foo(i)]
+ }
+
+ // Simple: drop new iterator.
+ let i = Cell::new(0);
+ {
+ IntoIterator::into_iter(five(&i));
+ }
+ assert_eq!(i.get(), 5);
+
+ // Call `next()` once.
+ let i = Cell::new(0);
+ {
+ let mut iter = IntoIterator::into_iter(five(&i));
+ let _x = iter.next();
+ assert_eq!(i.get(), 0);
+ assert_eq!(iter.count(), 4);
+ assert_eq!(i.get(), 4);
+ }
+ assert_eq!(i.get(), 5);
+
+ // Check `clone` and calling `next`/`next_back`.
+ let i = Cell::new(0);
+ {
+ let mut iter = IntoIterator::into_iter(five(&i));
+ iter.next();
+ assert_eq!(i.get(), 1);
+ iter.next_back();
+ assert_eq!(i.get(), 2);
+
+ let mut clone = iter.clone();
+ assert_eq!(i.get(), 2);
+
+ iter.next();
+ assert_eq!(i.get(), 3);
+
+ clone.next();
+ assert_eq!(i.get(), 4);
+
+ assert_eq!(clone.count(), 2);
+ assert_eq!(i.get(), 6);
+ }
+ assert_eq!(i.get(), 8);
+
+ // Check via `nth`.
+ let i = Cell::new(0);
+ {
+ let mut iter = IntoIterator::into_iter(five(&i));
+ let _x = iter.nth(2);
+ assert_eq!(i.get(), 2);
+ let _y = iter.last();
+ assert_eq!(i.get(), 3);
+ }
+ assert_eq!(i.get(), 5);
+
+ // Check every element.
+ let i = Cell::new(0);
+ for (index, _x) in IntoIterator::into_iter(five(&i)).enumerate() {
+ assert_eq!(i.get(), index);
+ }
+ assert_eq!(i.get(), 5);
+
+ let i = Cell::new(0);
+ for (index, _x) in IntoIterator::into_iter(five(&i)).rev().enumerate() {
+ assert_eq!(i.get(), index);
+ }
+ assert_eq!(i.get(), 5);
+}
+
+// This test does not work on targets without panic=unwind support.
+// To work around this problem, test is marked is should_panic, so it will
+// be automagically skipped on unsuitable targets, such as
+// wasm32-unknown-unknown.
+//
+// It means that we use panic for indicating success.
+#[test]
+#[should_panic(expected = "test succeeded")]
+fn array_default_impl_avoids_leaks_on_panic() {
+ use core::sync::atomic::{AtomicUsize, Ordering::Relaxed};
+ static COUNTER: AtomicUsize = AtomicUsize::new(0);
+ #[derive(Debug)]
+ struct Bomb(usize);
+
+ impl Default for Bomb {
+ fn default() -> Bomb {
+ if COUNTER.load(Relaxed) == 3 {
+ panic!("bomb limit exceeded");
+ }
+
+ COUNTER.fetch_add(1, Relaxed);
+ Bomb(COUNTER.load(Relaxed))
+ }
+ }
+
+ impl Drop for Bomb {
+ fn drop(&mut self) {
+ COUNTER.fetch_sub(1, Relaxed);
+ }
+ }
+
+ let res = std::panic::catch_unwind(|| <[Bomb; 5]>::default());
+ let panic_msg = match res {
+ Ok(_) => unreachable!(),
+ Err(p) => p.downcast::<&'static str>().unwrap(),
+ };
+ assert_eq!(*panic_msg, "bomb limit exceeded");
+ // check that all bombs are successfully dropped
+ assert_eq!(COUNTER.load(Relaxed), 0);
+ panic!("test succeeded")
+}
+
+#[test]
+fn empty_array_is_always_default() {
+ struct DoesNotImplDefault;
+
+ let _arr = <[DoesNotImplDefault; 0]>::default();
+}
+
+#[test]
+fn array_map() {
+ let a = [1, 2, 3];
+ let b = a.map(|v| v + 1);
+ assert_eq!(b, [2, 3, 4]);
+
+ let a = [1u8, 2, 3];
+ let b = a.map(|v| v as u64);
+ assert_eq!(b, [1, 2, 3]);
+}
+
+// See note on above test for why `should_panic` is used.
+#[test]
+#[should_panic(expected = "test succeeded")]
+fn array_map_drop_safety() {
+ static DROPPED: AtomicUsize = AtomicUsize::new(0);
+ struct DropCounter;
+ impl Drop for DropCounter {
+ fn drop(&mut self) {
+ DROPPED.fetch_add(1, Ordering::SeqCst);
+ }
+ }
+
+ let num_to_create = 5;
+ let success = std::panic::catch_unwind(|| {
+ let items = [0; 10];
+ let mut nth = 0;
+ items.map(|_| {
+ assert!(nth < num_to_create);
+ nth += 1;
+ DropCounter
+ });
+ });
+ assert!(success.is_err());
+ assert_eq!(DROPPED.load(Ordering::SeqCst), num_to_create);
+ panic!("test succeeded")
+}
+
+#[test]
+fn cell_allows_array_cycle() {
+ use core::cell::Cell;
+
+ #[derive(Debug)]
+ struct B<'a> {
+ a: [Cell<Option<&'a B<'a>>>; 2],
+ }
+
+ impl<'a> B<'a> {
+ fn new() -> B<'a> {
+ B { a: [Cell::new(None), Cell::new(None)] }
+ }
+ }
+
+ let b1 = B::new();
+ let b2 = B::new();
+ let b3 = B::new();
+
+ b1.a[0].set(Some(&b2));
+ b1.a[1].set(Some(&b3));
+
+ b2.a[0].set(Some(&b2));
+ b2.a[1].set(Some(&b3));
+
+ b3.a[0].set(Some(&b1));
+ b3.a[1].set(Some(&b2));
+}
+
+#[test]
+fn array_from_fn() {
+ let array = core::array::from_fn(|idx| idx);
+ assert_eq!(array, [0, 1, 2, 3, 4]);
+}
+
+#[test]
+fn array_try_from_fn() {
+ #[derive(Debug, PartialEq)]
+ enum SomeError {
+ Foo,
+ }
+
+ let array = core::array::try_from_fn(|i| Ok::<_, SomeError>(i));
+ assert_eq!(array, Ok([0, 1, 2, 3, 4]));
+
+ let another_array = core::array::try_from_fn::<Result<(), _>, 2, _>(|_| Err(SomeError::Foo));
+ assert_eq!(another_array, Err(SomeError::Foo));
+}
+
+#[cfg(not(panic = "abort"))]
+#[test]
+fn array_try_from_fn_drops_inserted_elements_on_err() {
+ static DROP_COUNTER: AtomicUsize = AtomicUsize::new(0);
+
+ struct CountDrop;
+ impl Drop for CountDrop {
+ fn drop(&mut self) {
+ DROP_COUNTER.fetch_add(1, Ordering::SeqCst);
+ }
+ }
+
+ let _ = catch_unwind_silent(move || {
+ let _: Result<[CountDrop; 4], ()> = core::array::try_from_fn(|idx| {
+ if idx == 2 {
+ return Err(());
+ }
+ Ok(CountDrop)
+ });
+ });
+
+ assert_eq!(DROP_COUNTER.load(Ordering::SeqCst), 2);
+}
+
+#[cfg(not(panic = "abort"))]
+#[test]
+fn array_try_from_fn_drops_inserted_elements_on_panic() {
+ static DROP_COUNTER: AtomicUsize = AtomicUsize::new(0);
+
+ struct CountDrop;
+ impl Drop for CountDrop {
+ fn drop(&mut self) {
+ DROP_COUNTER.fetch_add(1, Ordering::SeqCst);
+ }
+ }
+
+ let _ = catch_unwind_silent(move || {
+ let _: Result<[CountDrop; 4], ()> = core::array::try_from_fn(|idx| {
+ if idx == 2 {
+ panic!("peek a boo");
+ }
+ Ok(CountDrop)
+ });
+ });
+
+ assert_eq!(DROP_COUNTER.load(Ordering::SeqCst), 2);
+}
+
+#[cfg(not(panic = "abort"))]
+// https://stackoverflow.com/a/59211505
+fn catch_unwind_silent<F, R>(f: F) -> std::thread::Result<R>
+where
+ F: FnOnce() -> R + core::panic::UnwindSafe,
+{
+ let prev_hook = std::panic::take_hook();
+ std::panic::set_hook(Box::new(|_| {}));
+ let result = std::panic::catch_unwind(f);
+ std::panic::set_hook(prev_hook);
+ result
+}
+
+#[test]
+fn array_split_array_mut() {
+ let mut v = [1, 2, 3, 4, 5, 6];
+
+ {
+ let (left, right) = v.split_array_mut::<0>();
+ assert_eq!(left, &mut []);
+ assert_eq!(right, &mut [1, 2, 3, 4, 5, 6]);
+ }
+
+ {
+ let (left, right) = v.split_array_mut::<6>();
+ assert_eq!(left, &mut [1, 2, 3, 4, 5, 6]);
+ assert_eq!(right, &mut []);
+ }
+}
+
+#[test]
+fn array_rsplit_array_mut() {
+ let mut v = [1, 2, 3, 4, 5, 6];
+
+ {
+ let (left, right) = v.rsplit_array_mut::<0>();
+ assert_eq!(left, &mut [1, 2, 3, 4, 5, 6]);
+ assert_eq!(right, &mut []);
+ }
+
+ {
+ let (left, right) = v.rsplit_array_mut::<6>();
+ assert_eq!(left, &mut []);
+ assert_eq!(right, &mut [1, 2, 3, 4, 5, 6]);
+ }
+}
+
+#[should_panic]
+#[test]
+fn array_split_array_ref_out_of_bounds() {
+ let v = [1, 2, 3, 4, 5, 6];
+
+ v.split_array_ref::<7>();
+}
+
+#[should_panic]
+#[test]
+fn array_split_array_mut_out_of_bounds() {
+ let mut v = [1, 2, 3, 4, 5, 6];
+
+ v.split_array_mut::<7>();
+}
+
+#[should_panic]
+#[test]
+fn array_rsplit_array_ref_out_of_bounds() {
+ let v = [1, 2, 3, 4, 5, 6];
+
+ v.rsplit_array_ref::<7>();
+}
+
+#[should_panic]
+#[test]
+fn array_rsplit_array_mut_out_of_bounds() {
+ let mut v = [1, 2, 3, 4, 5, 6];
+
+ v.rsplit_array_mut::<7>();
+}
+
+#[test]
+fn array_intoiter_advance_by() {
+ use std::cell::Cell;
+ struct DropCounter<'a>(usize, &'a Cell<usize>);
+ impl Drop for DropCounter<'_> {
+ fn drop(&mut self) {
+ let x = self.1.get();
+ self.1.set(x + 1);
+ }
+ }
+
+ let counter = Cell::new(0);
+ let a: [_; 100] = std::array::from_fn(|i| DropCounter(i, &counter));
+ let mut it = IntoIterator::into_iter(a);
+
+ let r = it.advance_by(1);
+ assert_eq!(r, Ok(()));
+ assert_eq!(it.len(), 99);
+ assert_eq!(counter.get(), 1);
+
+ let r = it.advance_by(0);
+ assert_eq!(r, Ok(()));
+ assert_eq!(it.len(), 99);
+ assert_eq!(counter.get(), 1);
+
+ let r = it.advance_by(11);
+ assert_eq!(r, Ok(()));
+ assert_eq!(it.len(), 88);
+ assert_eq!(counter.get(), 12);
+
+ let x = it.next();
+ assert_eq!(x.as_ref().map(|x| x.0), Some(12));
+ assert_eq!(it.len(), 87);
+ assert_eq!(counter.get(), 12);
+ drop(x);
+ assert_eq!(counter.get(), 13);
+
+ let r = it.advance_by(123456);
+ assert_eq!(r, Err(87));
+ assert_eq!(it.len(), 0);
+ assert_eq!(counter.get(), 100);
+
+ let r = it.advance_by(0);
+ assert_eq!(r, Ok(()));
+ assert_eq!(it.len(), 0);
+ assert_eq!(counter.get(), 100);
+
+ let r = it.advance_by(10);
+ assert_eq!(r, Err(0));
+ assert_eq!(it.len(), 0);
+ assert_eq!(counter.get(), 100);
+}
+
+#[test]
+fn array_intoiter_advance_back_by() {
+ use std::cell::Cell;
+ struct DropCounter<'a>(usize, &'a Cell<usize>);
+ impl Drop for DropCounter<'_> {
+ fn drop(&mut self) {
+ let x = self.1.get();
+ self.1.set(x + 1);
+ }
+ }
+
+ let counter = Cell::new(0);
+ let a: [_; 100] = std::array::from_fn(|i| DropCounter(i, &counter));
+ let mut it = IntoIterator::into_iter(a);
+
+ let r = it.advance_back_by(1);
+ assert_eq!(r, Ok(()));
+ assert_eq!(it.len(), 99);
+ assert_eq!(counter.get(), 1);
+
+ let r = it.advance_back_by(0);
+ assert_eq!(r, Ok(()));
+ assert_eq!(it.len(), 99);
+ assert_eq!(counter.get(), 1);
+
+ let r = it.advance_back_by(11);
+ assert_eq!(r, Ok(()));
+ assert_eq!(it.len(), 88);
+ assert_eq!(counter.get(), 12);
+
+ let x = it.next_back();
+ assert_eq!(x.as_ref().map(|x| x.0), Some(87));
+ assert_eq!(it.len(), 87);
+ assert_eq!(counter.get(), 12);
+ drop(x);
+ assert_eq!(counter.get(), 13);
+
+ let r = it.advance_back_by(123456);
+ assert_eq!(r, Err(87));
+ assert_eq!(it.len(), 0);
+ assert_eq!(counter.get(), 100);
+
+ let r = it.advance_back_by(0);
+ assert_eq!(r, Ok(()));
+ assert_eq!(it.len(), 0);
+ assert_eq!(counter.get(), 100);
+
+ let r = it.advance_back_by(10);
+ assert_eq!(r, Err(0));
+ assert_eq!(it.len(), 0);
+ assert_eq!(counter.get(), 100);
+}
+
+#[test]
+fn array_mixed_equality_integers() {
+ let array3: [i32; 3] = [1, 2, 3];
+ let array3b: [i32; 3] = [3, 2, 1];
+ let array4: [i32; 4] = [1, 2, 3, 4];
+
+ let slice3: &[i32] = &{ array3 };
+ let slice3b: &[i32] = &{ array3b };
+ let slice4: &[i32] = &{ array4 };
+ assert!(array3 == slice3);
+ assert!(array3 != slice3b);
+ assert!(array3 != slice4);
+ assert!(slice3 == array3);
+ assert!(slice3b != array3);
+ assert!(slice4 != array3);
+
+ let mut3: &mut [i32] = &mut { array3 };
+ let mut3b: &mut [i32] = &mut { array3b };
+ let mut4: &mut [i32] = &mut { array4 };
+ assert!(array3 == mut3);
+ assert!(array3 != mut3b);
+ assert!(array3 != mut4);
+ assert!(mut3 == array3);
+ assert!(mut3b != array3);
+ assert!(mut4 != array3);
+}
+
+#[test]
+fn array_mixed_equality_nans() {
+ let array3: [f32; 3] = [1.0, std::f32::NAN, 3.0];
+
+ let slice3: &[f32] = &{ array3 };
+ assert!(!(array3 == slice3));
+ assert!(array3 != slice3);
+ assert!(!(slice3 == array3));
+ assert!(slice3 != array3);
+
+ let mut3: &mut [f32] = &mut { array3 };
+ assert!(!(array3 == mut3));
+ assert!(array3 != mut3);
+ assert!(!(mut3 == array3));
+ assert!(mut3 != array3);
+}
+
+#[test]
+fn array_into_iter_fold() {
+ // Strings to help MIRI catch if we double-free or something
+ let a = ["Aa".to_string(), "Bb".to_string(), "Cc".to_string()];
+ let mut s = "s".to_string();
+ a.into_iter().for_each(|b| s += &b);
+ assert_eq!(s, "sAaBbCc");
+
+ let a = [1, 2, 3, 4, 5, 6];
+ let mut it = a.into_iter();
+ it.advance_by(1).unwrap();
+ it.advance_back_by(2).unwrap();
+ let s = it.fold(10, |a, b| 10 * a + b);
+ assert_eq!(s, 10234);
+}
+
+#[test]
+fn array_into_iter_rfold() {
+ // Strings to help MIRI catch if we double-free or something
+ let a = ["Aa".to_string(), "Bb".to_string(), "Cc".to_string()];
+ let mut s = "s".to_string();
+ a.into_iter().rev().for_each(|b| s += &b);
+ assert_eq!(s, "sCcBbAa");
+
+ let a = [1, 2, 3, 4, 5, 6];
+ let mut it = a.into_iter();
+ it.advance_by(1).unwrap();
+ it.advance_back_by(2).unwrap();
+ let s = it.rfold(10, |a, b| 10 * a + b);
+ assert_eq!(s, 10432);
+}
diff --git a/library/core/tests/ascii.rs b/library/core/tests/ascii.rs
new file mode 100644
index 000000000..6d2cf3e83
--- /dev/null
+++ b/library/core/tests/ascii.rs
@@ -0,0 +1,463 @@
+use core::char::from_u32;
+
+#[test]
+fn test_is_ascii() {
+ assert!(b"".is_ascii());
+ assert!(b"banana\0\x7F".is_ascii());
+ assert!(b"banana\0\x7F".iter().all(|b| b.is_ascii()));
+ assert!(!b"Vi\xe1\xbb\x87t Nam".is_ascii());
+ assert!(!b"Vi\xe1\xbb\x87t Nam".iter().all(|b| b.is_ascii()));
+ assert!(!b"\xe1\xbb\x87".iter().any(|b| b.is_ascii()));
+
+ assert!("".is_ascii());
+ assert!("banana\0\u{7F}".is_ascii());
+ assert!("banana\0\u{7F}".chars().all(|c| c.is_ascii()));
+ assert!(!"ประเทศไทย中华Việt Nam".chars().all(|c| c.is_ascii()));
+ assert!(!"ประเทศไทย中华ệ ".chars().any(|c| c.is_ascii()));
+}
+
+#[test]
+fn test_to_ascii_uppercase() {
+ assert_eq!("url()URL()uRl()ürl".to_ascii_uppercase(), "URL()URL()URL()üRL");
+ assert_eq!("hıKß".to_ascii_uppercase(), "HıKß");
+
+ for i in 0..501 {
+ let upper =
+ if 'a' as u32 <= i && i <= 'z' as u32 { i + 'A' as u32 - 'a' as u32 } else { i };
+ assert_eq!(
+ (from_u32(i).unwrap()).to_string().to_ascii_uppercase(),
+ (from_u32(upper).unwrap()).to_string()
+ );
+ }
+}
+
+#[test]
+fn test_to_ascii_lowercase() {
+ assert_eq!("url()URL()uRl()Ürl".to_ascii_lowercase(), "url()url()url()Ürl");
+ // Dotted capital I, Kelvin sign, Sharp S.
+ assert_eq!("HİKß".to_ascii_lowercase(), "hİKß");
+
+ for i in 0..501 {
+ let lower =
+ if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 } else { i };
+ assert_eq!(
+ (from_u32(i).unwrap()).to_string().to_ascii_lowercase(),
+ (from_u32(lower).unwrap()).to_string()
+ );
+ }
+}
+
+#[test]
+fn test_make_ascii_lower_case() {
+ macro_rules! test {
+ ($from: expr, $to: expr) => {{
+ let mut x = $from;
+ x.make_ascii_lowercase();
+ assert_eq!(x, $to);
+ }};
+ }
+ test!(b'A', b'a');
+ test!(b'a', b'a');
+ test!(b'!', b'!');
+ test!('A', 'a');
+ test!('À', 'À');
+ test!('a', 'a');
+ test!('!', '!');
+ test!(b"H\xc3\x89".to_vec(), b"h\xc3\x89");
+ test!("HİKß".to_string(), "hİKß");
+}
+
+#[test]
+fn test_make_ascii_upper_case() {
+ macro_rules! test {
+ ($from: expr, $to: expr) => {{
+ let mut x = $from;
+ x.make_ascii_uppercase();
+ assert_eq!(x, $to);
+ }};
+ }
+ test!(b'a', b'A');
+ test!(b'A', b'A');
+ test!(b'!', b'!');
+ test!('a', 'A');
+ test!('à', 'à');
+ test!('A', 'A');
+ test!('!', '!');
+ test!(b"h\xc3\xa9".to_vec(), b"H\xc3\xa9");
+ test!("hıKß".to_string(), "HıKß");
+
+ let mut x = "Hello".to_string();
+ x[..3].make_ascii_uppercase(); // Test IndexMut on String.
+ assert_eq!(x, "HELlo")
+}
+
+#[test]
+fn test_eq_ignore_ascii_case() {
+ assert!("url()URL()uRl()Ürl".eq_ignore_ascii_case("url()url()url()Ürl"));
+ assert!(!"Ürl".eq_ignore_ascii_case("ürl"));
+ // Dotted capital I, Kelvin sign, Sharp S.
+ assert!("HİKß".eq_ignore_ascii_case("hİKß"));
+ assert!(!"İ".eq_ignore_ascii_case("i"));
+ assert!(!"K".eq_ignore_ascii_case("k"));
+ assert!(!"ß".eq_ignore_ascii_case("s"));
+
+ for i in 0..501 {
+ let lower =
+ if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 } else { i };
+ assert!(
+ (from_u32(i).unwrap())
+ .to_string()
+ .eq_ignore_ascii_case(&from_u32(lower).unwrap().to_string())
+ );
+ }
+}
+
+#[test]
+fn inference_works() {
+ let x = "a".to_string();
+ let _ = x.eq_ignore_ascii_case("A");
+}
+
+// Shorthands used by the is_ascii_* tests.
+macro_rules! assert_all {
+ ($what:ident, $($str:tt),+) => {{
+ $(
+ for b in $str.chars() {
+ if !b.$what() {
+ panic!("expected {}({}) but it isn't",
+ stringify!($what), b);
+ }
+ }
+ for b in $str.as_bytes().iter() {
+ if !b.$what() {
+ panic!("expected {}(0x{:02x})) but it isn't",
+ stringify!($what), b);
+ }
+ }
+ )+
+ }};
+ ($what:ident, $($str:tt),+,) => (assert_all!($what,$($str),+))
+}
+macro_rules! assert_none {
+ ($what:ident, $($str:tt),+) => {{
+ $(
+ for b in $str.chars() {
+ if b.$what() {
+ panic!("expected not-{}({}) but it is",
+ stringify!($what), b);
+ }
+ }
+ for b in $str.as_bytes().iter() {
+ if b.$what() {
+ panic!("expected not-{}(0x{:02x})) but it is",
+ stringify!($what), b);
+ }
+ }
+ )+
+ }};
+ ($what:ident, $($str:tt),+,) => (assert_none!($what,$($str),+))
+}
+
+#[test]
+fn test_is_ascii_alphabetic() {
+ assert_all!(
+ is_ascii_alphabetic,
+ "",
+ "abcdefghijklmnopqrstuvwxyz",
+ "ABCDEFGHIJKLMNOQPRSTUVWXYZ",
+ );
+ assert_none!(
+ is_ascii_alphabetic,
+ "0123456789",
+ "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
+ " \t\n\x0c\r",
+ "\x00\x01\x02\x03\x04\x05\x06\x07",
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+ "\x10\x11\x12\x13\x14\x15\x16\x17",
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+ "\x7f",
+ );
+}
+
+#[test]
+fn test_is_ascii_uppercase() {
+ assert_all!(is_ascii_uppercase, "", "ABCDEFGHIJKLMNOQPRSTUVWXYZ",);
+ assert_none!(
+ is_ascii_uppercase,
+ "abcdefghijklmnopqrstuvwxyz",
+ "0123456789",
+ "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
+ " \t\n\x0c\r",
+ "\x00\x01\x02\x03\x04\x05\x06\x07",
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+ "\x10\x11\x12\x13\x14\x15\x16\x17",
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+ "\x7f",
+ );
+}
+
+#[test]
+fn test_is_ascii_lowercase() {
+ assert_all!(is_ascii_lowercase, "abcdefghijklmnopqrstuvwxyz",);
+ assert_none!(
+ is_ascii_lowercase,
+ "ABCDEFGHIJKLMNOQPRSTUVWXYZ",
+ "0123456789",
+ "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
+ " \t\n\x0c\r",
+ "\x00\x01\x02\x03\x04\x05\x06\x07",
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+ "\x10\x11\x12\x13\x14\x15\x16\x17",
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+ "\x7f",
+ );
+}
+
+#[test]
+fn test_is_ascii_alphanumeric() {
+ assert_all!(
+ is_ascii_alphanumeric,
+ "",
+ "abcdefghijklmnopqrstuvwxyz",
+ "ABCDEFGHIJKLMNOQPRSTUVWXYZ",
+ "0123456789",
+ );
+ assert_none!(
+ is_ascii_alphanumeric,
+ "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
+ " \t\n\x0c\r",
+ "\x00\x01\x02\x03\x04\x05\x06\x07",
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+ "\x10\x11\x12\x13\x14\x15\x16\x17",
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+ "\x7f",
+ );
+}
+
+#[test]
+fn test_is_ascii_digit() {
+ assert_all!(is_ascii_digit, "", "0123456789",);
+ assert_none!(
+ is_ascii_digit,
+ "abcdefghijklmnopqrstuvwxyz",
+ "ABCDEFGHIJKLMNOQPRSTUVWXYZ",
+ "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
+ " \t\n\x0c\r",
+ "\x00\x01\x02\x03\x04\x05\x06\x07",
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+ "\x10\x11\x12\x13\x14\x15\x16\x17",
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+ "\x7f",
+ );
+}
+
+#[test]
+fn test_is_ascii_hexdigit() {
+ assert_all!(is_ascii_hexdigit, "", "0123456789", "abcdefABCDEF",);
+ assert_none!(
+ is_ascii_hexdigit,
+ "ghijklmnopqrstuvwxyz",
+ "GHIJKLMNOQPRSTUVWXYZ",
+ "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
+ " \t\n\x0c\r",
+ "\x00\x01\x02\x03\x04\x05\x06\x07",
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+ "\x10\x11\x12\x13\x14\x15\x16\x17",
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+ "\x7f",
+ );
+}
+
+#[test]
+fn test_is_ascii_punctuation() {
+ assert_all!(is_ascii_punctuation, "", "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",);
+ assert_none!(
+ is_ascii_punctuation,
+ "abcdefghijklmnopqrstuvwxyz",
+ "ABCDEFGHIJKLMNOQPRSTUVWXYZ",
+ "0123456789",
+ " \t\n\x0c\r",
+ "\x00\x01\x02\x03\x04\x05\x06\x07",
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+ "\x10\x11\x12\x13\x14\x15\x16\x17",
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+ "\x7f",
+ );
+}
+
+#[test]
+fn test_is_ascii_graphic() {
+ assert_all!(
+ is_ascii_graphic,
+ "",
+ "abcdefghijklmnopqrstuvwxyz",
+ "ABCDEFGHIJKLMNOQPRSTUVWXYZ",
+ "0123456789",
+ "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
+ );
+ assert_none!(
+ is_ascii_graphic,
+ " \t\n\x0c\r",
+ "\x00\x01\x02\x03\x04\x05\x06\x07",
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+ "\x10\x11\x12\x13\x14\x15\x16\x17",
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+ "\x7f",
+ );
+}
+
+#[test]
+fn test_is_ascii_whitespace() {
+ assert_all!(is_ascii_whitespace, "", " \t\n\x0c\r",);
+ assert_none!(
+ is_ascii_whitespace,
+ "abcdefghijklmnopqrstuvwxyz",
+ "ABCDEFGHIJKLMNOQPRSTUVWXYZ",
+ "0123456789",
+ "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
+ "\x00\x01\x02\x03\x04\x05\x06\x07",
+ "\x08\x0b\x0e\x0f",
+ "\x10\x11\x12\x13\x14\x15\x16\x17",
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+ "\x7f",
+ );
+}
+
+#[test]
+fn test_is_ascii_control() {
+ assert_all!(
+ is_ascii_control,
+ "",
+ "\x00\x01\x02\x03\x04\x05\x06\x07",
+ "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+ "\x10\x11\x12\x13\x14\x15\x16\x17",
+ "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+ "\x7f",
+ );
+ assert_none!(
+ is_ascii_control,
+ "abcdefghijklmnopqrstuvwxyz",
+ "ABCDEFGHIJKLMNOQPRSTUVWXYZ",
+ "0123456789",
+ "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
+ " ",
+ );
+}
+
+// `is_ascii` does a good amount of pointer manipulation and has
+// alignment-dependent computation. This is all sanity-checked via
+// `debug_assert!`s, so we test various sizes/alignments thoroughly versus an
+// "obviously correct" baseline function.
+#[test]
+fn test_is_ascii_align_size_thoroughly() {
+ // The "obviously-correct" baseline mentioned above.
+ fn is_ascii_baseline(s: &[u8]) -> bool {
+ s.iter().all(|b| b.is_ascii())
+ }
+
+ // Helper to repeat `l` copies of `b0` followed by `l` copies of `b1`.
+ fn repeat_concat(b0: u8, b1: u8, l: usize) -> Vec<u8> {
+ use core::iter::repeat;
+ repeat(b0).take(l).chain(repeat(b1).take(l)).collect()
+ }
+
+ // Miri is too slow
+ let iter = if cfg!(miri) { 0..20 } else { 0..100 };
+
+ for i in iter {
+ #[cfg(not(miri))]
+ let cases = &[
+ b"a".repeat(i),
+ b"\0".repeat(i),
+ b"\x7f".repeat(i),
+ b"\x80".repeat(i),
+ b"\xff".repeat(i),
+ repeat_concat(b'a', 0x80u8, i),
+ repeat_concat(0x80u8, b'a', i),
+ ];
+
+ #[cfg(miri)]
+ let cases = &[b"a".repeat(i), b"\x80".repeat(i), repeat_concat(b'a', 0x80u8, i)];
+
+ for case in cases {
+ for pos in 0..=case.len() {
+ // Potentially misaligned head
+ let prefix = &case[pos..];
+ assert_eq!(is_ascii_baseline(prefix), prefix.is_ascii(),);
+
+ // Potentially misaligned tail
+ let suffix = &case[..case.len() - pos];
+
+ assert_eq!(is_ascii_baseline(suffix), suffix.is_ascii(),);
+
+ // Both head and tail are potentially misaligned
+ let mid = &case[(pos / 2)..(case.len() - (pos / 2))];
+ assert_eq!(is_ascii_baseline(mid), mid.is_ascii(),);
+ }
+ }
+ }
+}
+
+#[test]
+fn ascii_const() {
+ // test that the `is_ascii` methods of `char` and `u8` are usable in a const context
+
+ const CHAR_IS_ASCII: bool = 'a'.is_ascii();
+ assert!(CHAR_IS_ASCII);
+
+ const BYTE_IS_ASCII: bool = 97u8.is_ascii();
+ assert!(BYTE_IS_ASCII);
+}
+
+#[test]
+fn ascii_ctype_const() {
+ macro_rules! suite {
+ ( $( $fn:ident => [$a:ident, $A:ident, $nine:ident, $dot:ident, $space:ident]; )* ) => {
+ $(
+ mod $fn {
+ const CHAR_A_LOWER: bool = 'a'.$fn();
+ const CHAR_A_UPPER: bool = 'A'.$fn();
+ const CHAR_NINE: bool = '9'.$fn();
+ const CHAR_DOT: bool = '.'.$fn();
+ const CHAR_SPACE: bool = ' '.$fn();
+
+ const U8_A_LOWER: bool = b'a'.$fn();
+ const U8_A_UPPER: bool = b'A'.$fn();
+ const U8_NINE: bool = b'9'.$fn();
+ const U8_DOT: bool = b'.'.$fn();
+ const U8_SPACE: bool = b' '.$fn();
+
+ pub fn run() {
+ assert_eq!(CHAR_A_LOWER, $a);
+ assert_eq!(CHAR_A_UPPER, $A);
+ assert_eq!(CHAR_NINE, $nine);
+ assert_eq!(CHAR_DOT, $dot);
+ assert_eq!(CHAR_SPACE, $space);
+
+ assert_eq!(U8_A_LOWER, $a);
+ assert_eq!(U8_A_UPPER, $A);
+ assert_eq!(U8_NINE, $nine);
+ assert_eq!(U8_DOT, $dot);
+ assert_eq!(U8_SPACE, $space);
+ }
+ }
+ )*
+
+ $( $fn::run(); )*
+ }
+ }
+
+ suite! {
+ // 'a' 'A' '9' '.' ' '
+ is_ascii_alphabetic => [true, true, false, false, false];
+ is_ascii_uppercase => [false, true, false, false, false];
+ is_ascii_lowercase => [true, false, false, false, false];
+ is_ascii_alphanumeric => [true, true, true, false, false];
+ is_ascii_digit => [false, false, true, false, false];
+ is_ascii_hexdigit => [true, true, true, false, false];
+ is_ascii_punctuation => [false, false, false, true, false];
+ is_ascii_graphic => [true, true, true, true, false];
+ is_ascii_whitespace => [false, false, false, false, true];
+ is_ascii_control => [false, false, false, false, false];
+ }
+}
diff --git a/library/core/tests/asserting.rs b/library/core/tests/asserting.rs
new file mode 100644
index 000000000..4b626ba6f
--- /dev/null
+++ b/library/core/tests/asserting.rs
@@ -0,0 +1,37 @@
+use core::asserting::{Capture, TryCaptureGeneric, TryCapturePrintable, Wrapper};
+
+macro_rules! test {
+ ($test_name:ident, $elem:expr, $captured_elem:expr, $output:literal) => {
+ #[test]
+ fn $test_name() {
+ let elem = $elem;
+ let mut capture = Capture::new();
+ assert!(capture.elem == None);
+ (&Wrapper(&elem)).try_capture(&mut capture);
+ assert!(capture.elem == $captured_elem);
+ assert_eq!(format!("{:?}", capture), $output);
+ }
+ };
+}
+
+#[derive(Debug, PartialEq)]
+struct NoCopy;
+
+#[derive(PartialEq)]
+struct NoCopyNoDebug;
+
+#[derive(Clone, Copy, PartialEq)]
+struct NoDebug;
+
+test!(
+ capture_with_non_copyable_and_non_debugabble_elem_has_correct_params,
+ NoCopyNoDebug,
+ None,
+ "N/A"
+);
+
+test!(capture_with_non_copyable_elem_has_correct_params, NoCopy, None, "N/A");
+
+test!(capture_with_non_debugabble_elem_has_correct_params, NoDebug, None, "N/A");
+
+test!(capture_with_copyable_and_debugabble_elem_has_correct_params, 1i32, Some(1i32), "1");
diff --git a/library/core/tests/atomic.rs b/library/core/tests/atomic.rs
new file mode 100644
index 000000000..13b12db20
--- /dev/null
+++ b/library/core/tests/atomic.rs
@@ -0,0 +1,314 @@
+use core::sync::atomic::Ordering::SeqCst;
+use core::sync::atomic::*;
+
+#[test]
+fn bool_() {
+ let a = AtomicBool::new(false);
+ assert_eq!(a.compare_exchange(false, true, SeqCst, SeqCst), Ok(false));
+ assert_eq!(a.compare_exchange(false, true, SeqCst, SeqCst), Err(true));
+
+ a.store(false, SeqCst);
+ assert_eq!(a.compare_exchange(false, true, SeqCst, SeqCst), Ok(false));
+}
+
+#[test]
+fn bool_and() {
+ let a = AtomicBool::new(true);
+ assert_eq!(a.fetch_and(false, SeqCst), true);
+ assert_eq!(a.load(SeqCst), false);
+}
+
+#[test]
+fn bool_nand() {
+ let a = AtomicBool::new(false);
+ assert_eq!(a.fetch_nand(false, SeqCst), false);
+ assert_eq!(a.load(SeqCst), true);
+ assert_eq!(a.fetch_nand(false, SeqCst), true);
+ assert_eq!(a.load(SeqCst), true);
+ assert_eq!(a.fetch_nand(true, SeqCst), true);
+ assert_eq!(a.load(SeqCst), false);
+ assert_eq!(a.fetch_nand(true, SeqCst), false);
+ assert_eq!(a.load(SeqCst), true);
+}
+
+#[test]
+fn uint_and() {
+ let x = AtomicUsize::new(0xf731);
+ assert_eq!(x.fetch_and(0x137f, SeqCst), 0xf731);
+ assert_eq!(x.load(SeqCst), 0xf731 & 0x137f);
+}
+
+#[test]
+fn uint_nand() {
+ let x = AtomicUsize::new(0xf731);
+ assert_eq!(x.fetch_nand(0x137f, SeqCst), 0xf731);
+ assert_eq!(x.load(SeqCst), !(0xf731 & 0x137f));
+}
+
+#[test]
+fn uint_or() {
+ let x = AtomicUsize::new(0xf731);
+ assert_eq!(x.fetch_or(0x137f, SeqCst), 0xf731);
+ assert_eq!(x.load(SeqCst), 0xf731 | 0x137f);
+}
+
+#[test]
+fn uint_xor() {
+ let x = AtomicUsize::new(0xf731);
+ assert_eq!(x.fetch_xor(0x137f, SeqCst), 0xf731);
+ assert_eq!(x.load(SeqCst), 0xf731 ^ 0x137f);
+}
+
+#[test]
+#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins
+fn uint_min() {
+ let x = AtomicUsize::new(0xf731);
+ assert_eq!(x.fetch_min(0x137f, SeqCst), 0xf731);
+ assert_eq!(x.load(SeqCst), 0x137f);
+ assert_eq!(x.fetch_min(0xf731, SeqCst), 0x137f);
+ assert_eq!(x.load(SeqCst), 0x137f);
+}
+
+#[test]
+#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins
+fn uint_max() {
+ let x = AtomicUsize::new(0x137f);
+ assert_eq!(x.fetch_max(0xf731, SeqCst), 0x137f);
+ assert_eq!(x.load(SeqCst), 0xf731);
+ assert_eq!(x.fetch_max(0x137f, SeqCst), 0xf731);
+ assert_eq!(x.load(SeqCst), 0xf731);
+}
+
+#[test]
+fn int_and() {
+ let x = AtomicIsize::new(0xf731);
+ assert_eq!(x.fetch_and(0x137f, SeqCst), 0xf731);
+ assert_eq!(x.load(SeqCst), 0xf731 & 0x137f);
+}
+
+#[test]
+fn int_nand() {
+ let x = AtomicIsize::new(0xf731);
+ assert_eq!(x.fetch_nand(0x137f, SeqCst), 0xf731);
+ assert_eq!(x.load(SeqCst), !(0xf731 & 0x137f));
+}
+
+#[test]
+fn int_or() {
+ let x = AtomicIsize::new(0xf731);
+ assert_eq!(x.fetch_or(0x137f, SeqCst), 0xf731);
+ assert_eq!(x.load(SeqCst), 0xf731 | 0x137f);
+}
+
+#[test]
+fn int_xor() {
+ let x = AtomicIsize::new(0xf731);
+ assert_eq!(x.fetch_xor(0x137f, SeqCst), 0xf731);
+ assert_eq!(x.load(SeqCst), 0xf731 ^ 0x137f);
+}
+
+#[test]
+#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins
+fn int_min() {
+ let x = AtomicIsize::new(0xf731);
+ assert_eq!(x.fetch_min(0x137f, SeqCst), 0xf731);
+ assert_eq!(x.load(SeqCst), 0x137f);
+ assert_eq!(x.fetch_min(0xf731, SeqCst), 0x137f);
+ assert_eq!(x.load(SeqCst), 0x137f);
+}
+
+#[test]
+#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins
+fn int_max() {
+ let x = AtomicIsize::new(0x137f);
+ assert_eq!(x.fetch_max(0xf731, SeqCst), 0x137f);
+ assert_eq!(x.load(SeqCst), 0xf731);
+ assert_eq!(x.fetch_max(0x137f, SeqCst), 0xf731);
+ assert_eq!(x.load(SeqCst), 0xf731);
+}
+
+#[test]
+#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins
+fn ptr_add_null() {
+ let atom = AtomicPtr::<i64>::new(core::ptr::null_mut());
+ assert_eq!(atom.fetch_ptr_add(1, SeqCst).addr(), 0);
+ assert_eq!(atom.load(SeqCst).addr(), 8);
+
+ assert_eq!(atom.fetch_byte_add(1, SeqCst).addr(), 8);
+ assert_eq!(atom.load(SeqCst).addr(), 9);
+
+ assert_eq!(atom.fetch_ptr_sub(1, SeqCst).addr(), 9);
+ assert_eq!(atom.load(SeqCst).addr(), 1);
+
+ assert_eq!(atom.fetch_byte_sub(1, SeqCst).addr(), 1);
+ assert_eq!(atom.load(SeqCst).addr(), 0);
+}
+
+#[test]
+#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins
+fn ptr_add_data() {
+ let num = 0i64;
+ let n = &num as *const i64 as *mut _;
+ let atom = AtomicPtr::<i64>::new(n);
+ assert_eq!(atom.fetch_ptr_add(1, SeqCst), n);
+ assert_eq!(atom.load(SeqCst), n.wrapping_add(1));
+
+ assert_eq!(atom.fetch_ptr_sub(1, SeqCst), n.wrapping_add(1));
+ assert_eq!(atom.load(SeqCst), n);
+ let bytes_from_n = |b| n.cast::<u8>().wrapping_add(b).cast::<i64>();
+
+ assert_eq!(atom.fetch_byte_add(1, SeqCst), n);
+ assert_eq!(atom.load(SeqCst), bytes_from_n(1));
+
+ assert_eq!(atom.fetch_byte_add(5, SeqCst), bytes_from_n(1));
+ assert_eq!(atom.load(SeqCst), bytes_from_n(6));
+
+ assert_eq!(atom.fetch_byte_sub(1, SeqCst), bytes_from_n(6));
+ assert_eq!(atom.load(SeqCst), bytes_from_n(5));
+
+ assert_eq!(atom.fetch_byte_sub(5, SeqCst), bytes_from_n(5));
+ assert_eq!(atom.load(SeqCst), n);
+}
+
+#[test]
+#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins
+fn ptr_bitops() {
+ let atom = AtomicPtr::<i64>::new(core::ptr::null_mut());
+ assert_eq!(atom.fetch_or(0b0111, SeqCst).addr(), 0);
+ assert_eq!(atom.load(SeqCst).addr(), 0b0111);
+
+ assert_eq!(atom.fetch_and(0b1101, SeqCst).addr(), 0b0111);
+ assert_eq!(atom.load(SeqCst).addr(), 0b0101);
+
+ assert_eq!(atom.fetch_xor(0b1111, SeqCst).addr(), 0b0101);
+ assert_eq!(atom.load(SeqCst).addr(), 0b1010);
+}
+
+#[test]
+#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins
+fn ptr_bitops_tagging() {
+ #[repr(align(16))]
+ struct Tagme(u128);
+
+ let tagme = Tagme(1000);
+ let ptr = &tagme as *const Tagme as *mut Tagme;
+ let atom: AtomicPtr<Tagme> = AtomicPtr::new(ptr);
+
+ const MASK_TAG: usize = 0b1111;
+ const MASK_PTR: usize = !MASK_TAG;
+
+ assert_eq!(ptr.addr() & MASK_TAG, 0);
+
+ assert_eq!(atom.fetch_or(0b0111, SeqCst), ptr);
+ assert_eq!(atom.load(SeqCst), ptr.map_addr(|a| a | 0b111));
+
+ assert_eq!(atom.fetch_and(MASK_PTR | 0b0010, SeqCst), ptr.map_addr(|a| a | 0b111));
+ assert_eq!(atom.load(SeqCst), ptr.map_addr(|a| a | 0b0010));
+
+ assert_eq!(atom.fetch_xor(0b1011, SeqCst), ptr.map_addr(|a| a | 0b0010));
+ assert_eq!(atom.load(SeqCst), ptr.map_addr(|a| a | 0b1001));
+
+ assert_eq!(atom.fetch_and(MASK_PTR, SeqCst), ptr.map_addr(|a| a | 0b1001));
+ assert_eq!(atom.load(SeqCst), ptr);
+}
+
+static S_FALSE: AtomicBool = AtomicBool::new(false);
+static S_TRUE: AtomicBool = AtomicBool::new(true);
+static S_INT: AtomicIsize = AtomicIsize::new(0);
+static S_UINT: AtomicUsize = AtomicUsize::new(0);
+
+#[test]
+fn static_init() {
+ // Note that we're not really testing the mutability here but it's important
+ // on Android at the moment (#49775)
+ assert!(!S_FALSE.swap(true, SeqCst));
+ assert!(S_TRUE.swap(false, SeqCst));
+ assert!(S_INT.fetch_add(1, SeqCst) == 0);
+ assert!(S_UINT.fetch_add(1, SeqCst) == 0);
+}
+
+#[test]
+fn atomic_access_bool() {
+ static mut ATOMIC: AtomicBool = AtomicBool::new(false);
+
+ unsafe {
+ assert_eq!(*ATOMIC.get_mut(), false);
+ ATOMIC.store(true, SeqCst);
+ assert_eq!(*ATOMIC.get_mut(), true);
+ ATOMIC.fetch_or(false, SeqCst);
+ assert_eq!(*ATOMIC.get_mut(), true);
+ ATOMIC.fetch_and(false, SeqCst);
+ assert_eq!(*ATOMIC.get_mut(), false);
+ ATOMIC.fetch_nand(true, SeqCst);
+ assert_eq!(*ATOMIC.get_mut(), true);
+ ATOMIC.fetch_xor(true, SeqCst);
+ assert_eq!(*ATOMIC.get_mut(), false);
+ }
+}
+
+#[test]
+fn atomic_alignment() {
+ use std::mem::{align_of, size_of};
+
+ #[cfg(target_has_atomic = "8")]
+ assert_eq!(align_of::<AtomicBool>(), size_of::<AtomicBool>());
+ #[cfg(target_has_atomic = "ptr")]
+ assert_eq!(align_of::<AtomicPtr<u8>>(), size_of::<AtomicPtr<u8>>());
+ #[cfg(target_has_atomic = "8")]
+ assert_eq!(align_of::<AtomicU8>(), size_of::<AtomicU8>());
+ #[cfg(target_has_atomic = "8")]
+ assert_eq!(align_of::<AtomicI8>(), size_of::<AtomicI8>());
+ #[cfg(target_has_atomic = "16")]
+ assert_eq!(align_of::<AtomicU16>(), size_of::<AtomicU16>());
+ #[cfg(target_has_atomic = "16")]
+ assert_eq!(align_of::<AtomicI16>(), size_of::<AtomicI16>());
+ #[cfg(target_has_atomic = "32")]
+ assert_eq!(align_of::<AtomicU32>(), size_of::<AtomicU32>());
+ #[cfg(target_has_atomic = "32")]
+ assert_eq!(align_of::<AtomicI32>(), size_of::<AtomicI32>());
+ #[cfg(target_has_atomic = "64")]
+ assert_eq!(align_of::<AtomicU64>(), size_of::<AtomicU64>());
+ #[cfg(target_has_atomic = "64")]
+ assert_eq!(align_of::<AtomicI64>(), size_of::<AtomicI64>());
+ #[cfg(target_has_atomic = "128")]
+ assert_eq!(align_of::<AtomicU128>(), size_of::<AtomicU128>());
+ #[cfg(target_has_atomic = "128")]
+ assert_eq!(align_of::<AtomicI128>(), size_of::<AtomicI128>());
+ #[cfg(target_has_atomic = "ptr")]
+ assert_eq!(align_of::<AtomicUsize>(), size_of::<AtomicUsize>());
+ #[cfg(target_has_atomic = "ptr")]
+ assert_eq!(align_of::<AtomicIsize>(), size_of::<AtomicIsize>());
+}
+
+#[test]
+fn atomic_compare_exchange() {
+ use Ordering::*;
+
+ static ATOMIC: AtomicIsize = AtomicIsize::new(0);
+
+ ATOMIC.compare_exchange(0, 1, Relaxed, Relaxed).ok();
+ ATOMIC.compare_exchange(0, 1, Acquire, Relaxed).ok();
+ ATOMIC.compare_exchange(0, 1, Release, Relaxed).ok();
+ ATOMIC.compare_exchange(0, 1, AcqRel, Relaxed).ok();
+ ATOMIC.compare_exchange(0, 1, SeqCst, Relaxed).ok();
+ ATOMIC.compare_exchange(0, 1, Acquire, Acquire).ok();
+ ATOMIC.compare_exchange(0, 1, AcqRel, Acquire).ok();
+ ATOMIC.compare_exchange(0, 1, SeqCst, Acquire).ok();
+ ATOMIC.compare_exchange(0, 1, SeqCst, SeqCst).ok();
+ ATOMIC.compare_exchange_weak(0, 1, Relaxed, Relaxed).ok();
+ ATOMIC.compare_exchange_weak(0, 1, Acquire, Relaxed).ok();
+ ATOMIC.compare_exchange_weak(0, 1, Release, Relaxed).ok();
+ ATOMIC.compare_exchange_weak(0, 1, AcqRel, Relaxed).ok();
+ ATOMIC.compare_exchange_weak(0, 1, SeqCst, Relaxed).ok();
+ ATOMIC.compare_exchange_weak(0, 1, Acquire, Acquire).ok();
+ ATOMIC.compare_exchange_weak(0, 1, AcqRel, Acquire).ok();
+ ATOMIC.compare_exchange_weak(0, 1, SeqCst, Acquire).ok();
+ ATOMIC.compare_exchange_weak(0, 1, SeqCst, SeqCst).ok();
+}
+
+#[test]
+fn atomic_const_from() {
+ const _ATOMIC_U8: AtomicU8 = AtomicU8::from(1);
+ const _ATOMIC_BOOL: AtomicBool = AtomicBool::from(true);
+ const _ATOMIC_PTR: AtomicPtr<u32> = AtomicPtr::from(core::ptr::null_mut());
+}
diff --git a/library/core/tests/bool.rs b/library/core/tests/bool.rs
new file mode 100644
index 000000000..4819ce911
--- /dev/null
+++ b/library/core/tests/bool.rs
@@ -0,0 +1,105 @@
+use core::cmp::Ordering::{Equal, Greater, Less};
+use core::ops::{BitAnd, BitOr, BitXor};
+
+#[test]
+fn test_bool() {
+ assert_eq!(false.eq(&true), false);
+ assert_eq!(false == false, true);
+ assert_eq!(false != true, true);
+ assert_eq!(false.ne(&false), false);
+
+ assert_eq!(false.bitand(false), false);
+ assert_eq!(true.bitand(false), false);
+ assert_eq!(false.bitand(true), false);
+ assert_eq!(true.bitand(true), true);
+
+ assert_eq!(false & false, false);
+ assert_eq!(true & false, false);
+ assert_eq!(false & true, false);
+ assert_eq!(true & true, true);
+
+ assert_eq!(false.bitor(false), false);
+ assert_eq!(true.bitor(false), true);
+ assert_eq!(false.bitor(true), true);
+ assert_eq!(true.bitor(true), true);
+
+ assert_eq!(false | false, false);
+ assert_eq!(true | false, true);
+ assert_eq!(false | true, true);
+ assert_eq!(true | true, true);
+
+ assert_eq!(false.bitxor(false), false);
+ assert_eq!(true.bitxor(false), true);
+ assert_eq!(false.bitxor(true), true);
+ assert_eq!(true.bitxor(true), false);
+
+ assert_eq!(false ^ false, false);
+ assert_eq!(true ^ false, true);
+ assert_eq!(false ^ true, true);
+ assert_eq!(true ^ true, false);
+
+ assert_eq!(!true, false);
+ assert_eq!(!false, true);
+
+ let s = false.to_string();
+ assert_eq!(s, "false");
+ let s = true.to_string();
+ assert_eq!(s, "true");
+
+ assert!(true > false);
+ assert!(!(false > true));
+
+ assert!(false < true);
+ assert!(!(true < false));
+
+ assert!(false <= false);
+ assert!(false >= false);
+ assert!(true <= true);
+ assert!(true >= true);
+
+ assert!(false <= true);
+ assert!(!(false >= true));
+ assert!(true >= false);
+ assert!(!(true <= false));
+
+ assert_eq!(true.cmp(&true), Equal);
+ assert_eq!(false.cmp(&false), Equal);
+ assert_eq!(true.cmp(&false), Greater);
+ assert_eq!(false.cmp(&true), Less);
+}
+
+#[test]
+pub fn test_bool_not() {
+ if !false {
+ assert!((true));
+ } else {
+ assert!((false));
+ }
+ if !true {
+ assert!((false));
+ } else {
+ assert!((true));
+ }
+}
+
+#[test]
+fn test_bool_to_option() {
+ assert_eq!(false.then_some(0), None);
+ assert_eq!(true.then_some(0), Some(0));
+ assert_eq!(false.then(|| 0), None);
+ assert_eq!(true.then(|| 0), Some(0));
+
+ const fn zero() -> i32 {
+ 0
+ }
+
+ const A: Option<i32> = false.then_some(0);
+ const B: Option<i32> = true.then_some(0);
+ const C: Option<i32> = false.then(zero);
+ const D: Option<i32> = true.then(zero);
+
+ assert_eq!(A, None);
+ assert_eq!(B, Some(0));
+ assert_eq!(C, None);
+ assert_eq!(D, Some(0));
+}
diff --git a/library/core/tests/cell.rs b/library/core/tests/cell.rs
new file mode 100644
index 000000000..7b77b2134
--- /dev/null
+++ b/library/core/tests/cell.rs
@@ -0,0 +1,479 @@
+use core::cell::*;
+use core::default::Default;
+use std::mem::drop;
+
+#[test]
+fn smoketest_unsafe_cell() {
+ let mut x = UnsafeCell::new(10);
+ let ref_mut = &mut x;
+ unsafe {
+ // The asserts are repeated in order to ensure that `get()`
+ // is non-mutating.
+ assert_eq!(*ref_mut.get(), 10);
+ assert_eq!(*ref_mut.get(), 10);
+ *ref_mut.get_mut() += 5;
+ assert_eq!(*ref_mut.get(), 15);
+ assert_eq!(*ref_mut.get(), 15);
+ assert_eq!(x.into_inner(), 15);
+ }
+}
+
+#[test]
+fn unsafe_cell_raw_get() {
+ let x = UnsafeCell::new(10);
+ let ptr = &x as *const UnsafeCell<i32>;
+ unsafe {
+ // The asserts are repeated in order to ensure that `raw_get()`
+ // is non-mutating.
+ assert_eq!(*UnsafeCell::raw_get(ptr), 10);
+ assert_eq!(*UnsafeCell::raw_get(ptr), 10);
+ *UnsafeCell::raw_get(ptr) += 5;
+ assert_eq!(*UnsafeCell::raw_get(ptr), 15);
+ assert_eq!(*UnsafeCell::raw_get(ptr), 15);
+ assert_eq!(x.into_inner(), 15);
+ }
+}
+
+#[test]
+fn smoketest_cell() {
+ let x = Cell::new(10);
+ assert_eq!(x, Cell::new(10));
+ assert_eq!(x.get(), 10);
+ x.set(20);
+ assert_eq!(x, Cell::new(20));
+ assert_eq!(x.get(), 20);
+
+ let y = Cell::new((30, 40));
+ assert_eq!(y, Cell::new((30, 40)));
+ assert_eq!(y.get(), (30, 40));
+}
+
+#[test]
+fn cell_update() {
+ let x = Cell::new(10);
+
+ assert_eq!(x.update(|x| x + 5), 15);
+ assert_eq!(x.get(), 15);
+
+ assert_eq!(x.update(|x| x / 3), 5);
+ assert_eq!(x.get(), 5);
+}
+
+#[test]
+fn cell_has_sensible_show() {
+ let x = Cell::new("foo bar");
+ assert!(format!("{x:?}").contains(x.get()));
+
+ x.set("baz qux");
+ assert!(format!("{x:?}").contains(x.get()));
+}
+
+#[test]
+fn ref_and_refmut_have_sensible_show() {
+ let refcell = RefCell::new("foo");
+
+ let refcell_refmut = refcell.borrow_mut();
+ assert_eq!(format!("{refcell_refmut}"), "foo"); // Display
+ assert!(format!("{refcell_refmut:?}").contains("foo")); // Debug
+ drop(refcell_refmut);
+
+ let refcell_ref = refcell.borrow();
+ assert_eq!(format!("{refcell_ref}"), "foo"); // Display
+ assert!(format!("{refcell_ref:?}").contains("foo")); // Debug
+ drop(refcell_ref);
+}
+
+#[test]
+fn double_imm_borrow() {
+ let x = RefCell::new(0);
+ let _b1 = x.borrow();
+ x.borrow();
+}
+
+#[test]
+fn no_mut_then_imm_borrow() {
+ let x = RefCell::new(0);
+ let _b1 = x.borrow_mut();
+ assert!(x.try_borrow().is_err());
+}
+
+#[test]
+fn no_imm_then_borrow_mut() {
+ let x = RefCell::new(0);
+ let _b1 = x.borrow();
+ assert!(x.try_borrow_mut().is_err());
+}
+
+#[test]
+fn no_double_borrow_mut() {
+ let x = RefCell::new(0);
+ assert!(x.try_borrow().is_ok());
+ let _b1 = x.borrow_mut();
+ assert!(x.try_borrow().is_err());
+}
+
+#[test]
+fn imm_release_borrow_mut() {
+ let x = RefCell::new(0);
+ {
+ let _b1 = x.borrow();
+ }
+ x.borrow_mut();
+}
+
+#[test]
+fn mut_release_borrow_mut() {
+ let x = RefCell::new(0);
+ {
+ let _b1 = x.borrow_mut();
+ }
+ x.borrow();
+}
+
+#[test]
+fn double_borrow_single_release_no_borrow_mut() {
+ let x = RefCell::new(0);
+ let _b1 = x.borrow();
+ {
+ let _b2 = x.borrow();
+ }
+ assert!(x.try_borrow().is_ok());
+ assert!(x.try_borrow_mut().is_err());
+}
+
+#[test]
+#[should_panic]
+fn discard_doesnt_unborrow() {
+ let x = RefCell::new(0);
+ let _b = x.borrow();
+ let _ = _b;
+ let _b = x.borrow_mut();
+}
+
+#[test]
+fn ref_clone_updates_flag() {
+ let x = RefCell::new(0);
+ {
+ let b1 = x.borrow();
+ assert!(x.try_borrow().is_ok());
+ assert!(x.try_borrow_mut().is_err());
+ {
+ let _b2 = Ref::clone(&b1);
+ assert!(x.try_borrow().is_ok());
+ assert!(x.try_borrow_mut().is_err());
+ }
+ assert!(x.try_borrow().is_ok());
+ assert!(x.try_borrow_mut().is_err());
+ }
+ assert!(x.try_borrow().is_ok());
+ assert!(x.try_borrow_mut().is_ok());
+}
+
+#[test]
+fn ref_map_does_not_update_flag() {
+ let x = RefCell::new(Some(5));
+ {
+ let b1: Ref<'_, Option<u32>> = x.borrow();
+ assert!(x.try_borrow().is_ok());
+ assert!(x.try_borrow_mut().is_err());
+ {
+ let b2: Ref<'_, u32> = Ref::map(b1, |o| o.as_ref().unwrap());
+ assert_eq!(*b2, 5);
+ assert!(x.try_borrow().is_ok());
+ assert!(x.try_borrow_mut().is_err());
+ }
+ assert!(x.try_borrow().is_ok());
+ assert!(x.try_borrow_mut().is_ok());
+ }
+ assert!(x.try_borrow().is_ok());
+ assert!(x.try_borrow_mut().is_ok());
+}
+
+#[test]
+fn ref_map_split_updates_flag() {
+ let x = RefCell::new([1, 2]);
+ {
+ let b1 = x.borrow();
+ assert!(x.try_borrow().is_ok());
+ assert!(x.try_borrow_mut().is_err());
+ {
+ let (_b2, _b3) = Ref::map_split(b1, |slc| slc.split_at(1));
+ assert!(x.try_borrow().is_ok());
+ assert!(x.try_borrow_mut().is_err());
+ }
+ assert!(x.try_borrow().is_ok());
+ assert!(x.try_borrow_mut().is_ok());
+ }
+ assert!(x.try_borrow().is_ok());
+ assert!(x.try_borrow_mut().is_ok());
+
+ {
+ let b1 = x.borrow_mut();
+ assert!(x.try_borrow().is_err());
+ assert!(x.try_borrow_mut().is_err());
+ {
+ let (_b2, _b3) = RefMut::map_split(b1, |slc| slc.split_at_mut(1));
+ assert!(x.try_borrow().is_err());
+ assert!(x.try_borrow_mut().is_err());
+ drop(_b2);
+ assert!(x.try_borrow().is_err());
+ assert!(x.try_borrow_mut().is_err());
+ }
+ assert!(x.try_borrow().is_ok());
+ assert!(x.try_borrow_mut().is_ok());
+ }
+ assert!(x.try_borrow().is_ok());
+ assert!(x.try_borrow_mut().is_ok());
+}
+
+#[test]
+fn ref_map_split() {
+ let x = RefCell::new([1, 2]);
+ let (b1, b2) = Ref::map_split(x.borrow(), |slc| slc.split_at(1));
+ assert_eq!(*b1, [1]);
+ assert_eq!(*b2, [2]);
+}
+
+#[test]
+fn ref_mut_map_split() {
+ let x = RefCell::new([1, 2]);
+ {
+ let (mut b1, mut b2) = RefMut::map_split(x.borrow_mut(), |slc| slc.split_at_mut(1));
+ assert_eq!(*b1, [1]);
+ assert_eq!(*b2, [2]);
+ b1[0] = 2;
+ b2[0] = 1;
+ }
+ assert_eq!(*x.borrow(), [2, 1]);
+}
+
+#[test]
+fn ref_map_accessor() {
+ struct X(RefCell<(u32, char)>);
+ impl X {
+ fn accessor(&self) -> Ref<'_, u32> {
+ Ref::map(self.0.borrow(), |tuple| &tuple.0)
+ }
+ }
+ let x = X(RefCell::new((7, 'z')));
+ let d: Ref<'_, u32> = x.accessor();
+ assert_eq!(*d, 7);
+}
+
+#[test]
+fn ref_mut_map_accessor() {
+ struct X(RefCell<(u32, char)>);
+ impl X {
+ fn accessor(&self) -> RefMut<'_, u32> {
+ RefMut::map(self.0.borrow_mut(), |tuple| &mut tuple.0)
+ }
+ }
+ let x = X(RefCell::new((7, 'z')));
+ {
+ let mut d: RefMut<'_, u32> = x.accessor();
+ assert_eq!(*d, 7);
+ *d += 1;
+ }
+ assert_eq!(*x.0.borrow(), (8, 'z'));
+}
+
+#[test]
+fn as_ptr() {
+ let c1: Cell<usize> = Cell::new(0);
+ c1.set(1);
+ assert_eq!(1, unsafe { *c1.as_ptr() });
+
+ let c2: Cell<usize> = Cell::new(0);
+ unsafe {
+ *c2.as_ptr() = 1;
+ }
+ assert_eq!(1, c2.get());
+
+ let r1: RefCell<usize> = RefCell::new(0);
+ *r1.borrow_mut() = 1;
+ assert_eq!(1, unsafe { *r1.as_ptr() });
+
+ let r2: RefCell<usize> = RefCell::new(0);
+ unsafe {
+ *r2.as_ptr() = 1;
+ }
+ assert_eq!(1, *r2.borrow());
+}
+
+#[test]
+fn cell_default() {
+ let cell: Cell<u32> = Default::default();
+ assert_eq!(0, cell.get());
+}
+
+#[test]
+fn cell_set() {
+ let cell = Cell::new(10);
+ cell.set(20);
+ assert_eq!(20, cell.get());
+
+ let cell = Cell::new("Hello".to_owned());
+ cell.set("World".to_owned());
+ assert_eq!("World".to_owned(), cell.into_inner());
+}
+
+#[test]
+fn cell_replace() {
+ let cell = Cell::new(10);
+ assert_eq!(10, cell.replace(20));
+ assert_eq!(20, cell.get());
+
+ let cell = Cell::new("Hello".to_owned());
+ assert_eq!("Hello".to_owned(), cell.replace("World".to_owned()));
+ assert_eq!("World".to_owned(), cell.into_inner());
+}
+
+#[test]
+fn cell_into_inner() {
+ let cell = Cell::new(10);
+ assert_eq!(10, cell.into_inner());
+
+ let cell = Cell::new("Hello world".to_owned());
+ assert_eq!("Hello world".to_owned(), cell.into_inner());
+}
+
+#[test]
+fn cell_exterior() {
+ #[derive(Copy, Clone)]
+ #[allow(dead_code)]
+ struct Point {
+ x: isize,
+ y: isize,
+ z: isize,
+ }
+
+ fn f(p: &Cell<Point>) {
+ assert_eq!(p.get().z, 12);
+ p.set(Point { x: 10, y: 11, z: 13 });
+ assert_eq!(p.get().z, 13);
+ }
+
+ let a = Point { x: 10, y: 11, z: 12 };
+ let b = &Cell::new(a);
+ assert_eq!(b.get().z, 12);
+ f(b);
+ assert_eq!(a.z, 12);
+ assert_eq!(b.get().z, 13);
+}
+
+#[test]
+fn cell_does_not_clone() {
+ #[derive(Copy)]
+ #[allow(dead_code)]
+ struct Foo {
+ x: isize,
+ }
+
+ impl Clone for Foo {
+ fn clone(&self) -> Foo {
+ // Using Cell in any way should never cause clone() to be
+ // invoked -- after all, that would permit evil user code to
+ // abuse `Cell` and trigger crashes.
+
+ panic!();
+ }
+ }
+
+ let x = Cell::new(Foo { x: 22 });
+ let _y = x.get();
+ let _z = x.clone();
+}
+
+#[test]
+fn refcell_default() {
+ let cell: RefCell<u64> = Default::default();
+ assert_eq!(0, *cell.borrow());
+}
+
+#[test]
+fn unsafe_cell_unsized() {
+ let cell: &UnsafeCell<[i32]> = &UnsafeCell::new([1, 2, 3]);
+ {
+ let val: &mut [i32] = unsafe { &mut *cell.get() };
+ val[0] = 4;
+ val[2] = 5;
+ }
+ let comp: &mut [i32] = &mut [4, 2, 5];
+ assert_eq!(unsafe { &mut *cell.get() }, comp);
+}
+
+#[test]
+fn refcell_unsized() {
+ let cell: &RefCell<[i32]> = &RefCell::new([1, 2, 3]);
+ {
+ let b = &mut *cell.borrow_mut();
+ b[0] = 4;
+ b[2] = 5;
+ }
+ let comp: &mut [i32] = &mut [4, 2, 5];
+ assert_eq!(&*cell.borrow(), comp);
+}
+
+#[test]
+fn refcell_ref_coercion() {
+ let cell: RefCell<[i32; 3]> = RefCell::new([1, 2, 3]);
+ {
+ let mut cellref: RefMut<'_, [i32; 3]> = cell.borrow_mut();
+ cellref[0] = 4;
+ let mut coerced: RefMut<'_, [i32]> = cellref;
+ coerced[2] = 5;
+ }
+ {
+ let comp: &mut [i32] = &mut [4, 2, 5];
+ let cellref: Ref<'_, [i32; 3]> = cell.borrow();
+ assert_eq!(&*cellref, comp);
+ let coerced: Ref<'_, [i32]> = cellref;
+ assert_eq!(&*coerced, comp);
+ }
+}
+
+#[test]
+#[should_panic]
+fn refcell_swap_borrows() {
+ let x = RefCell::new(0);
+ let _b = x.borrow();
+ let y = RefCell::new(1);
+ x.swap(&y);
+}
+
+#[test]
+#[should_panic]
+fn refcell_replace_borrows() {
+ let x = RefCell::new(0);
+ let _b = x.borrow();
+ x.replace(1);
+}
+
+#[test]
+fn refcell_format() {
+ let name = RefCell::new("rust");
+ let what = RefCell::new("rocks");
+ let msg = format!("{name} {}", &*what.borrow(), name = &*name.borrow());
+ assert_eq!(msg, "rust rocks".to_string());
+}
+
+#[allow(dead_code)]
+fn const_cells() {
+ const UNSAFE_CELL: UnsafeCell<i32> = UnsafeCell::new(3);
+ const _: i32 = UNSAFE_CELL.into_inner();
+
+ const REF_CELL: RefCell<i32> = RefCell::new(3);
+ const _: i32 = REF_CELL.into_inner();
+
+ const CELL: Cell<i32> = Cell::new(3);
+ const _: i32 = CELL.into_inner();
+
+ const UNSAFE_CELL_FROM: UnsafeCell<i32> = UnsafeCell::from(3);
+ const _: i32 = UNSAFE_CELL.into_inner();
+
+ const REF_CELL_FROM: RefCell<i32> = RefCell::from(3);
+ const _: i32 = REF_CELL.into_inner();
+
+ const CELL_FROM: Cell<i32> = Cell::from(3);
+ const _: i32 = CELL.into_inner();
+}
diff --git a/library/core/tests/char.rs b/library/core/tests/char.rs
new file mode 100644
index 000000000..8542e5c70
--- /dev/null
+++ b/library/core/tests/char.rs
@@ -0,0 +1,415 @@
+use std::convert::TryFrom;
+use std::str::FromStr;
+use std::{char, str};
+
+#[test]
+fn test_convert() {
+ assert_eq!(u32::from('a'), 0x61);
+ assert_eq!(u64::from('b'), 0x62);
+ assert_eq!(u128::from('c'), 0x63);
+ assert_eq!(char::from(b'\0'), '\0');
+ assert_eq!(char::from(b'a'), 'a');
+ assert_eq!(char::from(b'\xFF'), '\u{FF}');
+ assert_eq!(char::try_from(0_u32), Ok('\0'));
+ assert_eq!(char::try_from(0x61_u32), Ok('a'));
+ assert_eq!(char::try_from(0xD7FF_u32), Ok('\u{D7FF}'));
+ assert!(char::try_from(0xD800_u32).is_err());
+ assert!(char::try_from(0xDFFF_u32).is_err());
+ assert_eq!(char::try_from(0xE000_u32), Ok('\u{E000}'));
+ assert_eq!(char::try_from(0x10FFFF_u32), Ok('\u{10FFFF}'));
+ assert!(char::try_from(0x110000_u32).is_err());
+ assert!(char::try_from(0xFFFF_FFFF_u32).is_err());
+}
+
+#[test]
+const fn test_convert_const() {
+ assert!(u32::from('a') == 0x61);
+ assert!(u64::from('b') == 0x62);
+ assert!(u128::from('c') == 0x63);
+ assert!(char::from(b'\0') == '\0');
+ assert!(char::from(b'a') == 'a');
+ assert!(char::from(b'\xFF') == '\u{FF}');
+}
+
+#[test]
+fn test_from_str() {
+ assert_eq!(char::from_str("a").unwrap(), 'a');
+ assert_eq!(char::from_str("\0").unwrap(), '\0');
+ assert_eq!(char::from_str("\u{D7FF}").unwrap(), '\u{d7FF}');
+ assert!(char::from_str("").is_err());
+ assert!(char::from_str("abc").is_err());
+}
+
+#[test]
+fn test_is_lowercase() {
+ assert!('a'.is_lowercase());
+ assert!('ö'.is_lowercase());
+ assert!('ß'.is_lowercase());
+ assert!(!'Ü'.is_lowercase());
+ assert!(!'P'.is_lowercase());
+}
+
+#[test]
+fn test_is_uppercase() {
+ assert!(!'h'.is_uppercase());
+ assert!(!'ä'.is_uppercase());
+ assert!(!'ß'.is_uppercase());
+ assert!('Ö'.is_uppercase());
+ assert!('T'.is_uppercase());
+}
+
+#[test]
+fn test_is_whitespace() {
+ assert!(' '.is_whitespace());
+ assert!('\u{2007}'.is_whitespace());
+ assert!('\t'.is_whitespace());
+ assert!('\n'.is_whitespace());
+ assert!(!'a'.is_whitespace());
+ assert!(!'_'.is_whitespace());
+ assert!(!'\u{0}'.is_whitespace());
+}
+
+#[test]
+fn test_to_digit() {
+ assert_eq!('0'.to_digit(10), Some(0));
+ assert_eq!('1'.to_digit(2), Some(1));
+ assert_eq!('2'.to_digit(3), Some(2));
+ assert_eq!('9'.to_digit(10), Some(9));
+ assert_eq!('a'.to_digit(16), Some(10));
+ assert_eq!('A'.to_digit(16), Some(10));
+ assert_eq!('b'.to_digit(16), Some(11));
+ assert_eq!('B'.to_digit(16), Some(11));
+ assert_eq!('A'.to_digit(36), Some(10));
+ assert_eq!('z'.to_digit(36), Some(35));
+ assert_eq!('Z'.to_digit(36), Some(35));
+ assert_eq!('['.to_digit(36), None);
+ assert_eq!('`'.to_digit(36), None);
+ assert_eq!('{'.to_digit(36), None);
+ assert_eq!('$'.to_digit(36), None);
+ assert_eq!('@'.to_digit(16), None);
+ assert_eq!('G'.to_digit(16), None);
+ assert_eq!('g'.to_digit(16), None);
+ assert_eq!(' '.to_digit(10), None);
+ assert_eq!('/'.to_digit(10), None);
+ assert_eq!(':'.to_digit(10), None);
+ assert_eq!(':'.to_digit(11), None);
+}
+
+#[test]
+fn test_to_lowercase() {
+ fn lower(c: char) -> String {
+ let to_lowercase = c.to_lowercase();
+ assert_eq!(to_lowercase.len(), to_lowercase.count());
+ let iter: String = c.to_lowercase().collect();
+ let disp: String = c.to_lowercase().to_string();
+ assert_eq!(iter, disp);
+ let iter_rev: String = c.to_lowercase().rev().collect();
+ let disp_rev: String = disp.chars().rev().collect();
+ assert_eq!(iter_rev, disp_rev);
+ iter
+ }
+ assert_eq!(lower('A'), "a");
+ assert_eq!(lower('Ö'), "ö");
+ assert_eq!(lower('ß'), "ß");
+ assert_eq!(lower('Ü'), "ü");
+ assert_eq!(lower('💩'), "💩");
+ assert_eq!(lower('Σ'), "σ");
+ assert_eq!(lower('Τ'), "τ");
+ assert_eq!(lower('Ι'), "ι");
+ assert_eq!(lower('Γ'), "γ");
+ assert_eq!(lower('Μ'), "μ");
+ assert_eq!(lower('Α'), "α");
+ assert_eq!(lower('Σ'), "σ");
+ assert_eq!(lower('Dž'), "dž");
+ assert_eq!(lower('fi'), "fi");
+ assert_eq!(lower('İ'), "i\u{307}");
+}
+
+#[test]
+fn test_to_uppercase() {
+ fn upper(c: char) -> String {
+ let to_uppercase = c.to_uppercase();
+ assert_eq!(to_uppercase.len(), to_uppercase.count());
+ let iter: String = c.to_uppercase().collect();
+ let disp: String = c.to_uppercase().to_string();
+ assert_eq!(iter, disp);
+ let iter_rev: String = c.to_uppercase().rev().collect();
+ let disp_rev: String = disp.chars().rev().collect();
+ assert_eq!(iter_rev, disp_rev);
+ iter
+ }
+ assert_eq!(upper('a'), "A");
+ assert_eq!(upper('ö'), "Ö");
+ assert_eq!(upper('ß'), "SS"); // not ẞ: Latin capital letter sharp s
+ assert_eq!(upper('ü'), "Ü");
+ assert_eq!(upper('💩'), "💩");
+
+ assert_eq!(upper('σ'), "Σ");
+ assert_eq!(upper('τ'), "Τ");
+ assert_eq!(upper('ι'), "Ι");
+ assert_eq!(upper('γ'), "Γ");
+ assert_eq!(upper('μ'), "Μ");
+ assert_eq!(upper('α'), "Α");
+ assert_eq!(upper('ς'), "Σ");
+ assert_eq!(upper('Dž'), "DŽ");
+ assert_eq!(upper('fi'), "FI");
+ assert_eq!(upper('ᾀ'), "ἈΙ");
+}
+
+#[test]
+fn test_is_control() {
+ assert!('\u{0}'.is_control());
+ assert!('\u{3}'.is_control());
+ assert!('\u{6}'.is_control());
+ assert!('\u{9}'.is_control());
+ assert!('\u{7f}'.is_control());
+ assert!('\u{92}'.is_control());
+ assert!(!'\u{20}'.is_control());
+ assert!(!'\u{55}'.is_control());
+ assert!(!'\u{68}'.is_control());
+}
+
+#[test]
+fn test_is_numeric() {
+ assert!('2'.is_numeric());
+ assert!('7'.is_numeric());
+ assert!('¾'.is_numeric());
+ assert!(!'c'.is_numeric());
+ assert!(!'i'.is_numeric());
+ assert!(!'z'.is_numeric());
+ assert!(!'Q'.is_numeric());
+}
+
+#[test]
+fn test_escape_debug() {
+ fn string(c: char) -> String {
+ let iter: String = c.escape_debug().collect();
+ let disp: String = c.escape_debug().to_string();
+ assert_eq!(iter, disp);
+ iter
+ }
+ assert_eq!(string('\n'), "\\n");
+ assert_eq!(string('\r'), "\\r");
+ assert_eq!(string('\''), "\\'");
+ assert_eq!(string('"'), "\\\"");
+ assert_eq!(string(' '), " ");
+ assert_eq!(string('a'), "a");
+ assert_eq!(string('~'), "~");
+ assert_eq!(string('é'), "é");
+ assert_eq!(string('文'), "文");
+ assert_eq!(string('\x00'), "\\0");
+ assert_eq!(string('\x1f'), "\\u{1f}");
+ assert_eq!(string('\x7f'), "\\u{7f}");
+ assert_eq!(string('\u{80}'), "\\u{80}");
+ assert_eq!(string('\u{ff}'), "\u{ff}");
+ assert_eq!(string('\u{11b}'), "\u{11b}");
+ assert_eq!(string('\u{1d4b6}'), "\u{1d4b6}");
+ assert_eq!(string('\u{301}'), "\\u{301}"); // combining character
+ assert_eq!(string('\u{200b}'), "\\u{200b}"); // zero width space
+ assert_eq!(string('\u{e000}'), "\\u{e000}"); // private use 1
+ assert_eq!(string('\u{100000}'), "\\u{100000}"); // private use 2
+}
+
+#[test]
+fn test_escape_default() {
+ fn string(c: char) -> String {
+ let iter: String = c.escape_default().collect();
+ let disp: String = c.escape_default().to_string();
+ assert_eq!(iter, disp);
+ iter
+ }
+ assert_eq!(string('\n'), "\\n");
+ assert_eq!(string('\r'), "\\r");
+ assert_eq!(string('\''), "\\'");
+ assert_eq!(string('"'), "\\\"");
+ assert_eq!(string(' '), " ");
+ assert_eq!(string('a'), "a");
+ assert_eq!(string('~'), "~");
+ assert_eq!(string('é'), "\\u{e9}");
+ assert_eq!(string('\x00'), "\\u{0}");
+ assert_eq!(string('\x1f'), "\\u{1f}");
+ assert_eq!(string('\x7f'), "\\u{7f}");
+ assert_eq!(string('\u{80}'), "\\u{80}");
+ assert_eq!(string('\u{ff}'), "\\u{ff}");
+ assert_eq!(string('\u{11b}'), "\\u{11b}");
+ assert_eq!(string('\u{1d4b6}'), "\\u{1d4b6}");
+ assert_eq!(string('\u{200b}'), "\\u{200b}"); // zero width space
+ assert_eq!(string('\u{e000}'), "\\u{e000}"); // private use 1
+ assert_eq!(string('\u{100000}'), "\\u{100000}"); // private use 2
+}
+
+#[test]
+fn test_escape_unicode() {
+ fn string(c: char) -> String {
+ let iter: String = c.escape_unicode().collect();
+ let disp: String = c.escape_unicode().to_string();
+ assert_eq!(iter, disp);
+ iter
+ }
+
+ assert_eq!(string('\x00'), "\\u{0}");
+ assert_eq!(string('\n'), "\\u{a}");
+ assert_eq!(string(' '), "\\u{20}");
+ assert_eq!(string('a'), "\\u{61}");
+ assert_eq!(string('\u{11b}'), "\\u{11b}");
+ assert_eq!(string('\u{1d4b6}'), "\\u{1d4b6}");
+}
+
+#[test]
+fn test_encode_utf8() {
+ fn check(input: char, expect: &[u8]) {
+ let mut buf = [0; 4];
+ let ptr = buf.as_ptr();
+ let s = input.encode_utf8(&mut buf);
+ assert_eq!(s.as_ptr() as usize, ptr as usize);
+ assert!(str::from_utf8(s.as_bytes()).is_ok());
+ assert_eq!(s.as_bytes(), expect);
+ }
+
+ check('x', &[0x78]);
+ check('\u{e9}', &[0xc3, 0xa9]);
+ check('\u{a66e}', &[0xea, 0x99, 0xae]);
+ check('\u{1f4a9}', &[0xf0, 0x9f, 0x92, 0xa9]);
+}
+
+#[test]
+fn test_encode_utf16() {
+ fn check(input: char, expect: &[u16]) {
+ let mut buf = [0; 2];
+ let ptr = buf.as_mut_ptr();
+ let b = input.encode_utf16(&mut buf);
+ assert_eq!(b.as_mut_ptr() as usize, ptr as usize);
+ assert_eq!(b, expect);
+ }
+
+ check('x', &[0x0078]);
+ check('\u{e9}', &[0x00e9]);
+ check('\u{a66e}', &[0xa66e]);
+ check('\u{1f4a9}', &[0xd83d, 0xdca9]);
+}
+
+#[test]
+fn test_len_utf16() {
+ assert!('x'.len_utf16() == 1);
+ assert!('\u{e9}'.len_utf16() == 1);
+ assert!('\u{a66e}'.len_utf16() == 1);
+ assert!('\u{1f4a9}'.len_utf16() == 2);
+}
+
+#[test]
+fn test_decode_utf16() {
+ fn check(s: &[u16], expected: &[Result<char, u16>]) {
+ let v = char::decode_utf16(s.iter().cloned())
+ .map(|r| r.map_err(|e| e.unpaired_surrogate()))
+ .collect::<Vec<_>>();
+ assert_eq!(v, expected);
+ }
+ check(&[0xD800, 0x41, 0x42], &[Err(0xD800), Ok('A'), Ok('B')]);
+ check(&[0xD800, 0], &[Err(0xD800), Ok('\0')]);
+}
+
+#[test]
+fn test_decode_utf16_size_hint() {
+ fn check(s: &[u16]) {
+ let mut iter = char::decode_utf16(s.iter().cloned());
+
+ loop {
+ let count = iter.clone().count();
+ let (lower, upper) = iter.size_hint();
+
+ assert!(
+ lower <= count && count <= upper.unwrap(),
+ "lower = {lower}, count = {count}, upper = {upper:?}"
+ );
+
+ if let None = iter.next() {
+ break;
+ }
+ }
+ }
+
+ check(&[0xD800, 0xD800, 0xDC00]);
+ check(&[0xD800, 0xD800, 0x0]);
+ check(&[0xD800, 0x41, 0x42]);
+ check(&[0xD800, 0]);
+ check(&[0xD834, 0x006d]);
+}
+
+#[test]
+fn ed_iterator_specializations() {
+ // Check counting
+ assert_eq!('\n'.escape_default().count(), 2);
+ assert_eq!('c'.escape_default().count(), 1);
+ assert_eq!(' '.escape_default().count(), 1);
+ assert_eq!('\\'.escape_default().count(), 2);
+ assert_eq!('\''.escape_default().count(), 2);
+
+ // Check nth
+
+ // Check that OoB is handled correctly
+ assert_eq!('\n'.escape_default().nth(2), None);
+ assert_eq!('c'.escape_default().nth(1), None);
+ assert_eq!(' '.escape_default().nth(1), None);
+ assert_eq!('\\'.escape_default().nth(2), None);
+ assert_eq!('\''.escape_default().nth(2), None);
+
+ // Check the first char
+ assert_eq!('\n'.escape_default().nth(0), Some('\\'));
+ assert_eq!('c'.escape_default().nth(0), Some('c'));
+ assert_eq!(' '.escape_default().nth(0), Some(' '));
+ assert_eq!('\\'.escape_default().nth(0), Some('\\'));
+ assert_eq!('\''.escape_default().nth(0), Some('\\'));
+
+ // Check the second char
+ assert_eq!('\n'.escape_default().nth(1), Some('n'));
+ assert_eq!('\\'.escape_default().nth(1), Some('\\'));
+ assert_eq!('\''.escape_default().nth(1), Some('\''));
+
+ // Check the last char
+ assert_eq!('\n'.escape_default().last(), Some('n'));
+ assert_eq!('c'.escape_default().last(), Some('c'));
+ assert_eq!(' '.escape_default().last(), Some(' '));
+ assert_eq!('\\'.escape_default().last(), Some('\\'));
+ assert_eq!('\''.escape_default().last(), Some('\''));
+}
+
+#[test]
+fn eu_iterator_specializations() {
+ fn check(c: char) {
+ let len = c.escape_unicode().count();
+
+ // Check OoB
+ assert_eq!(c.escape_unicode().nth(len), None);
+
+ // For all possible in-bound offsets
+ let mut iter = c.escape_unicode();
+ for offset in 0..len {
+ // Check last
+ assert_eq!(iter.clone().last(), Some('}'));
+
+ // Check len
+ assert_eq!(iter.len(), len - offset);
+
+ // Check size_hint (= len in ExactSizeIterator)
+ assert_eq!(iter.size_hint(), (iter.len(), Some(iter.len())));
+
+ // Check counting
+ assert_eq!(iter.clone().count(), len - offset);
+
+ // Check nth
+ assert_eq!(c.escape_unicode().nth(offset), iter.next());
+ }
+
+ // Check post-last
+ assert_eq!(iter.clone().last(), None);
+ assert_eq!(iter.clone().count(), 0);
+ }
+
+ check('\u{0}');
+ check('\u{1}');
+ check('\u{12}');
+ check('\u{123}');
+ check('\u{1234}');
+ check('\u{12340}');
+ check('\u{10FFFF}');
+}
diff --git a/library/core/tests/clone.rs b/library/core/tests/clone.rs
new file mode 100644
index 000000000..33ca9f2c6
--- /dev/null
+++ b/library/core/tests/clone.rs
@@ -0,0 +1,15 @@
+#[test]
+fn test_borrowed_clone() {
+ let x = 5;
+ let y: &i32 = &x;
+ let z: &i32 = (&y).clone();
+ assert_eq!(*z, 5);
+}
+
+#[test]
+fn test_clone_from() {
+ let a = Box::new(5);
+ let mut b = Box::new(10);
+ b.clone_from(&a);
+ assert_eq!(*b, 5);
+}
diff --git a/library/core/tests/cmp.rs b/library/core/tests/cmp.rs
new file mode 100644
index 000000000..8d0e59d5a
--- /dev/null
+++ b/library/core/tests/cmp.rs
@@ -0,0 +1,250 @@
+use core::cmp::{
+ self,
+ Ordering::{self, *},
+};
+
+#[test]
+fn test_int_totalord() {
+ assert_eq!(5.cmp(&10), Less);
+ assert_eq!(10.cmp(&5), Greater);
+ assert_eq!(5.cmp(&5), Equal);
+ assert_eq!((-5).cmp(&12), Less);
+ assert_eq!(12.cmp(&-5), Greater);
+}
+
+#[test]
+fn test_bool_totalord() {
+ assert_eq!(true.cmp(&false), Greater);
+ assert_eq!(false.cmp(&true), Less);
+ assert_eq!(true.cmp(&true), Equal);
+ assert_eq!(false.cmp(&false), Equal);
+}
+
+#[test]
+fn test_mut_int_totalord() {
+ assert_eq!((&mut 5).cmp(&&mut 10), Less);
+ assert_eq!((&mut 10).cmp(&&mut 5), Greater);
+ assert_eq!((&mut 5).cmp(&&mut 5), Equal);
+ assert_eq!((&mut -5).cmp(&&mut 12), Less);
+ assert_eq!((&mut 12).cmp(&&mut -5), Greater);
+}
+
+#[test]
+fn test_ord_max_min() {
+ assert_eq!(1.max(2), 2);
+ assert_eq!(2.max(1), 2);
+ assert_eq!(1.min(2), 1);
+ assert_eq!(2.min(1), 1);
+ assert_eq!(1.max(1), 1);
+ assert_eq!(1.min(1), 1);
+}
+
+#[test]
+fn test_ord_min_max_by() {
+ let f = |x: &i32, y: &i32| x.abs().cmp(&y.abs());
+ assert_eq!(cmp::min_by(1, -1, f), 1);
+ assert_eq!(cmp::min_by(1, -2, f), 1);
+ assert_eq!(cmp::min_by(2, -1, f), -1);
+ assert_eq!(cmp::max_by(1, -1, f), -1);
+ assert_eq!(cmp::max_by(1, -2, f), -2);
+ assert_eq!(cmp::max_by(2, -1, f), 2);
+}
+
+#[test]
+fn test_ord_min_max_by_key() {
+ let f = |x: &i32| x.abs();
+ assert_eq!(cmp::min_by_key(1, -1, f), 1);
+ assert_eq!(cmp::min_by_key(1, -2, f), 1);
+ assert_eq!(cmp::min_by_key(2, -1, f), -1);
+ assert_eq!(cmp::max_by_key(1, -1, f), -1);
+ assert_eq!(cmp::max_by_key(1, -2, f), -2);
+ assert_eq!(cmp::max_by_key(2, -1, f), 2);
+}
+
+#[test]
+fn test_ordering_reverse() {
+ assert_eq!(Less.reverse(), Greater);
+ assert_eq!(Equal.reverse(), Equal);
+ assert_eq!(Greater.reverse(), Less);
+}
+
+#[test]
+fn test_ordering_order() {
+ assert!(Less < Equal);
+ assert_eq!(Greater.cmp(&Less), Greater);
+}
+
+#[test]
+fn test_ordering_then() {
+ assert_eq!(Equal.then(Less), Less);
+ assert_eq!(Equal.then(Equal), Equal);
+ assert_eq!(Equal.then(Greater), Greater);
+ assert_eq!(Less.then(Less), Less);
+ assert_eq!(Less.then(Equal), Less);
+ assert_eq!(Less.then(Greater), Less);
+ assert_eq!(Greater.then(Less), Greater);
+ assert_eq!(Greater.then(Equal), Greater);
+ assert_eq!(Greater.then(Greater), Greater);
+}
+
+#[test]
+fn test_ordering_then_with() {
+ assert_eq!(Equal.then_with(|| Less), Less);
+ assert_eq!(Equal.then_with(|| Equal), Equal);
+ assert_eq!(Equal.then_with(|| Greater), Greater);
+ assert_eq!(Less.then_with(|| Less), Less);
+ assert_eq!(Less.then_with(|| Equal), Less);
+ assert_eq!(Less.then_with(|| Greater), Less);
+ assert_eq!(Greater.then_with(|| Less), Greater);
+ assert_eq!(Greater.then_with(|| Equal), Greater);
+ assert_eq!(Greater.then_with(|| Greater), Greater);
+}
+
+#[test]
+fn test_user_defined_eq() {
+ // Our type.
+ struct SketchyNum {
+ num: isize,
+ }
+
+ // Our implementation of `PartialEq` to support `==` and `!=`.
+ impl PartialEq for SketchyNum {
+ // Our custom eq allows numbers which are near each other to be equal! :D
+ fn eq(&self, other: &SketchyNum) -> bool {
+ (self.num - other.num).abs() < 5
+ }
+ }
+
+ // Now these binary operators will work when applied!
+ assert!(SketchyNum { num: 37 } == SketchyNum { num: 34 });
+ assert!(SketchyNum { num: 25 } != SketchyNum { num: 57 });
+}
+
+#[test]
+fn ordering_const() {
+ // test that the methods of `Ordering` are usable in a const context
+
+ const ORDERING: Ordering = Greater;
+
+ const REVERSE: Ordering = ORDERING.reverse();
+ assert_eq!(REVERSE, Less);
+
+ const THEN: Ordering = Equal.then(ORDERING);
+ assert_eq!(THEN, Greater);
+}
+
+#[test]
+fn ordering_structural_eq() {
+ // test that consts of type `Ordering` are usable in patterns
+
+ const ORDERING: Ordering = Greater;
+
+ const REVERSE: Ordering = ORDERING.reverse();
+ match Ordering::Less {
+ REVERSE => {}
+ _ => unreachable!(),
+ };
+}
+
+#[test]
+fn cmp_default() {
+ // Test default methods in PartialOrd and PartialEq
+
+ #[derive(Debug)]
+ struct Fool(bool);
+
+ impl PartialEq for Fool {
+ fn eq(&self, other: &Fool) -> bool {
+ let Fool(this) = *self;
+ let Fool(other) = *other;
+ this != other
+ }
+ }
+
+ struct Int(isize);
+
+ impl PartialEq for Int {
+ fn eq(&self, other: &Int) -> bool {
+ let Int(this) = *self;
+ let Int(other) = *other;
+ this == other
+ }
+ }
+
+ impl PartialOrd for Int {
+ fn partial_cmp(&self, other: &Int) -> Option<Ordering> {
+ let Int(this) = *self;
+ let Int(other) = *other;
+ this.partial_cmp(&other)
+ }
+ }
+
+ struct RevInt(isize);
+
+ impl PartialEq for RevInt {
+ fn eq(&self, other: &RevInt) -> bool {
+ let RevInt(this) = *self;
+ let RevInt(other) = *other;
+ this == other
+ }
+ }
+
+ impl PartialOrd for RevInt {
+ fn partial_cmp(&self, other: &RevInt) -> Option<Ordering> {
+ let RevInt(this) = *self;
+ let RevInt(other) = *other;
+ other.partial_cmp(&this)
+ }
+ }
+
+ assert!(Int(2) > Int(1));
+ assert!(Int(2) >= Int(1));
+ assert!(Int(1) >= Int(1));
+ assert!(Int(1) < Int(2));
+ assert!(Int(1) <= Int(2));
+ assert!(Int(1) <= Int(1));
+
+ assert!(RevInt(2) < RevInt(1));
+ assert!(RevInt(2) <= RevInt(1));
+ assert!(RevInt(1) <= RevInt(1));
+ assert!(RevInt(1) > RevInt(2));
+ assert!(RevInt(1) >= RevInt(2));
+ assert!(RevInt(1) >= RevInt(1));
+
+ assert_eq!(Fool(true), Fool(false));
+ assert!(Fool(true) != Fool(true));
+ assert!(Fool(false) != Fool(false));
+ assert_eq!(Fool(false), Fool(true));
+}
+
+mod const_cmp {
+ use super::*;
+
+ struct S(i32);
+
+ impl const PartialEq for S {
+ fn eq(&self, other: &Self) -> bool {
+ self.0 == other.0
+ }
+ }
+
+ impl const PartialOrd for S {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ let ret = match (self.0, other.0) {
+ (a, b) if a > b => Ordering::Greater,
+ (a, b) if a < b => Ordering::Less,
+ _ => Ordering::Equal,
+ };
+
+ Some(ret)
+ }
+ }
+
+ const _: () = assert!(S(1) == S(1));
+ const _: () = assert!(S(0) != S(1));
+
+ const _: () = assert!(S(1) <= S(1));
+ const _: () = assert!(S(1) >= S(1));
+ const _: () = assert!(S(0) < S(1));
+ const _: () = assert!(S(1) > S(0));
+}
diff --git a/library/core/tests/const_ptr.rs b/library/core/tests/const_ptr.rs
new file mode 100644
index 000000000..152fed803
--- /dev/null
+++ b/library/core/tests/const_ptr.rs
@@ -0,0 +1,101 @@
+// Aligned to two bytes
+const DATA: [u16; 2] = [u16::from_ne_bytes([0x01, 0x23]), u16::from_ne_bytes([0x45, 0x67])];
+
+const fn unaligned_ptr() -> *const u16 {
+ // Since DATA.as_ptr() is aligned to two bytes, adding 1 byte to that produces an unaligned *const u16
+ unsafe { (DATA.as_ptr() as *const u8).add(1) as *const u16 }
+}
+
+#[test]
+fn read() {
+ use core::ptr;
+
+ const FOO: i32 = unsafe { ptr::read(&42 as *const i32) };
+ assert_eq!(FOO, 42);
+
+ const ALIGNED: i32 = unsafe { ptr::read_unaligned(&42 as *const i32) };
+ assert_eq!(ALIGNED, 42);
+
+ const UNALIGNED_PTR: *const u16 = unaligned_ptr();
+
+ const UNALIGNED: u16 = unsafe { ptr::read_unaligned(UNALIGNED_PTR) };
+ assert_eq!(UNALIGNED, u16::from_ne_bytes([0x23, 0x45]));
+}
+
+#[test]
+fn const_ptr_read() {
+ const FOO: i32 = unsafe { (&42 as *const i32).read() };
+ assert_eq!(FOO, 42);
+
+ const ALIGNED: i32 = unsafe { (&42 as *const i32).read_unaligned() };
+ assert_eq!(ALIGNED, 42);
+
+ const UNALIGNED_PTR: *const u16 = unaligned_ptr();
+
+ const UNALIGNED: u16 = unsafe { UNALIGNED_PTR.read_unaligned() };
+ assert_eq!(UNALIGNED, u16::from_ne_bytes([0x23, 0x45]));
+}
+
+#[test]
+fn mut_ptr_read() {
+ const FOO: i32 = unsafe { (&42 as *const i32 as *mut i32).read() };
+ assert_eq!(FOO, 42);
+
+ const ALIGNED: i32 = unsafe { (&42 as *const i32 as *mut i32).read_unaligned() };
+ assert_eq!(ALIGNED, 42);
+
+ const UNALIGNED_PTR: *mut u16 = unaligned_ptr() as *mut u16;
+
+ const UNALIGNED: u16 = unsafe { UNALIGNED_PTR.read_unaligned() };
+ assert_eq!(UNALIGNED, u16::from_ne_bytes([0x23, 0x45]));
+}
+
+#[test]
+fn write() {
+ use core::ptr;
+
+ const fn write_aligned() -> i32 {
+ let mut res = 0;
+ unsafe {
+ ptr::write(&mut res as *mut _, 42);
+ }
+ res
+ }
+ const ALIGNED: i32 = write_aligned();
+ assert_eq!(ALIGNED, 42);
+
+ const fn write_unaligned() -> [u16; 2] {
+ let mut two_aligned = [0u16; 2];
+ unsafe {
+ let unaligned_ptr = (two_aligned.as_mut_ptr() as *mut u8).add(1) as *mut u16;
+ ptr::write_unaligned(unaligned_ptr, u16::from_ne_bytes([0x23, 0x45]));
+ }
+ two_aligned
+ }
+ const UNALIGNED: [u16; 2] = write_unaligned();
+ assert_eq!(UNALIGNED, [u16::from_ne_bytes([0x00, 0x23]), u16::from_ne_bytes([0x45, 0x00])]);
+}
+
+#[test]
+fn mut_ptr_write() {
+ const fn aligned() -> i32 {
+ let mut res = 0;
+ unsafe {
+ (&mut res as *mut i32).write(42);
+ }
+ res
+ }
+ const ALIGNED: i32 = aligned();
+ assert_eq!(ALIGNED, 42);
+
+ const fn write_unaligned() -> [u16; 2] {
+ let mut two_aligned = [0u16; 2];
+ unsafe {
+ let unaligned_ptr = (two_aligned.as_mut_ptr() as *mut u8).add(1) as *mut u16;
+ unaligned_ptr.write_unaligned(u16::from_ne_bytes([0x23, 0x45]));
+ }
+ two_aligned
+ }
+ const UNALIGNED: [u16; 2] = write_unaligned();
+ assert_eq!(UNALIGNED, [u16::from_ne_bytes([0x00, 0x23]), u16::from_ne_bytes([0x45, 0x00])]);
+}
diff --git a/library/core/tests/convert.rs b/library/core/tests/convert.rs
new file mode 100644
index 000000000..f1048f4cf
--- /dev/null
+++ b/library/core/tests/convert.rs
@@ -0,0 +1,16 @@
+#[test]
+fn convert() {
+ const fn from(x: i32) -> i32 {
+ i32::from(x)
+ }
+
+ const FOO: i32 = from(42);
+ assert_eq!(FOO, 42);
+
+ const fn into(x: Vec<String>) -> Vec<String> {
+ x.into()
+ }
+
+ const BAR: Vec<String> = into(Vec::new());
+ assert_eq!(BAR, Vec::<String>::new());
+}
diff --git a/library/core/tests/fmt/builders.rs b/library/core/tests/fmt/builders.rs
new file mode 100644
index 000000000..487ce46be
--- /dev/null
+++ b/library/core/tests/fmt/builders.rs
@@ -0,0 +1,726 @@
+mod debug_struct {
+ use std::fmt;
+
+ #[test]
+ fn test_empty() {
+ struct Foo;
+
+ impl fmt::Debug for Foo {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt.debug_struct("Foo").finish()
+ }
+ }
+
+ assert_eq!("Foo", format!("{Foo:?}"));
+ assert_eq!("Foo", format!("{Foo:#?}"));
+ }
+
+ #[test]
+ fn test_single() {
+ struct Foo;
+
+ impl fmt::Debug for Foo {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt.debug_struct("Foo").field("bar", &true).finish()
+ }
+ }
+
+ assert_eq!("Foo { bar: true }", format!("{Foo:?}"));
+ assert_eq!(
+ "Foo {
+ bar: true,
+}",
+ format!("{Foo:#?}")
+ );
+ }
+
+ #[test]
+ fn test_multiple() {
+ struct Foo;
+
+ impl fmt::Debug for Foo {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt.debug_struct("Foo")
+ .field("bar", &true)
+ .field("baz", &format_args!("{}/{}", 10, 20))
+ .finish()
+ }
+ }
+
+ assert_eq!("Foo { bar: true, baz: 10/20 }", format!("{Foo:?}"));
+ assert_eq!(
+ "Foo {
+ bar: true,
+ baz: 10/20,
+}",
+ format!("{Foo:#?}")
+ );
+ }
+
+ #[test]
+ fn test_nested() {
+ struct Foo;
+
+ impl fmt::Debug for Foo {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt.debug_struct("Foo")
+ .field("bar", &true)
+ .field("baz", &format_args!("{}/{}", 10, 20))
+ .finish()
+ }
+ }
+
+ struct Bar;
+
+ impl fmt::Debug for Bar {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt.debug_struct("Bar").field("foo", &Foo).field("hello", &"world").finish()
+ }
+ }
+
+ assert_eq!(
+ "Bar { foo: Foo { bar: true, baz: 10/20 }, hello: \"world\" }",
+ format!("{Bar:?}")
+ );
+ assert_eq!(
+ "Bar {
+ foo: Foo {
+ bar: true,
+ baz: 10/20,
+ },
+ hello: \"world\",
+}",
+ format!("{Bar:#?}")
+ );
+ }
+
+ #[test]
+ fn test_only_non_exhaustive() {
+ struct Foo;
+
+ impl fmt::Debug for Foo {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt.debug_struct("Foo").finish_non_exhaustive()
+ }
+ }
+
+ assert_eq!("Foo { .. }", format!("{Foo:?}"));
+ assert_eq!("Foo { .. }", format!("{Foo:#?}"));
+ }
+
+ #[test]
+ fn test_multiple_and_non_exhaustive() {
+ struct Foo;
+
+ impl fmt::Debug for Foo {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt.debug_struct("Foo")
+ .field("bar", &true)
+ .field("baz", &format_args!("{}/{}", 10, 20))
+ .finish_non_exhaustive()
+ }
+ }
+
+ assert_eq!("Foo { bar: true, baz: 10/20, .. }", format!("{Foo:?}"));
+ assert_eq!(
+ "Foo {
+ bar: true,
+ baz: 10/20,
+ ..
+}",
+ format!("{Foo:#?}")
+ );
+ }
+
+ #[test]
+ fn test_nested_non_exhaustive() {
+ struct Foo;
+
+ impl fmt::Debug for Foo {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt.debug_struct("Foo")
+ .field("bar", &true)
+ .field("baz", &format_args!("{}/{}", 10, 20))
+ .finish_non_exhaustive()
+ }
+ }
+
+ struct Bar;
+
+ impl fmt::Debug for Bar {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt.debug_struct("Bar")
+ .field("foo", &Foo)
+ .field("hello", &"world")
+ .finish_non_exhaustive()
+ }
+ }
+
+ assert_eq!(
+ "Bar { foo: Foo { bar: true, baz: 10/20, .. }, hello: \"world\", .. }",
+ format!("{Bar:?}")
+ );
+ assert_eq!(
+ "Bar {
+ foo: Foo {
+ bar: true,
+ baz: 10/20,
+ ..
+ },
+ hello: \"world\",
+ ..
+}",
+ format!("{Bar:#?}")
+ );
+ }
+}
+
+mod debug_tuple {
+ use std::fmt;
+
+ #[test]
+ fn test_empty() {
+ struct Foo;
+
+ impl fmt::Debug for Foo {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt.debug_tuple("Foo").finish()
+ }
+ }
+
+ assert_eq!("Foo", format!("{Foo:?}"));
+ assert_eq!("Foo", format!("{Foo:#?}"));
+ }
+
+ #[test]
+ fn test_single() {
+ struct Foo;
+
+ impl fmt::Debug for Foo {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt.debug_tuple("Foo").field(&true).finish()
+ }
+ }
+
+ assert_eq!("Foo(true)", format!("{Foo:?}"));
+ assert_eq!(
+ "Foo(
+ true,
+)",
+ format!("{Foo:#?}")
+ );
+ }
+
+ #[test]
+ fn test_multiple() {
+ struct Foo;
+
+ impl fmt::Debug for Foo {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt.debug_tuple("Foo").field(&true).field(&format_args!("{}/{}", 10, 20)).finish()
+ }
+ }
+
+ assert_eq!("Foo(true, 10/20)", format!("{Foo:?}"));
+ assert_eq!(
+ "Foo(
+ true,
+ 10/20,
+)",
+ format!("{Foo:#?}")
+ );
+ }
+
+ #[test]
+ fn test_nested() {
+ struct Foo;
+
+ impl fmt::Debug for Foo {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt.debug_tuple("Foo").field(&true).field(&format_args!("{}/{}", 10, 20)).finish()
+ }
+ }
+
+ struct Bar;
+
+ impl fmt::Debug for Bar {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt.debug_tuple("Bar").field(&Foo).field(&"world").finish()
+ }
+ }
+
+ assert_eq!("Bar(Foo(true, 10/20), \"world\")", format!("{Bar:?}"));
+ assert_eq!(
+ "Bar(
+ Foo(
+ true,
+ 10/20,
+ ),
+ \"world\",
+)",
+ format!("{Bar:#?}")
+ );
+ }
+}
+
+mod debug_map {
+ use std::fmt;
+
+ #[test]
+ fn test_empty() {
+ struct Foo;
+
+ impl fmt::Debug for Foo {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt.debug_map().finish()
+ }
+ }
+
+ assert_eq!("{}", format!("{Foo:?}"));
+ assert_eq!("{}", format!("{Foo:#?}"));
+ }
+
+ #[test]
+ fn test_single() {
+ struct Entry;
+
+ impl fmt::Debug for Entry {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt.debug_map().entry(&"bar", &true).finish()
+ }
+ }
+
+ struct KeyValue;
+
+ impl fmt::Debug for KeyValue {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt.debug_map().key(&"bar").value(&true).finish()
+ }
+ }
+
+ assert_eq!(format!("{Entry:?}"), format!("{KeyValue:?}"));
+ assert_eq!(format!("{Entry:#?}"), format!("{KeyValue:#?}"));
+
+ assert_eq!("{\"bar\": true}", format!("{Entry:?}"));
+ assert_eq!(
+ "{
+ \"bar\": true,
+}",
+ format!("{Entry:#?}")
+ );
+ }
+
+ #[test]
+ fn test_multiple() {
+ struct Entry;
+
+ impl fmt::Debug for Entry {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt.debug_map()
+ .entry(&"bar", &true)
+ .entry(&10, &format_args!("{}/{}", 10, 20))
+ .finish()
+ }
+ }
+
+ struct KeyValue;
+
+ impl fmt::Debug for KeyValue {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt.debug_map()
+ .key(&"bar")
+ .value(&true)
+ .key(&10)
+ .value(&format_args!("{}/{}", 10, 20))
+ .finish()
+ }
+ }
+
+ assert_eq!(format!("{Entry:?}"), format!("{KeyValue:?}"));
+ assert_eq!(format!("{Entry:#?}"), format!("{KeyValue:#?}"));
+
+ assert_eq!("{\"bar\": true, 10: 10/20}", format!("{Entry:?}"));
+ assert_eq!(
+ "{
+ \"bar\": true,
+ 10: 10/20,
+}",
+ format!("{Entry:#?}")
+ );
+ }
+
+ #[test]
+ fn test_nested() {
+ struct Foo;
+
+ impl fmt::Debug for Foo {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt.debug_map()
+ .entry(&"bar", &true)
+ .entry(&10, &format_args!("{}/{}", 10, 20))
+ .finish()
+ }
+ }
+
+ struct Bar;
+
+ impl fmt::Debug for Bar {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt.debug_map().entry(&"foo", &Foo).entry(&Foo, &"world").finish()
+ }
+ }
+
+ assert_eq!(
+ "{\"foo\": {\"bar\": true, 10: 10/20}, \
+ {\"bar\": true, 10: 10/20}: \"world\"}",
+ format!("{Bar:?}")
+ );
+ assert_eq!(
+ "{
+ \"foo\": {
+ \"bar\": true,
+ 10: 10/20,
+ },
+ {
+ \"bar\": true,
+ 10: 10/20,
+ }: \"world\",
+}",
+ format!("{Bar:#?}")
+ );
+ }
+
+ #[test]
+ fn test_entry_err() {
+ // Ensure errors in a map entry don't trigger panics (#65231)
+ use std::fmt::Write;
+
+ struct ErrorFmt;
+
+ impl fmt::Debug for ErrorFmt {
+ fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
+ Err(fmt::Error)
+ }
+ }
+
+ struct KeyValue<K, V>(usize, K, V);
+
+ impl<K, V> fmt::Debug for KeyValue<K, V>
+ where
+ K: fmt::Debug,
+ V: fmt::Debug,
+ {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let mut map = fmt.debug_map();
+
+ for _ in 0..self.0 {
+ map.entry(&self.1, &self.2);
+ }
+
+ map.finish()
+ }
+ }
+
+ let mut buf = String::new();
+
+ assert!(write!(&mut buf, "{:?}", KeyValue(1, ErrorFmt, "bar")).is_err());
+ assert!(write!(&mut buf, "{:?}", KeyValue(1, "foo", ErrorFmt)).is_err());
+
+ assert!(write!(&mut buf, "{:?}", KeyValue(2, ErrorFmt, "bar")).is_err());
+ assert!(write!(&mut buf, "{:?}", KeyValue(2, "foo", ErrorFmt)).is_err());
+ }
+
+ #[test]
+ #[should_panic]
+ fn test_invalid_key_when_entry_is_incomplete() {
+ struct Foo;
+
+ impl fmt::Debug for Foo {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt.debug_map().key(&"bar").key(&"invalid").finish()
+ }
+ }
+
+ format!("{Foo:?}");
+ }
+
+ #[test]
+ #[should_panic]
+ fn test_invalid_finish_incomplete_entry() {
+ struct Foo;
+
+ impl fmt::Debug for Foo {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt.debug_map().key(&"bar").finish()
+ }
+ }
+
+ format!("{Foo:?}");
+ }
+
+ #[test]
+ #[should_panic]
+ fn test_invalid_value_before_key() {
+ struct Foo;
+
+ impl fmt::Debug for Foo {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt.debug_map().value(&"invalid").key(&"bar").finish()
+ }
+ }
+
+ format!("{Foo:?}");
+ }
+}
+
+mod debug_set {
+ use std::fmt;
+
+ #[test]
+ fn test_empty() {
+ struct Foo;
+
+ impl fmt::Debug for Foo {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt.debug_set().finish()
+ }
+ }
+
+ assert_eq!("{}", format!("{Foo:?}"));
+ assert_eq!("{}", format!("{Foo:#?}"));
+ }
+
+ #[test]
+ fn test_single() {
+ struct Foo;
+
+ impl fmt::Debug for Foo {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt.debug_set().entry(&true).finish()
+ }
+ }
+
+ assert_eq!("{true}", format!("{Foo:?}"));
+ assert_eq!(
+ "{
+ true,
+}",
+ format!("{Foo:#?}")
+ );
+ }
+
+ #[test]
+ fn test_multiple() {
+ struct Foo;
+
+ impl fmt::Debug for Foo {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt.debug_set().entry(&true).entry(&format_args!("{}/{}", 10, 20)).finish()
+ }
+ }
+
+ assert_eq!("{true, 10/20}", format!("{Foo:?}"));
+ assert_eq!(
+ "{
+ true,
+ 10/20,
+}",
+ format!("{Foo:#?}")
+ );
+ }
+
+ #[test]
+ fn test_nested() {
+ struct Foo;
+
+ impl fmt::Debug for Foo {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt.debug_set().entry(&true).entry(&format_args!("{}/{}", 10, 20)).finish()
+ }
+ }
+
+ struct Bar;
+
+ impl fmt::Debug for Bar {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt.debug_set().entry(&Foo).entry(&"world").finish()
+ }
+ }
+
+ assert_eq!("{{true, 10/20}, \"world\"}", format!("{Bar:?}"));
+ assert_eq!(
+ "{
+ {
+ true,
+ 10/20,
+ },
+ \"world\",
+}",
+ format!("{Bar:#?}")
+ );
+ }
+}
+
+mod debug_list {
+ use std::fmt;
+
+ #[test]
+ fn test_empty() {
+ struct Foo;
+
+ impl fmt::Debug for Foo {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt.debug_list().finish()
+ }
+ }
+
+ assert_eq!("[]", format!("{Foo:?}"));
+ assert_eq!("[]", format!("{Foo:#?}"));
+ }
+
+ #[test]
+ fn test_single() {
+ struct Foo;
+
+ impl fmt::Debug for Foo {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt.debug_list().entry(&true).finish()
+ }
+ }
+
+ assert_eq!("[true]", format!("{Foo:?}"));
+ assert_eq!(
+ "[
+ true,
+]",
+ format!("{Foo:#?}")
+ );
+ }
+
+ #[test]
+ fn test_multiple() {
+ struct Foo;
+
+ impl fmt::Debug for Foo {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt.debug_list().entry(&true).entry(&format_args!("{}/{}", 10, 20)).finish()
+ }
+ }
+
+ assert_eq!("[true, 10/20]", format!("{Foo:?}"));
+ assert_eq!(
+ "[
+ true,
+ 10/20,
+]",
+ format!("{Foo:#?}")
+ );
+ }
+
+ #[test]
+ fn test_nested() {
+ struct Foo;
+
+ impl fmt::Debug for Foo {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt.debug_list().entry(&true).entry(&format_args!("{}/{}", 10, 20)).finish()
+ }
+ }
+
+ struct Bar;
+
+ impl fmt::Debug for Bar {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt.debug_list().entry(&Foo).entry(&"world").finish()
+ }
+ }
+
+ assert_eq!("[[true, 10/20], \"world\"]", format!("{Bar:?}"));
+ assert_eq!(
+ "[
+ [
+ true,
+ 10/20,
+ ],
+ \"world\",
+]",
+ format!("{Bar:#?}")
+ );
+ }
+}
+
+#[test]
+fn test_formatting_parameters_are_forwarded() {
+ use std::collections::{BTreeMap, BTreeSet};
+ #[derive(Debug)]
+ #[allow(dead_code)]
+ struct Foo {
+ bar: u32,
+ baz: u32,
+ }
+ let struct_ = Foo { bar: 1024, baz: 7 };
+ let tuple = (1024, 7);
+ let list = [1024, 7];
+ let mut map = BTreeMap::new();
+ map.insert("bar", 1024);
+ map.insert("baz", 7);
+ let mut set = BTreeSet::new();
+ set.insert(1024);
+ set.insert(7);
+
+ assert_eq!(format!("{struct_:03?}"), "Foo { bar: 1024, baz: 007 }");
+ assert_eq!(format!("{tuple:03?}"), "(1024, 007)");
+ assert_eq!(format!("{list:03?}"), "[1024, 007]");
+ assert_eq!(format!("{map:03?}"), r#"{"bar": 1024, "baz": 007}"#);
+ assert_eq!(format!("{set:03?}"), "{007, 1024}");
+ assert_eq!(
+ format!("{struct_:#03?}"),
+ "
+Foo {
+ bar: 1024,
+ baz: 007,
+}
+ "
+ .trim()
+ );
+ assert_eq!(
+ format!("{tuple:#03?}"),
+ "
+(
+ 1024,
+ 007,
+)
+ "
+ .trim()
+ );
+ assert_eq!(
+ format!("{list:#03?}"),
+ "
+[
+ 1024,
+ 007,
+]
+ "
+ .trim()
+ );
+ assert_eq!(
+ format!("{map:#03?}"),
+ r#"
+{
+ "bar": 1024,
+ "baz": 007,
+}
+ "#
+ .trim()
+ );
+ assert_eq!(
+ format!("{set:#03?}"),
+ "
+{
+ 007,
+ 1024,
+}
+ "
+ .trim()
+ );
+}
diff --git a/library/core/tests/fmt/float.rs b/library/core/tests/fmt/float.rs
new file mode 100644
index 000000000..47a7400f7
--- /dev/null
+++ b/library/core/tests/fmt/float.rs
@@ -0,0 +1,55 @@
+#[test]
+fn test_format_f64() {
+ assert_eq!("1", format!("{:.0}", 1.0f64));
+ assert_eq!("9", format!("{:.0}", 9.4f64));
+ assert_eq!("10", format!("{:.0}", 9.9f64));
+ assert_eq!("9.8", format!("{:.1}", 9.849f64));
+ assert_eq!("9.9", format!("{:.1}", 9.851f64));
+ assert_eq!("1", format!("{:.0}", 0.5f64));
+ assert_eq!("1.23456789e6", format!("{:e}", 1234567.89f64));
+ assert_eq!("1.23456789e3", format!("{:e}", 1234.56789f64));
+ assert_eq!("1.23456789E6", format!("{:E}", 1234567.89f64));
+ assert_eq!("1.23456789E3", format!("{:E}", 1234.56789f64));
+ assert_eq!("0.0", format!("{:?}", 0.0f64));
+ assert_eq!("1.01", format!("{:?}", 1.01f64));
+
+ let high_cutoff = 1e16_f64;
+ assert_eq!("1e16", format!("{:?}", high_cutoff));
+ assert_eq!("-1e16", format!("{:?}", -high_cutoff));
+ assert!(!is_exponential(&format!("{:?}", high_cutoff * (1.0 - 2.0 * f64::EPSILON))));
+ assert_eq!("-3.0", format!("{:?}", -3f64));
+ assert_eq!("0.0001", format!("{:?}", 0.0001f64));
+ assert_eq!("9e-5", format!("{:?}", 0.00009f64));
+ assert_eq!("1234567.9", format!("{:.1?}", 1234567.89f64));
+ assert_eq!("1234.6", format!("{:.1?}", 1234.56789f64));
+}
+
+#[test]
+fn test_format_f32() {
+ assert_eq!("1", format!("{:.0}", 1.0f32));
+ assert_eq!("9", format!("{:.0}", 9.4f32));
+ assert_eq!("10", format!("{:.0}", 9.9f32));
+ assert_eq!("9.8", format!("{:.1}", 9.849f32));
+ assert_eq!("9.9", format!("{:.1}", 9.851f32));
+ assert_eq!("1", format!("{:.0}", 0.5f32));
+ assert_eq!("1.2345679e6", format!("{:e}", 1234567.89f32));
+ assert_eq!("1.2345679e3", format!("{:e}", 1234.56789f32));
+ assert_eq!("1.2345679E6", format!("{:E}", 1234567.89f32));
+ assert_eq!("1.2345679E3", format!("{:E}", 1234.56789f32));
+ assert_eq!("0.0", format!("{:?}", 0.0f32));
+ assert_eq!("1.01", format!("{:?}", 1.01f32));
+
+ let high_cutoff = 1e16_f32;
+ assert_eq!("1e16", format!("{:?}", high_cutoff));
+ assert_eq!("-1e16", format!("{:?}", -high_cutoff));
+ assert!(!is_exponential(&format!("{:?}", high_cutoff * (1.0 - 2.0 * f32::EPSILON))));
+ assert_eq!("-3.0", format!("{:?}", -3f32));
+ assert_eq!("0.0001", format!("{:?}", 0.0001f32));
+ assert_eq!("9e-5", format!("{:?}", 0.00009f32));
+ assert_eq!("1234567.9", format!("{:.1?}", 1234567.89f32));
+ assert_eq!("1234.6", format!("{:.1?}", 1234.56789f32));
+}
+
+fn is_exponential(s: &str) -> bool {
+ s.contains("e") || s.contains("E")
+}
diff --git a/library/core/tests/fmt/mod.rs b/library/core/tests/fmt/mod.rs
new file mode 100644
index 000000000..618076358
--- /dev/null
+++ b/library/core/tests/fmt/mod.rs
@@ -0,0 +1,45 @@
+mod builders;
+mod float;
+mod num;
+
+#[test]
+fn test_format_flags() {
+ // No residual flags left by pointer formatting
+ let p = "".as_ptr();
+ assert_eq!(format!("{:p} {:x}", p, 16), format!("{p:p} 10"));
+
+ assert_eq!(format!("{: >3}", 'a'), " a");
+}
+
+#[test]
+fn test_pointer_formats_data_pointer() {
+ let b: &[u8] = b"";
+ let s: &str = "";
+ assert_eq!(format!("{s:p}"), format!("{:p}", s.as_ptr()));
+ assert_eq!(format!("{b:p}"), format!("{:p}", b.as_ptr()));
+}
+
+#[test]
+fn test_estimated_capacity() {
+ assert_eq!(format_args!("").estimated_capacity(), 0);
+ assert_eq!(format_args!("{}", "").estimated_capacity(), 0);
+ assert_eq!(format_args!("Hello").estimated_capacity(), 5);
+ assert_eq!(format_args!("Hello, {}!", "").estimated_capacity(), 16);
+ assert_eq!(format_args!("{}, hello!", "World").estimated_capacity(), 0);
+ assert_eq!(format_args!("{}. 16-bytes piece", "World").estimated_capacity(), 32);
+}
+
+#[test]
+fn pad_integral_resets() {
+ struct Bar;
+
+ impl core::fmt::Display for Bar {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ "1".fmt(f)?;
+ f.pad_integral(true, "", "5")?;
+ "1".fmt(f)
+ }
+ }
+
+ assert_eq!(format!("{Bar:<03}"), "1 0051 ");
+}
diff --git a/library/core/tests/fmt/num.rs b/library/core/tests/fmt/num.rs
new file mode 100644
index 000000000..b9ede65c9
--- /dev/null
+++ b/library/core/tests/fmt/num.rs
@@ -0,0 +1,225 @@
+#[test]
+fn test_format_int() {
+ // Formatting integers should select the right implementation based off
+ // the type of the argument. Also, hex/octal/binary should be defined
+ // for integers, but they shouldn't emit the negative sign.
+ assert_eq!(format!("{}", 1isize), "1");
+ assert_eq!(format!("{}", 1i8), "1");
+ assert_eq!(format!("{}", 1i16), "1");
+ assert_eq!(format!("{}", 1i32), "1");
+ assert_eq!(format!("{}", 1i64), "1");
+ assert_eq!(format!("{}", -1isize), "-1");
+ assert_eq!(format!("{}", -1i8), "-1");
+ assert_eq!(format!("{}", -1i16), "-1");
+ assert_eq!(format!("{}", -1i32), "-1");
+ assert_eq!(format!("{}", -1i64), "-1");
+ assert_eq!(format!("{:?}", 1isize), "1");
+ assert_eq!(format!("{:?}", 1i8), "1");
+ assert_eq!(format!("{:?}", 1i16), "1");
+ assert_eq!(format!("{:?}", 1i32), "1");
+ assert_eq!(format!("{:?}", 1i64), "1");
+ assert_eq!(format!("{:b}", 1isize), "1");
+ assert_eq!(format!("{:b}", 1i8), "1");
+ assert_eq!(format!("{:b}", 1i16), "1");
+ assert_eq!(format!("{:b}", 1i32), "1");
+ assert_eq!(format!("{:b}", 1i64), "1");
+ assert_eq!(format!("{:x}", 1isize), "1");
+ assert_eq!(format!("{:x}", 1i8), "1");
+ assert_eq!(format!("{:x}", 1i16), "1");
+ assert_eq!(format!("{:x}", 1i32), "1");
+ assert_eq!(format!("{:x}", 1i64), "1");
+ assert_eq!(format!("{:X}", 1isize), "1");
+ assert_eq!(format!("{:X}", 1i8), "1");
+ assert_eq!(format!("{:X}", 1i16), "1");
+ assert_eq!(format!("{:X}", 1i32), "1");
+ assert_eq!(format!("{:X}", 1i64), "1");
+ assert_eq!(format!("{:o}", 1isize), "1");
+ assert_eq!(format!("{:o}", 1i8), "1");
+ assert_eq!(format!("{:o}", 1i16), "1");
+ assert_eq!(format!("{:o}", 1i32), "1");
+ assert_eq!(format!("{:o}", 1i64), "1");
+ assert_eq!(format!("{:e}", 1isize), "1e0");
+ assert_eq!(format!("{:e}", 1i8), "1e0");
+ assert_eq!(format!("{:e}", 1i16), "1e0");
+ assert_eq!(format!("{:e}", 1i32), "1e0");
+ assert_eq!(format!("{:e}", 1i64), "1e0");
+ assert_eq!(format!("{:E}", 1isize), "1E0");
+ assert_eq!(format!("{:E}", 1i8), "1E0");
+ assert_eq!(format!("{:E}", 1i16), "1E0");
+ assert_eq!(format!("{:E}", 1i32), "1E0");
+ assert_eq!(format!("{:E}", 1i64), "1E0");
+
+ assert_eq!(format!("{}", 1usize), "1");
+ assert_eq!(format!("{}", 1u8), "1");
+ assert_eq!(format!("{}", 1u16), "1");
+ assert_eq!(format!("{}", 1u32), "1");
+ assert_eq!(format!("{}", 1u64), "1");
+ assert_eq!(format!("{:?}", 1usize), "1");
+ assert_eq!(format!("{:?}", 1u8), "1");
+ assert_eq!(format!("{:?}", 1u16), "1");
+ assert_eq!(format!("{:?}", 1u32), "1");
+ assert_eq!(format!("{:?}", 1u64), "1");
+ assert_eq!(format!("{:b}", 1usize), "1");
+ assert_eq!(format!("{:b}", 1u8), "1");
+ assert_eq!(format!("{:b}", 1u16), "1");
+ assert_eq!(format!("{:b}", 1u32), "1");
+ assert_eq!(format!("{:b}", 1u64), "1");
+ assert_eq!(format!("{:x}", 1usize), "1");
+ assert_eq!(format!("{:x}", 1u8), "1");
+ assert_eq!(format!("{:x}", 1u16), "1");
+ assert_eq!(format!("{:x}", 1u32), "1");
+ assert_eq!(format!("{:x}", 1u64), "1");
+ assert_eq!(format!("{:X}", 1usize), "1");
+ assert_eq!(format!("{:X}", 1u8), "1");
+ assert_eq!(format!("{:X}", 1u16), "1");
+ assert_eq!(format!("{:X}", 1u32), "1");
+ assert_eq!(format!("{:X}", 1u64), "1");
+ assert_eq!(format!("{:o}", 1usize), "1");
+ assert_eq!(format!("{:o}", 1u8), "1");
+ assert_eq!(format!("{:o}", 1u16), "1");
+ assert_eq!(format!("{:o}", 1u32), "1");
+ assert_eq!(format!("{:o}", 1u64), "1");
+ assert_eq!(format!("{:e}", 1u8), "1e0");
+ assert_eq!(format!("{:e}", 1u16), "1e0");
+ assert_eq!(format!("{:e}", 1u32), "1e0");
+ assert_eq!(format!("{:e}", 1u64), "1e0");
+ assert_eq!(format!("{:E}", 1u8), "1E0");
+ assert_eq!(format!("{:E}", 1u16), "1E0");
+ assert_eq!(format!("{:E}", 1u32), "1E0");
+ assert_eq!(format!("{:E}", 1u64), "1E0");
+
+ // Test a larger number
+ assert_eq!(format!("{:b}", 55), "110111");
+ assert_eq!(format!("{:o}", 55), "67");
+ assert_eq!(format!("{}", 55), "55");
+ assert_eq!(format!("{:x}", 55), "37");
+ assert_eq!(format!("{:X}", 55), "37");
+ assert_eq!(format!("{:e}", 55), "5.5e1");
+ assert_eq!(format!("{:E}", 55), "5.5E1");
+ assert_eq!(format!("{:e}", 10000000000u64), "1e10");
+ assert_eq!(format!("{:E}", 10000000000u64), "1E10");
+ assert_eq!(format!("{:e}", 10000000001u64), "1.0000000001e10");
+ assert_eq!(format!("{:E}", 10000000001u64), "1.0000000001E10");
+}
+
+#[test]
+fn test_format_int_exp_limits() {
+ assert_eq!(format!("{:e}", i8::MIN), "-1.28e2");
+ assert_eq!(format!("{:e}", i8::MAX), "1.27e2");
+ assert_eq!(format!("{:e}", i16::MIN), "-3.2768e4");
+ assert_eq!(format!("{:e}", i16::MAX), "3.2767e4");
+ assert_eq!(format!("{:e}", i32::MIN), "-2.147483648e9");
+ assert_eq!(format!("{:e}", i32::MAX), "2.147483647e9");
+ assert_eq!(format!("{:e}", i64::MIN), "-9.223372036854775808e18");
+ assert_eq!(format!("{:e}", i64::MAX), "9.223372036854775807e18");
+ assert_eq!(format!("{:e}", i128::MIN), "-1.70141183460469231731687303715884105728e38");
+ assert_eq!(format!("{:e}", i128::MAX), "1.70141183460469231731687303715884105727e38");
+
+ assert_eq!(format!("{:e}", u8::MAX), "2.55e2");
+ assert_eq!(format!("{:e}", u16::MAX), "6.5535e4");
+ assert_eq!(format!("{:e}", u32::MAX), "4.294967295e9");
+ assert_eq!(format!("{:e}", u64::MAX), "1.8446744073709551615e19");
+ assert_eq!(format!("{:e}", u128::MAX), "3.40282366920938463463374607431768211455e38");
+}
+
+#[test]
+fn test_format_int_exp_precision() {
+ //test that float and integer match
+ let big_int: u32 = 314_159_265;
+ assert_eq!(format!("{big_int:.1e}"), format!("{:.1e}", f64::from(big_int)));
+
+ //test adding precision
+ assert_eq!(format!("{:.10e}", i8::MIN), "-1.2800000000e2");
+ assert_eq!(format!("{:.10e}", i16::MIN), "-3.2768000000e4");
+ assert_eq!(format!("{:.10e}", i32::MIN), "-2.1474836480e9");
+ assert_eq!(format!("{:.20e}", i64::MIN), "-9.22337203685477580800e18");
+ assert_eq!(format!("{:.40e}", i128::MIN), "-1.7014118346046923173168730371588410572800e38");
+
+ //test rounding
+ assert_eq!(format!("{:.1e}", i8::MIN), "-1.3e2");
+ assert_eq!(format!("{:.1e}", i16::MIN), "-3.3e4");
+ assert_eq!(format!("{:.1e}", i32::MIN), "-2.1e9");
+ assert_eq!(format!("{:.1e}", i64::MIN), "-9.2e18");
+ assert_eq!(format!("{:.1e}", i128::MIN), "-1.7e38");
+
+ //test huge precision
+ assert_eq!(format!("{:.1000e}", 1), format!("1.{}e0", "0".repeat(1000)));
+ //test zero precision
+ assert_eq!(format!("{:.0e}", 1), format!("1e0",));
+ assert_eq!(format!("{:.0e}", 35), format!("4e1",));
+
+ //test padding with precision (and sign)
+ assert_eq!(format!("{:+10.3e}", 1), " +1.000e0");
+}
+
+#[test]
+fn test_format_int_zero() {
+ assert_eq!(format!("{}", 0), "0");
+ assert_eq!(format!("{:?}", 0), "0");
+ assert_eq!(format!("{:b}", 0), "0");
+ assert_eq!(format!("{:o}", 0), "0");
+ assert_eq!(format!("{:x}", 0), "0");
+ assert_eq!(format!("{:X}", 0), "0");
+ assert_eq!(format!("{:e}", 0), "0e0");
+ assert_eq!(format!("{:E}", 0), "0E0");
+
+ assert_eq!(format!("{}", 0u32), "0");
+ assert_eq!(format!("{:?}", 0u32), "0");
+ assert_eq!(format!("{:b}", 0u32), "0");
+ assert_eq!(format!("{:o}", 0u32), "0");
+ assert_eq!(format!("{:x}", 0u32), "0");
+ assert_eq!(format!("{:X}", 0u32), "0");
+ assert_eq!(format!("{:e}", 0u32), "0e0");
+ assert_eq!(format!("{:E}", 0u32), "0E0");
+}
+
+#[test]
+fn test_format_int_flags() {
+ assert_eq!(format!("{:3}", 1), " 1");
+ assert_eq!(format!("{:>3}", 1), " 1");
+ assert_eq!(format!("{:>+3}", 1), " +1");
+ assert_eq!(format!("{:<3}", 1), "1 ");
+ assert_eq!(format!("{:#}", 1), "1");
+ assert_eq!(format!("{:#x}", 10), "0xa");
+ assert_eq!(format!("{:#X}", 10), "0xA");
+ assert_eq!(format!("{:#5x}", 10), " 0xa");
+ assert_eq!(format!("{:#o}", 10), "0o12");
+ assert_eq!(format!("{:08x}", 10), "0000000a");
+ assert_eq!(format!("{:8x}", 10), " a");
+ assert_eq!(format!("{:<8x}", 10), "a ");
+ assert_eq!(format!("{:>8x}", 10), " a");
+ assert_eq!(format!("{:#08x}", 10), "0x00000a");
+ assert_eq!(format!("{:08}", -10), "-0000010");
+ assert_eq!(format!("{:x}", !0u8), "ff");
+ assert_eq!(format!("{:X}", !0u8), "FF");
+ assert_eq!(format!("{:b}", !0u8), "11111111");
+ assert_eq!(format!("{:o}", !0u8), "377");
+ assert_eq!(format!("{:#x}", !0u8), "0xff");
+ assert_eq!(format!("{:#X}", !0u8), "0xFF");
+ assert_eq!(format!("{:#b}", !0u8), "0b11111111");
+ assert_eq!(format!("{:#o}", !0u8), "0o377");
+}
+
+#[test]
+fn test_format_int_sign_padding() {
+ assert_eq!(format!("{:+5}", 1), " +1");
+ assert_eq!(format!("{:+5}", -1), " -1");
+ assert_eq!(format!("{:05}", 1), "00001");
+ assert_eq!(format!("{:05}", -1), "-0001");
+ assert_eq!(format!("{:+05}", 1), "+0001");
+ assert_eq!(format!("{:+05}", -1), "-0001");
+}
+
+#[test]
+fn test_format_int_twos_complement() {
+ assert_eq!(format!("{}", i8::MIN), "-128");
+ assert_eq!(format!("{}", i16::MIN), "-32768");
+ assert_eq!(format!("{}", i32::MIN), "-2147483648");
+ assert_eq!(format!("{}", i64::MIN), "-9223372036854775808");
+}
+
+#[test]
+fn test_format_debug_hex() {
+ assert_eq!(format!("{:02x?}", b"Foo\0"), "[46, 6f, 6f, 00]");
+ assert_eq!(format!("{:02X?}", b"Foo\0"), "[46, 6F, 6F, 00]");
+}
diff --git a/library/core/tests/future.rs b/library/core/tests/future.rs
new file mode 100644
index 000000000..74b6f74e4
--- /dev/null
+++ b/library/core/tests/future.rs
@@ -0,0 +1,128 @@
+use std::future::{join, Future};
+use std::pin::Pin;
+use std::sync::Arc;
+use std::task::{Context, Poll, Wake};
+use std::thread;
+
+struct PollN {
+ val: usize,
+ polled: usize,
+ num: usize,
+}
+
+impl Future for PollN {
+ type Output = usize;
+
+ fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
+ self.polled += 1;
+
+ if self.polled == self.num {
+ return Poll::Ready(self.val);
+ }
+
+ cx.waker().wake_by_ref();
+ Poll::Pending
+ }
+}
+
+fn poll_n(val: usize, num: usize) -> PollN {
+ PollN { val, num, polled: 0 }
+}
+
+#[test]
+#[cfg_attr(miri, ignore)] // self-referential generators do not work with Miri's aliasing checks
+fn test_join() {
+ block_on(async move {
+ let x = join!(async { 0 }).await;
+ assert_eq!(x, 0);
+
+ let x = join!(async { 0 }, async { 1 }).await;
+ assert_eq!(x, (0, 1));
+
+ let x = join!(async { 0 }, async { 1 }, async { 2 }).await;
+ assert_eq!(x, (0, 1, 2));
+
+ let x = join!(
+ poll_n(0, 1),
+ poll_n(1, 5),
+ poll_n(2, 2),
+ poll_n(3, 1),
+ poll_n(4, 2),
+ poll_n(5, 3),
+ poll_n(6, 4),
+ poll_n(7, 1)
+ )
+ .await;
+ assert_eq!(x, (0, 1, 2, 3, 4, 5, 6, 7));
+
+ let y = String::new();
+ let x = join!(async {
+ println!("{}", &y);
+ 1
+ })
+ .await;
+ assert_eq!(x, 1);
+ });
+}
+
+/// Tests that `join!(…)` behaves "like a function": evaluating its arguments
+/// before applying any of its own logic.
+///
+/// _e.g._, `join!(async_fn(&borrowed), …)` does not consume `borrowed`;
+/// and `join!(opt_fut?, …)` does let that `?` refer to the callsite scope.
+mod test_join_function_like_value_arg_semantics {
+ use super::*;
+
+ async fn async_fn(_: impl Sized) {}
+
+ // no need to _run_ this test, just to compile it.
+ fn _join_does_not_unnecessarily_move_mentioned_bindings() {
+ let not_copy = vec![()];
+ let _ = join!(async_fn(&not_copy)); // should not move `not_copy`
+ let _ = &not_copy; // OK
+ }
+
+ #[test]
+ fn join_lets_control_flow_effects_such_as_try_flow_through() {
+ let maybe_fut = None;
+ if false {
+ *&mut { maybe_fut } = Some(async {});
+ loop {}
+ }
+ assert!(Option::is_none(&try { join!(maybe_fut?, async { unreachable!() }) }));
+ }
+
+ #[test]
+ fn join_is_able_to_handle_temporaries() {
+ let _ = join!(async_fn(&String::from("temporary")));
+ let () = block_on(join!(async_fn(&String::from("temporary"))));
+ }
+}
+
+fn block_on(fut: impl Future) {
+ struct Waker;
+ impl Wake for Waker {
+ fn wake(self: Arc<Self>) {
+ thread::current().unpark()
+ }
+ }
+
+ let waker = Arc::new(Waker).into();
+ let mut cx = Context::from_waker(&waker);
+ let mut fut = Box::pin(fut);
+
+ loop {
+ match fut.as_mut().poll(&mut cx) {
+ Poll::Ready(_) => break,
+ Poll::Pending => thread::park(),
+ }
+ }
+}
+
+// just tests by whether or not this compiles
+fn _pending_impl_all_auto_traits<T>() {
+ use std::panic::{RefUnwindSafe, UnwindSafe};
+ fn all_auto_traits<T: Send + Sync + Unpin + UnwindSafe + RefUnwindSafe>() {}
+
+ all_auto_traits::<std::future::Pending<T>>();
+}
diff --git a/library/core/tests/hash/mod.rs b/library/core/tests/hash/mod.rs
new file mode 100644
index 000000000..f7934d062
--- /dev/null
+++ b/library/core/tests/hash/mod.rs
@@ -0,0 +1,161 @@
+mod sip;
+
+use std::default::Default;
+use std::hash::{BuildHasher, Hash, Hasher};
+use std::ptr;
+use std::rc::Rc;
+
+struct MyHasher {
+ hash: u64,
+}
+
+impl Default for MyHasher {
+ fn default() -> MyHasher {
+ MyHasher { hash: 0 }
+ }
+}
+
+impl Hasher for MyHasher {
+ fn write(&mut self, buf: &[u8]) {
+ for byte in buf {
+ self.hash += *byte as u64;
+ }
+ }
+ fn write_str(&mut self, s: &str) {
+ self.write(s.as_bytes());
+ self.write_u8(0xFF);
+ }
+ fn finish(&self) -> u64 {
+ self.hash
+ }
+}
+
+#[test]
+fn test_writer_hasher() {
+ fn hash<T: Hash>(t: &T) -> u64 {
+ let mut s = MyHasher { hash: 0 };
+ t.hash(&mut s);
+ s.finish()
+ }
+
+ assert_eq!(hash(&()), 0);
+
+ assert_eq!(hash(&5_u8), 5);
+ assert_eq!(hash(&5_u16), 5);
+ assert_eq!(hash(&5_u32), 5);
+ assert_eq!(hash(&5_u64), 5);
+ assert_eq!(hash(&5_usize), 5);
+
+ assert_eq!(hash(&5_i8), 5);
+ assert_eq!(hash(&5_i16), 5);
+ assert_eq!(hash(&5_i32), 5);
+ assert_eq!(hash(&5_i64), 5);
+ assert_eq!(hash(&5_isize), 5);
+
+ assert_eq!(hash(&false), 0);
+ assert_eq!(hash(&true), 1);
+
+ assert_eq!(hash(&'a'), 97);
+
+ let s: &str = "a";
+ assert_eq!(hash(&s), 97 + 0xFF);
+ let s: Box<str> = String::from("a").into_boxed_str();
+ assert_eq!(hash(&s), 97 + 0xFF);
+ let s: Rc<&str> = Rc::new("a");
+ assert_eq!(hash(&s), 97 + 0xFF);
+ let cs: &[u8] = &[1, 2, 3];
+ assert_eq!(hash(&cs), 9);
+ let cs: Box<[u8]> = Box::new([1, 2, 3]);
+ assert_eq!(hash(&cs), 9);
+ let cs: Rc<[u8]> = Rc::new([1, 2, 3]);
+ assert_eq!(hash(&cs), 9);
+
+ let ptr = ptr::invalid::<i32>(5_usize);
+ assert_eq!(hash(&ptr), 5);
+
+ let ptr = ptr::invalid_mut::<i32>(5_usize);
+ assert_eq!(hash(&ptr), 5);
+
+ if cfg!(miri) {
+ // Miri cannot hash pointers
+ return;
+ }
+
+ let cs: &mut [u8] = &mut [1, 2, 3];
+ let ptr = cs.as_ptr();
+ let slice_ptr = cs as *const [u8];
+ assert_eq!(hash(&slice_ptr), hash(&ptr) + cs.len() as u64);
+
+ let slice_ptr = cs as *mut [u8];
+ assert_eq!(hash(&slice_ptr), hash(&ptr) + cs.len() as u64);
+}
+
+struct Custom {
+ hash: u64,
+}
+struct CustomHasher {
+ output: u64,
+}
+
+impl Hasher for CustomHasher {
+ fn finish(&self) -> u64 {
+ self.output
+ }
+ fn write(&mut self, _: &[u8]) {
+ panic!()
+ }
+ fn write_u64(&mut self, data: u64) {
+ self.output = data;
+ }
+}
+
+impl Default for CustomHasher {
+ fn default() -> CustomHasher {
+ CustomHasher { output: 0 }
+ }
+}
+
+impl Hash for Custom {
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ state.write_u64(self.hash);
+ }
+}
+
+#[test]
+fn test_custom_state() {
+ fn hash<T: Hash>(t: &T) -> u64 {
+ let mut c = CustomHasher { output: 0 };
+ t.hash(&mut c);
+ c.finish()
+ }
+
+ assert_eq!(hash(&Custom { hash: 5 }), 5);
+}
+
+// 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_indirect_hasher() {
+ let mut hasher = MyHasher { hash: 0 };
+ {
+ let mut indirect_hasher: &mut dyn Hasher = &mut hasher;
+ 5u32.hash(&mut indirect_hasher);
+ }
+ assert_eq!(hasher.hash, 5);
+}
+
+#[test]
+fn test_build_hasher_object_safe() {
+ use std::collections::hash_map::{DefaultHasher, RandomState};
+
+ let _: &dyn BuildHasher<Hasher = DefaultHasher> = &RandomState::new();
+}
+
+// just tests by whether or not this compiles
+fn _build_hasher_default_impl_all_auto_traits<T>() {
+ use std::panic::{RefUnwindSafe, UnwindSafe};
+ fn all_auto_traits<T: Send + Sync + Unpin + UnwindSafe + RefUnwindSafe>() {}
+
+ all_auto_traits::<std::hash::BuildHasherDefault<T>>();
+}
diff --git a/library/core/tests/hash/sip.rs b/library/core/tests/hash/sip.rs
new file mode 100644
index 000000000..877d08418
--- /dev/null
+++ b/library/core/tests/hash/sip.rs
@@ -0,0 +1,309 @@
+#![allow(deprecated)]
+
+use core::hash::{Hash, Hasher};
+use core::hash::{SipHasher, SipHasher13};
+use core::{mem, slice};
+
+// Hash just the bytes of the slice, without length prefix
+struct Bytes<'a>(&'a [u8]);
+
+impl<'a> Hash for Bytes<'a> {
+ #[allow(unused_must_use)]
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ let Bytes(v) = *self;
+ state.write(v);
+ }
+}
+
+fn hash_with<H: Hasher, T: Hash>(mut st: H, x: &T) -> u64 {
+ x.hash(&mut st);
+ st.finish()
+}
+
+fn hash<T: Hash>(x: &T) -> u64 {
+ hash_with(SipHasher::new(), x)
+}
+
+#[test]
+#[allow(unused_must_use)]
+fn test_siphash_1_3() {
+ let vecs: [[u8; 8]; 64] = [
+ [0xdc, 0xc4, 0x0f, 0x05, 0x58, 0x01, 0xac, 0xab],
+ [0x93, 0xca, 0x57, 0x7d, 0xf3, 0x9b, 0xf4, 0xc9],
+ [0x4d, 0xd4, 0xc7, 0x4d, 0x02, 0x9b, 0xcb, 0x82],
+ [0xfb, 0xf7, 0xdd, 0xe7, 0xb8, 0x0a, 0xf8, 0x8b],
+ [0x28, 0x83, 0xd3, 0x88, 0x60, 0x57, 0x75, 0xcf],
+ [0x67, 0x3b, 0x53, 0x49, 0x2f, 0xd5, 0xf9, 0xde],
+ [0xa7, 0x22, 0x9f, 0xc5, 0x50, 0x2b, 0x0d, 0xc5],
+ [0x40, 0x11, 0xb1, 0x9b, 0x98, 0x7d, 0x92, 0xd3],
+ [0x8e, 0x9a, 0x29, 0x8d, 0x11, 0x95, 0x90, 0x36],
+ [0xe4, 0x3d, 0x06, 0x6c, 0xb3, 0x8e, 0xa4, 0x25],
+ [0x7f, 0x09, 0xff, 0x92, 0xee, 0x85, 0xde, 0x79],
+ [0x52, 0xc3, 0x4d, 0xf9, 0xc1, 0x18, 0xc1, 0x70],
+ [0xa2, 0xd9, 0xb4, 0x57, 0xb1, 0x84, 0xa3, 0x78],
+ [0xa7, 0xff, 0x29, 0x12, 0x0c, 0x76, 0x6f, 0x30],
+ [0x34, 0x5d, 0xf9, 0xc0, 0x11, 0xa1, 0x5a, 0x60],
+ [0x56, 0x99, 0x51, 0x2a, 0x6d, 0xd8, 0x20, 0xd3],
+ [0x66, 0x8b, 0x90, 0x7d, 0x1a, 0xdd, 0x4f, 0xcc],
+ [0x0c, 0xd8, 0xdb, 0x63, 0x90, 0x68, 0xf2, 0x9c],
+ [0x3e, 0xe6, 0x73, 0xb4, 0x9c, 0x38, 0xfc, 0x8f],
+ [0x1c, 0x7d, 0x29, 0x8d, 0xe5, 0x9d, 0x1f, 0xf2],
+ [0x40, 0xe0, 0xcc, 0xa6, 0x46, 0x2f, 0xdc, 0xc0],
+ [0x44, 0xf8, 0x45, 0x2b, 0xfe, 0xab, 0x92, 0xb9],
+ [0x2e, 0x87, 0x20, 0xa3, 0x9b, 0x7b, 0xfe, 0x7f],
+ [0x23, 0xc1, 0xe6, 0xda, 0x7f, 0x0e, 0x5a, 0x52],
+ [0x8c, 0x9c, 0x34, 0x67, 0xb2, 0xae, 0x64, 0xf4],
+ [0x79, 0x09, 0x5b, 0x70, 0x28, 0x59, 0xcd, 0x45],
+ [0xa5, 0x13, 0x99, 0xca, 0xe3, 0x35, 0x3e, 0x3a],
+ [0x35, 0x3b, 0xde, 0x4a, 0x4e, 0xc7, 0x1d, 0xa9],
+ [0x0d, 0xd0, 0x6c, 0xef, 0x02, 0xed, 0x0b, 0xfb],
+ [0xf4, 0xe1, 0xb1, 0x4a, 0xb4, 0x3c, 0xd9, 0x88],
+ [0x63, 0xe6, 0xc5, 0x43, 0xd6, 0x11, 0x0f, 0x54],
+ [0xbc, 0xd1, 0x21, 0x8c, 0x1f, 0xdd, 0x70, 0x23],
+ [0x0d, 0xb6, 0xa7, 0x16, 0x6c, 0x7b, 0x15, 0x81],
+ [0xbf, 0xf9, 0x8f, 0x7a, 0xe5, 0xb9, 0x54, 0x4d],
+ [0x3e, 0x75, 0x2a, 0x1f, 0x78, 0x12, 0x9f, 0x75],
+ [0x91, 0x6b, 0x18, 0xbf, 0xbe, 0xa3, 0xa1, 0xce],
+ [0x06, 0x62, 0xa2, 0xad, 0xd3, 0x08, 0xf5, 0x2c],
+ [0x57, 0x30, 0xc3, 0xa3, 0x2d, 0x1c, 0x10, 0xb6],
+ [0xa1, 0x36, 0x3a, 0xae, 0x96, 0x74, 0xf4, 0xb3],
+ [0x92, 0x83, 0x10, 0x7b, 0x54, 0x57, 0x6b, 0x62],
+ [0x31, 0x15, 0xe4, 0x99, 0x32, 0x36, 0xd2, 0xc1],
+ [0x44, 0xd9, 0x1a, 0x3f, 0x92, 0xc1, 0x7c, 0x66],
+ [0x25, 0x88, 0x13, 0xc8, 0xfe, 0x4f, 0x70, 0x65],
+ [0xa6, 0x49, 0x89, 0xc2, 0xd1, 0x80, 0xf2, 0x24],
+ [0x6b, 0x87, 0xf8, 0xfa, 0xed, 0x1c, 0xca, 0xc2],
+ [0x96, 0x21, 0x04, 0x9f, 0xfc, 0x4b, 0x16, 0xc2],
+ [0x23, 0xd6, 0xb1, 0x68, 0x93, 0x9c, 0x6e, 0xa1],
+ [0xfd, 0x14, 0x51, 0x8b, 0x9c, 0x16, 0xfb, 0x49],
+ [0x46, 0x4c, 0x07, 0xdf, 0xf8, 0x43, 0x31, 0x9f],
+ [0xb3, 0x86, 0xcc, 0x12, 0x24, 0xaf, 0xfd, 0xc6],
+ [0x8f, 0x09, 0x52, 0x0a, 0xd1, 0x49, 0xaf, 0x7e],
+ [0x9a, 0x2f, 0x29, 0x9d, 0x55, 0x13, 0xf3, 0x1c],
+ [0x12, 0x1f, 0xf4, 0xa2, 0xdd, 0x30, 0x4a, 0xc4],
+ [0xd0, 0x1e, 0xa7, 0x43, 0x89, 0xe9, 0xfa, 0x36],
+ [0xe6, 0xbc, 0xf0, 0x73, 0x4c, 0xb3, 0x8f, 0x31],
+ [0x80, 0xe9, 0xa7, 0x70, 0x36, 0xbf, 0x7a, 0xa2],
+ [0x75, 0x6d, 0x3c, 0x24, 0xdb, 0xc0, 0xbc, 0xb4],
+ [0x13, 0x15, 0xb7, 0xfd, 0x52, 0xd8, 0xf8, 0x23],
+ [0x08, 0x8a, 0x7d, 0xa6, 0x4d, 0x5f, 0x03, 0x8f],
+ [0x48, 0xf1, 0xe8, 0xb7, 0xe5, 0xd0, 0x9c, 0xd8],
+ [0xee, 0x44, 0xa6, 0xf7, 0xbc, 0xe6, 0xf4, 0xf6],
+ [0xf2, 0x37, 0x18, 0x0f, 0xd8, 0x9a, 0xc5, 0xae],
+ [0xe0, 0x94, 0x66, 0x4b, 0x15, 0xf6, 0xb2, 0xc3],
+ [0xa8, 0xb3, 0xbb, 0xb7, 0x62, 0x90, 0x19, 0x9d],
+ ];
+
+ let k0 = 0x_07_06_05_04_03_02_01_00;
+ let k1 = 0x_0f_0e_0d_0c_0b_0a_09_08;
+ let mut buf = Vec::new();
+ let mut t = 0;
+ let mut state_inc = SipHasher13::new_with_keys(k0, k1);
+
+ while t < 64 {
+ let vec = u64::from_le_bytes(vecs[t]);
+ let out = hash_with(SipHasher13::new_with_keys(k0, k1), &Bytes(&buf));
+ assert_eq!(vec, out);
+
+ let full = hash_with(SipHasher13::new_with_keys(k0, k1), &Bytes(&buf));
+ let i = state_inc.finish();
+
+ assert_eq!(full, i);
+ assert_eq!(full, vec);
+
+ buf.push(t as u8);
+ Hasher::write(&mut state_inc, &[t as u8]);
+
+ t += 1;
+ }
+}
+
+#[test]
+#[allow(unused_must_use)]
+fn test_siphash_2_4() {
+ let vecs: [[u8; 8]; 64] = [
+ [0x31, 0x0e, 0x0e, 0xdd, 0x47, 0xdb, 0x6f, 0x72],
+ [0xfd, 0x67, 0xdc, 0x93, 0xc5, 0x39, 0xf8, 0x74],
+ [0x5a, 0x4f, 0xa9, 0xd9, 0x09, 0x80, 0x6c, 0x0d],
+ [0x2d, 0x7e, 0xfb, 0xd7, 0x96, 0x66, 0x67, 0x85],
+ [0xb7, 0x87, 0x71, 0x27, 0xe0, 0x94, 0x27, 0xcf],
+ [0x8d, 0xa6, 0x99, 0xcd, 0x64, 0x55, 0x76, 0x18],
+ [0xce, 0xe3, 0xfe, 0x58, 0x6e, 0x46, 0xc9, 0xcb],
+ [0x37, 0xd1, 0x01, 0x8b, 0xf5, 0x00, 0x02, 0xab],
+ [0x62, 0x24, 0x93, 0x9a, 0x79, 0xf5, 0xf5, 0x93],
+ [0xb0, 0xe4, 0xa9, 0x0b, 0xdf, 0x82, 0x00, 0x9e],
+ [0xf3, 0xb9, 0xdd, 0x94, 0xc5, 0xbb, 0x5d, 0x7a],
+ [0xa7, 0xad, 0x6b, 0x22, 0x46, 0x2f, 0xb3, 0xf4],
+ [0xfb, 0xe5, 0x0e, 0x86, 0xbc, 0x8f, 0x1e, 0x75],
+ [0x90, 0x3d, 0x84, 0xc0, 0x27, 0x56, 0xea, 0x14],
+ [0xee, 0xf2, 0x7a, 0x8e, 0x90, 0xca, 0x23, 0xf7],
+ [0xe5, 0x45, 0xbe, 0x49, 0x61, 0xca, 0x29, 0xa1],
+ [0xdb, 0x9b, 0xc2, 0x57, 0x7f, 0xcc, 0x2a, 0x3f],
+ [0x94, 0x47, 0xbe, 0x2c, 0xf5, 0xe9, 0x9a, 0x69],
+ [0x9c, 0xd3, 0x8d, 0x96, 0xf0, 0xb3, 0xc1, 0x4b],
+ [0xbd, 0x61, 0x79, 0xa7, 0x1d, 0xc9, 0x6d, 0xbb],
+ [0x98, 0xee, 0xa2, 0x1a, 0xf2, 0x5c, 0xd6, 0xbe],
+ [0xc7, 0x67, 0x3b, 0x2e, 0xb0, 0xcb, 0xf2, 0xd0],
+ [0x88, 0x3e, 0xa3, 0xe3, 0x95, 0x67, 0x53, 0x93],
+ [0xc8, 0xce, 0x5c, 0xcd, 0x8c, 0x03, 0x0c, 0xa8],
+ [0x94, 0xaf, 0x49, 0xf6, 0xc6, 0x50, 0xad, 0xb8],
+ [0xea, 0xb8, 0x85, 0x8a, 0xde, 0x92, 0xe1, 0xbc],
+ [0xf3, 0x15, 0xbb, 0x5b, 0xb8, 0x35, 0xd8, 0x17],
+ [0xad, 0xcf, 0x6b, 0x07, 0x63, 0x61, 0x2e, 0x2f],
+ [0xa5, 0xc9, 0x1d, 0xa7, 0xac, 0xaa, 0x4d, 0xde],
+ [0x71, 0x65, 0x95, 0x87, 0x66, 0x50, 0xa2, 0xa6],
+ [0x28, 0xef, 0x49, 0x5c, 0x53, 0xa3, 0x87, 0xad],
+ [0x42, 0xc3, 0x41, 0xd8, 0xfa, 0x92, 0xd8, 0x32],
+ [0xce, 0x7c, 0xf2, 0x72, 0x2f, 0x51, 0x27, 0x71],
+ [0xe3, 0x78, 0x59, 0xf9, 0x46, 0x23, 0xf3, 0xa7],
+ [0x38, 0x12, 0x05, 0xbb, 0x1a, 0xb0, 0xe0, 0x12],
+ [0xae, 0x97, 0xa1, 0x0f, 0xd4, 0x34, 0xe0, 0x15],
+ [0xb4, 0xa3, 0x15, 0x08, 0xbe, 0xff, 0x4d, 0x31],
+ [0x81, 0x39, 0x62, 0x29, 0xf0, 0x90, 0x79, 0x02],
+ [0x4d, 0x0c, 0xf4, 0x9e, 0xe5, 0xd4, 0xdc, 0xca],
+ [0x5c, 0x73, 0x33, 0x6a, 0x76, 0xd8, 0xbf, 0x9a],
+ [0xd0, 0xa7, 0x04, 0x53, 0x6b, 0xa9, 0x3e, 0x0e],
+ [0x92, 0x59, 0x58, 0xfc, 0xd6, 0x42, 0x0c, 0xad],
+ [0xa9, 0x15, 0xc2, 0x9b, 0xc8, 0x06, 0x73, 0x18],
+ [0x95, 0x2b, 0x79, 0xf3, 0xbc, 0x0a, 0xa6, 0xd4],
+ [0xf2, 0x1d, 0xf2, 0xe4, 0x1d, 0x45, 0x35, 0xf9],
+ [0x87, 0x57, 0x75, 0x19, 0x04, 0x8f, 0x53, 0xa9],
+ [0x10, 0xa5, 0x6c, 0xf5, 0xdf, 0xcd, 0x9a, 0xdb],
+ [0xeb, 0x75, 0x09, 0x5c, 0xcd, 0x98, 0x6c, 0xd0],
+ [0x51, 0xa9, 0xcb, 0x9e, 0xcb, 0xa3, 0x12, 0xe6],
+ [0x96, 0xaf, 0xad, 0xfc, 0x2c, 0xe6, 0x66, 0xc7],
+ [0x72, 0xfe, 0x52, 0x97, 0x5a, 0x43, 0x64, 0xee],
+ [0x5a, 0x16, 0x45, 0xb2, 0x76, 0xd5, 0x92, 0xa1],
+ [0xb2, 0x74, 0xcb, 0x8e, 0xbf, 0x87, 0x87, 0x0a],
+ [0x6f, 0x9b, 0xb4, 0x20, 0x3d, 0xe7, 0xb3, 0x81],
+ [0xea, 0xec, 0xb2, 0xa3, 0x0b, 0x22, 0xa8, 0x7f],
+ [0x99, 0x24, 0xa4, 0x3c, 0xc1, 0x31, 0x57, 0x24],
+ [0xbd, 0x83, 0x8d, 0x3a, 0xaf, 0xbf, 0x8d, 0xb7],
+ [0x0b, 0x1a, 0x2a, 0x32, 0x65, 0xd5, 0x1a, 0xea],
+ [0x13, 0x50, 0x79, 0xa3, 0x23, 0x1c, 0xe6, 0x60],
+ [0x93, 0x2b, 0x28, 0x46, 0xe4, 0xd7, 0x06, 0x66],
+ [0xe1, 0x91, 0x5f, 0x5c, 0xb1, 0xec, 0xa4, 0x6c],
+ [0xf3, 0x25, 0x96, 0x5c, 0xa1, 0x6d, 0x62, 0x9f],
+ [0x57, 0x5f, 0xf2, 0x8e, 0x60, 0x38, 0x1b, 0xe5],
+ [0x72, 0x45, 0x06, 0xeb, 0x4c, 0x32, 0x8a, 0x95],
+ ];
+
+ let k0 = 0x_07_06_05_04_03_02_01_00;
+ let k1 = 0x_0f_0e_0d_0c_0b_0a_09_08;
+ let mut buf = Vec::new();
+ let mut t = 0;
+ let mut state_inc = SipHasher::new_with_keys(k0, k1);
+
+ while t < 64 {
+ let vec = u64::from_le_bytes(vecs[t]);
+ let out = hash_with(SipHasher::new_with_keys(k0, k1), &Bytes(&buf));
+ assert_eq!(vec, out);
+
+ let full = hash_with(SipHasher::new_with_keys(k0, k1), &Bytes(&buf));
+ let i = state_inc.finish();
+
+ assert_eq!(full, i);
+ assert_eq!(full, vec);
+
+ buf.push(t as u8);
+ Hasher::write(&mut state_inc, &[t as u8]);
+
+ t += 1;
+ }
+}
+
+#[test]
+#[cfg(target_pointer_width = "32")]
+fn test_hash_usize() {
+ let val = 0xdeadbeef_deadbeef_u64;
+ assert_ne!(hash(&(val as u64)), hash(&(val as usize)));
+ assert_eq!(hash(&(val as u32)), hash(&(val as usize)));
+}
+
+#[test]
+#[cfg(target_pointer_width = "64")]
+fn test_hash_usize() {
+ let val = 0xdeadbeef_deadbeef_u64;
+ assert_eq!(hash(&(val as u64)), hash(&(val as usize)));
+ assert_ne!(hash(&(val as u32)), hash(&(val as usize)));
+}
+
+#[test]
+fn test_hash_idempotent() {
+ let val64 = 0xdeadbeef_deadbeef_u64;
+ assert_eq!(hash(&val64), hash(&val64));
+ let val32 = 0xdeadbeef_u32;
+ assert_eq!(hash(&val32), hash(&val32));
+}
+
+#[test]
+fn test_hash_no_bytes_dropped_64() {
+ let val = 0xdeadbeef_deadbeef_u64;
+
+ assert_ne!(hash(&val), hash(&zero_byte(val, 0)));
+ assert_ne!(hash(&val), hash(&zero_byte(val, 1)));
+ assert_ne!(hash(&val), hash(&zero_byte(val, 2)));
+ assert_ne!(hash(&val), hash(&zero_byte(val, 3)));
+ assert_ne!(hash(&val), hash(&zero_byte(val, 4)));
+ assert_ne!(hash(&val), hash(&zero_byte(val, 5)));
+ assert_ne!(hash(&val), hash(&zero_byte(val, 6)));
+ assert_ne!(hash(&val), hash(&zero_byte(val, 7)));
+
+ fn zero_byte(val: u64, byte: usize) -> u64 {
+ assert!(byte < 8);
+ val & !(0xff << (byte * 8))
+ }
+}
+
+#[test]
+fn test_hash_no_bytes_dropped_32() {
+ let val = 0xdeadbeef_u32;
+
+ assert_ne!(hash(&val), hash(&zero_byte(val, 0)));
+ assert_ne!(hash(&val), hash(&zero_byte(val, 1)));
+ assert_ne!(hash(&val), hash(&zero_byte(val, 2)));
+ assert_ne!(hash(&val), hash(&zero_byte(val, 3)));
+
+ fn zero_byte(val: u32, byte: usize) -> u32 {
+ assert!(byte < 4);
+ val & !(0xff << (byte * 8))
+ }
+}
+
+#[test]
+fn test_hash_no_concat_alias() {
+ let s = ("aa", "bb");
+ let t = ("aabb", "");
+ let u = ("a", "abb");
+
+ assert_ne!(s, t);
+ assert_ne!(t, u);
+ assert_ne!(hash(&s), hash(&t));
+ assert_ne!(hash(&s), hash(&u));
+
+ let u = [1, 0, 0, 0];
+ let v = (&u[..1], &u[1..3], &u[3..]);
+ let w = (&u[..], &u[4..4], &u[4..4]);
+
+ assert_ne!(v, w);
+ assert_ne!(hash(&v), hash(&w));
+}
+
+#[test]
+fn test_write_short_works() {
+ let test_usize = 0xd0c0b0a0usize;
+ let mut h1 = SipHasher::new();
+ h1.write_usize(test_usize);
+ h1.write(b"bytes");
+ h1.write(b"string");
+ h1.write_u8(0xFFu8);
+ h1.write_u8(0x01u8);
+ let mut h2 = SipHasher::new();
+ h2.write(unsafe {
+ slice::from_raw_parts(&test_usize as *const _ as *const u8, mem::size_of::<usize>())
+ });
+ h2.write(b"bytes");
+ h2.write(b"string");
+ h2.write(&[0xFFu8, 0x01u8]);
+ assert_eq!(h1.finish(), h2.finish());
+}
diff --git a/library/core/tests/intrinsics.rs b/library/core/tests/intrinsics.rs
new file mode 100644
index 000000000..06870c6d0
--- /dev/null
+++ b/library/core/tests/intrinsics.rs
@@ -0,0 +1,101 @@
+use core::any::TypeId;
+use core::intrinsics::assume;
+
+#[test]
+fn test_typeid_sized_types() {
+ struct X;
+ struct Y(u32);
+
+ assert_eq!(TypeId::of::<X>(), TypeId::of::<X>());
+ assert_eq!(TypeId::of::<Y>(), TypeId::of::<Y>());
+ assert!(TypeId::of::<X>() != TypeId::of::<Y>());
+}
+
+#[test]
+fn test_typeid_unsized_types() {
+ trait Z {}
+ struct X(str);
+ struct Y(dyn Z + 'static);
+
+ assert_eq!(TypeId::of::<X>(), TypeId::of::<X>());
+ assert_eq!(TypeId::of::<Y>(), TypeId::of::<Y>());
+ assert!(TypeId::of::<X>() != TypeId::of::<Y>());
+}
+
+// Check that `const_assume` feature allow `assume` intrinsic
+// to be used in const contexts.
+#[test]
+fn test_assume_can_be_in_const_contexts() {
+ const unsafe fn foo(x: usize, y: usize) -> usize {
+ // SAFETY: the entire function is not safe,
+ // but it is just an example not used elsewhere.
+ unsafe { assume(y != 0) };
+ x / y
+ }
+ let rs = unsafe { foo(42, 97) };
+ assert_eq!(rs, 0);
+}
+
+#[test]
+const fn test_write_bytes_in_const_contexts() {
+ use core::intrinsics::write_bytes;
+
+ const TEST: [u32; 3] = {
+ let mut arr = [1u32, 2, 3];
+ unsafe {
+ write_bytes(arr.as_mut_ptr(), 0, 2);
+ }
+ arr
+ };
+
+ assert!(TEST[0] == 0);
+ assert!(TEST[1] == 0);
+ assert!(TEST[2] == 3);
+
+ const TEST2: [u32; 3] = {
+ let mut arr = [1u32, 2, 3];
+ unsafe {
+ write_bytes(arr.as_mut_ptr(), 1, 2);
+ }
+ arr
+ };
+
+ assert!(TEST2[0] == 16843009);
+ assert!(TEST2[1] == 16843009);
+ assert!(TEST2[2] == 3);
+}
+
+#[test]
+fn test_hints_in_const_contexts() {
+ use core::intrinsics::{likely, unlikely};
+
+ // In const contexts, they just return their argument.
+ const {
+ assert!(true == likely(true));
+ assert!(false == likely(false));
+ assert!(true == unlikely(true));
+ assert!(false == unlikely(false));
+ assert!(42u32 == core::intrinsics::black_box(42u32));
+ assert!(42u32 == core::hint::black_box(42u32));
+ }
+}
+
+#[test]
+fn test_const_allocate_at_runtime() {
+ use core::intrinsics::const_allocate;
+ unsafe {
+ assert!(const_allocate(4, 4).is_null());
+ }
+}
+
+#[test]
+fn test_const_deallocate_at_runtime() {
+ use core::intrinsics::const_deallocate;
+ const X: &u32 = &42u32;
+ let x = &0u32;
+ unsafe {
+ const_deallocate(X as *const _ as *mut u8, 4, 4); // nop
+ const_deallocate(x as *const _ as *mut u8, 4, 4); // nop
+ const_deallocate(core::ptr::null_mut(), 1, 1); // nop
+ }
+}
diff --git a/library/core/tests/iter/adapters/chain.rs b/library/core/tests/iter/adapters/chain.rs
new file mode 100644
index 000000000..f419f9cec
--- /dev/null
+++ b/library/core/tests/iter/adapters/chain.rs
@@ -0,0 +1,280 @@
+use super::*;
+use core::iter::*;
+
+#[test]
+fn test_iterator_chain() {
+ let xs = [0, 1, 2, 3, 4, 5];
+ let ys = [30, 40, 50, 60];
+ let expected = [0, 1, 2, 3, 4, 5, 30, 40, 50, 60];
+ let it = xs.iter().chain(&ys);
+ let mut i = 0;
+ for &x in it {
+ assert_eq!(x, expected[i]);
+ i += 1;
+ }
+ assert_eq!(i, expected.len());
+
+ let ys = (30..).step_by(10).take(4);
+ let it = xs.iter().cloned().chain(ys);
+ let mut i = 0;
+ for x in it {
+ assert_eq!(x, expected[i]);
+ i += 1;
+ }
+ assert_eq!(i, expected.len());
+}
+
+#[test]
+fn test_iterator_chain_advance_by() {
+ fn test_chain(xs: &[i32], ys: &[i32]) {
+ let len = xs.len() + ys.len();
+
+ for i in 0..xs.len() {
+ let mut iter = Unfuse::new(xs).chain(Unfuse::new(ys));
+ iter.advance_by(i).unwrap();
+ assert_eq!(iter.next(), Some(&xs[i]));
+ assert_eq!(iter.advance_by(100), Err(len - i - 1));
+ iter.advance_by(0).unwrap();
+ }
+
+ for i in 0..ys.len() {
+ let mut iter = Unfuse::new(xs).chain(Unfuse::new(ys));
+ iter.advance_by(xs.len() + i).unwrap();
+ assert_eq!(iter.next(), Some(&ys[i]));
+ assert_eq!(iter.advance_by(100), Err(ys.len() - i - 1));
+ iter.advance_by(0).unwrap();
+ }
+
+ let mut iter = xs.iter().chain(ys);
+ iter.advance_by(len).unwrap();
+ assert_eq!(iter.next(), None);
+ iter.advance_by(0).unwrap();
+
+ let mut iter = xs.iter().chain(ys);
+ assert_eq!(iter.advance_by(len + 1), Err(len));
+ iter.advance_by(0).unwrap();
+ }
+
+ test_chain(&[], &[]);
+ test_chain(&[], &[0, 1, 2, 3, 4, 5]);
+ test_chain(&[0, 1, 2, 3, 4, 5], &[]);
+ test_chain(&[0, 1, 2, 3, 4, 5], &[30, 40, 50, 60]);
+}
+
+#[test]
+fn test_iterator_chain_advance_back_by() {
+ fn test_chain(xs: &[i32], ys: &[i32]) {
+ let len = xs.len() + ys.len();
+
+ for i in 0..ys.len() {
+ let mut iter = Unfuse::new(xs).chain(Unfuse::new(ys));
+ iter.advance_back_by(i).unwrap();
+ assert_eq!(iter.next_back(), Some(&ys[ys.len() - i - 1]));
+ assert_eq!(iter.advance_back_by(100), Err(len - i - 1));
+ iter.advance_back_by(0).unwrap();
+ }
+
+ for i in 0..xs.len() {
+ let mut iter = Unfuse::new(xs).chain(Unfuse::new(ys));
+ iter.advance_back_by(ys.len() + i).unwrap();
+ assert_eq!(iter.next_back(), Some(&xs[xs.len() - i - 1]));
+ assert_eq!(iter.advance_back_by(100), Err(xs.len() - i - 1));
+ iter.advance_back_by(0).unwrap();
+ }
+
+ let mut iter = xs.iter().chain(ys);
+ iter.advance_back_by(len).unwrap();
+ assert_eq!(iter.next_back(), None);
+ iter.advance_back_by(0).unwrap();
+
+ let mut iter = xs.iter().chain(ys);
+ assert_eq!(iter.advance_back_by(len + 1), Err(len));
+ iter.advance_back_by(0).unwrap();
+ }
+
+ test_chain(&[], &[]);
+ test_chain(&[], &[0, 1, 2, 3, 4, 5]);
+ test_chain(&[0, 1, 2, 3, 4, 5], &[]);
+ test_chain(&[0, 1, 2, 3, 4, 5], &[30, 40, 50, 60]);
+}
+
+#[test]
+fn test_iterator_chain_nth() {
+ let xs = [0, 1, 2, 3, 4, 5];
+ let ys = [30, 40, 50, 60];
+ let zs = [];
+ let expected = [0, 1, 2, 3, 4, 5, 30, 40, 50, 60];
+ for (i, x) in expected.iter().enumerate() {
+ assert_eq!(Some(x), xs.iter().chain(&ys).nth(i));
+ }
+ assert_eq!(zs.iter().chain(&xs).nth(0), Some(&0));
+
+ let mut it = xs.iter().chain(&zs);
+ assert_eq!(it.nth(5), Some(&5));
+ assert_eq!(it.next(), None);
+}
+
+#[test]
+fn test_iterator_chain_nth_back() {
+ let xs = [0, 1, 2, 3, 4, 5];
+ let ys = [30, 40, 50, 60];
+ let zs = [];
+ let expected = [0, 1, 2, 3, 4, 5, 30, 40, 50, 60];
+ for (i, x) in expected.iter().rev().enumerate() {
+ assert_eq!(Some(x), xs.iter().chain(&ys).nth_back(i));
+ }
+ assert_eq!(zs.iter().chain(&xs).nth_back(0), Some(&5));
+
+ let mut it = xs.iter().chain(&zs);
+ assert_eq!(it.nth_back(5), Some(&0));
+ assert_eq!(it.next(), None);
+}
+
+#[test]
+fn test_iterator_chain_last() {
+ let xs = [0, 1, 2, 3, 4, 5];
+ let ys = [30, 40, 50, 60];
+ let zs = [];
+ assert_eq!(xs.iter().chain(&ys).last(), Some(&60));
+ assert_eq!(zs.iter().chain(&ys).last(), Some(&60));
+ assert_eq!(ys.iter().chain(&zs).last(), Some(&60));
+ assert_eq!(zs.iter().chain(&zs).last(), None);
+}
+
+#[test]
+fn test_iterator_chain_count() {
+ let xs = [0, 1, 2, 3, 4, 5];
+ let ys = [30, 40, 50, 60];
+ let zs = [];
+ assert_eq!(xs.iter().chain(&ys).count(), 10);
+ assert_eq!(zs.iter().chain(&ys).count(), 4);
+}
+
+#[test]
+fn test_iterator_chain_find() {
+ let xs = [0, 1, 2, 3, 4, 5];
+ let ys = [30, 40, 50, 60];
+ let mut iter = xs.iter().chain(&ys);
+ assert_eq!(iter.find(|&&i| i == 4), Some(&4));
+ assert_eq!(iter.next(), Some(&5));
+ assert_eq!(iter.find(|&&i| i == 40), Some(&40));
+ assert_eq!(iter.next(), Some(&50));
+ assert_eq!(iter.find(|&&i| i == 100), None);
+ assert_eq!(iter.next(), None);
+}
+
+#[test]
+fn test_iterator_chain_size_hint() {
+ // this chains an iterator of length 0 with an iterator of length 1,
+ // so after calling `.next()` once, the iterator is empty and the
+ // state is `ChainState::Back`. `.size_hint()` should now disregard
+ // the size hint of the left iterator
+ let mut iter = Toggle { is_empty: true }.chain(once(()));
+ assert_eq!(iter.next(), Some(()));
+ assert_eq!(iter.size_hint(), (0, Some(0)));
+
+ let mut iter = once(()).chain(Toggle { is_empty: true });
+ assert_eq!(iter.next_back(), Some(()));
+ assert_eq!(iter.size_hint(), (0, Some(0)));
+}
+
+#[test]
+fn test_iterator_chain_unfused() {
+ // Chain shouldn't be fused in its second iterator, depending on direction
+ let mut iter = NonFused::new(empty()).chain(Toggle { is_empty: true });
+ assert!(iter.next().is_none());
+ assert!(iter.next().is_some());
+ assert!(iter.next().is_none());
+
+ let mut iter = Toggle { is_empty: true }.chain(NonFused::new(empty()));
+ assert!(iter.next_back().is_none());
+ assert!(iter.next_back().is_some());
+ assert!(iter.next_back().is_none());
+}
+
+#[test]
+fn test_chain_fold() {
+ let xs = [1, 2, 3];
+ let ys = [1, 2, 0];
+
+ let mut iter = xs.iter().chain(&ys);
+ iter.next();
+ let mut result = Vec::new();
+ iter.fold((), |(), &elt| result.push(elt));
+ assert_eq!(&[2, 3, 1, 2, 0], &result[..]);
+}
+
+#[test]
+fn test_chain_try_folds() {
+ let c = || (0..10).chain(10..20);
+
+ let f = &|acc, x| i32::checked_add(2 * acc, x);
+ assert_eq!(c().try_fold(7, f), (0..20).try_fold(7, f));
+ assert_eq!(c().try_rfold(7, f), (0..20).rev().try_fold(7, f));
+
+ let mut iter = c();
+ assert_eq!(iter.position(|x| x == 5), Some(5));
+ assert_eq!(iter.next(), Some(6), "stopped in front, state Both");
+ assert_eq!(iter.position(|x| x == 13), Some(6));
+ assert_eq!(iter.next(), Some(14), "stopped in back, state Back");
+ assert_eq!(iter.try_fold(0, |acc, x| Some(acc + x)), Some((15..20).sum()));
+
+ let mut iter = c().rev(); // use rev to access try_rfold
+ assert_eq!(iter.position(|x| x == 15), Some(4));
+ assert_eq!(iter.next(), Some(14), "stopped in back, state Both");
+ assert_eq!(iter.position(|x| x == 5), Some(8));
+ assert_eq!(iter.next(), Some(4), "stopped in front, state Front");
+ assert_eq!(iter.try_fold(0, |acc, x| Some(acc + x)), Some((0..4).sum()));
+
+ let mut iter = c();
+ iter.by_ref().rev().nth(14); // skip the last 15, ending in state Front
+ assert_eq!(iter.try_fold(7, f), (0..5).try_fold(7, f));
+
+ let mut iter = c();
+ iter.nth(14); // skip the first 15, ending in state Back
+ assert_eq!(iter.try_rfold(7, f), (15..20).try_rfold(7, f));
+}
+
+#[test]
+fn test_double_ended_chain() {
+ let xs = [1, 2, 3, 4, 5];
+ let ys = [7, 9, 11];
+ let mut it = xs.iter().chain(&ys).rev();
+ assert_eq!(it.next().unwrap(), &11);
+ assert_eq!(it.next().unwrap(), &9);
+ assert_eq!(it.next_back().unwrap(), &1);
+ assert_eq!(it.next_back().unwrap(), &2);
+ assert_eq!(it.next_back().unwrap(), &3);
+ assert_eq!(it.next_back().unwrap(), &4);
+ assert_eq!(it.next_back().unwrap(), &5);
+ assert_eq!(it.next_back().unwrap(), &7);
+ assert_eq!(it.next_back(), None);
+
+ // test that .chain() is well behaved with an unfused iterator
+ struct CrazyIterator(bool);
+ impl CrazyIterator {
+ fn new() -> CrazyIterator {
+ CrazyIterator(false)
+ }
+ }
+ impl Iterator for CrazyIterator {
+ type Item = i32;
+ fn next(&mut self) -> Option<i32> {
+ if self.0 {
+ Some(99)
+ } else {
+ self.0 = true;
+ None
+ }
+ }
+ }
+
+ impl DoubleEndedIterator for CrazyIterator {
+ fn next_back(&mut self) -> Option<i32> {
+ self.next()
+ }
+ }
+
+ assert_eq!(CrazyIterator::new().chain(0..10).rev().last(), Some(0));
+ assert!((0..10).chain(CrazyIterator::new()).rev().any(|i| i == 0));
+}
diff --git a/library/core/tests/iter/adapters/cloned.rs b/library/core/tests/iter/adapters/cloned.rs
new file mode 100644
index 000000000..78babb7fe
--- /dev/null
+++ b/library/core/tests/iter/adapters/cloned.rs
@@ -0,0 +1,52 @@
+use core::iter::*;
+
+#[test]
+fn test_cloned() {
+ let xs = [2, 4, 6, 8];
+
+ let mut it = xs.iter().cloned();
+ assert_eq!(it.len(), 4);
+ assert_eq!(it.next(), Some(2));
+ assert_eq!(it.len(), 3);
+ assert_eq!(it.next(), Some(4));
+ assert_eq!(it.len(), 2);
+ assert_eq!(it.next_back(), Some(8));
+ assert_eq!(it.len(), 1);
+ assert_eq!(it.next_back(), Some(6));
+ assert_eq!(it.len(), 0);
+ assert_eq!(it.next_back(), None);
+}
+
+#[test]
+fn test_cloned_side_effects() {
+ let mut count = 0;
+ {
+ let iter = [1, 2, 3]
+ .iter()
+ .map(|x| {
+ count += 1;
+ x
+ })
+ .cloned()
+ .zip(&[1]);
+ for _ in iter {}
+ }
+ assert_eq!(count, 2);
+}
+
+#[test]
+fn test_cloned_try_folds() {
+ let a = [1, 2, 3, 4, 5, 6, 7, 8, 9];
+ let f = &|acc, x| i32::checked_add(2 * acc, x);
+ let f_ref = &|acc, &x| i32::checked_add(2 * acc, x);
+ assert_eq!(a.iter().cloned().try_fold(7, f), a.iter().try_fold(7, f_ref));
+ assert_eq!(a.iter().cloned().try_rfold(7, f), a.iter().try_rfold(7, f_ref));
+
+ let a = [10, 20, 30, 40, 100, 60, 70, 80, 90];
+ let mut iter = a.iter().cloned();
+ assert_eq!(iter.try_fold(0_i8, |acc, x| acc.checked_add(x)), None);
+ assert_eq!(iter.next(), Some(60));
+ let mut iter = a.iter().cloned();
+ assert_eq!(iter.try_rfold(0_i8, |acc, x| acc.checked_add(x)), None);
+ assert_eq!(iter.next_back(), Some(70));
+}
diff --git a/library/core/tests/iter/adapters/copied.rs b/library/core/tests/iter/adapters/copied.rs
new file mode 100644
index 000000000..b12f2035d
--- /dev/null
+++ b/library/core/tests/iter/adapters/copied.rs
@@ -0,0 +1,18 @@
+use core::iter::*;
+
+#[test]
+fn test_copied() {
+ let xs = [2, 4, 6, 8];
+
+ let mut it = xs.iter().copied();
+ assert_eq!(it.len(), 4);
+ assert_eq!(it.next(), Some(2));
+ assert_eq!(it.len(), 3);
+ assert_eq!(it.next(), Some(4));
+ assert_eq!(it.len(), 2);
+ assert_eq!(it.next_back(), Some(8));
+ assert_eq!(it.len(), 1);
+ assert_eq!(it.next_back(), Some(6));
+ assert_eq!(it.len(), 0);
+ assert_eq!(it.next_back(), None);
+}
diff --git a/library/core/tests/iter/adapters/cycle.rs b/library/core/tests/iter/adapters/cycle.rs
new file mode 100644
index 000000000..8831c09b4
--- /dev/null
+++ b/library/core/tests/iter/adapters/cycle.rs
@@ -0,0 +1,31 @@
+use core::iter::*;
+
+#[test]
+fn test_cycle() {
+ let cycle_len = 3;
+ let it = (0..).step_by(1).take(cycle_len).cycle();
+ assert_eq!(it.size_hint(), (usize::MAX, None));
+ for (i, x) in it.take(100).enumerate() {
+ assert_eq!(i % cycle_len, x);
+ }
+
+ let mut it = (0..).step_by(1).take(0).cycle();
+ assert_eq!(it.size_hint(), (0, Some(0)));
+ assert_eq!(it.next(), None);
+
+ assert_eq!(empty::<i32>().cycle().fold(0, |acc, x| acc + x), 0);
+
+ assert_eq!(once(1).cycle().skip(1).take(4).fold(0, |acc, x| acc + x), 4);
+
+ assert_eq!((0..10).cycle().take(5).sum::<i32>(), 10);
+ assert_eq!((0..10).cycle().take(15).sum::<i32>(), 55);
+ assert_eq!((0..10).cycle().take(25).sum::<i32>(), 100);
+
+ let mut iter = (0..10).cycle();
+ iter.nth(14);
+ assert_eq!(iter.take(8).sum::<i32>(), 38);
+
+ let mut iter = (0..10).cycle();
+ iter.nth(9);
+ assert_eq!(iter.take(3).sum::<i32>(), 3);
+}
diff --git a/library/core/tests/iter/adapters/enumerate.rs b/library/core/tests/iter/adapters/enumerate.rs
new file mode 100644
index 000000000..0e6033878
--- /dev/null
+++ b/library/core/tests/iter/adapters/enumerate.rs
@@ -0,0 +1,107 @@
+use core::iter::*;
+
+#[test]
+fn test_iterator_enumerate() {
+ let xs = [0, 1, 2, 3, 4, 5];
+ let it = xs.iter().enumerate();
+ for (i, &x) in it {
+ assert_eq!(i, x);
+ }
+}
+
+#[test]
+fn test_iterator_enumerate_nth() {
+ let xs = [0, 1, 2, 3, 4, 5];
+ for (i, &x) in xs.iter().enumerate() {
+ assert_eq!(i, x);
+ }
+
+ let mut it = xs.iter().enumerate();
+ while let Some((i, &x)) = it.nth(0) {
+ assert_eq!(i, x);
+ }
+
+ let mut it = xs.iter().enumerate();
+ while let Some((i, &x)) = it.nth(1) {
+ assert_eq!(i, x);
+ }
+
+ let (i, &x) = xs.iter().enumerate().nth(3).unwrap();
+ assert_eq!(i, x);
+ assert_eq!(i, 3);
+}
+
+#[test]
+fn test_iterator_enumerate_nth_back() {
+ let xs = [0, 1, 2, 3, 4, 5];
+ let mut it = xs.iter().enumerate();
+ while let Some((i, &x)) = it.nth_back(0) {
+ assert_eq!(i, x);
+ }
+
+ let mut it = xs.iter().enumerate();
+ while let Some((i, &x)) = it.nth_back(1) {
+ assert_eq!(i, x);
+ }
+
+ let (i, &x) = xs.iter().enumerate().nth_back(3).unwrap();
+ assert_eq!(i, x);
+ assert_eq!(i, 2);
+}
+
+#[test]
+fn test_iterator_enumerate_count() {
+ let xs = [0, 1, 2, 3, 4, 5];
+ assert_eq!(xs.iter().enumerate().count(), 6);
+}
+
+#[test]
+fn test_iterator_enumerate_fold() {
+ let xs = [0, 1, 2, 3, 4, 5];
+ let mut it = xs.iter().enumerate();
+ // steal a couple to get an interesting offset
+ assert_eq!(it.next(), Some((0, &0)));
+ assert_eq!(it.next(), Some((1, &1)));
+ let i = it.fold(2, |i, (j, &x)| {
+ assert_eq!(i, j);
+ assert_eq!(x, xs[j]);
+ i + 1
+ });
+ assert_eq!(i, xs.len());
+
+ let mut it = xs.iter().enumerate();
+ assert_eq!(it.next(), Some((0, &0)));
+ let i = it.rfold(xs.len() - 1, |i, (j, &x)| {
+ assert_eq!(i, j);
+ assert_eq!(x, xs[j]);
+ i - 1
+ });
+ assert_eq!(i, 0);
+}
+
+#[test]
+fn test_enumerate_try_folds() {
+ let f = &|acc, (i, x)| usize::checked_add(2 * acc, x / (i + 1) + i);
+ assert_eq!((9..18).enumerate().try_fold(7, f), (0..9).map(|i| (i, i + 9)).try_fold(7, f));
+ assert_eq!((9..18).enumerate().try_rfold(7, f), (0..9).map(|i| (i, i + 9)).try_rfold(7, f));
+
+ let mut iter = (100..200).enumerate();
+ let f = &|acc, (i, x)| u8::checked_add(acc, u8::checked_div(x, i as u8 + 1)?);
+ assert_eq!(iter.try_fold(0, f), None);
+ assert_eq!(iter.next(), Some((7, 107)));
+ assert_eq!(iter.try_rfold(0, f), None);
+ assert_eq!(iter.next_back(), Some((11, 111)));
+}
+
+#[test]
+fn test_double_ended_enumerate() {
+ let xs = [1, 2, 3, 4, 5, 6];
+ let mut it = xs.iter().cloned().enumerate();
+ assert_eq!(it.next(), Some((0, 1)));
+ assert_eq!(it.next(), Some((1, 2)));
+ assert_eq!(it.next_back(), Some((5, 6)));
+ assert_eq!(it.next_back(), Some((4, 5)));
+ assert_eq!(it.next_back(), Some((3, 4)));
+ assert_eq!(it.next_back(), Some((2, 3)));
+ assert_eq!(it.next(), None);
+}
diff --git a/library/core/tests/iter/adapters/filter.rs b/library/core/tests/iter/adapters/filter.rs
new file mode 100644
index 000000000..a2050d89d
--- /dev/null
+++ b/library/core/tests/iter/adapters/filter.rs
@@ -0,0 +1,52 @@
+use core::iter::*;
+
+#[test]
+fn test_iterator_filter_count() {
+ let xs = [0, 1, 2, 3, 4, 5, 6, 7, 8];
+ assert_eq!(xs.iter().filter(|&&x| x % 2 == 0).count(), 5);
+}
+
+#[test]
+fn test_iterator_filter_fold() {
+ let xs = [0, 1, 2, 3, 4, 5, 6, 7, 8];
+ let ys = [0, 2, 4, 6, 8];
+ let it = xs.iter().filter(|&&x| x % 2 == 0);
+ let i = it.fold(0, |i, &x| {
+ assert_eq!(x, ys[i]);
+ i + 1
+ });
+ assert_eq!(i, ys.len());
+
+ let it = xs.iter().filter(|&&x| x % 2 == 0);
+ let i = it.rfold(ys.len(), |i, &x| {
+ assert_eq!(x, ys[i - 1]);
+ i - 1
+ });
+ assert_eq!(i, 0);
+}
+
+#[test]
+fn test_filter_try_folds() {
+ fn p(&x: &i32) -> bool {
+ 0 <= x && x < 10
+ }
+ let f = &|acc, x| i32::checked_add(2 * acc, x);
+ assert_eq!((-10..20).filter(p).try_fold(7, f), (0..10).try_fold(7, f));
+ assert_eq!((-10..20).filter(p).try_rfold(7, f), (0..10).try_rfold(7, f));
+
+ let mut iter = (0..40).filter(|&x| x % 2 == 1);
+ assert_eq!(iter.try_fold(0, i8::checked_add), None);
+ assert_eq!(iter.next(), Some(25));
+ assert_eq!(iter.try_rfold(0, i8::checked_add), None);
+ assert_eq!(iter.next_back(), Some(31));
+}
+
+#[test]
+fn test_double_ended_filter() {
+ let xs = [1, 2, 3, 4, 5, 6];
+ let mut it = xs.iter().filter(|&x| *x & 1 == 0);
+ assert_eq!(it.next_back().unwrap(), &6);
+ assert_eq!(it.next_back().unwrap(), &4);
+ assert_eq!(it.next().unwrap(), &2);
+ assert_eq!(it.next_back(), None);
+}
diff --git a/library/core/tests/iter/adapters/filter_map.rs b/library/core/tests/iter/adapters/filter_map.rs
new file mode 100644
index 000000000..46738eda6
--- /dev/null
+++ b/library/core/tests/iter/adapters/filter_map.rs
@@ -0,0 +1,50 @@
+use core::iter::*;
+
+#[test]
+fn test_filter_map() {
+ let it = (0..).step_by(1).take(10).filter_map(|x| if x % 2 == 0 { Some(x * x) } else { None });
+ assert_eq!(it.collect::<Vec<usize>>(), [0 * 0, 2 * 2, 4 * 4, 6 * 6, 8 * 8]);
+}
+
+#[test]
+fn test_filter_map_fold() {
+ let xs = [0, 1, 2, 3, 4, 5, 6, 7, 8];
+ let ys = [0 * 0, 2 * 2, 4 * 4, 6 * 6, 8 * 8];
+ let it = xs.iter().filter_map(|&x| if x % 2 == 0 { Some(x * x) } else { None });
+ let i = it.fold(0, |i, x| {
+ assert_eq!(x, ys[i]);
+ i + 1
+ });
+ assert_eq!(i, ys.len());
+
+ let it = xs.iter().filter_map(|&x| if x % 2 == 0 { Some(x * x) } else { None });
+ let i = it.rfold(ys.len(), |i, x| {
+ assert_eq!(x, ys[i - 1]);
+ i - 1
+ });
+ assert_eq!(i, 0);
+}
+
+#[test]
+fn test_filter_map_try_folds() {
+ let mp = &|x| if 0 <= x && x < 10 { Some(x * 2) } else { None };
+ let f = &|acc, x| i32::checked_add(2 * acc, x);
+ assert_eq!((-9..20).filter_map(mp).try_fold(7, f), (0..10).map(|x| 2 * x).try_fold(7, f));
+ assert_eq!((-9..20).filter_map(mp).try_rfold(7, f), (0..10).map(|x| 2 * x).try_rfold(7, f));
+
+ let mut iter = (0..40).filter_map(|x| if x % 2 == 1 { None } else { Some(x * 2 + 10) });
+ assert_eq!(iter.try_fold(0, i8::checked_add), None);
+ assert_eq!(iter.next(), Some(38));
+ assert_eq!(iter.try_rfold(0, i8::checked_add), None);
+ assert_eq!(iter.next_back(), Some(78));
+}
+
+#[test]
+fn test_double_ended_filter_map() {
+ let xs = [1, 2, 3, 4, 5, 6];
+ let mut it = xs.iter().filter_map(|&x| if x & 1 == 0 { Some(x * 2) } else { None });
+ assert_eq!(it.next_back().unwrap(), 12);
+ assert_eq!(it.next_back().unwrap(), 8);
+ assert_eq!(it.next().unwrap(), 4);
+ assert_eq!(it.next_back(), None);
+}
diff --git a/library/core/tests/iter/adapters/flat_map.rs b/library/core/tests/iter/adapters/flat_map.rs
new file mode 100644
index 000000000..ee945e698
--- /dev/null
+++ b/library/core/tests/iter/adapters/flat_map.rs
@@ -0,0 +1,74 @@
+use core::iter::*;
+
+#[test]
+fn test_iterator_flat_map() {
+ let xs = [0, 3, 6];
+ let ys = [0, 1, 2, 3, 4, 5, 6, 7, 8];
+ let it = xs.iter().flat_map(|&x| (x..).step_by(1).take(3));
+ let mut i = 0;
+ for x in it {
+ assert_eq!(x, ys[i]);
+ i += 1;
+ }
+ assert_eq!(i, ys.len());
+}
+
+/// Tests `FlatMap::fold` with items already picked off the front and back,
+/// to make sure all parts of the `FlatMap` are folded correctly.
+#[test]
+fn test_iterator_flat_map_fold() {
+ let xs = [0, 3, 6];
+ let ys = [1, 2, 3, 4, 5, 6, 7];
+ let mut it = xs.iter().flat_map(|&x| x..x + 3);
+ assert_eq!(it.next(), Some(0));
+ assert_eq!(it.next_back(), Some(8));
+ let i = it.fold(0, |i, x| {
+ assert_eq!(x, ys[i]);
+ i + 1
+ });
+ assert_eq!(i, ys.len());
+
+ let mut it = xs.iter().flat_map(|&x| x..x + 3);
+ assert_eq!(it.next(), Some(0));
+ assert_eq!(it.next_back(), Some(8));
+ let i = it.rfold(ys.len(), |i, x| {
+ assert_eq!(x, ys[i - 1]);
+ i - 1
+ });
+ assert_eq!(i, 0);
+}
+
+#[test]
+fn test_flat_map_try_folds() {
+ let f = &|acc, x| i32::checked_add(acc * 2 / 3, x);
+ let mr = &|x| (5 * x)..(5 * x + 5);
+ assert_eq!((0..10).flat_map(mr).try_fold(7, f), (0..50).try_fold(7, f));
+ assert_eq!((0..10).flat_map(mr).try_rfold(7, f), (0..50).try_rfold(7, f));
+ let mut iter = (0..10).flat_map(mr);
+ iter.next();
+ iter.next_back(); // have front and back iters in progress
+ assert_eq!(iter.try_rfold(7, f), (1..49).try_rfold(7, f));
+
+ let mut iter = (0..10).flat_map(|x| (4 * x)..(4 * x + 4));
+ assert_eq!(iter.try_fold(0, i8::checked_add), None);
+ assert_eq!(iter.next(), Some(17));
+ assert_eq!(iter.try_rfold(0, i8::checked_add), None);
+ assert_eq!(iter.next_back(), Some(35));
+}
+
+#[test]
+fn test_double_ended_flat_map() {
+ let u = [0, 1];
+ let v = [5, 6, 7, 8];
+ let mut it = u.iter().flat_map(|x| &v[*x..v.len()]);
+ assert_eq!(it.next_back().unwrap(), &8);
+ assert_eq!(it.next().unwrap(), &5);
+ assert_eq!(it.next_back().unwrap(), &7);
+ assert_eq!(it.next_back().unwrap(), &6);
+ assert_eq!(it.next_back().unwrap(), &8);
+ assert_eq!(it.next().unwrap(), &6);
+ assert_eq!(it.next_back().unwrap(), &7);
+ assert_eq!(it.next_back(), None);
+ assert_eq!(it.next(), None);
+ assert_eq!(it.next_back(), None);
+}
diff --git a/library/core/tests/iter/adapters/flatten.rs b/library/core/tests/iter/adapters/flatten.rs
new file mode 100644
index 000000000..f8ab8c9d4
--- /dev/null
+++ b/library/core/tests/iter/adapters/flatten.rs
@@ -0,0 +1,170 @@
+use super::*;
+use core::iter::*;
+
+#[test]
+fn test_iterator_flatten() {
+ let xs = [0, 3, 6];
+ let ys = [0, 1, 2, 3, 4, 5, 6, 7, 8];
+ let it = xs.iter().map(|&x| (x..).step_by(1).take(3)).flatten();
+ let mut i = 0;
+ for x in it {
+ assert_eq!(x, ys[i]);
+ i += 1;
+ }
+ assert_eq!(i, ys.len());
+}
+
+/// Tests `Flatten::fold` with items already picked off the front and back,
+/// to make sure all parts of the `Flatten` are folded correctly.
+#[test]
+fn test_iterator_flatten_fold() {
+ let xs = [0, 3, 6];
+ let ys = [1, 2, 3, 4, 5, 6, 7];
+ let mut it = xs.iter().map(|&x| x..x + 3).flatten();
+ assert_eq!(it.next(), Some(0));
+ assert_eq!(it.next_back(), Some(8));
+ let i = it.fold(0, |i, x| {
+ assert_eq!(x, ys[i]);
+ i + 1
+ });
+ assert_eq!(i, ys.len());
+
+ let mut it = xs.iter().map(|&x| x..x + 3).flatten();
+ assert_eq!(it.next(), Some(0));
+ assert_eq!(it.next_back(), Some(8));
+ let i = it.rfold(ys.len(), |i, x| {
+ assert_eq!(x, ys[i - 1]);
+ i - 1
+ });
+ assert_eq!(i, 0);
+}
+
+#[test]
+fn test_flatten_try_folds() {
+ let f = &|acc, x| i32::checked_add(acc * 2 / 3, x);
+ let mr = &|x| (5 * x)..(5 * x + 5);
+ assert_eq!((0..10).map(mr).flatten().try_fold(7, f), (0..50).try_fold(7, f));
+ assert_eq!((0..10).map(mr).flatten().try_rfold(7, f), (0..50).try_rfold(7, f));
+ let mut iter = (0..10).map(mr).flatten();
+ iter.next();
+ iter.next_back(); // have front and back iters in progress
+ assert_eq!(iter.try_rfold(7, f), (1..49).try_rfold(7, f));
+
+ let mut iter = (0..10).map(|x| (4 * x)..(4 * x + 4)).flatten();
+ assert_eq!(iter.try_fold(0, i8::checked_add), None);
+ assert_eq!(iter.next(), Some(17));
+ assert_eq!(iter.try_rfold(0, i8::checked_add), None);
+ assert_eq!(iter.next_back(), Some(35));
+}
+
+#[test]
+fn test_flatten_advance_by() {
+ let mut it = once(0..10).chain(once(10..30)).chain(once(30..40)).flatten();
+
+ it.advance_by(5).unwrap();
+ assert_eq!(it.next(), Some(5));
+ it.advance_by(9).unwrap();
+ assert_eq!(it.next(), Some(15));
+ it.advance_back_by(4).unwrap();
+ assert_eq!(it.next_back(), Some(35));
+ it.advance_back_by(9).unwrap();
+ assert_eq!(it.next_back(), Some(25));
+
+ assert_eq!(it.advance_by(usize::MAX), Err(9));
+ assert_eq!(it.advance_back_by(usize::MAX), Err(0));
+ it.advance_by(0).unwrap();
+ it.advance_back_by(0).unwrap();
+ assert_eq!(it.size_hint(), (0, Some(0)));
+}
+
+#[test]
+fn test_flatten_non_fused_outer() {
+ let mut iter = NonFused::new(once(0..2)).flatten();
+
+ assert_eq!(iter.next_back(), Some(1));
+ assert_eq!(iter.next(), Some(0));
+ assert_eq!(iter.next(), None);
+ assert_eq!(iter.next(), None);
+
+ let mut iter = NonFused::new(once(0..2)).flatten();
+
+ assert_eq!(iter.next(), Some(0));
+ assert_eq!(iter.next_back(), Some(1));
+ assert_eq!(iter.next_back(), None);
+ assert_eq!(iter.next_back(), None);
+}
+
+#[test]
+fn test_flatten_non_fused_inner() {
+ let mut iter = once(0..1).chain(once(1..3)).flat_map(NonFused::new);
+
+ assert_eq!(iter.next_back(), Some(2));
+ assert_eq!(iter.next(), Some(0));
+ assert_eq!(iter.next(), Some(1));
+ assert_eq!(iter.next(), None);
+ assert_eq!(iter.next(), None);
+
+ let mut iter = once(0..1).chain(once(1..3)).flat_map(NonFused::new);
+
+ assert_eq!(iter.next(), Some(0));
+ assert_eq!(iter.next_back(), Some(2));
+ assert_eq!(iter.next_back(), Some(1));
+ assert_eq!(iter.next_back(), None);
+ assert_eq!(iter.next_back(), None);
+}
+
+#[test]
+fn test_double_ended_flatten() {
+ let u = [0, 1];
+ let v = [5, 6, 7, 8];
+ let mut it = u.iter().map(|x| &v[*x..v.len()]).flatten();
+ assert_eq!(it.next_back().unwrap(), &8);
+ assert_eq!(it.next().unwrap(), &5);
+ assert_eq!(it.next_back().unwrap(), &7);
+ assert_eq!(it.next_back().unwrap(), &6);
+ assert_eq!(it.next_back().unwrap(), &8);
+ assert_eq!(it.next().unwrap(), &6);
+ assert_eq!(it.next_back().unwrap(), &7);
+ assert_eq!(it.next_back(), None);
+ assert_eq!(it.next(), None);
+ assert_eq!(it.next_back(), None);
+}
+
+#[test]
+fn test_trusted_len_flatten() {
+ fn assert_trusted_len<T: TrustedLen>(_: &T) {}
+ let mut iter = IntoIterator::into_iter([[0; 3]; 4]).flatten();
+ assert_trusted_len(&iter);
+
+ assert_eq!(iter.size_hint(), (12, Some(12)));
+ iter.next();
+ assert_eq!(iter.size_hint(), (11, Some(11)));
+ iter.next_back();
+ assert_eq!(iter.size_hint(), (10, Some(10)));
+
+ let iter = IntoIterator::into_iter([[(); usize::MAX]; 1]).flatten();
+ assert_eq!(iter.size_hint(), (usize::MAX, Some(usize::MAX)));
+
+ let iter = IntoIterator::into_iter([[(); usize::MAX]; 2]).flatten();
+ assert_eq!(iter.size_hint(), (usize::MAX, None));
+
+ let mut a = [(); 10];
+ let mut b = [(); 10];
+
+ let iter = IntoIterator::into_iter([&mut a, &mut b]).flatten();
+ assert_trusted_len(&iter);
+ assert_eq!(iter.size_hint(), (20, Some(20)));
+ core::mem::drop(iter);
+
+ let iter = IntoIterator::into_iter([&a, &b]).flatten();
+ assert_trusted_len(&iter);
+ assert_eq!(iter.size_hint(), (20, Some(20)));
+
+ let iter = [(), (), ()].iter().flat_map(|_| [(); 1000]);
+ assert_trusted_len(&iter);
+ assert_eq!(iter.size_hint(), (3000, Some(3000)));
+
+ let iter = [(), ()].iter().flat_map(|_| &a);
+ assert_trusted_len(&iter);
+ assert_eq!(iter.size_hint(), (20, Some(20)));
+}
diff --git a/library/core/tests/iter/adapters/fuse.rs b/library/core/tests/iter/adapters/fuse.rs
new file mode 100644
index 000000000..f41b379b3
--- /dev/null
+++ b/library/core/tests/iter/adapters/fuse.rs
@@ -0,0 +1,75 @@
+use core::iter::*;
+
+#[test]
+fn test_fuse_nth() {
+ let xs = [0, 1, 2];
+ let mut it = xs.iter();
+
+ assert_eq!(it.len(), 3);
+ assert_eq!(it.nth(2), Some(&2));
+ assert_eq!(it.len(), 0);
+ assert_eq!(it.nth(2), None);
+ assert_eq!(it.len(), 0);
+}
+
+#[test]
+fn test_fuse_last() {
+ let xs = [0, 1, 2];
+ let it = xs.iter();
+
+ assert_eq!(it.len(), 3);
+ assert_eq!(it.last(), Some(&2));
+}
+
+#[test]
+fn test_fuse_count() {
+ let xs = [0, 1, 2];
+ let it = xs.iter();
+
+ assert_eq!(it.len(), 3);
+ assert_eq!(it.count(), 3);
+ // Can't check len now because count consumes.
+}
+
+#[test]
+fn test_fuse_fold() {
+ let xs = [0, 1, 2];
+ let it = xs.iter(); // `FusedIterator`
+ let i = it.fuse().fold(0, |i, &x| {
+ assert_eq!(x, xs[i]);
+ i + 1
+ });
+ assert_eq!(i, xs.len());
+
+ let it = xs.iter(); // `FusedIterator`
+ let i = it.fuse().rfold(xs.len(), |i, &x| {
+ assert_eq!(x, xs[i - 1]);
+ i - 1
+ });
+ assert_eq!(i, 0);
+
+ let it = xs.iter().scan((), |_, &x| Some(x)); // `!FusedIterator`
+ let i = it.fuse().fold(0, |i, x| {
+ assert_eq!(x, xs[i]);
+ i + 1
+ });
+ assert_eq!(i, xs.len());
+}
+
+#[test]
+fn test_fuse() {
+ let mut it = 0..3;
+ assert_eq!(it.len(), 3);
+ assert_eq!(it.next(), Some(0));
+ assert_eq!(it.len(), 2);
+ assert_eq!(it.next(), Some(1));
+ assert_eq!(it.len(), 1);
+ assert_eq!(it.next(), Some(2));
+ assert_eq!(it.len(), 0);
+ assert_eq!(it.next(), None);
+ assert_eq!(it.len(), 0);
+ assert_eq!(it.next(), None);
+ assert_eq!(it.len(), 0);
+ assert_eq!(it.next(), None);
+ assert_eq!(it.len(), 0);
+}
diff --git a/library/core/tests/iter/adapters/inspect.rs b/library/core/tests/iter/adapters/inspect.rs
new file mode 100644
index 000000000..939e3a28a
--- /dev/null
+++ b/library/core/tests/iter/adapters/inspect.rs
@@ -0,0 +1,38 @@
+use core::iter::*;
+
+#[test]
+fn test_inspect() {
+ let xs = [1, 2, 3, 4];
+ let mut n = 0;
+
+ let ys = xs.iter().cloned().inspect(|_| n += 1).collect::<Vec<usize>>();
+
+ assert_eq!(n, xs.len());
+ assert_eq!(&xs[..], &ys[..]);
+}
+
+#[test]
+fn test_inspect_fold() {
+ let xs = [1, 2, 3, 4];
+ let mut n = 0;
+ {
+ let it = xs.iter().inspect(|_| n += 1);
+ let i = it.fold(0, |i, &x| {
+ assert_eq!(x, xs[i]);
+ i + 1
+ });
+ assert_eq!(i, xs.len());
+ }
+ assert_eq!(n, xs.len());
+
+ let mut n = 0;
+ {
+ let it = xs.iter().inspect(|_| n += 1);
+ let i = it.rfold(xs.len(), |i, &x| {
+ assert_eq!(x, xs[i - 1]);
+ i - 1
+ });
+ assert_eq!(i, 0);
+ }
+ assert_eq!(n, xs.len());
+}
diff --git a/library/core/tests/iter/adapters/intersperse.rs b/library/core/tests/iter/adapters/intersperse.rs
new file mode 100644
index 000000000..72ae59b6b
--- /dev/null
+++ b/library/core/tests/iter/adapters/intersperse.rs
@@ -0,0 +1,154 @@
+use core::iter::*;
+
+#[test]
+fn test_intersperse() {
+ let v = std::iter::empty().intersperse(0u32).collect::<Vec<_>>();
+ assert_eq!(v, vec![]);
+
+ let v = std::iter::once(1).intersperse(0).collect::<Vec<_>>();
+ assert_eq!(v, vec![1]);
+
+ let xs = ["a", "", "b", "c"];
+ let v: Vec<&str> = xs.iter().map(|x| *x).intersperse(", ").collect();
+ let text: String = v.concat();
+ assert_eq!(text, "a, , b, c".to_string());
+
+ let ys = [0, 1, 2, 3];
+ let mut it = ys[..0].iter().map(|x| *x).intersperse(1);
+ assert!(it.next() == None);
+}
+
+#[test]
+fn test_intersperse_size_hint() {
+ let iter = std::iter::empty::<i32>().intersperse(0);
+ assert_eq!(iter.size_hint(), (0, Some(0)));
+
+ let xs = ["a", "", "b", "c"];
+ let mut iter = xs.iter().map(|x| *x).intersperse(", ");
+ assert_eq!(iter.size_hint(), (7, Some(7)));
+
+ assert_eq!(iter.next(), Some("a"));
+ assert_eq!(iter.size_hint(), (6, Some(6)));
+ assert_eq!(iter.next(), Some(", "));
+ assert_eq!(iter.size_hint(), (5, Some(5)));
+
+ assert_eq!([].iter().intersperse(&()).size_hint(), (0, Some(0)));
+}
+
+#[test]
+fn test_fold_specialization_intersperse() {
+ let mut iter = (1..2).intersperse(0);
+ iter.clone().for_each(|x| assert_eq!(Some(x), iter.next()));
+
+ let mut iter = (1..3).intersperse(0);
+ iter.clone().for_each(|x| assert_eq!(Some(x), iter.next()));
+
+ let mut iter = (1..4).intersperse(0);
+ iter.clone().for_each(|x| assert_eq!(Some(x), iter.next()));
+}
+
+#[test]
+fn test_try_fold_specialization_intersperse_ok() {
+ let mut iter = (1..2).intersperse(0);
+ iter.clone().try_for_each(|x| {
+ assert_eq!(Some(x), iter.next());
+ Some(())
+ });
+
+ let mut iter = (1..3).intersperse(0);
+ iter.clone().try_for_each(|x| {
+ assert_eq!(Some(x), iter.next());
+ Some(())
+ });
+
+ let mut iter = (1..4).intersperse(0);
+ iter.clone().try_for_each(|x| {
+ assert_eq!(Some(x), iter.next());
+ Some(())
+ });
+}
+
+#[test]
+fn test_intersperse_with() {
+ #[derive(PartialEq, Debug)]
+ struct NotClone {
+ u: u32,
+ }
+ let r = [NotClone { u: 0 }, NotClone { u: 1 }]
+ .into_iter()
+ .intersperse_with(|| NotClone { u: 2 })
+ .collect::<Vec<_>>();
+ assert_eq!(r, vec![NotClone { u: 0 }, NotClone { u: 2 }, NotClone { u: 1 }]);
+
+ let mut ctr = 100;
+ let separator = || {
+ ctr *= 2;
+ ctr
+ };
+ let r = (0..3).intersperse_with(separator).collect::<Vec<_>>();
+ assert_eq!(r, vec![0, 200, 1, 400, 2]);
+}
+
+#[test]
+fn test_intersperse_fold() {
+ let v = (1..4).intersperse(9).fold(Vec::new(), |mut acc, x| {
+ acc.push(x);
+ acc
+ });
+ assert_eq!(v.as_slice(), [1, 9, 2, 9, 3]);
+
+ let mut iter = (1..4).intersperse(9);
+ assert_eq!(iter.next(), Some(1));
+ let v = iter.fold(Vec::new(), |mut acc, x| {
+ acc.push(x);
+ acc
+ });
+ assert_eq!(v.as_slice(), [9, 2, 9, 3]);
+
+ struct NoneAtStart(i32); // Produces: None, Some(2), Some(3), None, ...
+ impl Iterator for NoneAtStart {
+ type Item = i32;
+ fn next(&mut self) -> Option<i32> {
+ self.0 += 1;
+ Some(self.0).filter(|i| i % 3 != 1)
+ }
+ }
+
+ let v = NoneAtStart(0).intersperse(1000).fold(0, |a, b| a + b);
+ assert_eq!(v, 0);
+}
+
+#[test]
+fn test_intersperse_collect_string() {
+ let contents = [1, 2, 3];
+
+ let contents_string = contents
+ .into_iter()
+ .map(|id| id.to_string())
+ .intersperse(", ".to_owned())
+ .collect::<String>();
+ assert_eq!(contents_string, "1, 2, 3");
+}
+
+#[test]
+fn test_try_fold_specialization_intersperse_err() {
+ let orig_iter = ["a", "b"].iter().copied().intersperse("-");
+
+ // Abort after the first item.
+ let mut iter = orig_iter.clone();
+ iter.try_for_each(|_| None::<()>);
+ assert_eq!(iter.next(), Some("-"));
+ assert_eq!(iter.next(), Some("b"));
+ assert_eq!(iter.next(), None);
+
+ // Abort after the second item.
+ let mut iter = orig_iter.clone();
+ iter.try_for_each(|item| if item == "-" { None } else { Some(()) });
+ assert_eq!(iter.next(), Some("b"));
+ assert_eq!(iter.next(), None);
+
+ // Abort after the third item.
+ let mut iter = orig_iter.clone();
+ iter.try_for_each(|item| if item == "b" { None } else { Some(()) });
+ assert_eq!(iter.next(), None);
+}
diff --git a/library/core/tests/iter/adapters/map.rs b/library/core/tests/iter/adapters/map.rs
new file mode 100644
index 000000000..77ce3819b
--- /dev/null
+++ b/library/core/tests/iter/adapters/map.rs
@@ -0,0 +1,27 @@
+use core::iter::*;
+
+#[test]
+fn test_map_try_folds() {
+ let f = &|acc, x| i32::checked_add(2 * acc, x);
+ assert_eq!((0..10).map(|x| x + 3).try_fold(7, f), (3..13).try_fold(7, f));
+ assert_eq!((0..10).map(|x| x + 3).try_rfold(7, f), (3..13).try_rfold(7, f));
+
+ let mut iter = (0..40).map(|x| x + 10);
+ assert_eq!(iter.try_fold(0, i8::checked_add), None);
+ assert_eq!(iter.next(), Some(20));
+ assert_eq!(iter.try_rfold(0, i8::checked_add), None);
+ assert_eq!(iter.next_back(), Some(46));
+}
+
+#[test]
+fn test_double_ended_map() {
+ let xs = [1, 2, 3, 4, 5, 6];
+ let mut it = xs.iter().map(|&x| x * -1);
+ assert_eq!(it.next(), Some(-1));
+ assert_eq!(it.next(), Some(-2));
+ assert_eq!(it.next_back(), Some(-6));
+ assert_eq!(it.next_back(), Some(-5));
+ assert_eq!(it.next(), Some(-3));
+ assert_eq!(it.next_back(), Some(-4));
+ assert_eq!(it.next(), None);
+}
diff --git a/library/core/tests/iter/adapters/mod.rs b/library/core/tests/iter/adapters/mod.rs
new file mode 100644
index 000000000..567d9fe49
--- /dev/null
+++ b/library/core/tests/iter/adapters/mod.rs
@@ -0,0 +1,185 @@
+mod chain;
+mod cloned;
+mod copied;
+mod cycle;
+mod enumerate;
+mod filter;
+mod filter_map;
+mod flat_map;
+mod flatten;
+mod fuse;
+mod inspect;
+mod intersperse;
+mod map;
+mod peekable;
+mod scan;
+mod skip;
+mod skip_while;
+mod step_by;
+mod take;
+mod take_while;
+mod zip;
+
+use core::cell::Cell;
+
+/// An iterator that panics whenever `next` or next_back` is called
+/// after `None` has already been returned. This does not violate
+/// `Iterator`'s contract. Used to test that iterator adapters don't
+/// poll their inner iterators after exhausting them.
+pub struct NonFused<I> {
+ iter: I,
+ done: bool,
+}
+
+impl<I> NonFused<I> {
+ pub fn new(iter: I) -> Self {
+ Self { iter, done: false }
+ }
+}
+
+impl<I> Iterator for NonFused<I>
+where
+ I: Iterator,
+{
+ type Item = I::Item;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ assert!(!self.done, "this iterator has already returned None");
+ self.iter.next().or_else(|| {
+ self.done = true;
+ None
+ })
+ }
+}
+
+impl<I> DoubleEndedIterator for NonFused<I>
+where
+ I: DoubleEndedIterator,
+{
+ fn next_back(&mut self) -> Option<Self::Item> {
+ assert!(!self.done, "this iterator has already returned None");
+ self.iter.next_back().or_else(|| {
+ self.done = true;
+ None
+ })
+ }
+}
+
+/// An iterator wrapper that panics whenever `next` or `next_back` is called
+/// after `None` has been returned.
+pub struct Unfuse<I> {
+ iter: I,
+ exhausted: bool,
+}
+
+impl<I> Unfuse<I> {
+ pub fn new<T>(iter: T) -> Self
+ where
+ T: IntoIterator<IntoIter = I>,
+ {
+ Self { iter: iter.into_iter(), exhausted: false }
+ }
+}
+
+impl<I> Iterator for Unfuse<I>
+where
+ I: Iterator,
+{
+ type Item = I::Item;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ assert!(!self.exhausted);
+ let next = self.iter.next();
+ self.exhausted = next.is_none();
+ next
+ }
+}
+
+impl<I> DoubleEndedIterator for Unfuse<I>
+where
+ I: DoubleEndedIterator,
+{
+ fn next_back(&mut self) -> Option<Self::Item> {
+ assert!(!self.exhausted);
+ let next = self.iter.next_back();
+ self.exhausted = next.is_none();
+ next
+ }
+}
+
+pub struct Toggle {
+ is_empty: bool,
+}
+
+impl Iterator for Toggle {
+ type Item = ();
+
+ // alternates between `None` and `Some(())`
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.is_empty {
+ self.is_empty = false;
+ None
+ } else {
+ self.is_empty = true;
+ Some(())
+ }
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ if self.is_empty { (0, Some(0)) } else { (1, Some(1)) }
+ }
+}
+
+impl DoubleEndedIterator for Toggle {
+ fn next_back(&mut self) -> Option<Self::Item> {
+ self.next()
+ }
+}
+
+/// This is an iterator that follows the Iterator contract,
+/// but it is not fused. After having returned None once, it will start
+/// producing elements if .next() is called again.
+pub struct CycleIter<'a, T> {
+ index: usize,
+ data: &'a [T],
+}
+
+impl<'a, T> CycleIter<'a, T> {
+ pub fn new(data: &'a [T]) -> Self {
+ Self { index: 0, data }
+ }
+}
+
+impl<'a, T> Iterator for CycleIter<'a, T> {
+ type Item = &'a T;
+ fn next(&mut self) -> Option<Self::Item> {
+ let elt = self.data.get(self.index);
+ self.index += 1;
+ self.index %= 1 + self.data.len();
+ elt
+ }
+}
+
+#[derive(Debug)]
+struct CountClone(Cell<i32>);
+
+impl CountClone {
+ pub fn new() -> Self {
+ Self(Cell::new(0))
+ }
+}
+
+impl PartialEq<i32> for CountClone {
+ fn eq(&self, rhs: &i32) -> bool {
+ self.0.get() == *rhs
+ }
+}
+
+impl Clone for CountClone {
+ fn clone(&self) -> Self {
+ let ret = CountClone(self.0.clone());
+ let n = self.0.get();
+ self.0.set(n + 1);
+ ret
+ }
+}
diff --git a/library/core/tests/iter/adapters/peekable.rs b/library/core/tests/iter/adapters/peekable.rs
new file mode 100644
index 000000000..c1a1c29b6
--- /dev/null
+++ b/library/core/tests/iter/adapters/peekable.rs
@@ -0,0 +1,272 @@
+use super::*;
+use core::iter::*;
+
+#[test]
+fn test_iterator_peekable() {
+ let xs = vec![0, 1, 2, 3, 4, 5];
+
+ let mut it = xs.iter().cloned().peekable();
+ assert_eq!(it.len(), 6);
+ assert_eq!(it.peek().unwrap(), &0);
+ assert_eq!(it.len(), 6);
+ assert_eq!(it.next().unwrap(), 0);
+ assert_eq!(it.len(), 5);
+ assert_eq!(it.next().unwrap(), 1);
+ assert_eq!(it.len(), 4);
+ assert_eq!(it.next().unwrap(), 2);
+ assert_eq!(it.len(), 3);
+ assert_eq!(it.peek().unwrap(), &3);
+ assert_eq!(it.len(), 3);
+ assert_eq!(it.peek().unwrap(), &3);
+ assert_eq!(it.len(), 3);
+ assert_eq!(it.next().unwrap(), 3);
+ assert_eq!(it.len(), 2);
+ assert_eq!(it.next().unwrap(), 4);
+ assert_eq!(it.len(), 1);
+ assert_eq!(it.peek().unwrap(), &5);
+ assert_eq!(it.len(), 1);
+ assert_eq!(it.next().unwrap(), 5);
+ assert_eq!(it.len(), 0);
+ assert!(it.peek().is_none());
+ assert_eq!(it.len(), 0);
+ assert!(it.next().is_none());
+ assert_eq!(it.len(), 0);
+
+ let mut it = xs.iter().cloned().peekable();
+ assert_eq!(it.len(), 6);
+ assert_eq!(it.peek().unwrap(), &0);
+ assert_eq!(it.len(), 6);
+ assert_eq!(it.next_back().unwrap(), 5);
+ assert_eq!(it.len(), 5);
+ assert_eq!(it.next_back().unwrap(), 4);
+ assert_eq!(it.len(), 4);
+ assert_eq!(it.next_back().unwrap(), 3);
+ assert_eq!(it.len(), 3);
+ assert_eq!(it.peek().unwrap(), &0);
+ assert_eq!(it.len(), 3);
+ assert_eq!(it.peek().unwrap(), &0);
+ assert_eq!(it.len(), 3);
+ assert_eq!(it.next_back().unwrap(), 2);
+ assert_eq!(it.len(), 2);
+ assert_eq!(it.next_back().unwrap(), 1);
+ assert_eq!(it.len(), 1);
+ assert_eq!(it.peek().unwrap(), &0);
+ assert_eq!(it.len(), 1);
+ assert_eq!(it.next_back().unwrap(), 0);
+ assert_eq!(it.len(), 0);
+ assert!(it.peek().is_none());
+ assert_eq!(it.len(), 0);
+ assert!(it.next_back().is_none());
+ assert_eq!(it.len(), 0);
+}
+
+#[test]
+fn test_iterator_peekable_count() {
+ let xs = [0, 1, 2, 3, 4, 5];
+ let ys = [10];
+ let zs: [i32; 0] = [];
+
+ assert_eq!(xs.iter().peekable().count(), 6);
+
+ let mut it = xs.iter().peekable();
+ assert_eq!(it.peek(), Some(&&0));
+ assert_eq!(it.count(), 6);
+
+ assert_eq!(ys.iter().peekable().count(), 1);
+
+ let mut it = ys.iter().peekable();
+ assert_eq!(it.peek(), Some(&&10));
+ assert_eq!(it.count(), 1);
+
+ assert_eq!(zs.iter().peekable().count(), 0);
+
+ let mut it = zs.iter().peekable();
+ assert_eq!(it.peek(), None);
+}
+
+#[test]
+fn test_iterator_peekable_nth() {
+ let xs = [0, 1, 2, 3, 4, 5];
+ let mut it = xs.iter().peekable();
+
+ assert_eq!(it.peek(), Some(&&0));
+ assert_eq!(it.nth(0), Some(&0));
+ assert_eq!(it.peek(), Some(&&1));
+ assert_eq!(it.nth(1), Some(&2));
+ assert_eq!(it.peek(), Some(&&3));
+ assert_eq!(it.nth(2), Some(&5));
+ assert_eq!(it.next(), None);
+}
+
+#[test]
+fn test_iterator_peekable_last() {
+ let xs = [0, 1, 2, 3, 4, 5];
+ let ys = [0];
+
+ let mut it = xs.iter().peekable();
+ assert_eq!(it.peek(), Some(&&0));
+ assert_eq!(it.last(), Some(&5));
+
+ let mut it = ys.iter().peekable();
+ assert_eq!(it.peek(), Some(&&0));
+ assert_eq!(it.last(), Some(&0));
+
+ let mut it = ys.iter().peekable();
+ assert_eq!(it.next(), Some(&0));
+ assert_eq!(it.peek(), None);
+ assert_eq!(it.last(), None);
+}
+
+#[test]
+fn test_iterator_peekable_fold() {
+ let xs = [0, 1, 2, 3, 4, 5];
+ let mut it = xs.iter().peekable();
+ assert_eq!(it.peek(), Some(&&0));
+ let i = it.fold(0, |i, &x| {
+ assert_eq!(x, xs[i]);
+ i + 1
+ });
+ assert_eq!(i, xs.len());
+}
+
+#[test]
+fn test_iterator_peekable_rfold() {
+ let xs = [0, 1, 2, 3, 4, 5];
+ let mut it = xs.iter().peekable();
+ assert_eq!(it.peek(), Some(&&0));
+ let i = it.rfold(0, |i, &x| {
+ assert_eq!(x, xs[xs.len() - 1 - i]);
+ i + 1
+ });
+ assert_eq!(i, xs.len());
+}
+
+#[test]
+fn test_iterator_peekable_next_if_eq() {
+ // first, try on references
+ let xs = ["Heart", "of", "Gold"];
+ let mut it = xs.into_iter().peekable();
+ // try before `peek()`
+ assert_eq!(it.next_if_eq(&"trillian"), None);
+ assert_eq!(it.next_if_eq(&"Heart"), Some("Heart"));
+ // try after peek()
+ assert_eq!(it.peek(), Some(&"of"));
+ assert_eq!(it.next_if_eq(&"of"), Some("of"));
+ assert_eq!(it.next_if_eq(&"zaphod"), None);
+ // make sure `next()` still behaves
+ assert_eq!(it.next(), Some("Gold"));
+
+ // make sure comparison works for owned values
+ let xs = [String::from("Ludicrous"), "speed".into()];
+ let mut it = xs.into_iter().peekable();
+ // make sure basic functionality works
+ assert_eq!(it.next_if_eq("Ludicrous"), Some("Ludicrous".into()));
+ assert_eq!(it.next_if_eq("speed"), Some("speed".into()));
+ assert_eq!(it.next_if_eq(""), None);
+}
+
+#[test]
+fn test_iterator_peekable_mut() {
+ let mut it = [1, 2, 3].into_iter().peekable();
+ if let Some(p) = it.peek_mut() {
+ if *p == 1 {
+ *p = 5;
+ }
+ }
+ assert_eq!(it.collect::<Vec<_>>(), vec![5, 2, 3]);
+}
+
+#[test]
+fn test_iterator_peekable_remember_peek_none_1() {
+ // Check that the loop using .peek() terminates
+ let data = [1, 2, 3];
+ let mut iter = CycleIter::new(&data).peekable();
+
+ let mut n = 0;
+ while let Some(_) = iter.next() {
+ let is_the_last = iter.peek().is_none();
+ assert_eq!(is_the_last, n == data.len() - 1);
+ n += 1;
+ if n > data.len() {
+ break;
+ }
+ }
+ assert_eq!(n, data.len());
+}
+
+#[test]
+fn test_iterator_peekable_remember_peek_none_2() {
+ let data = [0];
+ let mut iter = CycleIter::new(&data).peekable();
+ iter.next();
+ assert_eq!(iter.peek(), None);
+ assert_eq!(iter.last(), None);
+}
+
+#[test]
+fn test_iterator_peekable_remember_peek_none_3() {
+ let data = [0];
+ let mut iter = CycleIter::new(&data).peekable();
+ iter.peek();
+ assert_eq!(iter.nth(0), Some(&0));
+
+ let mut iter = CycleIter::new(&data).peekable();
+ iter.next();
+ assert_eq!(iter.peek(), None);
+ assert_eq!(iter.nth(0), None);
+}
+
+#[test]
+fn test_peek_try_folds() {
+ let f = &|acc, x| i32::checked_add(2 * acc, x);
+
+ assert_eq!((1..20).peekable().try_fold(7, f), (1..20).try_fold(7, f));
+ assert_eq!((1..20).peekable().try_rfold(7, f), (1..20).try_rfold(7, f));
+
+ let mut iter = (1..20).peekable();
+ assert_eq!(iter.peek(), Some(&1));
+ assert_eq!(iter.try_fold(7, f), (1..20).try_fold(7, f));
+
+ let mut iter = (1..20).peekable();
+ assert_eq!(iter.peek(), Some(&1));
+ assert_eq!(iter.try_rfold(7, f), (1..20).try_rfold(7, f));
+
+ let mut iter = [100, 20, 30, 40, 50, 60, 70].iter().cloned().peekable();
+ assert_eq!(iter.peek(), Some(&100));
+ assert_eq!(iter.try_fold(0, i8::checked_add), None);
+ assert_eq!(iter.peek(), Some(&40));
+
+ let mut iter = [100, 20, 30, 40, 50, 60, 70].iter().cloned().peekable();
+ assert_eq!(iter.peek(), Some(&100));
+ assert_eq!(iter.try_rfold(0, i8::checked_add), None);
+ assert_eq!(iter.peek(), Some(&100));
+ assert_eq!(iter.next_back(), Some(50));
+
+ let mut iter = (2..5).peekable();
+ assert_eq!(iter.peek(), Some(&2));
+ assert_eq!(iter.try_for_each(Err), Err(2));
+ assert_eq!(iter.peek(), Some(&3));
+ assert_eq!(iter.try_for_each(Err), Err(3));
+ assert_eq!(iter.peek(), Some(&4));
+ assert_eq!(iter.try_for_each(Err), Err(4));
+ assert_eq!(iter.peek(), None);
+ assert_eq!(iter.try_for_each(Err), Ok(()));
+
+ let mut iter = (2..5).peekable();
+ assert_eq!(iter.peek(), Some(&2));
+ assert_eq!(iter.try_rfold((), |(), x| Err(x)), Err(4));
+ assert_eq!(iter.peek(), Some(&2));
+ assert_eq!(iter.try_rfold((), |(), x| Err(x)), Err(3));
+ assert_eq!(iter.peek(), Some(&2));
+ assert_eq!(iter.try_rfold((), |(), x| Err(x)), Err(2));
+ assert_eq!(iter.peek(), None);
+ assert_eq!(iter.try_rfold((), |(), x| Err(x)), Ok(()));
+}
+
+#[test]
+fn test_peekable_non_fused() {
+ let mut iter = NonFused::new(empty::<i32>()).peekable();
+
+ assert_eq!(iter.peek(), None);
+ assert_eq!(iter.next_back(), None);
+}
diff --git a/library/core/tests/iter/adapters/scan.rs b/library/core/tests/iter/adapters/scan.rs
new file mode 100644
index 000000000..1d28ca6b7
--- /dev/null
+++ b/library/core/tests/iter/adapters/scan.rs
@@ -0,0 +1,20 @@
+use core::iter::*;
+
+#[test]
+fn test_iterator_scan() {
+ // test the type inference
+ fn add(old: &mut isize, new: &usize) -> Option<f64> {
+ *old += *new as isize;
+ Some(*old as f64)
+ }
+ let xs = [0, 1, 2, 3, 4];
+ let ys = [0f64, 1.0, 3.0, 6.0, 10.0];
+
+ let it = xs.iter().scan(0, add);
+ let mut i = 0;
+ for x in it {
+ assert_eq!(x, ys[i]);
+ i += 1;
+ }
+ assert_eq!(i, ys.len());
+}
diff --git a/library/core/tests/iter/adapters/skip.rs b/library/core/tests/iter/adapters/skip.rs
new file mode 100644
index 000000000..65f235e86
--- /dev/null
+++ b/library/core/tests/iter/adapters/skip.rs
@@ -0,0 +1,203 @@
+use core::iter::*;
+
+use super::Unfuse;
+
+#[test]
+fn test_iterator_skip() {
+ let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30];
+ let ys = [13, 15, 16, 17, 19, 20, 30];
+ let mut it = xs.iter().skip(5);
+ let mut i = 0;
+ while let Some(&x) = it.next() {
+ assert_eq!(x, ys[i]);
+ i += 1;
+ assert_eq!(it.len(), xs.len() - 5 - i);
+ }
+ assert_eq!(i, ys.len());
+ assert_eq!(it.len(), 0);
+}
+
+#[test]
+fn test_iterator_skip_doubleended() {
+ let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30];
+ let mut it = xs.iter().rev().skip(5);
+ assert_eq!(it.next(), Some(&15));
+ assert_eq!(it.by_ref().rev().next(), Some(&0));
+ assert_eq!(it.next(), Some(&13));
+ assert_eq!(it.by_ref().rev().next(), Some(&1));
+ assert_eq!(it.next(), Some(&5));
+ assert_eq!(it.by_ref().rev().next(), Some(&2));
+ assert_eq!(it.next(), Some(&3));
+ assert_eq!(it.next(), None);
+ let mut it = xs.iter().rev().skip(5).rev();
+ assert_eq!(it.next(), Some(&0));
+ assert_eq!(it.rev().next(), Some(&15));
+ let mut it_base = xs.iter();
+ {
+ let mut it = it_base.by_ref().skip(5).rev();
+ assert_eq!(it.next(), Some(&30));
+ assert_eq!(it.next(), Some(&20));
+ assert_eq!(it.next(), Some(&19));
+ assert_eq!(it.next(), Some(&17));
+ assert_eq!(it.next(), Some(&16));
+ assert_eq!(it.next(), Some(&15));
+ assert_eq!(it.next(), Some(&13));
+ assert_eq!(it.next(), None);
+ }
+ // make sure the skipped parts have not been consumed
+ assert_eq!(it_base.next(), Some(&0));
+ assert_eq!(it_base.next(), Some(&1));
+ assert_eq!(it_base.next(), Some(&2));
+ assert_eq!(it_base.next(), Some(&3));
+ assert_eq!(it_base.next(), Some(&5));
+ assert_eq!(it_base.next(), None);
+ let it = xs.iter().skip(5).rev();
+ assert_eq!(it.last(), Some(&13));
+}
+
+#[test]
+fn test_iterator_skip_nth() {
+ let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30];
+
+ let mut it = xs.iter().skip(0);
+ assert_eq!(it.nth(0), Some(&0));
+ assert_eq!(it.nth(1), Some(&2));
+
+ let mut it = xs.iter().skip(5);
+ assert_eq!(it.nth(0), Some(&13));
+ assert_eq!(it.nth(1), Some(&16));
+
+ let mut it = xs.iter().skip(12);
+ assert_eq!(it.nth(0), None);
+}
+
+#[test]
+fn test_skip_advance_by() {
+ assert_eq!((0..0).skip(10).advance_by(0), Ok(()));
+ assert_eq!((0..0).skip(10).advance_by(1), Err(0));
+ assert_eq!((0u128..(usize::MAX as u128) + 1).skip(usize::MAX).advance_by(usize::MAX), Err(1));
+ assert_eq!((0u128..u128::MAX).skip(usize::MAX).advance_by(1), Ok(()));
+
+ assert_eq!((0..2).skip(1).advance_back_by(10), Err(1));
+ assert_eq!((0..0).skip(1).advance_back_by(0), Ok(()));
+}
+
+#[test]
+fn test_iterator_skip_count() {
+ let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30];
+
+ assert_eq!(xs.iter().skip(0).count(), 12);
+ assert_eq!(xs.iter().skip(1).count(), 11);
+ assert_eq!(xs.iter().skip(11).count(), 1);
+ assert_eq!(xs.iter().skip(12).count(), 0);
+ assert_eq!(xs.iter().skip(13).count(), 0);
+}
+
+#[test]
+fn test_iterator_skip_last() {
+ let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30];
+
+ assert_eq!(xs.iter().skip(0).last(), Some(&30));
+ assert_eq!(xs.iter().skip(1).last(), Some(&30));
+ assert_eq!(xs.iter().skip(11).last(), Some(&30));
+ assert_eq!(xs.iter().skip(12).last(), None);
+ assert_eq!(xs.iter().skip(13).last(), None);
+
+ let mut it = xs.iter().skip(5);
+ assert_eq!(it.next(), Some(&13));
+ assert_eq!(it.last(), Some(&30));
+}
+
+#[test]
+fn test_iterator_skip_fold() {
+ let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30];
+ let ys = [13, 15, 16, 17, 19, 20, 30];
+
+ let it = xs.iter().skip(5);
+ let i = it.fold(0, |i, &x| {
+ assert_eq!(x, ys[i]);
+ i + 1
+ });
+ assert_eq!(i, ys.len());
+
+ let mut it = xs.iter().skip(5);
+ assert_eq!(it.next(), Some(&ys[0])); // process skips before folding
+ let i = it.fold(1, |i, &x| {
+ assert_eq!(x, ys[i]);
+ i + 1
+ });
+ assert_eq!(i, ys.len());
+
+ let it = xs.iter().skip(5);
+ let i = it.rfold(ys.len(), |i, &x| {
+ let i = i - 1;
+ assert_eq!(x, ys[i]);
+ i
+ });
+ assert_eq!(i, 0);
+
+ let mut it = xs.iter().skip(5);
+ assert_eq!(it.next(), Some(&ys[0])); // process skips before folding
+ let i = it.rfold(ys.len(), |i, &x| {
+ let i = i - 1;
+ assert_eq!(x, ys[i]);
+ i
+ });
+ assert_eq!(i, 1);
+}
+
+#[test]
+fn test_skip_try_folds() {
+ let f = &|acc, x| i32::checked_add(2 * acc, x);
+ assert_eq!((1..20).skip(9).try_fold(7, f), (10..20).try_fold(7, f));
+ assert_eq!((1..20).skip(9).try_rfold(7, f), (10..20).try_rfold(7, f));
+
+ let mut iter = (0..30).skip(10);
+ assert_eq!(iter.try_fold(0, i8::checked_add), None);
+ assert_eq!(iter.next(), Some(20));
+ assert_eq!(iter.try_rfold(0, i8::checked_add), None);
+ assert_eq!(iter.next_back(), Some(24));
+}
+
+#[test]
+fn test_skip_nth_back() {
+ let xs = [0, 1, 2, 3, 4, 5];
+ let mut it = xs.iter().skip(2);
+ assert_eq!(it.nth_back(0), Some(&5));
+ assert_eq!(it.nth_back(1), Some(&3));
+ assert_eq!(it.nth_back(0), Some(&2));
+ assert_eq!(it.nth_back(0), None);
+
+ let ys = [2, 3, 4, 5];
+ let mut ity = ys.iter();
+ let mut it = xs.iter().skip(2);
+ assert_eq!(it.nth_back(1), ity.nth_back(1));
+ assert_eq!(it.clone().nth(0), ity.clone().nth(0));
+ assert_eq!(it.nth_back(0), ity.nth_back(0));
+ assert_eq!(it.clone().nth(0), ity.clone().nth(0));
+ assert_eq!(it.nth_back(0), ity.nth_back(0));
+ assert_eq!(it.clone().nth(0), ity.clone().nth(0));
+ assert_eq!(it.nth_back(0), ity.nth_back(0));
+ assert_eq!(it.clone().nth(0), ity.clone().nth(0));
+
+ let mut it = xs.iter().skip(2);
+ assert_eq!(it.nth_back(4), None);
+ assert_eq!(it.nth_back(0), None);
+
+ let mut it = xs.iter();
+ it.by_ref().skip(2).nth_back(3);
+ assert_eq!(it.next_back(), Some(&1));
+
+ let mut it = xs.iter();
+ it.by_ref().skip(2).nth_back(10);
+ assert_eq!(it.next_back(), Some(&1));
+}
+
+#[test]
+fn test_skip_non_fused() {
+ let non_fused = Unfuse::new(0..10);
+
+ // `Skip` would previously exhaust the iterator in this `next` call and then erroneously try to
+ // advance it further. `Unfuse` tests that this doesn't happen by panicking in that scenario.
+ let _ = non_fused.skip(20).next();
+}
diff --git a/library/core/tests/iter/adapters/skip_while.rs b/library/core/tests/iter/adapters/skip_while.rs
new file mode 100644
index 000000000..929d4f6e6
--- /dev/null
+++ b/library/core/tests/iter/adapters/skip_while.rs
@@ -0,0 +1,50 @@
+use core::iter::*;
+
+#[test]
+fn test_iterator_skip_while() {
+ let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19];
+ let ys = [15, 16, 17, 19];
+ let it = xs.iter().skip_while(|&x| *x < 15);
+ let mut i = 0;
+ for x in it {
+ assert_eq!(*x, ys[i]);
+ i += 1;
+ }
+ assert_eq!(i, ys.len());
+}
+
+#[test]
+fn test_iterator_skip_while_fold() {
+ let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19];
+ let ys = [15, 16, 17, 19];
+ let it = xs.iter().skip_while(|&x| *x < 15);
+ let i = it.fold(0, |i, &x| {
+ assert_eq!(x, ys[i]);
+ i + 1
+ });
+ assert_eq!(i, ys.len());
+
+ let mut it = xs.iter().skip_while(|&x| *x < 15);
+ assert_eq!(it.next(), Some(&ys[0])); // process skips before folding
+ let i = it.fold(1, |i, &x| {
+ assert_eq!(x, ys[i]);
+ i + 1
+ });
+ assert_eq!(i, ys.len());
+}
+
+#[test]
+fn test_skip_while_try_fold() {
+ let f = &|acc, x| i32::checked_add(2 * acc, x);
+ fn p(&x: &i32) -> bool {
+ (x % 10) <= 5
+ }
+ assert_eq!((1..20).skip_while(p).try_fold(7, f), (6..20).try_fold(7, f));
+ let mut iter = (1..20).skip_while(p);
+ assert_eq!(iter.nth(5), Some(11));
+ assert_eq!(iter.try_fold(7, f), (12..20).try_fold(7, f));
+
+ let mut iter = (0..50).skip_while(|&x| (x % 20) < 15);
+ assert_eq!(iter.try_fold(0, i8::checked_add), None);
+ assert_eq!(iter.next(), Some(23));
+}
diff --git a/library/core/tests/iter/adapters/step_by.rs b/library/core/tests/iter/adapters/step_by.rs
new file mode 100644
index 000000000..94f2fa8c2
--- /dev/null
+++ b/library/core/tests/iter/adapters/step_by.rs
@@ -0,0 +1,246 @@
+use core::iter::*;
+
+#[test]
+fn test_iterator_step_by() {
+ // Identity
+ let mut it = (0..).step_by(1).take(3);
+ assert_eq!(it.next(), Some(0));
+ assert_eq!(it.next(), Some(1));
+ assert_eq!(it.next(), Some(2));
+ assert_eq!(it.next(), None);
+
+ let mut it = (0..).step_by(3).take(4);
+ assert_eq!(it.next(), Some(0));
+ assert_eq!(it.next(), Some(3));
+ assert_eq!(it.next(), Some(6));
+ assert_eq!(it.next(), Some(9));
+ assert_eq!(it.next(), None);
+
+ let mut it = (0..3).step_by(1);
+ assert_eq!(it.next_back(), Some(2));
+ assert_eq!(it.next_back(), Some(1));
+ assert_eq!(it.next_back(), Some(0));
+ assert_eq!(it.next_back(), None);
+
+ let mut it = (0..11).step_by(3);
+ assert_eq!(it.next_back(), Some(9));
+ assert_eq!(it.next_back(), Some(6));
+ assert_eq!(it.next_back(), Some(3));
+ assert_eq!(it.next_back(), Some(0));
+ assert_eq!(it.next_back(), None);
+}
+
+#[test]
+fn test_iterator_step_by_nth() {
+ let mut it = (0..16).step_by(5);
+ assert_eq!(it.nth(0), Some(0));
+ assert_eq!(it.nth(0), Some(5));
+ assert_eq!(it.nth(0), Some(10));
+ assert_eq!(it.nth(0), Some(15));
+ assert_eq!(it.nth(0), None);
+
+ let it = (0..18).step_by(5);
+ assert_eq!(it.clone().nth(0), Some(0));
+ assert_eq!(it.clone().nth(1), Some(5));
+ assert_eq!(it.clone().nth(2), Some(10));
+ assert_eq!(it.clone().nth(3), Some(15));
+ assert_eq!(it.clone().nth(4), None);
+ assert_eq!(it.clone().nth(42), None);
+}
+
+#[test]
+fn test_iterator_step_by_nth_overflow() {
+ #[cfg(target_pointer_width = "16")]
+ type Bigger = u32;
+ #[cfg(target_pointer_width = "32")]
+ type Bigger = u64;
+ #[cfg(target_pointer_width = "64")]
+ type Bigger = u128;
+
+ #[derive(Clone)]
+ struct Test(Bigger);
+ impl Iterator for &mut Test {
+ type Item = i32;
+ fn next(&mut self) -> Option<Self::Item> {
+ Some(21)
+ }
+ fn nth(&mut self, n: usize) -> Option<Self::Item> {
+ self.0 += n as Bigger + 1;
+ Some(42)
+ }
+ }
+
+ let mut it = Test(0);
+ let root = usize::MAX >> (usize::BITS / 2);
+ let n = root + 20;
+ (&mut it).step_by(n).nth(n);
+ assert_eq!(it.0, n as Bigger * n as Bigger);
+
+ // large step
+ let mut it = Test(0);
+ (&mut it).step_by(usize::MAX).nth(5);
+ assert_eq!(it.0, (usize::MAX as Bigger) * 5);
+
+ // n + 1 overflows
+ let mut it = Test(0);
+ (&mut it).step_by(2).nth(usize::MAX);
+ assert_eq!(it.0, (usize::MAX as Bigger) * 2);
+
+ // n + 1 overflows
+ let mut it = Test(0);
+ (&mut it).step_by(1).nth(usize::MAX);
+ assert_eq!(it.0, (usize::MAX as Bigger) * 1);
+}
+
+#[test]
+fn test_iterator_step_by_nth_try_fold() {
+ let mut it = (0..).step_by(10);
+ assert_eq!(it.try_fold(0, i8::checked_add), None);
+ assert_eq!(it.next(), Some(60));
+ assert_eq!(it.try_fold(0, i8::checked_add), None);
+ assert_eq!(it.next(), Some(90));
+
+ let mut it = (100..).step_by(10);
+ assert_eq!(it.try_fold(50, i8::checked_add), None);
+ assert_eq!(it.next(), Some(110));
+
+ let mut it = (100..=100).step_by(10);
+ assert_eq!(it.next(), Some(100));
+ assert_eq!(it.try_fold(0, i8::checked_add), Some(0));
+}
+
+#[test]
+fn test_iterator_step_by_nth_back() {
+ let mut it = (0..16).step_by(5);
+ assert_eq!(it.nth_back(0), Some(15));
+ assert_eq!(it.nth_back(0), Some(10));
+ assert_eq!(it.nth_back(0), Some(5));
+ assert_eq!(it.nth_back(0), Some(0));
+ assert_eq!(it.nth_back(0), None);
+
+ let mut it = (0..16).step_by(5);
+ assert_eq!(it.next(), Some(0)); // to set `first_take` to `false`
+ assert_eq!(it.nth_back(0), Some(15));
+ assert_eq!(it.nth_back(0), Some(10));
+ assert_eq!(it.nth_back(0), Some(5));
+ assert_eq!(it.nth_back(0), None);
+
+ let it = || (0..18).step_by(5);
+ assert_eq!(it().nth_back(0), Some(15));
+ assert_eq!(it().nth_back(1), Some(10));
+ assert_eq!(it().nth_back(2), Some(5));
+ assert_eq!(it().nth_back(3), Some(0));
+ assert_eq!(it().nth_back(4), None);
+ assert_eq!(it().nth_back(42), None);
+}
+
+#[test]
+fn test_iterator_step_by_nth_try_rfold() {
+ let mut it = (0..100).step_by(10);
+ assert_eq!(it.try_rfold(0, i8::checked_add), None);
+ assert_eq!(it.next_back(), Some(70));
+ assert_eq!(it.next(), Some(0));
+ assert_eq!(it.try_rfold(0, i8::checked_add), None);
+ assert_eq!(it.next_back(), Some(30));
+
+ let mut it = (0..100).step_by(10);
+ assert_eq!(it.try_rfold(50, i8::checked_add), None);
+ assert_eq!(it.next_back(), Some(80));
+
+ let mut it = (100..=100).step_by(10);
+ assert_eq!(it.next_back(), Some(100));
+ assert_eq!(it.try_fold(0, i8::checked_add), Some(0));
+}
+
+#[test]
+#[should_panic]
+fn test_iterator_step_by_zero() {
+ let mut it = (0..).step_by(0);
+ it.next();
+}
+
+#[test]
+fn test_iterator_step_by_size_hint() {
+ struct StubSizeHint(usize, Option<usize>);
+ impl Iterator for StubSizeHint {
+ type Item = ();
+ fn next(&mut self) -> Option<()> {
+ self.0 -= 1;
+ if let Some(ref mut upper) = self.1 {
+ *upper -= 1;
+ }
+ Some(())
+ }
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (self.0, self.1)
+ }
+ }
+
+ // The two checks in each case are needed because the logic
+ // is different before the first call to `next()`.
+
+ let mut it = StubSizeHint(10, Some(10)).step_by(1);
+ assert_eq!(it.size_hint(), (10, Some(10)));
+ it.next();
+ assert_eq!(it.size_hint(), (9, Some(9)));
+
+ // exact multiple
+ let mut it = StubSizeHint(10, Some(10)).step_by(3);
+ assert_eq!(it.size_hint(), (4, Some(4)));
+ it.next();
+ assert_eq!(it.size_hint(), (3, Some(3)));
+
+ // larger base range, but not enough to get another element
+ let mut it = StubSizeHint(12, Some(12)).step_by(3);
+ assert_eq!(it.size_hint(), (4, Some(4)));
+ it.next();
+ assert_eq!(it.size_hint(), (3, Some(3)));
+
+ // smaller base range, so fewer resulting elements
+ let mut it = StubSizeHint(9, Some(9)).step_by(3);
+ assert_eq!(it.size_hint(), (3, Some(3)));
+ it.next();
+ assert_eq!(it.size_hint(), (2, Some(2)));
+
+ // infinite upper bound
+ let mut it = StubSizeHint(usize::MAX, None).step_by(1);
+ assert_eq!(it.size_hint(), (usize::MAX, None));
+ it.next();
+ assert_eq!(it.size_hint(), (usize::MAX - 1, None));
+
+ // still infinite with larger step
+ let mut it = StubSizeHint(7, None).step_by(3);
+ assert_eq!(it.size_hint(), (3, None));
+ it.next();
+ assert_eq!(it.size_hint(), (2, None));
+
+ // propagates ExactSizeIterator
+ let a = [1, 2, 3, 4, 5];
+ let it = a.iter().step_by(2);
+ assert_eq!(it.len(), 3);
+
+ // Cannot be TrustedLen as a step greater than one makes an iterator
+ // with (usize::MAX, None) no longer meet the safety requirements
+ trait TrustedLenCheck {
+ fn test(self) -> bool;
+ }
+ impl<T: Iterator> TrustedLenCheck for T {
+ default fn test(self) -> bool {
+ false
+ }
+ }
+ impl<T: TrustedLen> TrustedLenCheck for T {
+ fn test(self) -> bool {
+ true
+ }
+ }
+ assert!(TrustedLenCheck::test(a.iter()));
+ assert!(!TrustedLenCheck::test(a.iter().step_by(1)));
+}
+
+#[test]
+fn test_step_by_skip() {
+ assert_eq!((0..640).step_by(128).skip(1).collect::<Vec<_>>(), [128, 256, 384, 512]);
+ assert_eq!((0..=50).step_by(10).nth(3), Some(30));
+ assert_eq!((200..=255u8).step_by(10).nth(3), Some(230));
+}
diff --git a/library/core/tests/iter/adapters/take.rs b/library/core/tests/iter/adapters/take.rs
new file mode 100644
index 000000000..bfb659f0a
--- /dev/null
+++ b/library/core/tests/iter/adapters/take.rs
@@ -0,0 +1,148 @@
+use core::iter::*;
+
+#[test]
+fn test_iterator_take() {
+ let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19];
+ let ys = [0, 1, 2, 3, 5];
+
+ let mut it = xs.iter().take(ys.len());
+ let mut i = 0;
+ assert_eq!(it.len(), ys.len());
+ while let Some(&x) = it.next() {
+ assert_eq!(x, ys[i]);
+ i += 1;
+ assert_eq!(it.len(), ys.len() - i);
+ }
+ assert_eq!(i, ys.len());
+ assert_eq!(it.len(), 0);
+
+ let mut it = xs.iter().take(ys.len());
+ let mut i = 0;
+ assert_eq!(it.len(), ys.len());
+ while let Some(&x) = it.next_back() {
+ i += 1;
+ assert_eq!(x, ys[ys.len() - i]);
+ assert_eq!(it.len(), ys.len() - i);
+ }
+ assert_eq!(i, ys.len());
+ assert_eq!(it.len(), 0);
+}
+
+#[test]
+fn test_iterator_take_nth() {
+ let xs = [0, 1, 2, 4, 5];
+ let mut it = xs.iter();
+ {
+ let mut take = it.by_ref().take(3);
+ let mut i = 0;
+ while let Some(&x) = take.nth(0) {
+ assert_eq!(x, i);
+ i += 1;
+ }
+ }
+ assert_eq!(it.nth(1), Some(&5));
+ assert_eq!(it.nth(0), None);
+
+ let xs = [0, 1, 2, 3, 4];
+ let mut it = xs.iter().take(7);
+ let mut i = 1;
+ while let Some(&x) = it.nth(1) {
+ assert_eq!(x, i);
+ i += 2;
+ }
+}
+
+#[test]
+fn test_iterator_take_nth_back() {
+ let xs = [0, 1, 2, 4, 5];
+ let mut it = xs.iter();
+ {
+ let mut take = it.by_ref().take(3);
+ let mut i = 0;
+ while let Some(&x) = take.nth_back(0) {
+ i += 1;
+ assert_eq!(x, 3 - i);
+ }
+ }
+ assert_eq!(it.nth_back(0), None);
+
+ let xs = [0, 1, 2, 3, 4];
+ let mut it = xs.iter().take(7);
+ assert_eq!(it.nth_back(1), Some(&3));
+ assert_eq!(it.nth_back(1), Some(&1));
+ assert_eq!(it.nth_back(1), None);
+}
+
+#[test]
+fn test_take_advance_by() {
+ let mut take = (0..10).take(3);
+ assert_eq!(take.advance_by(2), Ok(()));
+ assert_eq!(take.next(), Some(2));
+ assert_eq!(take.advance_by(1), Err(0));
+
+ assert_eq!((0..0).take(10).advance_by(0), Ok(()));
+ assert_eq!((0..0).take(10).advance_by(1), Err(0));
+ assert_eq!((0..10).take(4).advance_by(5), Err(4));
+
+ let mut take = (0..10).take(3);
+ assert_eq!(take.advance_back_by(2), Ok(()));
+ assert_eq!(take.next(), Some(0));
+ assert_eq!(take.advance_back_by(1), Err(0));
+
+ assert_eq!((0..2).take(1).advance_back_by(10), Err(1));
+ assert_eq!((0..0).take(1).advance_back_by(1), Err(0));
+ assert_eq!((0..0).take(1).advance_back_by(0), Ok(()));
+ assert_eq!((0..usize::MAX).take(100).advance_back_by(usize::MAX), Err(100));
+}
+
+#[test]
+fn test_iterator_take_short() {
+ let xs = [0, 1, 2, 3];
+
+ let mut it = xs.iter().take(5);
+ let mut i = 0;
+ assert_eq!(it.len(), xs.len());
+ while let Some(&x) = it.next() {
+ assert_eq!(x, xs[i]);
+ i += 1;
+ assert_eq!(it.len(), xs.len() - i);
+ }
+ assert_eq!(i, xs.len());
+ assert_eq!(it.len(), 0);
+
+ let mut it = xs.iter().take(5);
+ let mut i = 0;
+ assert_eq!(it.len(), xs.len());
+ while let Some(&x) = it.next_back() {
+ i += 1;
+ assert_eq!(x, xs[xs.len() - i]);
+ assert_eq!(it.len(), xs.len() - i);
+ }
+ assert_eq!(i, xs.len());
+ assert_eq!(it.len(), 0);
+}
+
+#[test]
+fn test_take_try_folds() {
+ let f = &|acc, x| i32::checked_add(2 * acc, x);
+ assert_eq!((10..30).take(10).try_fold(7, f), (10..20).try_fold(7, f));
+ assert_eq!((10..30).take(10).try_rfold(7, f), (10..20).try_rfold(7, f));
+
+ let mut iter = (10..30).take(20);
+ assert_eq!(iter.try_fold(0, i8::checked_add), None);
+ assert_eq!(iter.next(), Some(20));
+ assert_eq!(iter.try_rfold(0, i8::checked_add), None);
+ assert_eq!(iter.next_back(), Some(24));
+
+ let mut iter = (2..20).take(3);
+ assert_eq!(iter.try_for_each(Err), Err(2));
+ assert_eq!(iter.try_for_each(Err), Err(3));
+ assert_eq!(iter.try_for_each(Err), Err(4));
+ assert_eq!(iter.try_for_each(Err), Ok(()));
+
+ let mut iter = (2..20).take(3).rev();
+ assert_eq!(iter.try_for_each(Err), Err(4));
+ assert_eq!(iter.try_for_each(Err), Err(3));
+ assert_eq!(iter.try_for_each(Err), Err(2));
+ assert_eq!(iter.try_for_each(Err), Ok(()));
+}
diff --git a/library/core/tests/iter/adapters/take_while.rs b/library/core/tests/iter/adapters/take_while.rs
new file mode 100644
index 000000000..6f1ebab29
--- /dev/null
+++ b/library/core/tests/iter/adapters/take_while.rs
@@ -0,0 +1,29 @@
+use core::iter::*;
+
+#[test]
+fn test_iterator_take_while() {
+ let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19];
+ let ys = [0, 1, 2, 3, 5, 13];
+ let it = xs.iter().take_while(|&x| *x < 15);
+ let mut i = 0;
+ for x in it {
+ assert_eq!(*x, ys[i]);
+ i += 1;
+ }
+ assert_eq!(i, ys.len());
+}
+
+#[test]
+fn test_take_while_folds() {
+ let f = &|acc, x| i32::checked_add(2 * acc, x);
+ assert_eq!((1..20).take_while(|&x| x != 10).try_fold(7, f), (1..10).try_fold(7, f));
+ let mut iter = (1..20).take_while(|&x| x != 10);
+ assert_eq!(iter.try_fold(0, |x, y| Some(x + y)), Some((1..10).sum()));
+ assert_eq!(iter.next(), None, "flag should be set");
+ let iter = (1..20).take_while(|&x| x != 10);
+ assert_eq!(iter.fold(0, |x, y| x + y), (1..10).sum());
+
+ let mut iter = (10..50).take_while(|&x| x != 40);
+ assert_eq!(iter.try_fold(0, i8::checked_add), None);
+ assert_eq!(iter.next(), Some(20));
+}
diff --git a/library/core/tests/iter/adapters/zip.rs b/library/core/tests/iter/adapters/zip.rs
new file mode 100644
index 000000000..585cfbb90
--- /dev/null
+++ b/library/core/tests/iter/adapters/zip.rs
@@ -0,0 +1,315 @@
+use super::*;
+use core::iter::*;
+
+#[test]
+fn test_zip_nth() {
+ let xs = [0, 1, 2, 4, 5];
+ let ys = [10, 11, 12];
+
+ let mut it = xs.iter().zip(&ys);
+ assert_eq!(it.nth(0), Some((&0, &10)));
+ assert_eq!(it.nth(1), Some((&2, &12)));
+ assert_eq!(it.nth(0), None);
+
+ let mut it = xs.iter().zip(&ys);
+ assert_eq!(it.nth(3), None);
+
+ let mut it = ys.iter().zip(&xs);
+ assert_eq!(it.nth(3), None);
+}
+
+#[test]
+fn test_zip_nth_side_effects() {
+ let mut a = Vec::new();
+ let mut b = Vec::new();
+ let value = [1, 2, 3, 4, 5, 6]
+ .iter()
+ .cloned()
+ .map(|n| {
+ a.push(n);
+ n * 10
+ })
+ .zip([2, 3, 4, 5, 6, 7, 8].iter().cloned().map(|n| {
+ b.push(n * 100);
+ n * 1000
+ }))
+ .skip(1)
+ .nth(3);
+ assert_eq!(value, Some((50, 6000)));
+ assert_eq!(a, vec![1, 2, 3, 4, 5]);
+ assert_eq!(b, vec![200, 300, 400, 500, 600]);
+}
+
+#[test]
+fn test_zip_next_back_side_effects() {
+ let mut a = Vec::new();
+ let mut b = Vec::new();
+ let mut iter = [1, 2, 3, 4, 5, 6]
+ .iter()
+ .cloned()
+ .map(|n| {
+ a.push(n);
+ n * 10
+ })
+ .zip([2, 3, 4, 5, 6, 7, 8].iter().cloned().map(|n| {
+ b.push(n * 100);
+ n * 1000
+ }));
+
+ // The second iterator is one item longer, so `next_back` is called on it
+ // one more time.
+ assert_eq!(iter.next_back(), Some((60, 7000)));
+ assert_eq!(iter.next_back(), Some((50, 6000)));
+ assert_eq!(iter.next_back(), Some((40, 5000)));
+ assert_eq!(iter.next_back(), Some((30, 4000)));
+ assert_eq!(a, vec![6, 5, 4, 3]);
+ assert_eq!(b, vec![800, 700, 600, 500, 400]);
+}
+
+#[test]
+fn test_zip_nth_back_side_effects() {
+ let mut a = Vec::new();
+ let mut b = Vec::new();
+ let value = [1, 2, 3, 4, 5, 6]
+ .iter()
+ .cloned()
+ .map(|n| {
+ a.push(n);
+ n * 10
+ })
+ .zip([2, 3, 4, 5, 6, 7, 8].iter().cloned().map(|n| {
+ b.push(n * 100);
+ n * 1000
+ }))
+ .nth_back(3);
+ assert_eq!(value, Some((30, 4000)));
+ assert_eq!(a, vec![6, 5, 4, 3]);
+ assert_eq!(b, vec![800, 700, 600, 500, 400]);
+}
+
+#[test]
+fn test_zip_next_back_side_effects_exhausted() {
+ let mut a = Vec::new();
+ let mut b = Vec::new();
+ let mut iter = [1, 2, 3, 4, 5, 6]
+ .iter()
+ .cloned()
+ .map(|n| {
+ a.push(n);
+ n * 10
+ })
+ .zip([2, 3, 4].iter().cloned().map(|n| {
+ b.push(n * 100);
+ n * 1000
+ }));
+
+ iter.next();
+ iter.next();
+ iter.next();
+ iter.next();
+ assert_eq!(iter.next_back(), None);
+ assert_eq!(a, vec![1, 2, 3, 4, 6, 5]);
+ assert_eq!(b, vec![200, 300, 400]);
+}
+
+#[test]
+fn test_zip_cloned_sideffectful() {
+ let xs = [CountClone::new(), CountClone::new(), CountClone::new(), CountClone::new()];
+ let ys = [CountClone::new(), CountClone::new()];
+
+ for _ in xs.iter().cloned().zip(ys.iter().cloned()) {}
+
+ assert_eq!(&xs, &[1, 1, 1, 0][..]);
+ assert_eq!(&ys, &[1, 1][..]);
+
+ let xs = [CountClone::new(), CountClone::new()];
+ let ys = [CountClone::new(), CountClone::new(), CountClone::new(), CountClone::new()];
+
+ for _ in xs.iter().cloned().zip(ys.iter().cloned()) {}
+
+ assert_eq!(&xs, &[1, 1][..]);
+ assert_eq!(&ys, &[1, 1, 0, 0][..]);
+}
+
+#[test]
+fn test_zip_map_sideffectful() {
+ let mut xs = [0; 6];
+ let mut ys = [0; 4];
+
+ for _ in xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)) {}
+
+ assert_eq!(&xs, &[1, 1, 1, 1, 1, 0]);
+ assert_eq!(&ys, &[1, 1, 1, 1]);
+
+ let mut xs = [0; 4];
+ let mut ys = [0; 6];
+
+ for _ in xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)) {}
+
+ assert_eq!(&xs, &[1, 1, 1, 1]);
+ assert_eq!(&ys, &[1, 1, 1, 1, 0, 0]);
+}
+
+#[test]
+fn test_zip_map_rev_sideffectful() {
+ let mut xs = [0; 6];
+ let mut ys = [0; 4];
+
+ {
+ let mut it = xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1));
+ it.next_back();
+ }
+ assert_eq!(&xs, &[0, 0, 0, 1, 1, 1]);
+ assert_eq!(&ys, &[0, 0, 0, 1]);
+
+ let mut xs = [0; 6];
+ let mut ys = [0; 4];
+
+ {
+ let mut it = xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1));
+ (&mut it).take(5).count();
+ it.next_back();
+ }
+ assert_eq!(&xs, &[1, 1, 1, 1, 1, 1]);
+ assert_eq!(&ys, &[1, 1, 1, 1]);
+}
+
+#[test]
+fn test_zip_nested_sideffectful() {
+ let mut xs = [0; 6];
+ let ys = [0; 4];
+
+ {
+ // test that it has the side effect nested inside enumerate
+ let it = xs.iter_mut().map(|x| *x = 1).enumerate().zip(&ys);
+ it.count();
+ }
+ assert_eq!(&xs, &[1, 1, 1, 1, 1, 0]);
+}
+
+#[test]
+fn test_zip_nth_back_side_effects_exhausted() {
+ let mut a = Vec::new();
+ let mut b = Vec::new();
+ let mut iter = [1, 2, 3, 4, 5, 6]
+ .iter()
+ .cloned()
+ .map(|n| {
+ a.push(n);
+ n * 10
+ })
+ .zip([2, 3, 4].iter().cloned().map(|n| {
+ b.push(n * 100);
+ n * 1000
+ }));
+
+ iter.next();
+ iter.next();
+ iter.next();
+ iter.next();
+ assert_eq!(iter.nth_back(0), None);
+ assert_eq!(a, vec![1, 2, 3, 4, 6, 5]);
+ assert_eq!(b, vec![200, 300, 400]);
+}
+
+#[test]
+fn test_zip_trusted_random_access_composition() {
+ let a = [0, 1, 2, 3, 4];
+ let b = a;
+ let c = a;
+
+ let a = a.iter().copied();
+ let b = b.iter().copied();
+ let mut c = c.iter().copied();
+ c.next();
+
+ let mut z1 = a.zip(b);
+ assert_eq!(z1.next().unwrap(), (0, 0));
+
+ let mut z2 = z1.zip(c);
+ fn assert_trusted_random_access<T: TrustedRandomAccess>(_a: &T) {}
+ assert_trusted_random_access(&z2);
+ assert_eq!(z2.next().unwrap(), ((1, 1), 1));
+}
+
+#[test]
+#[cfg(panic = "unwind")]
+fn test_zip_trusted_random_access_next_back_drop() {
+ use std::panic::catch_unwind;
+ use std::panic::AssertUnwindSafe;
+
+ let mut counter = 0;
+
+ let it = [42].iter().map(|e| {
+ let c = counter;
+ counter += 1;
+ if c == 0 {
+ panic!("bomb");
+ }
+
+ e
+ });
+ let it2 = [(); 0].iter();
+ let mut zip = it.zip(it2);
+ catch_unwind(AssertUnwindSafe(|| {
+ zip.next_back();
+ }))
+ .unwrap_err();
+ assert!(zip.next().is_none());
+ assert_eq!(counter, 1);
+}
+
+#[test]
+fn test_double_ended_zip() {
+ let xs = [1, 2, 3, 4, 5, 6];
+ let ys = [1, 2, 3, 7];
+ let mut it = xs.iter().cloned().zip(ys);
+ assert_eq!(it.next(), Some((1, 1)));
+ assert_eq!(it.next(), Some((2, 2)));
+ assert_eq!(it.next_back(), Some((4, 7)));
+ assert_eq!(it.next_back(), Some((3, 3)));
+ assert_eq!(it.next(), None);
+}
+
+#[test]
+fn test_issue_82282() {
+ fn overflowed_zip(arr: &[i32]) -> impl Iterator<Item = (i32, &())> {
+ static UNIT_EMPTY_ARR: [(); 0] = [];
+
+ let mapped = arr.into_iter().map(|i| *i);
+ let mut zipped = mapped.zip(UNIT_EMPTY_ARR.iter());
+ zipped.next();
+ zipped
+ }
+
+ let arr = [1, 2, 3];
+ let zip = overflowed_zip(&arr).zip(overflowed_zip(&arr));
+
+ assert_eq!(zip.size_hint(), (0, Some(0)));
+ for _ in zip {
+ panic!();
+ }
+}
+
+#[test]
+fn test_issue_82291() {
+ use std::cell::Cell;
+
+ let mut v1 = [()];
+ let v2 = [()];
+
+ let called = Cell::new(0);
+
+ let mut zip = v1
+ .iter_mut()
+ .map(|r| {
+ called.set(called.get() + 1);
+ r
+ })
+ .zip(&v2);
+
+ zip.next_back();
+ assert_eq!(called.get(), 1);
+ zip.next();
+ assert_eq!(called.get(), 1);
+}
diff --git a/library/core/tests/iter/mod.rs b/library/core/tests/iter/mod.rs
new file mode 100644
index 000000000..770b6f760
--- /dev/null
+++ b/library/core/tests/iter/mod.rs
@@ -0,0 +1,102 @@
+//! Note
+//! ----
+//! You're probably viewing this file because you're adding a test (or you might
+//! just be browsing, in that case, hey there!).
+//!
+//! The iter test suite is split into two big modules, and some miscellaneous
+//! smaller modules. The two big modules are `adapters` and `traits`.
+//!
+//! `adapters` are for methods on `Iterator` that adapt the data inside the
+//! iterator, whether it be by emitting another iterator or returning an item
+//! from inside the iterator after executing a closure on each item.
+//!
+//! `traits` are for trait's that extend an `Iterator` (and the `Iterator`
+//! trait itself, mostly containing miscellaneous methods). For the most part,
+//! if a test in `traits` uses a specific adapter, then it should be moved to
+//! that adapter's test file in `adapters`.
+
+mod adapters;
+mod range;
+mod sources;
+mod traits;
+
+use core::cell::Cell;
+use core::convert::TryFrom;
+use core::iter::*;
+
+pub fn is_trusted_len<I: TrustedLen>(_: I) {}
+
+#[test]
+fn test_multi_iter() {
+ let xs = [1, 2, 3, 4];
+ let ys = [4, 3, 2, 1];
+ assert!(xs.iter().eq(ys.iter().rev()));
+ assert!(xs.iter().lt(xs.iter().skip(2)));
+}
+
+#[test]
+fn test_counter_from_iter() {
+ let it = (0..).step_by(5).take(10);
+ let xs: Vec<isize> = FromIterator::from_iter(it);
+ assert_eq!(xs, [0, 5, 10, 15, 20, 25, 30, 35, 40, 45]);
+}
+
+#[test]
+fn test_functor_laws() {
+ // identity:
+ fn identity<T>(x: T) -> T {
+ x
+ }
+ assert_eq!((0..10).map(identity).sum::<usize>(), (0..10).sum());
+
+ // composition:
+ fn f(x: usize) -> usize {
+ x + 3
+ }
+ fn g(x: usize) -> usize {
+ x * 2
+ }
+ fn h(x: usize) -> usize {
+ g(f(x))
+ }
+ assert_eq!((0..10).map(f).map(g).sum::<usize>(), (0..10).map(h).sum());
+}
+
+#[test]
+fn test_monad_laws_left_identity() {
+ fn f(x: usize) -> impl Iterator<Item = usize> {
+ (0..10).map(move |y| x * y)
+ }
+ assert_eq!(once(42).flat_map(f.clone()).sum::<usize>(), f(42).sum());
+}
+
+#[test]
+fn test_monad_laws_right_identity() {
+ assert_eq!((0..10).flat_map(|x| once(x)).sum::<usize>(), (0..10).sum());
+}
+
+#[test]
+fn test_monad_laws_associativity() {
+ fn f(x: usize) -> impl Iterator<Item = usize> {
+ 0..x
+ }
+ fn g(x: usize) -> impl Iterator<Item = usize> {
+ (0..x).rev()
+ }
+ assert_eq!(
+ (0..10).flat_map(f).flat_map(g).sum::<usize>(),
+ (0..10).flat_map(|x| f(x).flat_map(g)).sum::<usize>()
+ );
+}
+
+#[test]
+pub fn extend_for_unit() {
+ let mut x = 0;
+ {
+ let iter = (0..5).map(|_| {
+ x += 1;
+ });
+ ().extend(iter);
+ }
+ assert_eq!(x, 5);
+}
diff --git a/library/core/tests/iter/range.rs b/library/core/tests/iter/range.rs
new file mode 100644
index 000000000..84498a8ea
--- /dev/null
+++ b/library/core/tests/iter/range.rs
@@ -0,0 +1,472 @@
+use super::*;
+
+#[test]
+fn test_range() {
+ assert_eq!((0..5).collect::<Vec<_>>(), [0, 1, 2, 3, 4]);
+ assert_eq!((-10..-1).collect::<Vec<_>>(), [-10, -9, -8, -7, -6, -5, -4, -3, -2]);
+ assert_eq!((0..5).rev().collect::<Vec<_>>(), [4, 3, 2, 1, 0]);
+ assert_eq!((200..-5).count(), 0);
+ assert_eq!((200..-5).rev().count(), 0);
+ assert_eq!((200..200).count(), 0);
+ assert_eq!((200..200).rev().count(), 0);
+
+ assert_eq!((0..100).size_hint(), (100, Some(100)));
+ // this test is only meaningful when sizeof usize < sizeof u64
+ assert_eq!((usize::MAX - 1..usize::MAX).size_hint(), (1, Some(1)));
+ assert_eq!((-10..-1).size_hint(), (9, Some(9)));
+ assert_eq!((-1..-10).size_hint(), (0, Some(0)));
+
+ assert_eq!((-70..58).size_hint(), (128, Some(128)));
+ assert_eq!((-128..127).size_hint(), (255, Some(255)));
+ assert_eq!(
+ (-2..isize::MAX).size_hint(),
+ (isize::MAX as usize + 2, Some(isize::MAX as usize + 2))
+ );
+}
+
+#[test]
+fn test_char_range() {
+ use std::char;
+ // Miri is too slow
+ let from = if cfg!(miri) { char::from_u32(0xD800 - 10).unwrap() } else { '\0' };
+ let to = if cfg!(miri) { char::from_u32(0xDFFF + 10).unwrap() } else { char::MAX };
+ assert!((from..=to).eq((from as u32..=to as u32).filter_map(char::from_u32)));
+ assert!((from..=to).rev().eq((from as u32..=to as u32).filter_map(char::from_u32).rev()));
+
+ assert_eq!(('\u{D7FF}'..='\u{E000}').count(), 2);
+ assert_eq!(('\u{D7FF}'..='\u{E000}').size_hint(), (2, Some(2)));
+ assert_eq!(('\u{D7FF}'..'\u{E000}').count(), 1);
+ assert_eq!(('\u{D7FF}'..'\u{E000}').size_hint(), (1, Some(1)));
+}
+
+#[test]
+fn test_range_exhaustion() {
+ let mut r = 10..10;
+ assert!(r.is_empty());
+ assert_eq!(r.next(), None);
+ assert_eq!(r.next_back(), None);
+ assert_eq!(r, 10..10);
+
+ let mut r = 10..12;
+ assert_eq!(r.next(), Some(10));
+ assert_eq!(r.next(), Some(11));
+ assert!(r.is_empty());
+ assert_eq!(r, 12..12);
+ assert_eq!(r.next(), None);
+
+ let mut r = 10..12;
+ assert_eq!(r.next_back(), Some(11));
+ assert_eq!(r.next_back(), Some(10));
+ assert!(r.is_empty());
+ assert_eq!(r, 10..10);
+ assert_eq!(r.next_back(), None);
+
+ let mut r = 100..10;
+ assert!(r.is_empty());
+ assert_eq!(r.next(), None);
+ assert_eq!(r.next_back(), None);
+ assert_eq!(r, 100..10);
+}
+
+#[test]
+fn test_range_inclusive_exhaustion() {
+ let mut r = 10..=10;
+ assert_eq!(r.next(), Some(10));
+ assert!(r.is_empty());
+ assert_eq!(r.next(), None);
+ assert_eq!(r.next(), None);
+
+ assert_eq!(*r.start(), 10);
+ assert_eq!(*r.end(), 10);
+ assert_ne!(r, 10..=10);
+
+ let mut r = 10..=10;
+ assert_eq!(r.next_back(), Some(10));
+ assert!(r.is_empty());
+ assert_eq!(r.next_back(), None);
+
+ assert_eq!(*r.start(), 10);
+ assert_eq!(*r.end(), 10);
+ assert_ne!(r, 10..=10);
+
+ let mut r = 10..=12;
+ assert_eq!(r.next(), Some(10));
+ assert_eq!(r.next(), Some(11));
+ assert_eq!(r.next(), Some(12));
+ assert!(r.is_empty());
+ assert_eq!(r.next(), None);
+
+ let mut r = 10..=12;
+ assert_eq!(r.next_back(), Some(12));
+ assert_eq!(r.next_back(), Some(11));
+ assert_eq!(r.next_back(), Some(10));
+ assert!(r.is_empty());
+ assert_eq!(r.next_back(), None);
+
+ let mut r = 10..=12;
+ assert_eq!(r.nth(2), Some(12));
+ assert!(r.is_empty());
+ assert_eq!(r.next(), None);
+
+ let mut r = 10..=12;
+ assert_eq!(r.nth(5), None);
+ assert!(r.is_empty());
+ assert_eq!(r.next(), None);
+
+ let mut r = 100..=10;
+ assert_eq!(r.next(), None);
+ assert!(r.is_empty());
+ assert_eq!(r.next(), None);
+ assert_eq!(r.next(), None);
+ assert_eq!(r, 100..=10);
+
+ let mut r = 100..=10;
+ assert_eq!(r.next_back(), None);
+ assert!(r.is_empty());
+ assert_eq!(r.next_back(), None);
+ assert_eq!(r.next_back(), None);
+ assert_eq!(r, 100..=10);
+}
+
+#[test]
+fn test_range_nth() {
+ assert_eq!((10..15).nth(0), Some(10));
+ assert_eq!((10..15).nth(1), Some(11));
+ assert_eq!((10..15).nth(4), Some(14));
+ assert_eq!((10..15).nth(5), None);
+
+ let mut r = 10..20;
+ assert_eq!(r.nth(2), Some(12));
+ assert_eq!(r, 13..20);
+ assert_eq!(r.nth(2), Some(15));
+ assert_eq!(r, 16..20);
+ assert_eq!(r.nth(10), None);
+ assert_eq!(r, 20..20);
+}
+
+#[test]
+fn test_range_nth_back() {
+ assert_eq!((10..15).nth_back(0), Some(14));
+ assert_eq!((10..15).nth_back(1), Some(13));
+ assert_eq!((10..15).nth_back(4), Some(10));
+ assert_eq!((10..15).nth_back(5), None);
+ assert_eq!((-120..80_i8).nth_back(199), Some(-120));
+
+ let mut r = 10..20;
+ assert_eq!(r.nth_back(2), Some(17));
+ assert_eq!(r, 10..17);
+ assert_eq!(r.nth_back(2), Some(14));
+ assert_eq!(r, 10..14);
+ assert_eq!(r.nth_back(10), None);
+ assert_eq!(r, 10..10);
+}
+
+#[test]
+fn test_range_from_nth() {
+ assert_eq!((10..).nth(0), Some(10));
+ assert_eq!((10..).nth(1), Some(11));
+ assert_eq!((10..).nth(4), Some(14));
+
+ let mut r = 10..;
+ assert_eq!(r.nth(2), Some(12));
+ assert_eq!(r, 13..);
+ assert_eq!(r.nth(2), Some(15));
+ assert_eq!(r, 16..);
+ assert_eq!(r.nth(10), Some(26));
+ assert_eq!(r, 27..);
+
+ assert_eq!((0..).size_hint(), (usize::MAX, None));
+}
+
+#[test]
+fn test_range_from_take() {
+ let mut it = (0..).take(3);
+ assert_eq!(it.next(), Some(0));
+ assert_eq!(it.next(), Some(1));
+ assert_eq!(it.next(), Some(2));
+ assert_eq!(it.next(), None);
+ is_trusted_len((0..).take(3));
+ assert_eq!((0..).take(3).size_hint(), (3, Some(3)));
+ assert_eq!((0..).take(0).size_hint(), (0, Some(0)));
+ assert_eq!((0..).take(usize::MAX).size_hint(), (usize::MAX, Some(usize::MAX)));
+}
+
+#[test]
+fn test_range_from_take_collect() {
+ let v: Vec<_> = (0..).take(3).collect();
+ assert_eq!(v, vec![0, 1, 2]);
+}
+
+#[test]
+fn test_range_inclusive_nth() {
+ assert_eq!((10..=15).nth(0), Some(10));
+ assert_eq!((10..=15).nth(1), Some(11));
+ assert_eq!((10..=15).nth(5), Some(15));
+ assert_eq!((10..=15).nth(6), None);
+
+ let mut exhausted_via_next = 10_u8..=20;
+ while exhausted_via_next.next().is_some() {}
+
+ let mut r = 10_u8..=20;
+ assert_eq!(r.nth(2), Some(12));
+ assert_eq!(r, 13..=20);
+ assert_eq!(r.nth(2), Some(15));
+ assert_eq!(r, 16..=20);
+ assert_eq!(r.is_empty(), false);
+ assert_eq!(ExactSizeIterator::is_empty(&r), false);
+ assert_eq!(r.nth(10), None);
+ assert_eq!(r.is_empty(), true);
+ assert_eq!(r, exhausted_via_next);
+ assert_eq!(ExactSizeIterator::is_empty(&r), true);
+}
+
+#[test]
+fn test_range_inclusive_nth_back() {
+ assert_eq!((10..=15).nth_back(0), Some(15));
+ assert_eq!((10..=15).nth_back(1), Some(14));
+ assert_eq!((10..=15).nth_back(5), Some(10));
+ assert_eq!((10..=15).nth_back(6), None);
+ assert_eq!((-120..=80_i8).nth_back(200), Some(-120));
+
+ let mut exhausted_via_next_back = 10_u8..=20;
+ while exhausted_via_next_back.next_back().is_some() {}
+
+ let mut r = 10_u8..=20;
+ assert_eq!(r.nth_back(2), Some(18));
+ assert_eq!(r, 10..=17);
+ assert_eq!(r.nth_back(2), Some(15));
+ assert_eq!(r, 10..=14);
+ assert_eq!(r.is_empty(), false);
+ assert_eq!(ExactSizeIterator::is_empty(&r), false);
+ assert_eq!(r.nth_back(10), None);
+ assert_eq!(r.is_empty(), true);
+ assert_eq!(r, exhausted_via_next_back);
+ assert_eq!(ExactSizeIterator::is_empty(&r), true);
+}
+
+#[test]
+fn test_range_len() {
+ assert_eq!((0..10_u8).len(), 10);
+ assert_eq!((9..10_u8).len(), 1);
+ assert_eq!((10..10_u8).len(), 0);
+ assert_eq!((11..10_u8).len(), 0);
+ assert_eq!((100..10_u8).len(), 0);
+}
+
+#[test]
+fn test_range_inclusive_len() {
+ assert_eq!((0..=10_u8).len(), 11);
+ assert_eq!((9..=10_u8).len(), 2);
+ assert_eq!((10..=10_u8).len(), 1);
+ assert_eq!((11..=10_u8).len(), 0);
+ assert_eq!((100..=10_u8).len(), 0);
+}
+
+#[test]
+fn test_range_step() {
+ #![allow(deprecated)]
+
+ assert_eq!((0..20).step_by(5).collect::<Vec<isize>>(), [0, 5, 10, 15]);
+ assert_eq!((1..21).rev().step_by(5).collect::<Vec<isize>>(), [20, 15, 10, 5]);
+ assert_eq!((1..21).rev().step_by(6).collect::<Vec<isize>>(), [20, 14, 8, 2]);
+ assert_eq!((200..255).step_by(50).collect::<Vec<u8>>(), [200, 250]);
+ assert_eq!((200..-5).step_by(1).collect::<Vec<isize>>(), []);
+ assert_eq!((200..200).step_by(1).collect::<Vec<isize>>(), []);
+
+ assert_eq!((0..20).step_by(1).size_hint(), (20, Some(20)));
+ assert_eq!((0..20).step_by(21).size_hint(), (1, Some(1)));
+ assert_eq!((0..20).step_by(5).size_hint(), (4, Some(4)));
+ assert_eq!((1..21).rev().step_by(5).size_hint(), (4, Some(4)));
+ assert_eq!((1..21).rev().step_by(6).size_hint(), (4, Some(4)));
+ assert_eq!((20..-5).step_by(1).size_hint(), (0, Some(0)));
+ assert_eq!((20..20).step_by(1).size_hint(), (0, Some(0)));
+ assert_eq!((i8::MIN..i8::MAX).step_by(-(i8::MIN as i32) as usize).size_hint(), (2, Some(2)));
+ assert_eq!((i16::MIN..i16::MAX).step_by(i16::MAX as usize).size_hint(), (3, Some(3)));
+ assert_eq!((isize::MIN..isize::MAX).step_by(1).size_hint(), (usize::MAX, Some(usize::MAX)));
+}
+
+#[test]
+fn test_range_advance_by() {
+ let mut r = 0..usize::MAX;
+ r.advance_by(0).unwrap();
+ r.advance_back_by(0).unwrap();
+
+ assert_eq!(r.len(), usize::MAX);
+
+ r.advance_by(1).unwrap();
+ r.advance_back_by(1).unwrap();
+
+ assert_eq!((r.start, r.end), (1, usize::MAX - 1));
+
+ assert_eq!(r.advance_by(usize::MAX), Err(usize::MAX - 2));
+
+ r.advance_by(0).unwrap();
+ r.advance_back_by(0).unwrap();
+
+ let mut r = 0u128..u128::MAX;
+
+ r.advance_by(usize::MAX).unwrap();
+ r.advance_back_by(usize::MAX).unwrap();
+
+ assert_eq!((r.start, r.end), (0u128 + usize::MAX as u128, u128::MAX - usize::MAX as u128));
+}
+
+#[test]
+fn test_range_inclusive_step() {
+ assert_eq!((0..=50).step_by(10).collect::<Vec<_>>(), [0, 10, 20, 30, 40, 50]);
+ assert_eq!((0..=5).step_by(1).collect::<Vec<_>>(), [0, 1, 2, 3, 4, 5]);
+ assert_eq!((200..=255u8).step_by(10).collect::<Vec<_>>(), [200, 210, 220, 230, 240, 250]);
+ assert_eq!((250..=255u8).step_by(1).collect::<Vec<_>>(), [250, 251, 252, 253, 254, 255]);
+}
+
+#[test]
+fn test_range_last_max() {
+ assert_eq!((0..20).last(), Some(19));
+ assert_eq!((-20..0).last(), Some(-1));
+ assert_eq!((5..5).last(), None);
+
+ assert_eq!((0..20).max(), Some(19));
+ assert_eq!((-20..0).max(), Some(-1));
+ assert_eq!((5..5).max(), None);
+}
+
+#[test]
+fn test_range_inclusive_last_max() {
+ assert_eq!((0..=20).last(), Some(20));
+ assert_eq!((-20..=0).last(), Some(0));
+ assert_eq!((5..=5).last(), Some(5));
+ let mut r = 10..=10;
+ r.next();
+ assert_eq!(r.last(), None);
+
+ assert_eq!((0..=20).max(), Some(20));
+ assert_eq!((-20..=0).max(), Some(0));
+ assert_eq!((5..=5).max(), Some(5));
+ let mut r = 10..=10;
+ r.next();
+ assert_eq!(r.max(), None);
+}
+
+#[test]
+fn test_range_min() {
+ assert_eq!((0..20).min(), Some(0));
+ assert_eq!((-20..0).min(), Some(-20));
+ assert_eq!((5..5).min(), None);
+}
+
+#[test]
+fn test_range_inclusive_min() {
+ assert_eq!((0..=20).min(), Some(0));
+ assert_eq!((-20..=0).min(), Some(-20));
+ assert_eq!((5..=5).min(), Some(5));
+ let mut r = 10..=10;
+ r.next();
+ assert_eq!(r.min(), None);
+}
+
+#[test]
+fn test_range_inclusive_folds() {
+ assert_eq!((1..=10).sum::<i32>(), 55);
+ assert_eq!((1..=10).rev().sum::<i32>(), 55);
+
+ let mut it = 44..=50;
+ assert_eq!(it.try_fold(0, i8::checked_add), None);
+ assert_eq!(it, 47..=50);
+ assert_eq!(it.try_fold(0, i8::checked_add), None);
+ assert_eq!(it, 50..=50);
+ assert_eq!(it.try_fold(0, i8::checked_add), Some(50));
+ assert!(it.is_empty());
+ assert_eq!(it.try_fold(0, i8::checked_add), Some(0));
+ assert!(it.is_empty());
+
+ let mut it = 40..=47;
+ assert_eq!(it.try_rfold(0, i8::checked_add), None);
+ assert_eq!(it, 40..=44);
+ assert_eq!(it.try_rfold(0, i8::checked_add), None);
+ assert_eq!(it, 40..=41);
+ assert_eq!(it.try_rfold(0, i8::checked_add), Some(81));
+ assert!(it.is_empty());
+ assert_eq!(it.try_rfold(0, i8::checked_add), Some(0));
+ assert!(it.is_empty());
+
+ let mut it = 10..=20;
+ assert_eq!(it.try_fold(0, |a, b| Some(a + b)), Some(165));
+ assert!(it.is_empty());
+ assert_eq!(it.try_fold(0, |a, b| Some(a + b)), Some(0));
+ assert!(it.is_empty());
+
+ let mut it = 10..=20;
+ assert_eq!(it.try_rfold(0, |a, b| Some(a + b)), Some(165));
+ assert!(it.is_empty());
+ assert_eq!(it.try_rfold(0, |a, b| Some(a + b)), Some(0));
+ assert!(it.is_empty());
+}
+
+#[test]
+fn test_range_size_hint() {
+ assert_eq!((0..0usize).size_hint(), (0, Some(0)));
+ assert_eq!((0..100usize).size_hint(), (100, Some(100)));
+ assert_eq!((0..usize::MAX).size_hint(), (usize::MAX, Some(usize::MAX)));
+
+ let umax = u128::try_from(usize::MAX).unwrap();
+ assert_eq!((0..0u128).size_hint(), (0, Some(0)));
+ assert_eq!((0..100u128).size_hint(), (100, Some(100)));
+ assert_eq!((0..umax).size_hint(), (usize::MAX, Some(usize::MAX)));
+ assert_eq!((0..umax + 1).size_hint(), (usize::MAX, None));
+
+ assert_eq!((0..0isize).size_hint(), (0, Some(0)));
+ assert_eq!((-100..100isize).size_hint(), (200, Some(200)));
+ assert_eq!((isize::MIN..isize::MAX).size_hint(), (usize::MAX, Some(usize::MAX)));
+
+ let imin = i128::try_from(isize::MIN).unwrap();
+ let imax = i128::try_from(isize::MAX).unwrap();
+ assert_eq!((0..0i128).size_hint(), (0, Some(0)));
+ assert_eq!((-100..100i128).size_hint(), (200, Some(200)));
+ assert_eq!((imin..imax).size_hint(), (usize::MAX, Some(usize::MAX)));
+ assert_eq!((imin..imax + 1).size_hint(), (usize::MAX, None));
+}
+
+#[test]
+fn test_range_inclusive_size_hint() {
+ assert_eq!((1..=0usize).size_hint(), (0, Some(0)));
+ assert_eq!((0..=0usize).size_hint(), (1, Some(1)));
+ assert_eq!((0..=100usize).size_hint(), (101, Some(101)));
+ assert_eq!((0..=usize::MAX - 1).size_hint(), (usize::MAX, Some(usize::MAX)));
+ assert_eq!((0..=usize::MAX).size_hint(), (usize::MAX, None));
+
+ let umax = u128::try_from(usize::MAX).unwrap();
+ assert_eq!((1..=0u128).size_hint(), (0, Some(0)));
+ assert_eq!((0..=0u128).size_hint(), (1, Some(1)));
+ assert_eq!((0..=100u128).size_hint(), (101, Some(101)));
+ assert_eq!((0..=umax - 1).size_hint(), (usize::MAX, Some(usize::MAX)));
+ assert_eq!((0..=umax).size_hint(), (usize::MAX, None));
+ assert_eq!((0..=umax + 1).size_hint(), (usize::MAX, None));
+
+ assert_eq!((0..=-1isize).size_hint(), (0, Some(0)));
+ assert_eq!((0..=0isize).size_hint(), (1, Some(1)));
+ assert_eq!((-100..=100isize).size_hint(), (201, Some(201)));
+ assert_eq!((isize::MIN..=isize::MAX - 1).size_hint(), (usize::MAX, Some(usize::MAX)));
+ assert_eq!((isize::MIN..=isize::MAX).size_hint(), (usize::MAX, None));
+
+ let imin = i128::try_from(isize::MIN).unwrap();
+ let imax = i128::try_from(isize::MAX).unwrap();
+ assert_eq!((0..=-1i128).size_hint(), (0, Some(0)));
+ assert_eq!((0..=0i128).size_hint(), (1, Some(1)));
+ assert_eq!((-100..=100i128).size_hint(), (201, Some(201)));
+ assert_eq!((imin..=imax - 1).size_hint(), (usize::MAX, Some(usize::MAX)));
+ assert_eq!((imin..=imax).size_hint(), (usize::MAX, None));
+ assert_eq!((imin..=imax + 1).size_hint(), (usize::MAX, None));
+}
+
+#[test]
+fn test_double_ended_range() {
+ assert_eq!((11..14).rev().collect::<Vec<_>>(), [13, 12, 11]);
+ for _ in (10..0).rev() {
+ panic!("unreachable");
+ }
+
+ assert_eq!((11..14).rev().collect::<Vec<_>>(), [13, 12, 11]);
+ for _ in (10..0).rev() {
+ panic!("unreachable");
+ }
+}
diff --git a/library/core/tests/iter/sources.rs b/library/core/tests/iter/sources.rs
new file mode 100644
index 000000000..d0114ade6
--- /dev/null
+++ b/library/core/tests/iter/sources.rs
@@ -0,0 +1,108 @@
+use super::*;
+use core::iter::*;
+
+#[test]
+fn test_repeat() {
+ let mut it = repeat(42);
+ assert_eq!(it.next(), Some(42));
+ assert_eq!(it.next(), Some(42));
+ assert_eq!(it.next(), Some(42));
+ assert_eq!(repeat(42).size_hint(), (usize::MAX, None));
+}
+
+#[test]
+fn test_repeat_take() {
+ let mut it = repeat(42).take(3);
+ assert_eq!(it.next(), Some(42));
+ assert_eq!(it.next(), Some(42));
+ assert_eq!(it.next(), Some(42));
+ assert_eq!(it.next(), None);
+ is_trusted_len(repeat(42).take(3));
+ assert_eq!(repeat(42).take(3).size_hint(), (3, Some(3)));
+ assert_eq!(repeat(42).take(0).size_hint(), (0, Some(0)));
+ assert_eq!(repeat(42).take(usize::MAX).size_hint(), (usize::MAX, Some(usize::MAX)));
+}
+
+#[test]
+fn test_repeat_take_collect() {
+ let v: Vec<_> = repeat(42).take(3).collect();
+ assert_eq!(v, vec![42, 42, 42]);
+}
+
+#[test]
+fn test_repeat_with() {
+ #[derive(PartialEq, Debug)]
+ struct NotClone(usize);
+ let mut it = repeat_with(|| NotClone(42));
+ assert_eq!(it.next(), Some(NotClone(42)));
+ assert_eq!(it.next(), Some(NotClone(42)));
+ assert_eq!(it.next(), Some(NotClone(42)));
+ assert_eq!(repeat_with(|| NotClone(42)).size_hint(), (usize::MAX, None));
+}
+
+#[test]
+fn test_repeat_with_take() {
+ let mut it = repeat_with(|| 42).take(3);
+ assert_eq!(it.next(), Some(42));
+ assert_eq!(it.next(), Some(42));
+ assert_eq!(it.next(), Some(42));
+ assert_eq!(it.next(), None);
+ is_trusted_len(repeat_with(|| 42).take(3));
+ assert_eq!(repeat_with(|| 42).take(3).size_hint(), (3, Some(3)));
+ assert_eq!(repeat_with(|| 42).take(0).size_hint(), (0, Some(0)));
+ assert_eq!(repeat_with(|| 42).take(usize::MAX).size_hint(), (usize::MAX, Some(usize::MAX)));
+}
+
+#[test]
+fn test_repeat_with_take_collect() {
+ let mut curr = 1;
+ let v: Vec<_> = repeat_with(|| {
+ let tmp = curr;
+ curr *= 2;
+ tmp
+ })
+ .take(5)
+ .collect();
+ assert_eq!(v, vec![1, 2, 4, 8, 16]);
+}
+
+#[test]
+fn test_successors() {
+ let mut powers_of_10 = successors(Some(1_u16), |n| n.checked_mul(10));
+ assert_eq!(powers_of_10.by_ref().collect::<Vec<_>>(), &[1, 10, 100, 1_000, 10_000]);
+ assert_eq!(powers_of_10.next(), None);
+
+ let mut empty = successors(None::<u32>, |_| unimplemented!());
+ assert_eq!(empty.next(), None);
+ assert_eq!(empty.next(), None);
+}
+
+#[test]
+fn test_once() {
+ let mut it = once(42);
+ assert_eq!(it.next(), Some(42));
+ assert_eq!(it.next(), None);
+}
+
+#[test]
+fn test_once_with() {
+ let count = Cell::new(0);
+ let mut it = once_with(|| {
+ count.set(count.get() + 1);
+ 42
+ });
+
+ assert_eq!(count.get(), 0);
+ assert_eq!(it.next(), Some(42));
+ assert_eq!(count.get(), 1);
+ assert_eq!(it.next(), None);
+ assert_eq!(count.get(), 1);
+ assert_eq!(it.next(), None);
+ assert_eq!(count.get(), 1);
+}
+
+#[test]
+fn test_empty() {
+ let mut it = empty::<i32>();
+ assert_eq!(it.next(), None);
+}
diff --git a/library/core/tests/iter/traits/accum.rs b/library/core/tests/iter/traits/accum.rs
new file mode 100644
index 000000000..f3eeb31fe
--- /dev/null
+++ b/library/core/tests/iter/traits/accum.rs
@@ -0,0 +1,66 @@
+use core::iter::*;
+
+#[test]
+fn test_iterator_sum() {
+ let v: &[i32] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+ assert_eq!(v[..4].iter().cloned().sum::<i32>(), 6);
+ assert_eq!(v.iter().cloned().sum::<i32>(), 55);
+ assert_eq!(v[..0].iter().cloned().sum::<i32>(), 0);
+}
+
+#[test]
+fn test_iterator_sum_result() {
+ let v: &[Result<i32, ()>] = &[Ok(1), Ok(2), Ok(3), Ok(4)];
+ assert_eq!(v.iter().cloned().sum::<Result<i32, _>>(), Ok(10));
+ let v: &[Result<i32, ()>] = &[Ok(1), Err(()), Ok(3), Ok(4)];
+ assert_eq!(v.iter().cloned().sum::<Result<i32, _>>(), Err(()));
+
+ #[derive(PartialEq, Debug)]
+ struct S(Result<i32, ()>);
+
+ impl Sum<Result<i32, ()>> for S {
+ fn sum<I: Iterator<Item = Result<i32, ()>>>(mut iter: I) -> Self {
+ // takes the sum by repeatedly calling `next` on `iter`,
+ // thus testing that repeated calls to `ResultShunt::try_fold`
+ // produce the expected results
+ Self(iter.by_ref().sum())
+ }
+ }
+
+ let v: &[Result<i32, ()>] = &[Ok(1), Ok(2), Ok(3), Ok(4)];
+ assert_eq!(v.iter().cloned().sum::<S>(), S(Ok(10)));
+ let v: &[Result<i32, ()>] = &[Ok(1), Err(()), Ok(3), Ok(4)];
+ assert_eq!(v.iter().cloned().sum::<S>(), S(Err(())));
+}
+
+#[test]
+fn test_iterator_sum_option() {
+ let v: &[Option<i32>] = &[Some(1), Some(2), Some(3), Some(4)];
+ assert_eq!(v.iter().cloned().sum::<Option<i32>>(), Some(10));
+ let v: &[Option<i32>] = &[Some(1), None, Some(3), Some(4)];
+ assert_eq!(v.iter().cloned().sum::<Option<i32>>(), None);
+}
+
+#[test]
+fn test_iterator_product() {
+ let v: &[i32] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+ assert_eq!(v[..4].iter().cloned().product::<i32>(), 0);
+ assert_eq!(v[1..5].iter().cloned().product::<i32>(), 24);
+ assert_eq!(v[..0].iter().cloned().product::<i32>(), 1);
+}
+
+#[test]
+fn test_iterator_product_result() {
+ let v: &[Result<i32, ()>] = &[Ok(1), Ok(2), Ok(3), Ok(4)];
+ assert_eq!(v.iter().cloned().product::<Result<i32, _>>(), Ok(24));
+ let v: &[Result<i32, ()>] = &[Ok(1), Err(()), Ok(3), Ok(4)];
+ assert_eq!(v.iter().cloned().product::<Result<i32, _>>(), Err(()));
+}
+
+#[test]
+fn test_iterator_product_option() {
+ let v: &[Option<i32>] = &[Some(1), Some(2), Some(3), Some(4)];
+ assert_eq!(v.iter().cloned().product::<Option<i32>>(), Some(24));
+ let v: &[Option<i32>] = &[Some(1), None, Some(3), Some(4)];
+ assert_eq!(v.iter().cloned().product::<Option<i32>>(), None);
+}
diff --git a/library/core/tests/iter/traits/double_ended.rs b/library/core/tests/iter/traits/double_ended.rs
new file mode 100644
index 000000000..00ef4a6e6
--- /dev/null
+++ b/library/core/tests/iter/traits/double_ended.rs
@@ -0,0 +1,91 @@
+//! Note
+//! ----
+//! You're probably viewing this file because you're adding a test (or you might
+//! just be browsing, in that case, hey there!).
+//!
+//! If you've made a test that happens to use one of DoubleEnded's methods, but
+//! it tests another adapter or trait, you should *add it to the adapter or
+//! trait's test file*.
+//!
+//! Some examples would be `adapters::cloned::test_cloned_try_folds` or
+//! `adapters::flat_map::test_double_ended_flat_map`, which use `try_fold` and
+//! `next_back`, but test their own adapter.
+
+#[test]
+fn test_iterator_rev_nth_back() {
+ let v: &[_] = &[0, 1, 2, 3, 4];
+ for i in 0..v.len() {
+ assert_eq!(v.iter().rev().nth_back(i).unwrap(), &v[i]);
+ }
+ assert_eq!(v.iter().rev().nth_back(v.len()), None);
+}
+
+#[test]
+fn test_iterator_rev_nth() {
+ let v: &[_] = &[0, 1, 2, 3, 4];
+ for i in 0..v.len() {
+ assert_eq!(v.iter().rev().nth(i).unwrap(), &v[v.len() - 1 - i]);
+ }
+ assert_eq!(v.iter().rev().nth(v.len()), None);
+}
+
+#[test]
+fn test_rev() {
+ let xs = [2, 4, 6, 8, 10, 12, 14, 16];
+ let mut it = xs.iter();
+ it.next();
+ it.next();
+ assert!(it.rev().cloned().collect::<Vec<isize>>() == vec![16, 14, 12, 10, 8, 6]);
+}
+
+#[test]
+fn test_rev_try_folds() {
+ let f = &|acc, x| i32::checked_add(2 * acc, x);
+ assert_eq!((1..10).rev().try_fold(7, f), (1..10).try_rfold(7, f));
+ assert_eq!((1..10).rev().try_rfold(7, f), (1..10).try_fold(7, f));
+
+ let a = [10, 20, 30, 40, 100, 60, 70, 80, 90];
+ let mut iter = a.iter().rev();
+ assert_eq!(iter.try_fold(0_i8, |acc, &x| acc.checked_add(x)), None);
+ assert_eq!(iter.next(), Some(&70));
+ let mut iter = a.iter().rev();
+ assert_eq!(iter.try_rfold(0_i8, |acc, &x| acc.checked_add(x)), None);
+ assert_eq!(iter.next_back(), Some(&60));
+}
+
+#[test]
+fn test_rposition() {
+ fn f(xy: &(isize, char)) -> bool {
+ let (_x, y) = *xy;
+ y == 'b'
+ }
+ fn g(xy: &(isize, char)) -> bool {
+ let (_x, y) = *xy;
+ y == 'd'
+ }
+ let v = [(0, 'a'), (1, 'b'), (2, 'c'), (3, 'b')];
+
+ assert_eq!(v.iter().rposition(f), Some(3));
+ assert!(v.iter().rposition(g).is_none());
+}
+
+#[test]
+fn test_rev_rposition() {
+ let v = [0, 0, 1, 1];
+ assert_eq!(v.iter().rev().rposition(|&x| x == 1), Some(1));
+}
+
+#[test]
+#[should_panic]
+fn test_rposition_panic() {
+ let u = (Box::new(0), Box::new(0));
+ let v: [(Box<_>, Box<_>); 4] = [u.clone(), u.clone(), u.clone(), u];
+ let mut i = 0;
+ v.iter().rposition(|_elt| {
+ if i == 2 {
+ panic!()
+ }
+ i += 1;
+ false
+ });
+}
diff --git a/library/core/tests/iter/traits/iterator.rs b/library/core/tests/iter/traits/iterator.rs
new file mode 100644
index 000000000..37345c1d3
--- /dev/null
+++ b/library/core/tests/iter/traits/iterator.rs
@@ -0,0 +1,593 @@
+/// A wrapper struct that implements `Eq` and `Ord` based on the wrapped
+/// integer modulo 3. Used to test that `Iterator::max` and `Iterator::min`
+/// return the correct element if some of them are equal.
+#[derive(Debug)]
+struct Mod3(i32);
+
+impl PartialEq for Mod3 {
+ fn eq(&self, other: &Self) -> bool {
+ self.0 % 3 == other.0 % 3
+ }
+}
+
+impl Eq for Mod3 {}
+
+impl PartialOrd for Mod3 {
+ fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl Ord for Mod3 {
+ fn cmp(&self, other: &Self) -> core::cmp::Ordering {
+ (self.0 % 3).cmp(&(other.0 % 3))
+ }
+}
+
+#[test]
+fn test_lt() {
+ let empty: [isize; 0] = [];
+ let xs = [1, 2, 3];
+ let ys = [1, 2, 0];
+
+ assert!(!xs.iter().lt(ys.iter()));
+ assert!(!xs.iter().le(ys.iter()));
+ assert!(xs.iter().gt(ys.iter()));
+ assert!(xs.iter().ge(ys.iter()));
+
+ assert!(ys.iter().lt(xs.iter()));
+ assert!(ys.iter().le(xs.iter()));
+ assert!(!ys.iter().gt(xs.iter()));
+ assert!(!ys.iter().ge(xs.iter()));
+
+ assert!(empty.iter().lt(xs.iter()));
+ assert!(empty.iter().le(xs.iter()));
+ assert!(!empty.iter().gt(xs.iter()));
+ assert!(!empty.iter().ge(xs.iter()));
+
+ // Sequence with NaN
+ let u = [1.0f64, 2.0];
+ let v = [0.0f64 / 0.0, 3.0];
+
+ assert!(!u.iter().lt(v.iter()));
+ assert!(!u.iter().le(v.iter()));
+ assert!(!u.iter().gt(v.iter()));
+ assert!(!u.iter().ge(v.iter()));
+
+ let a = [0.0f64 / 0.0];
+ let b = [1.0f64];
+ let c = [2.0f64];
+
+ assert!(a.iter().lt(b.iter()) == (a[0] < b[0]));
+ assert!(a.iter().le(b.iter()) == (a[0] <= b[0]));
+ assert!(a.iter().gt(b.iter()) == (a[0] > b[0]));
+ assert!(a.iter().ge(b.iter()) == (a[0] >= b[0]));
+
+ assert!(c.iter().lt(b.iter()) == (c[0] < b[0]));
+ assert!(c.iter().le(b.iter()) == (c[0] <= b[0]));
+ assert!(c.iter().gt(b.iter()) == (c[0] > b[0]));
+ assert!(c.iter().ge(b.iter()) == (c[0] >= b[0]));
+}
+
+#[test]
+fn test_cmp_by() {
+ use core::cmp::Ordering;
+
+ let f = |x: i32, y: i32| (x * x).cmp(&y);
+ let xs = || [1, 2, 3, 4].iter().copied();
+ let ys = || [1, 4, 16].iter().copied();
+
+ assert_eq!(xs().cmp_by(ys(), f), Ordering::Less);
+ assert_eq!(ys().cmp_by(xs(), f), Ordering::Greater);
+ assert_eq!(xs().cmp_by(xs().map(|x| x * x), f), Ordering::Equal);
+ assert_eq!(xs().rev().cmp_by(ys().rev(), f), Ordering::Greater);
+ assert_eq!(xs().cmp_by(ys().rev(), f), Ordering::Less);
+ assert_eq!(xs().cmp_by(ys().take(2), f), Ordering::Greater);
+}
+
+#[test]
+fn test_partial_cmp_by() {
+ use core::cmp::Ordering;
+
+ let f = |x: i32, y: i32| (x * x).partial_cmp(&y);
+ let xs = || [1, 2, 3, 4].iter().copied();
+ let ys = || [1, 4, 16].iter().copied();
+
+ assert_eq!(xs().partial_cmp_by(ys(), f), Some(Ordering::Less));
+ assert_eq!(ys().partial_cmp_by(xs(), f), Some(Ordering::Greater));
+ assert_eq!(xs().partial_cmp_by(xs().map(|x| x * x), f), Some(Ordering::Equal));
+ assert_eq!(xs().rev().partial_cmp_by(ys().rev(), f), Some(Ordering::Greater));
+ assert_eq!(xs().partial_cmp_by(xs().rev(), f), Some(Ordering::Less));
+ assert_eq!(xs().partial_cmp_by(ys().take(2), f), Some(Ordering::Greater));
+
+ let f = |x: f64, y: f64| (x * x).partial_cmp(&y);
+ let xs = || [1.0, 2.0, 3.0, 4.0].iter().copied();
+ let ys = || [1.0, 4.0, f64::NAN, 16.0].iter().copied();
+
+ assert_eq!(xs().partial_cmp_by(ys(), f), None);
+ assert_eq!(ys().partial_cmp_by(xs(), f), Some(Ordering::Greater));
+}
+
+#[test]
+fn test_eq_by() {
+ let f = |x: i32, y: i32| x * x == y;
+ let xs = || [1, 2, 3, 4].iter().copied();
+ let ys = || [1, 4, 9, 16].iter().copied();
+
+ assert!(xs().eq_by(ys(), f));
+ assert!(!ys().eq_by(xs(), f));
+ assert!(!xs().eq_by(xs(), f));
+ assert!(!ys().eq_by(ys(), f));
+
+ assert!(!xs().take(3).eq_by(ys(), f));
+ assert!(!xs().eq_by(ys().take(3), f));
+ assert!(xs().take(3).eq_by(ys().take(3), f));
+}
+
+#[test]
+fn test_iterator_nth() {
+ let v: &[_] = &[0, 1, 2, 3, 4];
+ for i in 0..v.len() {
+ assert_eq!(v.iter().nth(i).unwrap(), &v[i]);
+ }
+ assert_eq!(v.iter().nth(v.len()), None);
+}
+
+#[test]
+fn test_iterator_nth_back() {
+ let v: &[_] = &[0, 1, 2, 3, 4];
+ for i in 0..v.len() {
+ assert_eq!(v.iter().nth_back(i).unwrap(), &v[v.len() - 1 - i]);
+ }
+ assert_eq!(v.iter().nth_back(v.len()), None);
+}
+
+#[test]
+fn test_iterator_advance_by() {
+ let v: &[_] = &[0, 1, 2, 3, 4];
+
+ for i in 0..v.len() {
+ let mut iter = v.iter();
+ assert_eq!(iter.advance_by(i), Ok(()));
+ assert_eq!(iter.next().unwrap(), &v[i]);
+ assert_eq!(iter.advance_by(100), Err(v.len() - 1 - i));
+ }
+
+ assert_eq!(v.iter().advance_by(v.len()), Ok(()));
+ assert_eq!(v.iter().advance_by(100), Err(v.len()));
+}
+
+#[test]
+fn test_iterator_advance_back_by() {
+ let v: &[_] = &[0, 1, 2, 3, 4];
+
+ for i in 0..v.len() {
+ let mut iter = v.iter();
+ assert_eq!(iter.advance_back_by(i), Ok(()));
+ assert_eq!(iter.next_back().unwrap(), &v[v.len() - 1 - i]);
+ assert_eq!(iter.advance_back_by(100), Err(v.len() - 1 - i));
+ }
+
+ assert_eq!(v.iter().advance_back_by(v.len()), Ok(()));
+ assert_eq!(v.iter().advance_back_by(100), Err(v.len()));
+}
+
+#[test]
+fn test_iterator_rev_advance_back_by() {
+ let v: &[_] = &[0, 1, 2, 3, 4];
+
+ for i in 0..v.len() {
+ let mut iter = v.iter().rev();
+ assert_eq!(iter.advance_back_by(i), Ok(()));
+ assert_eq!(iter.next_back().unwrap(), &v[i]);
+ assert_eq!(iter.advance_back_by(100), Err(v.len() - 1 - i));
+ }
+
+ assert_eq!(v.iter().rev().advance_back_by(v.len()), Ok(()));
+ assert_eq!(v.iter().rev().advance_back_by(100), Err(v.len()));
+}
+
+#[test]
+fn test_iterator_last() {
+ let v: &[_] = &[0, 1, 2, 3, 4];
+ assert_eq!(v.iter().last().unwrap(), &4);
+ assert_eq!(v[..1].iter().last().unwrap(), &0);
+}
+
+#[test]
+fn test_iterator_max() {
+ let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+ assert_eq!(v[..4].iter().cloned().max(), Some(3));
+ assert_eq!(v.iter().cloned().max(), Some(10));
+ assert_eq!(v[..0].iter().cloned().max(), None);
+ assert_eq!(v.iter().cloned().map(Mod3).max().map(|x| x.0), Some(8));
+}
+
+#[test]
+fn test_iterator_min() {
+ let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+ assert_eq!(v[..4].iter().cloned().min(), Some(0));
+ assert_eq!(v.iter().cloned().min(), Some(0));
+ assert_eq!(v[..0].iter().cloned().min(), None);
+ assert_eq!(v.iter().cloned().map(Mod3).min().map(|x| x.0), Some(0));
+}
+
+#[test]
+fn test_iterator_size_hint() {
+ let c = (0..).step_by(1);
+ let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
+ let v2 = &[10, 11, 12];
+ let vi = v.iter();
+
+ assert_eq!((0..).size_hint(), (usize::MAX, None));
+ assert_eq!(c.size_hint(), (usize::MAX, None));
+ assert_eq!(vi.clone().size_hint(), (10, Some(10)));
+
+ assert_eq!(c.clone().take(5).size_hint(), (5, Some(5)));
+ assert_eq!(c.clone().skip(5).size_hint().1, None);
+ assert_eq!(c.clone().take_while(|_| false).size_hint(), (0, None));
+ assert_eq!(c.clone().map_while(|_| None::<()>).size_hint(), (0, None));
+ assert_eq!(c.clone().skip_while(|_| false).size_hint(), (0, None));
+ assert_eq!(c.clone().enumerate().size_hint(), (usize::MAX, None));
+ assert_eq!(c.clone().chain(vi.clone().cloned()).size_hint(), (usize::MAX, None));
+ assert_eq!(c.clone().zip(vi.clone()).size_hint(), (10, Some(10)));
+ assert_eq!(c.clone().scan(0, |_, _| Some(0)).size_hint(), (0, None));
+ assert_eq!(c.clone().filter(|_| false).size_hint(), (0, None));
+ assert_eq!(c.clone().map(|_| 0).size_hint(), (usize::MAX, None));
+ assert_eq!(c.filter_map(|_| Some(0)).size_hint(), (0, None));
+
+ assert_eq!(vi.clone().take(5).size_hint(), (5, Some(5)));
+ assert_eq!(vi.clone().take(12).size_hint(), (10, Some(10)));
+ assert_eq!(vi.clone().skip(3).size_hint(), (7, Some(7)));
+ assert_eq!(vi.clone().skip(12).size_hint(), (0, Some(0)));
+ assert_eq!(vi.clone().take_while(|_| false).size_hint(), (0, Some(10)));
+ assert_eq!(vi.clone().map_while(|_| None::<()>).size_hint(), (0, Some(10)));
+ assert_eq!(vi.clone().skip_while(|_| false).size_hint(), (0, Some(10)));
+ assert_eq!(vi.clone().enumerate().size_hint(), (10, Some(10)));
+ assert_eq!(vi.clone().chain(v2).size_hint(), (13, Some(13)));
+ assert_eq!(vi.clone().zip(v2).size_hint(), (3, Some(3)));
+ assert_eq!(vi.clone().scan(0, |_, _| Some(0)).size_hint(), (0, Some(10)));
+ assert_eq!(vi.clone().filter(|_| false).size_hint(), (0, Some(10)));
+ assert_eq!(vi.clone().map(|&i| i + 1).size_hint(), (10, Some(10)));
+ assert_eq!(vi.filter_map(|_| Some(0)).size_hint(), (0, Some(10)));
+}
+
+#[test]
+fn test_all() {
+ let v: Box<[isize]> = Box::new([1, 2, 3, 4, 5]);
+ assert!(v.iter().all(|&x| x < 10));
+ assert!(!v.iter().all(|&x| x % 2 == 0));
+ assert!(!v.iter().all(|&x| x > 100));
+ assert!(v[..0].iter().all(|_| panic!()));
+}
+
+#[test]
+fn test_any() {
+ let v: Box<[isize]> = Box::new([1, 2, 3, 4, 5]);
+ assert!(v.iter().any(|&x| x < 10));
+ assert!(v.iter().any(|&x| x % 2 == 0));
+ assert!(!v.iter().any(|&x| x > 100));
+ assert!(!v[..0].iter().any(|_| panic!()));
+}
+
+#[test]
+fn test_find() {
+ let v: &[isize] = &[1, 3, 9, 27, 103, 14, 11];
+ assert_eq!(*v.iter().find(|&&x| x & 1 == 0).unwrap(), 14);
+ assert_eq!(*v.iter().find(|&&x| x % 3 == 0).unwrap(), 3);
+ assert!(v.iter().find(|&&x| x % 12 == 0).is_none());
+}
+
+#[test]
+fn test_try_find() {
+ let xs: &[isize] = &[];
+ assert_eq!(xs.iter().try_find(testfn), Ok(None));
+ let xs: &[isize] = &[1, 2, 3, 4];
+ assert_eq!(xs.iter().try_find(testfn), Ok(Some(&2)));
+ let xs: &[isize] = &[1, 3, 4];
+ assert_eq!(xs.iter().try_find(testfn), Err(()));
+
+ let xs: &[isize] = &[1, 2, 3, 4, 5, 6, 7];
+ let mut iter = xs.iter();
+ assert_eq!(iter.try_find(testfn), Ok(Some(&2)));
+ assert_eq!(iter.try_find(testfn), Err(()));
+ assert_eq!(iter.next(), Some(&5));
+
+ fn testfn(x: &&isize) -> Result<bool, ()> {
+ if **x == 2 {
+ return Ok(true);
+ }
+ if **x == 4 {
+ return Err(());
+ }
+ Ok(false)
+ }
+}
+
+#[test]
+fn test_try_find_api_usability() -> Result<(), Box<dyn std::error::Error>> {
+ let a = ["1", "2"];
+
+ let is_my_num = |s: &str, search: i32| -> Result<bool, std::num::ParseIntError> {
+ Ok(s.parse::<i32>()? == search)
+ };
+
+ let val = a.iter().try_find(|&&s| is_my_num(s, 2))?;
+ assert_eq!(val, Some(&"2"));
+
+ Ok(())
+}
+
+#[test]
+fn test_position() {
+ let v = &[1, 3, 9, 27, 103, 14, 11];
+ assert_eq!(v.iter().position(|x| *x & 1 == 0).unwrap(), 5);
+ assert_eq!(v.iter().position(|x| *x % 3 == 0).unwrap(), 1);
+ assert!(v.iter().position(|x| *x % 12 == 0).is_none());
+}
+
+#[test]
+fn test_count() {
+ let xs = &[1, 2, 2, 1, 5, 9, 0, 2];
+ assert_eq!(xs.iter().filter(|x| **x == 2).count(), 3);
+ assert_eq!(xs.iter().filter(|x| **x == 5).count(), 1);
+ assert_eq!(xs.iter().filter(|x| **x == 95).count(), 0);
+}
+
+#[test]
+fn test_max_by_key() {
+ let xs: &[isize] = &[-3, 0, 1, 5, -10];
+ assert_eq!(*xs.iter().max_by_key(|x| x.abs()).unwrap(), -10);
+}
+
+#[test]
+fn test_max_by() {
+ let xs: &[isize] = &[-3, 0, 1, 5, -10];
+ assert_eq!(*xs.iter().max_by(|x, y| x.abs().cmp(&y.abs())).unwrap(), -10);
+}
+
+#[test]
+fn test_min_by_key() {
+ let xs: &[isize] = &[-3, 0, 1, 5, -10];
+ assert_eq!(*xs.iter().min_by_key(|x| x.abs()).unwrap(), 0);
+}
+
+#[test]
+fn test_min_by() {
+ let xs: &[isize] = &[-3, 0, 1, 5, -10];
+ assert_eq!(*xs.iter().min_by(|x, y| x.abs().cmp(&y.abs())).unwrap(), 0);
+}
+
+#[test]
+fn test_by_ref() {
+ let mut xs = 0..10;
+ // sum the first five values
+ let partial_sum = xs.by_ref().take(5).fold(0, |a, b| a + b);
+ assert_eq!(partial_sum, 10);
+ assert_eq!(xs.next(), Some(5));
+}
+
+#[test]
+fn test_is_sorted() {
+ assert!([1, 2, 2, 9].iter().is_sorted());
+ assert!(![1, 3, 2].iter().is_sorted());
+ assert!([0].iter().is_sorted());
+ assert!(std::iter::empty::<i32>().is_sorted());
+ assert!(![0.0, 1.0, f32::NAN].iter().is_sorted());
+ assert!([-2, -1, 0, 3].iter().is_sorted());
+ assert!(![-2i32, -1, 0, 3].iter().is_sorted_by_key(|n| n.abs()));
+ assert!(!["c", "bb", "aaa"].iter().is_sorted());
+ assert!(["c", "bb", "aaa"].iter().is_sorted_by_key(|s| s.len()));
+}
+
+#[test]
+fn test_partition() {
+ fn check(xs: &mut [i32], ref p: impl Fn(&i32) -> bool, expected: usize) {
+ let i = xs.iter_mut().partition_in_place(p);
+ assert_eq!(expected, i);
+ assert!(xs[..i].iter().all(p));
+ assert!(!xs[i..].iter().any(p));
+ assert!(xs.iter().is_partitioned(p));
+ if i == 0 || i == xs.len() {
+ assert!(xs.iter().rev().is_partitioned(p));
+ } else {
+ assert!(!xs.iter().rev().is_partitioned(p));
+ }
+ }
+
+ check(&mut [], |_| true, 0);
+ check(&mut [], |_| false, 0);
+
+ check(&mut [0], |_| true, 1);
+ check(&mut [0], |_| false, 0);
+
+ check(&mut [-1, 1], |&x| x > 0, 1);
+ check(&mut [-1, 1], |&x| x < 0, 1);
+
+ let ref mut xs = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
+ check(xs, |_| true, 10);
+ check(xs, |_| false, 0);
+ check(xs, |&x| x % 2 == 0, 5); // evens
+ check(xs, |&x| x % 2 == 1, 5); // odds
+ check(xs, |&x| x % 3 == 0, 4); // multiple of 3
+ check(xs, |&x| x % 4 == 0, 3); // multiple of 4
+ check(xs, |&x| x % 5 == 0, 2); // multiple of 5
+ check(xs, |&x| x < 3, 3); // small
+ check(xs, |&x| x > 6, 3); // large
+}
+
+#[test]
+fn test_iterator_rev_advance_by() {
+ let v: &[_] = &[0, 1, 2, 3, 4];
+
+ for i in 0..v.len() {
+ let mut iter = v.iter().rev();
+ assert_eq!(iter.advance_by(i), Ok(()));
+ assert_eq!(iter.next().unwrap(), &v[v.len() - 1 - i]);
+ assert_eq!(iter.advance_by(100), Err(v.len() - 1 - i));
+ }
+
+ assert_eq!(v.iter().rev().advance_by(v.len()), Ok(()));
+ assert_eq!(v.iter().rev().advance_by(100), Err(v.len()));
+}
+
+#[test]
+fn test_find_map() {
+ let xs: &[isize] = &[];
+ assert_eq!(xs.iter().find_map(half_if_even), None);
+ let xs: &[isize] = &[3, 5];
+ assert_eq!(xs.iter().find_map(half_if_even), None);
+ let xs: &[isize] = &[4, 5];
+ assert_eq!(xs.iter().find_map(half_if_even), Some(2));
+ let xs: &[isize] = &[3, 6];
+ assert_eq!(xs.iter().find_map(half_if_even), Some(3));
+
+ let xs: &[isize] = &[1, 2, 3, 4, 5, 6, 7];
+ let mut iter = xs.iter();
+ assert_eq!(iter.find_map(half_if_even), Some(1));
+ assert_eq!(iter.find_map(half_if_even), Some(2));
+ assert_eq!(iter.find_map(half_if_even), Some(3));
+ assert_eq!(iter.next(), Some(&7));
+
+ fn half_if_even(x: &isize) -> Option<isize> {
+ if x % 2 == 0 { Some(x / 2) } else { None }
+ }
+}
+
+#[test]
+fn test_try_reduce() {
+ let v = [1usize, 2, 3, 4, 5];
+ let sum = v.into_iter().try_reduce(|x, y| x.checked_add(y));
+ assert_eq!(sum, Some(Some(15)));
+
+ let v = [1, 2, 3, 4, 5, usize::MAX];
+ let sum = v.into_iter().try_reduce(|x, y| x.checked_add(y));
+ assert_eq!(sum, None);
+
+ let v: [usize; 0] = [];
+ let sum = v.into_iter().try_reduce(|x, y| x.checked_add(y));
+ assert_eq!(sum, Some(None));
+
+ let v = ["1", "2", "3", "4", "5"];
+ let max = v.into_iter().try_reduce(|x, y| {
+ if x.parse::<usize>().ok()? > y.parse::<usize>().ok()? { Some(x) } else { Some(y) }
+ });
+ assert_eq!(max, Some(Some("5")));
+
+ let v = ["1", "2", "3", "4", "5"];
+ let max: Result<Option<_>, <usize as std::str::FromStr>::Err> =
+ v.into_iter().try_reduce(|x, y| {
+ if x.parse::<usize>()? > y.parse::<usize>()? { Ok(x) } else { Ok(y) }
+ });
+ assert_eq!(max, Ok(Some("5")));
+}
+
+#[test]
+fn test_iterator_len() {
+ let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+ assert_eq!(v[..4].iter().count(), 4);
+ assert_eq!(v[..10].iter().count(), 10);
+ assert_eq!(v[..0].iter().count(), 0);
+}
+
+#[test]
+fn test_collect() {
+ let a = vec![1, 2, 3, 4, 5];
+ let b: Vec<isize> = a.iter().cloned().collect();
+ assert!(a == b);
+}
+
+#[test]
+fn test_try_collect() {
+ use core::ops::ControlFlow::{Break, Continue};
+
+ let u = vec![Some(1), Some(2), Some(3)];
+ let v = u.into_iter().try_collect::<Vec<i32>>();
+ assert_eq!(v, Some(vec![1, 2, 3]));
+
+ let u = vec![Some(1), Some(2), None, Some(3)];
+ let mut it = u.into_iter();
+ let v = it.try_collect::<Vec<i32>>();
+ assert_eq!(v, None);
+ let v = it.try_collect::<Vec<i32>>();
+ assert_eq!(v, Some(vec![3]));
+
+ let u: Vec<Result<i32, ()>> = vec![Ok(1), Ok(2), Ok(3)];
+ let v = u.into_iter().try_collect::<Vec<i32>>();
+ assert_eq!(v, Ok(vec![1, 2, 3]));
+
+ let u = vec![Ok(1), Ok(2), Err(()), Ok(3)];
+ let v = u.into_iter().try_collect::<Vec<i32>>();
+ assert_eq!(v, Err(()));
+
+ let numbers = vec![1, 2, 3, 4, 5];
+ let all_positive = numbers
+ .iter()
+ .cloned()
+ .map(|n| if n > 0 { Some(n) } else { None })
+ .try_collect::<Vec<i32>>();
+ assert_eq!(all_positive, Some(numbers));
+
+ let numbers = vec![-2, -1, 0, 1, 2];
+ let all_positive =
+ numbers.into_iter().map(|n| if n > 0 { Some(n) } else { None }).try_collect::<Vec<i32>>();
+ assert_eq!(all_positive, None);
+
+ let u = [Continue(1), Continue(2), Break(3), Continue(4), Continue(5)];
+ let mut it = u.into_iter();
+
+ let v = it.try_collect::<Vec<_>>();
+ assert_eq!(v, Break(3));
+
+ let v = it.try_collect::<Vec<_>>();
+ assert_eq!(v, Continue(vec![4, 5]));
+}
+
+#[test]
+fn test_collect_into() {
+ let a = vec![1, 2, 3, 4, 5];
+ let mut b = Vec::new();
+ a.iter().cloned().collect_into(&mut b);
+ assert!(a == b);
+}
+
+#[test]
+fn iter_try_collect_uses_try_fold_not_next() {
+ // This makes sure it picks up optimizations, and doesn't use the `&mut I` impl.
+ struct PanicOnNext<I>(I);
+ impl<I: Iterator> Iterator for PanicOnNext<I> {
+ type Item = I::Item;
+ fn next(&mut self) -> Option<Self::Item> {
+ panic!("Iterator::next should not be called!")
+ }
+ fn try_fold<B, F, R>(&mut self, init: B, f: F) -> R
+ where
+ Self: Sized,
+ F: FnMut(B, Self::Item) -> R,
+ R: std::ops::Try<Output = B>,
+ {
+ self.0.try_fold(init, f)
+ }
+ }
+
+ let it = (0..10).map(Some);
+ let _ = PanicOnNext(it).try_collect::<Vec<_>>();
+ // validation is just that it didn't panic.
+}
+
+#[test]
+fn test_next_chunk() {
+ let mut it = 0..12;
+ assert_eq!(it.next_chunk().unwrap(), [0, 1, 2, 3]);
+ assert_eq!(it.next_chunk().unwrap(), []);
+ assert_eq!(it.next_chunk().unwrap(), [4, 5, 6, 7, 8, 9]);
+ assert_eq!(it.next_chunk::<4>().unwrap_err().as_slice(), &[10, 11]);
+}
+
+// just tests by whether or not this compiles
+fn _empty_impl_all_auto_traits<T>() {
+ use std::panic::{RefUnwindSafe, UnwindSafe};
+ fn all_auto_traits<T: Send + Sync + Unpin + UnwindSafe + RefUnwindSafe>() {}
+
+ all_auto_traits::<std::iter::Empty<T>>();
+}
diff --git a/library/core/tests/iter/traits/mod.rs b/library/core/tests/iter/traits/mod.rs
new file mode 100644
index 000000000..80619f53f
--- /dev/null
+++ b/library/core/tests/iter/traits/mod.rs
@@ -0,0 +1,4 @@
+mod accum;
+mod double_ended;
+mod iterator;
+mod step;
diff --git a/library/core/tests/iter/traits/step.rs b/library/core/tests/iter/traits/step.rs
new file mode 100644
index 000000000..3d82a40cd
--- /dev/null
+++ b/library/core/tests/iter/traits/step.rs
@@ -0,0 +1,89 @@
+use core::iter::*;
+
+#[test]
+fn test_steps_between() {
+ assert_eq!(Step::steps_between(&20_u8, &200_u8), Some(180_usize));
+ assert_eq!(Step::steps_between(&-20_i8, &80_i8), Some(100_usize));
+ assert_eq!(Step::steps_between(&-120_i8, &80_i8), Some(200_usize));
+ assert_eq!(Step::steps_between(&20_u32, &4_000_100_u32), Some(4_000_080_usize));
+ assert_eq!(Step::steps_between(&-20_i32, &80_i32), Some(100_usize));
+ assert_eq!(Step::steps_between(&-2_000_030_i32, &2_000_050_i32), Some(4_000_080_usize));
+
+ // Skip u64/i64 to avoid differences with 32-bit vs 64-bit platforms
+
+ assert_eq!(Step::steps_between(&20_u128, &200_u128), Some(180_usize));
+ assert_eq!(Step::steps_between(&-20_i128, &80_i128), Some(100_usize));
+ if cfg!(target_pointer_width = "64") {
+ assert_eq!(Step::steps_between(&10_u128, &0x1_0000_0000_0000_0009_u128), Some(usize::MAX));
+ }
+ assert_eq!(Step::steps_between(&10_u128, &0x1_0000_0000_0000_000a_u128), None);
+ assert_eq!(Step::steps_between(&10_i128, &0x1_0000_0000_0000_000a_i128), None);
+ assert_eq!(
+ Step::steps_between(&-0x1_0000_0000_0000_0000_i128, &0x1_0000_0000_0000_0000_i128,),
+ None,
+ );
+}
+
+#[test]
+fn test_step_forward() {
+ assert_eq!(Step::forward_checked(55_u8, 200_usize), Some(255_u8));
+ assert_eq!(Step::forward_checked(252_u8, 200_usize), None);
+ assert_eq!(Step::forward_checked(0_u8, 256_usize), None);
+ assert_eq!(Step::forward_checked(-110_i8, 200_usize), Some(90_i8));
+ assert_eq!(Step::forward_checked(-110_i8, 248_usize), None);
+ assert_eq!(Step::forward_checked(-126_i8, 256_usize), None);
+
+ assert_eq!(Step::forward_checked(35_u16, 100_usize), Some(135_u16));
+ assert_eq!(Step::forward_checked(35_u16, 65500_usize), Some(u16::MAX));
+ assert_eq!(Step::forward_checked(36_u16, 65500_usize), None);
+ assert_eq!(Step::forward_checked(-110_i16, 200_usize), Some(90_i16));
+ assert_eq!(Step::forward_checked(-20_030_i16, 50_050_usize), Some(30_020_i16));
+ assert_eq!(Step::forward_checked(-10_i16, 40_000_usize), None);
+ assert_eq!(Step::forward_checked(-10_i16, 70_000_usize), None);
+
+ assert_eq!(Step::forward_checked(10_u128, 70_000_usize), Some(70_010_u128));
+ assert_eq!(Step::forward_checked(10_i128, 70_030_usize), Some(70_040_i128));
+ assert_eq!(
+ Step::forward_checked(0xffff_ffff_ffff_ffff__ffff_ffff_ffff_ff00_u128, 0xff_usize),
+ Some(u128::MAX),
+ );
+ assert_eq!(
+ Step::forward_checked(0xffff_ffff_ffff_ffff__ffff_ffff_ffff_ff00_u128, 0x100_usize),
+ None
+ );
+ assert_eq!(
+ Step::forward_checked(0x7fff_ffff_ffff_ffff__ffff_ffff_ffff_ff00_i128, 0xff_usize),
+ Some(i128::MAX),
+ );
+ assert_eq!(
+ Step::forward_checked(0x7fff_ffff_ffff_ffff__ffff_ffff_ffff_ff00_i128, 0x100_usize),
+ None
+ );
+}
+
+#[test]
+fn test_step_backward() {
+ assert_eq!(Step::backward_checked(255_u8, 200_usize), Some(55_u8));
+ assert_eq!(Step::backward_checked(100_u8, 200_usize), None);
+ assert_eq!(Step::backward_checked(255_u8, 256_usize), None);
+ assert_eq!(Step::backward_checked(90_i8, 200_usize), Some(-110_i8));
+ assert_eq!(Step::backward_checked(110_i8, 248_usize), None);
+ assert_eq!(Step::backward_checked(127_i8, 256_usize), None);
+
+ assert_eq!(Step::backward_checked(135_u16, 100_usize), Some(35_u16));
+ assert_eq!(Step::backward_checked(u16::MAX, 65500_usize), Some(35_u16));
+ assert_eq!(Step::backward_checked(10_u16, 11_usize), None);
+ assert_eq!(Step::backward_checked(90_i16, 200_usize), Some(-110_i16));
+ assert_eq!(Step::backward_checked(30_020_i16, 50_050_usize), Some(-20_030_i16));
+ assert_eq!(Step::backward_checked(-10_i16, 40_000_usize), None);
+ assert_eq!(Step::backward_checked(-10_i16, 70_000_usize), None);
+
+ assert_eq!(Step::backward_checked(70_010_u128, 70_000_usize), Some(10_u128));
+ assert_eq!(Step::backward_checked(70_020_i128, 70_030_usize), Some(-10_i128));
+ assert_eq!(Step::backward_checked(10_u128, 7_usize), Some(3_u128));
+ assert_eq!(Step::backward_checked(10_u128, 11_usize), None);
+ assert_eq!(
+ Step::backward_checked(-0x7fff_ffff_ffff_ffff__ffff_ffff_ffff_ff00_i128, 0x100_usize),
+ Some(i128::MIN)
+ );
+}
diff --git a/library/core/tests/lazy.rs b/library/core/tests/lazy.rs
new file mode 100644
index 000000000..70fcc6d2d
--- /dev/null
+++ b/library/core/tests/lazy.rs
@@ -0,0 +1,138 @@
+use core::{
+ cell::{Cell, LazyCell, OnceCell},
+ sync::atomic::{AtomicUsize, Ordering::SeqCst},
+};
+
+#[test]
+fn once_cell() {
+ let c = OnceCell::new();
+ assert!(c.get().is_none());
+ c.get_or_init(|| 92);
+ assert_eq!(c.get(), Some(&92));
+
+ c.get_or_init(|| panic!("Kabom!"));
+ assert_eq!(c.get(), Some(&92));
+}
+
+#[test]
+fn once_cell_get_mut() {
+ let mut c = OnceCell::new();
+ assert!(c.get_mut().is_none());
+ c.set(90).unwrap();
+ *c.get_mut().unwrap() += 2;
+ assert_eq!(c.get_mut(), Some(&mut 92));
+}
+
+#[test]
+fn once_cell_drop() {
+ static DROP_CNT: AtomicUsize = AtomicUsize::new(0);
+ struct Dropper;
+ impl Drop for Dropper {
+ fn drop(&mut self) {
+ DROP_CNT.fetch_add(1, SeqCst);
+ }
+ }
+
+ let x = OnceCell::new();
+ x.get_or_init(|| Dropper);
+ assert_eq!(DROP_CNT.load(SeqCst), 0);
+ drop(x);
+ assert_eq!(DROP_CNT.load(SeqCst), 1);
+}
+
+#[test]
+fn unsync_once_cell_drop_empty() {
+ let x = OnceCell::<&'static str>::new();
+ drop(x);
+}
+
+#[test]
+const fn once_cell_const() {
+ let _once_cell: OnceCell<u32> = OnceCell::new();
+ let _once_cell: OnceCell<u32> = OnceCell::from(32);
+}
+
+#[test]
+fn clone() {
+ let s = OnceCell::new();
+ let c = s.clone();
+ assert!(c.get().is_none());
+
+ s.set("hello").unwrap();
+ let c = s.clone();
+ assert_eq!(c.get().map(|c| *c), Some("hello"));
+}
+
+#[test]
+fn from_impl() {
+ assert_eq!(OnceCell::from("value").get(), Some(&"value"));
+ assert_ne!(OnceCell::from("foo").get(), Some(&"bar"));
+}
+
+#[test]
+fn partialeq_impl() {
+ assert!(OnceCell::from("value") == OnceCell::from("value"));
+ assert!(OnceCell::from("foo") != OnceCell::from("bar"));
+
+ assert!(OnceCell::<&'static str>::new() == OnceCell::new());
+ assert!(OnceCell::<&'static str>::new() != OnceCell::from("value"));
+}
+
+#[test]
+fn into_inner() {
+ let cell: OnceCell<&'static str> = OnceCell::new();
+ assert_eq!(cell.into_inner(), None);
+ let cell = OnceCell::new();
+ cell.set("hello").unwrap();
+ assert_eq!(cell.into_inner(), Some("hello"));
+}
+
+#[test]
+fn lazy_new() {
+ let called = Cell::new(0);
+ let x = LazyCell::new(|| {
+ called.set(called.get() + 1);
+ 92
+ });
+
+ assert_eq!(called.get(), 0);
+
+ let y = *x - 30;
+ assert_eq!(y, 62);
+ assert_eq!(called.get(), 1);
+
+ let y = *x - 30;
+ assert_eq!(y, 62);
+ assert_eq!(called.get(), 1);
+}
+
+#[test]
+fn aliasing_in_get() {
+ let x = OnceCell::new();
+ x.set(42).unwrap();
+ let at_x = x.get().unwrap(); // --- (shared) borrow of inner `Option<T>` --+
+ let _ = x.set(27); // <-- temporary (unique) borrow of inner `Option<T>` |
+ println!("{at_x}"); // <------- up until here ---------------------------+
+}
+
+#[test]
+#[should_panic(expected = "reentrant init")]
+fn reentrant_init() {
+ let x: OnceCell<Box<i32>> = OnceCell::new();
+ let dangling_ref: Cell<Option<&i32>> = Cell::new(None);
+ x.get_or_init(|| {
+ let r = x.get_or_init(|| Box::new(92));
+ dangling_ref.set(Some(r));
+ Box::new(62)
+ });
+ eprintln!("use after free: {:?}", dangling_ref.get().unwrap());
+}
+
+#[test]
+fn dropck() {
+ let cell = OnceCell::new();
+ {
+ let s = String::new();
+ cell.set(&s).unwrap();
+ }
+}
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
new file mode 100644
index 000000000..db94368f6
--- /dev/null
+++ b/library/core/tests/lib.rs
@@ -0,0 +1,142 @@
+#![feature(alloc_layout_extra)]
+#![feature(array_chunks)]
+#![feature(array_methods)]
+#![feature(array_windows)]
+#![feature(bench_black_box)]
+#![feature(cell_update)]
+#![feature(const_assume)]
+#![feature(const_black_box)]
+#![feature(const_bool_to_option)]
+#![feature(const_cell_into_inner)]
+#![feature(const_convert)]
+#![feature(const_heap)]
+#![feature(const_maybe_uninit_as_mut_ptr)]
+#![feature(const_maybe_uninit_assume_init_read)]
+#![feature(const_nonnull_new)]
+#![feature(const_num_from_num)]
+#![feature(const_ptr_as_ref)]
+#![feature(const_ptr_read)]
+#![feature(const_ptr_write)]
+#![feature(const_trait_impl)]
+#![feature(const_likely)]
+#![feature(core_intrinsics)]
+#![feature(core_private_bignum)]
+#![feature(core_private_diy_float)]
+#![feature(dec2flt)]
+#![feature(div_duration)]
+#![feature(duration_consts_float)]
+#![feature(duration_constants)]
+#![feature(exact_size_is_empty)]
+#![feature(extern_types)]
+#![feature(flt2dec)]
+#![feature(fmt_internals)]
+#![feature(float_minimum_maximum)]
+#![feature(future_join)]
+#![feature(generic_assert_internals)]
+#![feature(array_try_from_fn)]
+#![feature(hasher_prefixfree_extras)]
+#![feature(hashmap_internals)]
+#![feature(try_find)]
+#![feature(inline_const)]
+#![feature(is_sorted)]
+#![feature(pattern)]
+#![feature(pin_macro)]
+#![feature(sort_internals)]
+#![feature(slice_take)]
+#![feature(slice_from_ptr_range)]
+#![feature(split_as_slice)]
+#![feature(maybe_uninit_uninit_array)]
+#![feature(maybe_uninit_array_assume_init)]
+#![feature(maybe_uninit_write_slice)]
+#![feature(min_specialization)]
+#![feature(numfmt)]
+#![feature(step_trait)]
+#![feature(str_internals)]
+#![feature(std_internals)]
+#![feature(test)]
+#![feature(trusted_len)]
+#![feature(try_blocks)]
+#![feature(try_trait_v2)]
+#![feature(slice_internals)]
+#![feature(slice_partition_dedup)]
+#![feature(int_log)]
+#![feature(iter_advance_by)]
+#![feature(iter_collect_into)]
+#![feature(iter_partition_in_place)]
+#![feature(iter_intersperse)]
+#![feature(iter_is_partitioned)]
+#![feature(iter_next_chunk)]
+#![feature(iter_order_by)]
+#![feature(iterator_try_collect)]
+#![feature(iterator_try_reduce)]
+#![feature(const_mut_refs)]
+#![feature(const_pin)]
+#![feature(never_type)]
+#![feature(unwrap_infallible)]
+#![feature(result_into_ok_or_err)]
+#![feature(portable_simd)]
+#![feature(ptr_metadata)]
+#![feature(once_cell)]
+#![feature(option_result_contains)]
+#![feature(unsized_tuple_coercion)]
+#![feature(const_option)]
+#![feature(const_option_ext)]
+#![feature(const_result)]
+#![feature(integer_atomics)]
+#![feature(int_roundings)]
+#![feature(slice_group_by)]
+#![feature(split_array)]
+#![feature(strict_provenance)]
+#![feature(strict_provenance_atomic_ptr)]
+#![feature(trusted_random_access)]
+#![feature(unsize)]
+#![feature(unzip_option)]
+#![feature(const_array_from_ref)]
+#![feature(const_slice_from_ref)]
+#![feature(waker_getters)]
+#![feature(slice_flatten)]
+#![feature(provide_any)]
+#![deny(unsafe_op_in_unsafe_fn)]
+
+extern crate test;
+
+mod alloc;
+mod any;
+mod array;
+mod ascii;
+mod asserting;
+mod atomic;
+mod bool;
+mod cell;
+mod char;
+mod clone;
+mod cmp;
+mod const_ptr;
+mod convert;
+mod fmt;
+mod future;
+mod hash;
+mod intrinsics;
+mod iter;
+mod lazy;
+mod macros;
+mod manually_drop;
+mod mem;
+mod nonzero;
+mod num;
+mod ops;
+mod option;
+mod pattern;
+mod pin;
+mod pin_macro;
+mod ptr;
+mod result;
+mod simd;
+mod slice;
+mod str;
+mod str_lossy;
+mod task;
+mod time;
+mod tuple;
+mod unicode;
+mod waker;
diff --git a/library/core/tests/macros.rs b/library/core/tests/macros.rs
new file mode 100644
index 000000000..ff3632e35
--- /dev/null
+++ b/library/core/tests/macros.rs
@@ -0,0 +1,20 @@
+#[test]
+fn assert_eq_trailing_comma() {
+ assert_eq!(1, 1,);
+}
+
+#[test]
+fn assert_escape() {
+ assert!(r#"☃\backslash"#.contains("\\"));
+}
+
+#[test]
+fn assert_ne_trailing_comma() {
+ assert_ne!(1, 2,);
+}
+
+#[rustfmt::skip]
+#[test]
+fn matches_leading_pipe() {
+ matches!(1, | 1 | 2 | 3);
+}
diff --git a/library/core/tests/manually_drop.rs b/library/core/tests/manually_drop.rs
new file mode 100644
index 000000000..9eac27973
--- /dev/null
+++ b/library/core/tests/manually_drop.rs
@@ -0,0 +1,27 @@
+use core::mem::ManuallyDrop;
+
+#[test]
+fn smoke() {
+ #[derive(Clone)]
+ struct TypeWithDrop;
+ impl Drop for TypeWithDrop {
+ fn drop(&mut self) {
+ unreachable!("Should not get dropped");
+ }
+ }
+
+ let x = ManuallyDrop::new(TypeWithDrop);
+ drop(x);
+
+ // also test unsizing
+ let x: Box<ManuallyDrop<[TypeWithDrop]>> =
+ Box::new(ManuallyDrop::new([TypeWithDrop, TypeWithDrop]));
+ drop(x);
+
+ // test clone and clone_from implementations
+ let mut x = ManuallyDrop::new(TypeWithDrop);
+ let y = x.clone();
+ x.clone_from(&y);
+ drop(x);
+ drop(y);
+}
diff --git a/library/core/tests/mem.rs b/library/core/tests/mem.rs
new file mode 100644
index 000000000..6856d1a1f
--- /dev/null
+++ b/library/core/tests/mem.rs
@@ -0,0 +1,343 @@
+use core::mem::*;
+
+#[cfg(panic = "unwind")]
+use std::rc::Rc;
+
+#[test]
+fn size_of_basic() {
+ assert_eq!(size_of::<u8>(), 1);
+ assert_eq!(size_of::<u16>(), 2);
+ assert_eq!(size_of::<u32>(), 4);
+ assert_eq!(size_of::<u64>(), 8);
+}
+
+#[test]
+#[cfg(target_pointer_width = "16")]
+fn size_of_16() {
+ assert_eq!(size_of::<usize>(), 2);
+ assert_eq!(size_of::<*const usize>(), 2);
+}
+
+#[test]
+#[cfg(target_pointer_width = "32")]
+fn size_of_32() {
+ assert_eq!(size_of::<usize>(), 4);
+ assert_eq!(size_of::<*const usize>(), 4);
+}
+
+#[test]
+#[cfg(target_pointer_width = "64")]
+fn size_of_64() {
+ assert_eq!(size_of::<usize>(), 8);
+ assert_eq!(size_of::<*const usize>(), 8);
+}
+
+#[test]
+fn size_of_val_basic() {
+ assert_eq!(size_of_val(&1u8), 1);
+ assert_eq!(size_of_val(&1u16), 2);
+ assert_eq!(size_of_val(&1u32), 4);
+ assert_eq!(size_of_val(&1u64), 8);
+}
+
+#[test]
+fn align_of_basic() {
+ assert_eq!(align_of::<u8>(), 1);
+ assert_eq!(align_of::<u16>(), 2);
+ assert_eq!(align_of::<u32>(), 4);
+}
+
+#[test]
+#[cfg(target_pointer_width = "16")]
+fn align_of_16() {
+ assert_eq!(align_of::<usize>(), 2);
+ assert_eq!(align_of::<*const usize>(), 2);
+}
+
+#[test]
+#[cfg(target_pointer_width = "32")]
+fn align_of_32() {
+ assert_eq!(align_of::<usize>(), 4);
+ assert_eq!(align_of::<*const usize>(), 4);
+}
+
+#[test]
+#[cfg(target_pointer_width = "64")]
+fn align_of_64() {
+ assert_eq!(align_of::<usize>(), 8);
+ assert_eq!(align_of::<*const usize>(), 8);
+}
+
+#[test]
+fn align_of_val_basic() {
+ assert_eq!(align_of_val(&1u8), 1);
+ assert_eq!(align_of_val(&1u16), 2);
+ assert_eq!(align_of_val(&1u32), 4);
+}
+
+#[test]
+fn test_swap() {
+ let mut x = 31337;
+ let mut y = 42;
+ swap(&mut x, &mut y);
+ assert_eq!(x, 42);
+ assert_eq!(y, 31337);
+}
+
+#[test]
+fn test_replace() {
+ let mut x = Some("test".to_string());
+ let y = replace(&mut x, None);
+ assert!(x.is_none());
+ assert!(y.is_some());
+}
+
+#[test]
+fn test_transmute_copy() {
+ assert_eq!(1, unsafe { transmute_copy(&1) });
+}
+
+#[test]
+fn test_transmute_copy_shrink() {
+ assert_eq!(0_u8, unsafe { transmute_copy(&0_u64) });
+}
+
+#[test]
+fn test_transmute_copy_unaligned() {
+ #[repr(C)]
+ #[derive(Default)]
+ struct Unaligned {
+ a: u8,
+ b: [u8; 8],
+ }
+
+ let u = Unaligned::default();
+ assert_eq!(0_u64, unsafe { transmute_copy(&u.b) });
+}
+
+#[test]
+#[cfg(panic = "unwind")]
+fn test_transmute_copy_grow_panics() {
+ use std::panic;
+
+ let err = panic::catch_unwind(panic::AssertUnwindSafe(|| unsafe {
+ let _unused: u64 = transmute_copy(&1_u8);
+ }));
+
+ match err {
+ Ok(_) => unreachable!(),
+ Err(payload) => {
+ payload
+ .downcast::<&'static str>()
+ .and_then(|s| {
+ if *s == "cannot transmute_copy if U is larger than T" { Ok(s) } else { Err(s) }
+ })
+ .unwrap_or_else(|p| panic::resume_unwind(p));
+ }
+ }
+}
+
+#[test]
+#[allow(dead_code)]
+fn test_discriminant_send_sync() {
+ enum Regular {
+ A,
+ B(i32),
+ }
+ enum NotSendSync {
+ A(*const i32),
+ }
+
+ fn is_send_sync<T: Send + Sync>() {}
+
+ is_send_sync::<Discriminant<Regular>>();
+ is_send_sync::<Discriminant<NotSendSync>>();
+}
+
+#[test]
+fn assume_init_good() {
+ const TRUE: bool = unsafe { MaybeUninit::<bool>::new(true).assume_init() };
+
+ assert!(TRUE);
+}
+
+#[test]
+fn uninit_array_assume_init() {
+ let mut array: [MaybeUninit<i16>; 5] = MaybeUninit::uninit_array();
+ array[0].write(3);
+ array[1].write(1);
+ array[2].write(4);
+ array[3].write(1);
+ array[4].write(5);
+
+ let array = unsafe { MaybeUninit::array_assume_init(array) };
+
+ assert_eq!(array, [3, 1, 4, 1, 5]);
+
+ let [] = unsafe { MaybeUninit::<!>::array_assume_init([]) };
+}
+
+#[test]
+fn uninit_write_slice() {
+ let mut dst = [MaybeUninit::new(255); 64];
+ let src = [0; 64];
+
+ assert_eq!(MaybeUninit::write_slice(&mut dst, &src), &src);
+}
+
+#[test]
+#[should_panic(expected = "source slice length (32) does not match destination slice length (64)")]
+fn uninit_write_slice_panic_lt() {
+ let mut dst = [MaybeUninit::uninit(); 64];
+ let src = [0; 32];
+
+ MaybeUninit::write_slice(&mut dst, &src);
+}
+
+#[test]
+#[should_panic(expected = "source slice length (128) does not match destination slice length (64)")]
+fn uninit_write_slice_panic_gt() {
+ let mut dst = [MaybeUninit::uninit(); 64];
+ let src = [0; 128];
+
+ MaybeUninit::write_slice(&mut dst, &src);
+}
+
+#[test]
+fn uninit_clone_from_slice() {
+ let mut dst = [MaybeUninit::new(255); 64];
+ let src = [0; 64];
+
+ assert_eq!(MaybeUninit::write_slice_cloned(&mut dst, &src), &src);
+}
+
+#[test]
+#[should_panic(expected = "destination and source slices have different lengths")]
+fn uninit_write_slice_cloned_panic_lt() {
+ let mut dst = [MaybeUninit::uninit(); 64];
+ let src = [0; 32];
+
+ MaybeUninit::write_slice_cloned(&mut dst, &src);
+}
+
+#[test]
+#[should_panic(expected = "destination and source slices have different lengths")]
+fn uninit_write_slice_cloned_panic_gt() {
+ let mut dst = [MaybeUninit::uninit(); 64];
+ let src = [0; 128];
+
+ MaybeUninit::write_slice_cloned(&mut dst, &src);
+}
+
+#[test]
+#[cfg(panic = "unwind")]
+fn uninit_write_slice_cloned_mid_panic() {
+ use std::panic;
+
+ enum IncrementOrPanic {
+ Increment(Rc<()>),
+ ExpectedPanic,
+ UnexpectedPanic,
+ }
+
+ impl Clone for IncrementOrPanic {
+ fn clone(&self) -> Self {
+ match self {
+ Self::Increment(rc) => Self::Increment(rc.clone()),
+ Self::ExpectedPanic => panic!("expected panic on clone"),
+ Self::UnexpectedPanic => panic!("unexpected panic on clone"),
+ }
+ }
+ }
+
+ let rc = Rc::new(());
+
+ let mut dst = [
+ MaybeUninit::uninit(),
+ MaybeUninit::uninit(),
+ MaybeUninit::uninit(),
+ MaybeUninit::uninit(),
+ ];
+
+ let src = [
+ IncrementOrPanic::Increment(rc.clone()),
+ IncrementOrPanic::Increment(rc.clone()),
+ IncrementOrPanic::ExpectedPanic,
+ IncrementOrPanic::UnexpectedPanic,
+ ];
+
+ let err = panic::catch_unwind(panic::AssertUnwindSafe(|| {
+ MaybeUninit::write_slice_cloned(&mut dst, &src);
+ }));
+
+ drop(src);
+
+ match err {
+ Ok(_) => unreachable!(),
+ Err(payload) => {
+ payload
+ .downcast::<&'static str>()
+ .and_then(|s| if *s == "expected panic on clone" { Ok(s) } else { Err(s) })
+ .unwrap_or_else(|p| panic::resume_unwind(p));
+
+ assert_eq!(Rc::strong_count(&rc), 1)
+ }
+ }
+}
+
+#[test]
+fn uninit_write_slice_cloned_no_drop() {
+ #[derive(Clone)]
+ struct Bomb;
+
+ impl Drop for Bomb {
+ fn drop(&mut self) {
+ panic!("dropped a bomb! kaboom")
+ }
+ }
+
+ let mut dst = [MaybeUninit::uninit()];
+ let src = [Bomb];
+
+ MaybeUninit::write_slice_cloned(&mut dst, &src);
+
+ forget(src);
+}
+
+#[test]
+fn uninit_const_assume_init_read() {
+ const FOO: u32 = unsafe { MaybeUninit::new(42).assume_init_read() };
+ assert_eq!(FOO, 42);
+}
+
+#[test]
+fn const_maybe_uninit() {
+ use std::ptr;
+
+ #[derive(Debug, PartialEq)]
+ struct Foo {
+ x: u8,
+ y: u8,
+ }
+
+ const FIELD_BY_FIELD: Foo = unsafe {
+ let mut val = MaybeUninit::uninit();
+ init_y(&mut val); // order shouldn't matter
+ init_x(&mut val);
+ val.assume_init()
+ };
+
+ const fn init_x(foo: &mut MaybeUninit<Foo>) {
+ unsafe {
+ *ptr::addr_of_mut!((*foo.as_mut_ptr()).x) = 1;
+ }
+ }
+
+ const fn init_y(foo: &mut MaybeUninit<Foo>) {
+ unsafe {
+ *ptr::addr_of_mut!((*foo.as_mut_ptr()).y) = 2;
+ }
+ }
+
+ assert_eq!(FIELD_BY_FIELD, Foo { x: 1, y: 2 });
+}
diff --git a/library/core/tests/nonzero.rs b/library/core/tests/nonzero.rs
new file mode 100644
index 000000000..a0ca919a8
--- /dev/null
+++ b/library/core/tests/nonzero.rs
@@ -0,0 +1,336 @@
+use core::convert::TryFrom;
+use core::num::{
+ IntErrorKind, NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize,
+ NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize,
+};
+use core::option::Option::{self, None, Some};
+use std::mem::size_of;
+
+#[test]
+fn test_create_nonzero_instance() {
+ let _a = unsafe { NonZeroU32::new_unchecked(21) };
+}
+
+#[test]
+fn test_size_nonzero_in_option() {
+ assert_eq!(size_of::<NonZeroU32>(), size_of::<Option<NonZeroU32>>());
+ assert_eq!(size_of::<NonZeroI32>(), size_of::<Option<NonZeroI32>>());
+}
+
+#[test]
+fn test_match_on_nonzero_option() {
+ let a = Some(unsafe { NonZeroU32::new_unchecked(42) });
+ match a {
+ Some(val) => assert_eq!(val.get(), 42),
+ None => panic!("unexpected None while matching on Some(NonZeroU32(_))"),
+ }
+
+ match unsafe { Some(NonZeroU32::new_unchecked(43)) } {
+ Some(val) => assert_eq!(val.get(), 43),
+ None => panic!("unexpected None while matching on Some(NonZeroU32(_))"),
+ }
+}
+
+#[test]
+fn test_match_option_empty_vec() {
+ let a: Option<Vec<isize>> = Some(vec![]);
+ match a {
+ None => panic!("unexpected None while matching on Some(vec![])"),
+ _ => {}
+ }
+}
+
+#[test]
+fn test_match_option_vec() {
+ let a = Some(vec![1, 2, 3, 4]);
+ match a {
+ Some(v) => assert_eq!(v, [1, 2, 3, 4]),
+ None => panic!("unexpected None while matching on Some(vec![1, 2, 3, 4])"),
+ }
+}
+
+#[test]
+fn test_match_option_rc() {
+ use std::rc::Rc;
+
+ let five = Rc::new(5);
+ match Some(five) {
+ Some(r) => assert_eq!(*r, 5),
+ None => panic!("unexpected None while matching on Some(Rc::new(5))"),
+ }
+}
+
+#[test]
+fn test_match_option_arc() {
+ use std::sync::Arc;
+
+ let five = Arc::new(5);
+ match Some(five) {
+ Some(a) => assert_eq!(*a, 5),
+ None => panic!("unexpected None while matching on Some(Arc::new(5))"),
+ }
+}
+
+#[test]
+fn test_match_option_empty_string() {
+ let a = Some(String::new());
+ match a {
+ None => panic!("unexpected None while matching on Some(String::new())"),
+ _ => {}
+ }
+}
+
+#[test]
+fn test_match_option_string() {
+ let five = "Five".to_string();
+ match Some(five) {
+ Some(s) => assert_eq!(s, "Five"),
+ None => panic!("{}", "unexpected None while matching on Some(String { ... })"),
+ }
+}
+
+mod atom {
+ use core::num::NonZeroU32;
+
+ #[derive(PartialEq, Eq)]
+ pub struct Atom {
+ index: NonZeroU32, // private
+ }
+ pub const FOO_ATOM: Atom = Atom { index: unsafe { NonZeroU32::new_unchecked(7) } };
+}
+
+macro_rules! atom {
+ ("foo") => {
+ atom::FOO_ATOM
+ };
+}
+
+#[test]
+fn test_match_nonzero_const_pattern() {
+ match atom!("foo") {
+ // Using as a pattern is supported by the compiler:
+ atom!("foo") => {}
+ _ => panic!("Expected the const item as a pattern to match."),
+ }
+}
+
+#[test]
+fn test_from_nonzero() {
+ let nz = NonZeroU32::new(1).unwrap();
+ let num: u32 = nz.into();
+ assert_eq!(num, 1u32);
+}
+
+#[test]
+fn test_from_signed_nonzero() {
+ let nz = NonZeroI32::new(1).unwrap();
+ let num: i32 = nz.into();
+ assert_eq!(num, 1i32);
+}
+
+#[test]
+fn test_from_str() {
+ assert_eq!("123".parse::<NonZeroU8>(), Ok(NonZeroU8::new(123).unwrap()));
+ assert_eq!("0".parse::<NonZeroU8>().err().map(|e| e.kind().clone()), Some(IntErrorKind::Zero));
+ assert_eq!(
+ "-1".parse::<NonZeroU8>().err().map(|e| e.kind().clone()),
+ Some(IntErrorKind::InvalidDigit)
+ );
+ assert_eq!(
+ "-129".parse::<NonZeroI8>().err().map(|e| e.kind().clone()),
+ Some(IntErrorKind::NegOverflow)
+ );
+ assert_eq!(
+ "257".parse::<NonZeroU8>().err().map(|e| e.kind().clone()),
+ Some(IntErrorKind::PosOverflow)
+ );
+}
+
+#[test]
+fn test_nonzero_bitor() {
+ let nz_alt = NonZeroU8::new(0b1010_1010).unwrap();
+ let nz_low = NonZeroU8::new(0b0000_1111).unwrap();
+
+ let both_nz: NonZeroU8 = nz_alt | nz_low;
+ assert_eq!(both_nz.get(), 0b1010_1111);
+
+ let rhs_int: NonZeroU8 = nz_low | 0b1100_0000u8;
+ assert_eq!(rhs_int.get(), 0b1100_1111);
+
+ let rhs_zero: NonZeroU8 = nz_alt | 0u8;
+ assert_eq!(rhs_zero.get(), 0b1010_1010);
+
+ let lhs_int: NonZeroU8 = 0b0110_0110u8 | nz_alt;
+ assert_eq!(lhs_int.get(), 0b1110_1110);
+
+ let lhs_zero: NonZeroU8 = 0u8 | nz_low;
+ assert_eq!(lhs_zero.get(), 0b0000_1111);
+}
+
+#[test]
+fn test_nonzero_bitor_assign() {
+ let mut target = NonZeroU8::new(0b1010_1010).unwrap();
+
+ target |= NonZeroU8::new(0b0000_1111).unwrap();
+ assert_eq!(target.get(), 0b1010_1111);
+
+ target |= 0b0001_0000;
+ assert_eq!(target.get(), 0b1011_1111);
+
+ target |= 0;
+ assert_eq!(target.get(), 0b1011_1111);
+}
+
+#[test]
+fn test_nonzero_from_int_on_success() {
+ assert_eq!(NonZeroU8::try_from(5), Ok(NonZeroU8::new(5).unwrap()));
+ assert_eq!(NonZeroU32::try_from(5), Ok(NonZeroU32::new(5).unwrap()));
+
+ assert_eq!(NonZeroI8::try_from(-5), Ok(NonZeroI8::new(-5).unwrap()));
+ assert_eq!(NonZeroI32::try_from(-5), Ok(NonZeroI32::new(-5).unwrap()));
+}
+
+#[test]
+fn test_nonzero_from_int_on_err() {
+ assert!(NonZeroU8::try_from(0).is_err());
+ assert!(NonZeroU32::try_from(0).is_err());
+
+ assert!(NonZeroI8::try_from(0).is_err());
+ assert!(NonZeroI32::try_from(0).is_err());
+}
+
+#[test]
+fn nonzero_const() {
+ // test that the methods of `NonZeroX>` are usable in a const context
+ // Note: only tests NonZero8
+
+ const NONZERO_U8: NonZeroU8 = unsafe { NonZeroU8::new_unchecked(5) };
+
+ const GET: u8 = NONZERO_U8.get();
+ assert_eq!(GET, 5);
+
+ const ZERO: Option<NonZeroU8> = NonZeroU8::new(0);
+ assert!(ZERO.is_none());
+
+ const ONE: Option<NonZeroU8> = NonZeroU8::new(1);
+ assert!(ONE.is_some());
+
+ const FROM_NONZERO_U8: u8 = u8::from(NONZERO_U8);
+ assert_eq!(FROM_NONZERO_U8, 5);
+
+ const NONZERO_CONVERT: NonZeroU32 = NonZeroU32::from(NONZERO_U8);
+ assert_eq!(NONZERO_CONVERT.get(), 5);
+}
+
+#[test]
+fn nonzero_leading_zeros() {
+ assert_eq!(NonZeroU8::new(1).unwrap().leading_zeros(), 7);
+ assert_eq!(NonZeroI8::new(1).unwrap().leading_zeros(), 7);
+ assert_eq!(NonZeroU16::new(1).unwrap().leading_zeros(), 15);
+ assert_eq!(NonZeroI16::new(1).unwrap().leading_zeros(), 15);
+ assert_eq!(NonZeroU32::new(1).unwrap().leading_zeros(), 31);
+ assert_eq!(NonZeroI32::new(1).unwrap().leading_zeros(), 31);
+ assert_eq!(NonZeroU64::new(1).unwrap().leading_zeros(), 63);
+ assert_eq!(NonZeroI64::new(1).unwrap().leading_zeros(), 63);
+ assert_eq!(NonZeroU128::new(1).unwrap().leading_zeros(), 127);
+ assert_eq!(NonZeroI128::new(1).unwrap().leading_zeros(), 127);
+ assert_eq!(NonZeroUsize::new(1).unwrap().leading_zeros(), usize::BITS - 1);
+ assert_eq!(NonZeroIsize::new(1).unwrap().leading_zeros(), usize::BITS - 1);
+
+ assert_eq!(NonZeroU8::new(u8::MAX >> 2).unwrap().leading_zeros(), 2);
+ assert_eq!(NonZeroI8::new((u8::MAX >> 2) as i8).unwrap().leading_zeros(), 2);
+ assert_eq!(NonZeroU16::new(u16::MAX >> 2).unwrap().leading_zeros(), 2);
+ assert_eq!(NonZeroI16::new((u16::MAX >> 2) as i16).unwrap().leading_zeros(), 2);
+ assert_eq!(NonZeroU32::new(u32::MAX >> 2).unwrap().leading_zeros(), 2);
+ assert_eq!(NonZeroI32::new((u32::MAX >> 2) as i32).unwrap().leading_zeros(), 2);
+ assert_eq!(NonZeroU64::new(u64::MAX >> 2).unwrap().leading_zeros(), 2);
+ assert_eq!(NonZeroI64::new((u64::MAX >> 2) as i64).unwrap().leading_zeros(), 2);
+ assert_eq!(NonZeroU128::new(u128::MAX >> 2).unwrap().leading_zeros(), 2);
+ assert_eq!(NonZeroI128::new((u128::MAX >> 2) as i128).unwrap().leading_zeros(), 2);
+ assert_eq!(NonZeroUsize::new(usize::MAX >> 2).unwrap().leading_zeros(), 2);
+ assert_eq!(NonZeroIsize::new((usize::MAX >> 2) as isize).unwrap().leading_zeros(), 2);
+
+ assert_eq!(NonZeroU8::new(u8::MAX).unwrap().leading_zeros(), 0);
+ assert_eq!(NonZeroI8::new(-1i8).unwrap().leading_zeros(), 0);
+ assert_eq!(NonZeroU16::new(u16::MAX).unwrap().leading_zeros(), 0);
+ assert_eq!(NonZeroI16::new(-1i16).unwrap().leading_zeros(), 0);
+ assert_eq!(NonZeroU32::new(u32::MAX).unwrap().leading_zeros(), 0);
+ assert_eq!(NonZeroI32::new(-1i32).unwrap().leading_zeros(), 0);
+ assert_eq!(NonZeroU64::new(u64::MAX).unwrap().leading_zeros(), 0);
+ assert_eq!(NonZeroI64::new(-1i64).unwrap().leading_zeros(), 0);
+ assert_eq!(NonZeroU128::new(u128::MAX).unwrap().leading_zeros(), 0);
+ assert_eq!(NonZeroI128::new(-1i128).unwrap().leading_zeros(), 0);
+ assert_eq!(NonZeroUsize::new(usize::MAX).unwrap().leading_zeros(), 0);
+ assert_eq!(NonZeroIsize::new(-1isize).unwrap().leading_zeros(), 0);
+
+ const LEADING_ZEROS: u32 = NonZeroU16::new(1).unwrap().leading_zeros();
+ assert_eq!(LEADING_ZEROS, 15);
+}
+
+#[test]
+fn nonzero_trailing_zeros() {
+ assert_eq!(NonZeroU8::new(1).unwrap().trailing_zeros(), 0);
+ assert_eq!(NonZeroI8::new(1).unwrap().trailing_zeros(), 0);
+ assert_eq!(NonZeroU16::new(1).unwrap().trailing_zeros(), 0);
+ assert_eq!(NonZeroI16::new(1).unwrap().trailing_zeros(), 0);
+ assert_eq!(NonZeroU32::new(1).unwrap().trailing_zeros(), 0);
+ assert_eq!(NonZeroI32::new(1).unwrap().trailing_zeros(), 0);
+ assert_eq!(NonZeroU64::new(1).unwrap().trailing_zeros(), 0);
+ assert_eq!(NonZeroI64::new(1).unwrap().trailing_zeros(), 0);
+ assert_eq!(NonZeroU128::new(1).unwrap().trailing_zeros(), 0);
+ assert_eq!(NonZeroI128::new(1).unwrap().trailing_zeros(), 0);
+ assert_eq!(NonZeroUsize::new(1).unwrap().trailing_zeros(), 0);
+ assert_eq!(NonZeroIsize::new(1).unwrap().trailing_zeros(), 0);
+
+ assert_eq!(NonZeroU8::new(1 << 2).unwrap().trailing_zeros(), 2);
+ assert_eq!(NonZeroI8::new(1 << 2).unwrap().trailing_zeros(), 2);
+ assert_eq!(NonZeroU16::new(1 << 2).unwrap().trailing_zeros(), 2);
+ assert_eq!(NonZeroI16::new(1 << 2).unwrap().trailing_zeros(), 2);
+ assert_eq!(NonZeroU32::new(1 << 2).unwrap().trailing_zeros(), 2);
+ assert_eq!(NonZeroI32::new(1 << 2).unwrap().trailing_zeros(), 2);
+ assert_eq!(NonZeroU64::new(1 << 2).unwrap().trailing_zeros(), 2);
+ assert_eq!(NonZeroI64::new(1 << 2).unwrap().trailing_zeros(), 2);
+ assert_eq!(NonZeroU128::new(1 << 2).unwrap().trailing_zeros(), 2);
+ assert_eq!(NonZeroI128::new(1 << 2).unwrap().trailing_zeros(), 2);
+ assert_eq!(NonZeroUsize::new(1 << 2).unwrap().trailing_zeros(), 2);
+ assert_eq!(NonZeroIsize::new(1 << 2).unwrap().trailing_zeros(), 2);
+
+ assert_eq!(NonZeroU8::new(1 << 7).unwrap().trailing_zeros(), 7);
+ assert_eq!(NonZeroI8::new(1 << 7).unwrap().trailing_zeros(), 7);
+ assert_eq!(NonZeroU16::new(1 << 15).unwrap().trailing_zeros(), 15);
+ assert_eq!(NonZeroI16::new(1 << 15).unwrap().trailing_zeros(), 15);
+ assert_eq!(NonZeroU32::new(1 << 31).unwrap().trailing_zeros(), 31);
+ assert_eq!(NonZeroI32::new(1 << 31).unwrap().trailing_zeros(), 31);
+ assert_eq!(NonZeroU64::new(1 << 63).unwrap().trailing_zeros(), 63);
+ assert_eq!(NonZeroI64::new(1 << 63).unwrap().trailing_zeros(), 63);
+ assert_eq!(NonZeroU128::new(1 << 127).unwrap().trailing_zeros(), 127);
+ assert_eq!(NonZeroI128::new(1 << 127).unwrap().trailing_zeros(), 127);
+
+ assert_eq!(
+ NonZeroUsize::new(1 << (usize::BITS - 1)).unwrap().trailing_zeros(),
+ usize::BITS - 1
+ );
+ assert_eq!(
+ NonZeroIsize::new(1 << (usize::BITS - 1)).unwrap().trailing_zeros(),
+ usize::BITS - 1
+ );
+
+ const TRAILING_ZEROS: u32 = NonZeroU16::new(1 << 2).unwrap().trailing_zeros();
+ assert_eq!(TRAILING_ZEROS, 2);
+}
+
+#[test]
+fn test_nonzero_uint_div() {
+ let nz = NonZeroU32::new(1).unwrap();
+
+ let x: u32 = 42u32 / nz;
+ assert_eq!(x, 42u32);
+}
+
+#[test]
+fn test_nonzero_uint_rem() {
+ let nz = NonZeroU32::new(10).unwrap();
+
+ let x: u32 = 42u32 % nz;
+ assert_eq!(x, 2u32);
+}
diff --git a/library/core/tests/num/bignum.rs b/library/core/tests/num/bignum.rs
new file mode 100644
index 000000000..416e7cea7
--- /dev/null
+++ b/library/core/tests/num/bignum.rs
@@ -0,0 +1,276 @@
+use core::num::bignum::tests::Big8x3 as Big;
+use core::num::bignum::Big32x40;
+
+#[test]
+#[should_panic]
+fn test_from_u64_overflow() {
+ Big::from_u64(0x1000000);
+}
+
+#[test]
+fn test_add() {
+ assert_eq!(*Big::from_small(3).add(&Big::from_small(4)), Big::from_small(7));
+ assert_eq!(*Big::from_small(3).add(&Big::from_small(0)), Big::from_small(3));
+ assert_eq!(*Big::from_small(0).add(&Big::from_small(3)), Big::from_small(3));
+ assert_eq!(*Big::from_small(3).add(&Big::from_u64(0xfffe)), Big::from_u64(0x10001));
+ assert_eq!(*Big::from_u64(0xfedc).add(&Big::from_u64(0x789)), Big::from_u64(0x10665));
+ assert_eq!(*Big::from_u64(0x789).add(&Big::from_u64(0xfedc)), Big::from_u64(0x10665));
+}
+
+#[test]
+#[should_panic]
+fn test_add_overflow_1() {
+ Big::from_small(1).add(&Big::from_u64(0xffffff));
+}
+
+#[test]
+#[should_panic]
+fn test_add_overflow_2() {
+ Big::from_u64(0xffffff).add(&Big::from_small(1));
+}
+
+#[test]
+fn test_add_small() {
+ assert_eq!(*Big::from_small(3).add_small(4), Big::from_small(7));
+ assert_eq!(*Big::from_small(3).add_small(0), Big::from_small(3));
+ assert_eq!(*Big::from_small(0).add_small(3), Big::from_small(3));
+ assert_eq!(*Big::from_small(7).add_small(250), Big::from_u64(257));
+ assert_eq!(*Big::from_u64(0x7fff).add_small(1), Big::from_u64(0x8000));
+ assert_eq!(*Big::from_u64(0x2ffe).add_small(0x35), Big::from_u64(0x3033));
+ assert_eq!(*Big::from_small(0xdc).add_small(0x89), Big::from_u64(0x165));
+}
+
+#[test]
+#[should_panic]
+fn test_add_small_overflow() {
+ Big::from_u64(0xffffff).add_small(1);
+}
+
+#[test]
+fn test_sub() {
+ assert_eq!(*Big::from_small(7).sub(&Big::from_small(4)), Big::from_small(3));
+ assert_eq!(*Big::from_u64(0x10665).sub(&Big::from_u64(0x789)), Big::from_u64(0xfedc));
+ assert_eq!(*Big::from_u64(0x10665).sub(&Big::from_u64(0xfedc)), Big::from_u64(0x789));
+ assert_eq!(*Big::from_u64(0x10665).sub(&Big::from_u64(0x10664)), Big::from_small(1));
+ assert_eq!(*Big::from_u64(0x10665).sub(&Big::from_u64(0x10665)), Big::from_small(0));
+}
+
+#[test]
+#[should_panic]
+fn test_sub_underflow_1() {
+ Big::from_u64(0x10665).sub(&Big::from_u64(0x10666));
+}
+
+#[test]
+#[should_panic]
+fn test_sub_underflow_2() {
+ Big::from_small(0).sub(&Big::from_u64(0x123456));
+}
+
+#[test]
+fn test_mul_small() {
+ assert_eq!(*Big::from_small(7).mul_small(5), Big::from_small(35));
+ assert_eq!(*Big::from_small(0xff).mul_small(0xff), Big::from_u64(0xfe01));
+ assert_eq!(*Big::from_u64(0xffffff / 13).mul_small(13), Big::from_u64(0xffffff));
+}
+
+#[test]
+#[should_panic]
+fn test_mul_small_overflow() {
+ Big::from_u64(0x800000).mul_small(2);
+}
+
+#[test]
+fn test_mul_pow2() {
+ assert_eq!(*Big::from_small(0x7).mul_pow2(4), Big::from_small(0x70));
+ assert_eq!(*Big::from_small(0xff).mul_pow2(1), Big::from_u64(0x1fe));
+ assert_eq!(*Big::from_small(0xff).mul_pow2(12), Big::from_u64(0xff000));
+ assert_eq!(*Big::from_small(0x1).mul_pow2(23), Big::from_u64(0x800000));
+ assert_eq!(*Big::from_u64(0x123).mul_pow2(0), Big::from_u64(0x123));
+ assert_eq!(*Big::from_u64(0x123).mul_pow2(7), Big::from_u64(0x9180));
+ assert_eq!(*Big::from_u64(0x123).mul_pow2(15), Big::from_u64(0x918000));
+ assert_eq!(*Big::from_small(0).mul_pow2(23), Big::from_small(0));
+}
+
+#[test]
+#[should_panic]
+fn test_mul_pow2_overflow_1() {
+ Big::from_u64(0x1).mul_pow2(24);
+}
+
+#[test]
+#[should_panic]
+fn test_mul_pow2_overflow_2() {
+ Big::from_u64(0x123).mul_pow2(16);
+}
+
+#[test]
+fn test_mul_pow5() {
+ assert_eq!(*Big::from_small(42).mul_pow5(0), Big::from_small(42));
+ assert_eq!(*Big::from_small(1).mul_pow5(2), Big::from_small(25));
+ assert_eq!(*Big::from_small(1).mul_pow5(4), Big::from_u64(25 * 25));
+ assert_eq!(*Big::from_small(4).mul_pow5(3), Big::from_u64(500));
+ assert_eq!(*Big::from_small(140).mul_pow5(2), Big::from_u64(25 * 140));
+ assert_eq!(*Big::from_small(25).mul_pow5(1), Big::from_small(125));
+ assert_eq!(*Big::from_small(125).mul_pow5(7), Big::from_u64(9765625));
+ assert_eq!(*Big::from_small(0).mul_pow5(127), Big::from_small(0));
+}
+
+#[test]
+#[should_panic]
+fn test_mul_pow5_overflow_1() {
+ Big::from_small(1).mul_pow5(12);
+}
+
+#[test]
+#[should_panic]
+fn test_mul_pow5_overflow_2() {
+ Big::from_small(230).mul_pow5(8);
+}
+
+#[test]
+fn test_mul_digits() {
+ assert_eq!(*Big::from_small(3).mul_digits(&[5]), Big::from_small(15));
+ assert_eq!(*Big::from_small(0xff).mul_digits(&[0xff]), Big::from_u64(0xfe01));
+ assert_eq!(*Big::from_u64(0x123).mul_digits(&[0x56, 0x4]), Big::from_u64(0x4edc2));
+ assert_eq!(*Big::from_u64(0x12345).mul_digits(&[0x67]), Big::from_u64(0x7530c3));
+ assert_eq!(*Big::from_small(0x12).mul_digits(&[0x67, 0x45, 0x3]), Big::from_u64(0x3ae13e));
+ assert_eq!(*Big::from_u64(0xffffff / 13).mul_digits(&[13]), Big::from_u64(0xffffff));
+ assert_eq!(*Big::from_small(13).mul_digits(&[0x3b, 0xb1, 0x13]), Big::from_u64(0xffffff));
+}
+
+#[test]
+#[should_panic]
+fn test_mul_digits_overflow_1() {
+ Big::from_u64(0x800000).mul_digits(&[2]);
+}
+
+#[test]
+#[should_panic]
+fn test_mul_digits_overflow_2() {
+ Big::from_u64(0x1000).mul_digits(&[0, 0x10]);
+}
+
+#[test]
+fn test_div_rem_small() {
+ let as_val = |(q, r): (&mut Big, u8)| (q.clone(), r);
+ assert_eq!(as_val(Big::from_small(0xff).div_rem_small(15)), (Big::from_small(17), 0));
+ assert_eq!(as_val(Big::from_small(0xff).div_rem_small(16)), (Big::from_small(15), 15));
+ assert_eq!(as_val(Big::from_small(3).div_rem_small(40)), (Big::from_small(0), 3));
+ assert_eq!(
+ as_val(Big::from_u64(0xffffff).div_rem_small(123)),
+ (Big::from_u64(0xffffff / 123), (0xffffffu64 % 123) as u8)
+ );
+ assert_eq!(
+ as_val(Big::from_u64(0x10000).div_rem_small(123)),
+ (Big::from_u64(0x10000 / 123), (0x10000u64 % 123) as u8)
+ );
+}
+
+#[test]
+fn test_div_rem() {
+ fn div_rem(n: u64, d: u64) -> (Big, Big) {
+ let mut q = Big::from_small(42);
+ let mut r = Big::from_small(42);
+ Big::from_u64(n).div_rem(&Big::from_u64(d), &mut q, &mut r);
+ (q, r)
+ }
+ assert_eq!(div_rem(1, 1), (Big::from_small(1), Big::from_small(0)));
+ assert_eq!(div_rem(4, 3), (Big::from_small(1), Big::from_small(1)));
+ assert_eq!(div_rem(1, 7), (Big::from_small(0), Big::from_small(1)));
+ assert_eq!(div_rem(45, 9), (Big::from_small(5), Big::from_small(0)));
+ assert_eq!(div_rem(103, 9), (Big::from_small(11), Big::from_small(4)));
+ assert_eq!(div_rem(123456, 77), (Big::from_u64(1603), Big::from_small(25)));
+ assert_eq!(div_rem(0xffff, 1), (Big::from_u64(0xffff), Big::from_small(0)));
+ assert_eq!(div_rem(0xeeee, 0xffff), (Big::from_small(0), Big::from_u64(0xeeee)));
+ assert_eq!(div_rem(2_000_000, 2), (Big::from_u64(1_000_000), Big::from_u64(0)));
+}
+
+#[test]
+fn test_is_zero() {
+ assert!(Big::from_small(0).is_zero());
+ assert!(!Big::from_small(3).is_zero());
+ assert!(!Big::from_u64(0x123).is_zero());
+ assert!(!Big::from_u64(0xffffff).sub(&Big::from_u64(0xfffffe)).is_zero());
+ assert!(Big::from_u64(0xffffff).sub(&Big::from_u64(0xffffff)).is_zero());
+}
+
+#[test]
+fn test_get_bit() {
+ let x = Big::from_small(0b1101);
+ assert_eq!(x.get_bit(0), 1);
+ assert_eq!(x.get_bit(1), 0);
+ assert_eq!(x.get_bit(2), 1);
+ assert_eq!(x.get_bit(3), 1);
+ let y = Big::from_u64(1 << 15);
+ assert_eq!(y.get_bit(14), 0);
+ assert_eq!(y.get_bit(15), 1);
+ assert_eq!(y.get_bit(16), 0);
+}
+
+#[test]
+#[should_panic]
+fn test_get_bit_out_of_range() {
+ Big::from_small(42).get_bit(24);
+}
+
+#[test]
+fn test_bit_length() {
+ for i in 0..8 * 3 {
+ // 010000...000
+ assert_eq!(Big::from_small(1).mul_pow2(i).bit_length(), i + 1);
+ }
+ for i in 1..8 * 3 - 1 {
+ // 010000...001
+ assert_eq!(Big::from_small(1).mul_pow2(i).add(&Big::from_small(1)).bit_length(), i + 1);
+ // 110000...000
+ assert_eq!(Big::from_small(3).mul_pow2(i).bit_length(), i + 2);
+ }
+ assert_eq!(Big::from_small(0).bit_length(), 0);
+ assert_eq!(Big::from_small(1).bit_length(), 1);
+ assert_eq!(Big::from_small(5).bit_length(), 3);
+ assert_eq!(Big::from_small(0x18).bit_length(), 5);
+ assert_eq!(Big::from_u64(0x4073).bit_length(), 15);
+ assert_eq!(Big::from_u64(0xffffff).bit_length(), 24);
+}
+
+#[test]
+fn test_bit_length_32x40() {
+ for i in 0..32 * 40 {
+ // 010000...000
+ assert_eq!(Big32x40::from_small(1).mul_pow2(i).bit_length(), i + 1);
+ }
+ for i in 1..32 * 40 - 1 {
+ // 010000...001
+ assert_eq!(
+ Big32x40::from_small(1).mul_pow2(i).add(&Big32x40::from_small(1)).bit_length(),
+ i + 1
+ );
+ // 110000...000
+ assert_eq!(Big32x40::from_small(3).mul_pow2(i).bit_length(), i + 2);
+ }
+ assert_eq!(Big32x40::from_small(0).bit_length(), 0);
+ assert_eq!(Big32x40::from_small(1).bit_length(), 1);
+ assert_eq!(Big32x40::from_small(5).bit_length(), 3);
+ assert_eq!(Big32x40::from_small(0x18).bit_length(), 5);
+ assert_eq!(Big32x40::from_u64(0x4073).bit_length(), 15);
+ assert_eq!(Big32x40::from_u64(0xffffff).bit_length(), 24);
+ assert_eq!(Big32x40::from_u64(0xffffffffffffffff).bit_length(), 64);
+}
+
+#[test]
+fn test_ord() {
+ assert!(Big::from_u64(0) < Big::from_u64(0xffffff));
+ assert!(Big::from_u64(0x102) < Big::from_u64(0x201));
+}
+
+#[test]
+fn test_fmt() {
+ assert_eq!(format!("{:?}", Big::from_u64(0)), "0x0");
+ assert_eq!(format!("{:?}", Big::from_u64(0x1)), "0x1");
+ assert_eq!(format!("{:?}", Big::from_u64(0x12)), "0x12");
+ assert_eq!(format!("{:?}", Big::from_u64(0x123)), "0x1_23");
+ assert_eq!(format!("{:?}", Big::from_u64(0x1234)), "0x12_34");
+ assert_eq!(format!("{:?}", Big::from_u64(0x12345)), "0x1_23_45");
+ assert_eq!(format!("{:?}", Big::from_u64(0x123456)), "0x12_34_56");
+}
diff --git a/library/core/tests/num/const_from.rs b/library/core/tests/num/const_from.rs
new file mode 100644
index 000000000..aca18ef39
--- /dev/null
+++ b/library/core/tests/num/const_from.rs
@@ -0,0 +1,25 @@
+#[test]
+fn from() {
+ use core::convert::TryFrom;
+ use core::num::TryFromIntError;
+
+ // From
+ const FROM: i64 = i64::from(1i32);
+ assert_eq!(FROM, 1i64);
+
+ // From int to float
+ const FROM_F64: f64 = f64::from(42u8);
+ assert_eq!(FROM_F64, 42f64);
+
+ // Upper bounded
+ const U8_FROM_U16: Result<u8, TryFromIntError> = u8::try_from(1u16);
+ assert_eq!(U8_FROM_U16, Ok(1u8));
+
+ // Both bounded
+ const I8_FROM_I16: Result<i8, TryFromIntError> = i8::try_from(1i16);
+ assert_eq!(I8_FROM_I16, Ok(1i8));
+
+ // Lower bounded
+ const I16_FROM_U16: Result<i16, TryFromIntError> = i16::try_from(1u16);
+ assert_eq!(I16_FROM_U16, Ok(1i16));
+}
diff --git a/library/core/tests/num/dec2flt/float.rs b/library/core/tests/num/dec2flt/float.rs
new file mode 100644
index 000000000..7a9587a18
--- /dev/null
+++ b/library/core/tests/num/dec2flt/float.rs
@@ -0,0 +1,33 @@
+use core::num::dec2flt::float::RawFloat;
+
+#[test]
+fn test_f32_integer_decode() {
+ assert_eq!(3.14159265359f32.integer_decode(), (13176795, -22, 1));
+ assert_eq!((-8573.5918555f32).integer_decode(), (8779358, -10, -1));
+ assert_eq!(2f32.powf(100.0).integer_decode(), (8388608, 77, 1));
+ assert_eq!(0f32.integer_decode(), (0, -150, 1));
+ assert_eq!((-0f32).integer_decode(), (0, -150, -1));
+ assert_eq!(f32::INFINITY.integer_decode(), (8388608, 105, 1));
+ assert_eq!(f32::NEG_INFINITY.integer_decode(), (8388608, 105, -1));
+
+ // Ignore the "sign" (quiet / signalling flag) of NAN.
+ // It can vary between runtime operations and LLVM folding.
+ let (nan_m, nan_e, _nan_s) = f32::NAN.integer_decode();
+ assert_eq!((nan_m, nan_e), (12582912, 105));
+}
+
+#[test]
+fn test_f64_integer_decode() {
+ assert_eq!(3.14159265359f64.integer_decode(), (7074237752028906, -51, 1));
+ assert_eq!((-8573.5918555f64).integer_decode(), (4713381968463931, -39, -1));
+ assert_eq!(2f64.powf(100.0).integer_decode(), (4503599627370496, 48, 1));
+ assert_eq!(0f64.integer_decode(), (0, -1075, 1));
+ assert_eq!((-0f64).integer_decode(), (0, -1075, -1));
+ assert_eq!(f64::INFINITY.integer_decode(), (4503599627370496, 972, 1));
+ assert_eq!(f64::NEG_INFINITY.integer_decode(), (4503599627370496, 972, -1));
+
+ // Ignore the "sign" (quiet / signalling flag) of NAN.
+ // It can vary between runtime operations and LLVM folding.
+ let (nan_m, nan_e, _nan_s) = f64::NAN.integer_decode();
+ assert_eq!((nan_m, nan_e), (6755399441055744, 972));
+}
diff --git a/library/core/tests/num/dec2flt/lemire.rs b/library/core/tests/num/dec2flt/lemire.rs
new file mode 100644
index 000000000..f71bbb7c7
--- /dev/null
+++ b/library/core/tests/num/dec2flt/lemire.rs
@@ -0,0 +1,53 @@
+use core::num::dec2flt::lemire::compute_float;
+
+fn compute_float32(q: i64, w: u64) -> (i32, u64) {
+ let fp = compute_float::<f32>(q, w);
+ (fp.e, fp.f)
+}
+
+fn compute_float64(q: i64, w: u64) -> (i32, u64) {
+ let fp = compute_float::<f64>(q, w);
+ (fp.e, fp.f)
+}
+
+#[test]
+fn compute_float_f32_rounding() {
+ // These test near-halfway cases for single-precision floats.
+ assert_eq!(compute_float32(0, 16777216), (151, 0));
+ assert_eq!(compute_float32(0, 16777217), (151, 0));
+ assert_eq!(compute_float32(0, 16777218), (151, 1));
+ assert_eq!(compute_float32(0, 16777219), (151, 2));
+ assert_eq!(compute_float32(0, 16777220), (151, 2));
+
+ // These are examples of the above tests, with
+ // digits from the exponent shifted to the mantissa.
+ assert_eq!(compute_float32(-10, 167772160000000000), (151, 0));
+ assert_eq!(compute_float32(-10, 167772170000000000), (151, 0));
+ assert_eq!(compute_float32(-10, 167772180000000000), (151, 1));
+ // Let's check the lines to see if anything is different in table...
+ assert_eq!(compute_float32(-10, 167772190000000000), (151, 2));
+ assert_eq!(compute_float32(-10, 167772200000000000), (151, 2));
+}
+
+#[test]
+fn compute_float_f64_rounding() {
+ // These test near-halfway cases for double-precision floats.
+ assert_eq!(compute_float64(0, 9007199254740992), (1076, 0));
+ assert_eq!(compute_float64(0, 9007199254740993), (1076, 0));
+ assert_eq!(compute_float64(0, 9007199254740994), (1076, 1));
+ assert_eq!(compute_float64(0, 9007199254740995), (1076, 2));
+ assert_eq!(compute_float64(0, 9007199254740996), (1076, 2));
+ assert_eq!(compute_float64(0, 18014398509481984), (1077, 0));
+ assert_eq!(compute_float64(0, 18014398509481986), (1077, 0));
+ assert_eq!(compute_float64(0, 18014398509481988), (1077, 1));
+ assert_eq!(compute_float64(0, 18014398509481990), (1077, 2));
+ assert_eq!(compute_float64(0, 18014398509481992), (1077, 2));
+
+ // These are examples of the above tests, with
+ // digits from the exponent shifted to the mantissa.
+ assert_eq!(compute_float64(-3, 9007199254740992000), (1076, 0));
+ assert_eq!(compute_float64(-3, 9007199254740993000), (1076, 0));
+ assert_eq!(compute_float64(-3, 9007199254740994000), (1076, 1));
+ assert_eq!(compute_float64(-3, 9007199254740995000), (1076, 2));
+ assert_eq!(compute_float64(-3, 9007199254740996000), (1076, 2));
+}
diff --git a/library/core/tests/num/dec2flt/mod.rs b/library/core/tests/num/dec2flt/mod.rs
new file mode 100644
index 000000000..c4e105cba
--- /dev/null
+++ b/library/core/tests/num/dec2flt/mod.rs
@@ -0,0 +1,140 @@
+#![allow(overflowing_literals)]
+
+mod float;
+mod lemire;
+mod parse;
+
+// Take a float literal, turn it into a string in various ways (that are all trusted
+// to be correct) and see if those strings are parsed back to the value of the literal.
+// Requires a *polymorphic literal*, i.e., one that can serve as f64 as well as f32.
+macro_rules! test_literal {
+ ($x: expr) => {{
+ let x32: f32 = $x;
+ let x64: f64 = $x;
+ let inputs = &[stringify!($x).into(), format!("{:?}", x64), format!("{:e}", x64)];
+ for input in inputs {
+ assert_eq!(input.parse(), Ok(x64));
+ assert_eq!(input.parse(), Ok(x32));
+ let neg_input = &format!("-{input}");
+ assert_eq!(neg_input.parse(), Ok(-x64));
+ assert_eq!(neg_input.parse(), Ok(-x32));
+ }
+ }};
+}
+
+#[test]
+fn ordinary() {
+ test_literal!(1.0);
+ test_literal!(3e-5);
+ test_literal!(0.1);
+ test_literal!(12345.);
+ test_literal!(0.9999999);
+ test_literal!(2.2250738585072014e-308);
+}
+
+#[test]
+fn special_code_paths() {
+ test_literal!(36893488147419103229.0); // 2^65 - 3, triggers half-to-even with even significand
+ test_literal!(101e-33); // Triggers the tricky underflow case in AlgorithmM (for f32)
+ test_literal!(1e23); // Triggers AlgorithmR
+ test_literal!(2075e23); // Triggers another path through AlgorithmR
+ test_literal!(8713e-23); // ... and yet another.
+}
+
+#[test]
+fn large() {
+ test_literal!(1e300);
+ test_literal!(123456789.34567e250);
+ test_literal!(943794359898089732078308743689303290943794359843568973207830874368930329.);
+}
+
+#[test]
+fn subnormals() {
+ test_literal!(5e-324);
+ test_literal!(91e-324);
+ test_literal!(1e-322);
+ test_literal!(13245643e-320);
+ test_literal!(2.22507385851e-308);
+ test_literal!(2.1e-308);
+ test_literal!(4.9406564584124654e-324);
+}
+
+#[test]
+fn infinity() {
+ test_literal!(1e400);
+ test_literal!(1e309);
+ test_literal!(2e308);
+ test_literal!(1.7976931348624e308);
+}
+
+#[test]
+fn zero() {
+ test_literal!(0.0);
+ test_literal!(1e-325);
+ test_literal!(1e-326);
+ test_literal!(1e-500);
+}
+
+#[test]
+fn fast_path_correct() {
+ // This number triggers the fast path and is handled incorrectly when compiling on
+ // x86 without SSE2 (i.e., using the x87 FPU stack).
+ test_literal!(1.448997445238699);
+}
+
+#[test]
+fn lonely_dot() {
+ assert!(".".parse::<f32>().is_err());
+ assert!(".".parse::<f64>().is_err());
+}
+
+#[test]
+fn exponentiated_dot() {
+ assert!(".e0".parse::<f32>().is_err());
+ assert!(".e0".parse::<f64>().is_err());
+}
+
+#[test]
+fn lonely_sign() {
+ assert!("+".parse::<f32>().is_err());
+ assert!("-".parse::<f64>().is_err());
+}
+
+#[test]
+fn whitespace() {
+ assert!(" 1.0".parse::<f32>().is_err());
+ assert!("1.0 ".parse::<f64>().is_err());
+}
+
+#[test]
+fn nan() {
+ assert!("NaN".parse::<f32>().unwrap().is_nan());
+ assert!("NaN".parse::<f64>().unwrap().is_nan());
+}
+
+#[test]
+fn inf() {
+ assert_eq!("inf".parse(), Ok(f64::INFINITY));
+ assert_eq!("-inf".parse(), Ok(f64::NEG_INFINITY));
+ assert_eq!("inf".parse(), Ok(f32::INFINITY));
+ assert_eq!("-inf".parse(), Ok(f32::NEG_INFINITY));
+}
+
+#[test]
+fn massive_exponent() {
+ let max = i64::MAX;
+ assert_eq!(format!("1e{max}000").parse(), Ok(f64::INFINITY));
+ assert_eq!(format!("1e-{max}000").parse(), Ok(0.0));
+ assert_eq!(format!("1e{max}000").parse(), Ok(f64::INFINITY));
+}
+
+#[test]
+fn borderline_overflow() {
+ let mut s = "0.".to_string();
+ for _ in 0..375 {
+ s.push('3');
+ }
+ // At the time of this writing, this returns Err(..), but this is a bug that should be fixed.
+ // It makes no sense to enshrine that in a test, the important part is that it doesn't panic.
+ let _ = s.parse::<f64>();
+}
diff --git a/library/core/tests/num/dec2flt/parse.rs b/library/core/tests/num/dec2flt/parse.rs
new file mode 100644
index 000000000..edc77377d
--- /dev/null
+++ b/library/core/tests/num/dec2flt/parse.rs
@@ -0,0 +1,177 @@
+use core::num::dec2flt::number::Number;
+use core::num::dec2flt::parse::parse_number;
+use core::num::dec2flt::{dec2flt, pfe_invalid};
+
+fn new_number(e: i64, m: u64) -> Number {
+ Number { exponent: e, mantissa: m, negative: false, many_digits: false }
+}
+
+#[test]
+fn missing_pieces() {
+ let permutations = &[".e", "1e", "e4", "e", ".12e", "321.e", "32.12e+", "12.32e-"];
+ for &s in permutations {
+ assert_eq!(dec2flt::<f64>(s), Err(pfe_invalid()));
+ }
+}
+
+#[test]
+fn invalid_chars() {
+ let invalid = "r,?<j";
+ let error = Err(pfe_invalid());
+ let valid_strings = &["123", "666.", ".1", "5e1", "7e-3", "0.0e+1"];
+ for c in invalid.chars() {
+ for s in valid_strings {
+ for i in 0..s.len() {
+ let mut input = String::new();
+ input.push_str(s);
+ input.insert(i, c);
+ assert!(dec2flt::<f64>(&input) == error, "did not reject invalid {:?}", input);
+ }
+ }
+ }
+}
+
+fn parse_positive(s: &[u8]) -> Option<Number> {
+ parse_number(s, false)
+}
+
+#[test]
+fn valid() {
+ assert_eq!(parse_positive(b"123.456e789"), Some(new_number(786, 123456)));
+ assert_eq!(parse_positive(b"123.456e+789"), Some(new_number(786, 123456)));
+ assert_eq!(parse_positive(b"123.456e-789"), Some(new_number(-792, 123456)));
+ assert_eq!(parse_positive(b".050"), Some(new_number(-3, 50)));
+ assert_eq!(parse_positive(b"999"), Some(new_number(0, 999)));
+ assert_eq!(parse_positive(b"1.e300"), Some(new_number(300, 1)));
+ assert_eq!(parse_positive(b".1e300"), Some(new_number(299, 1)));
+ assert_eq!(parse_positive(b"101e-33"), Some(new_number(-33, 101)));
+ let zeros = "0".repeat(25);
+ let s = format!("1.5e{zeros}");
+ assert_eq!(parse_positive(s.as_bytes()), Some(new_number(-1, 15)));
+}
+
+macro_rules! assert_float_result_bits_eq {
+ ($bits:literal, $ty:ty, $str:literal) => {{
+ let p = dec2flt::<$ty>($str);
+ assert_eq!(p.map(|x| x.to_bits()), Ok($bits));
+ }};
+}
+
+#[test]
+fn issue31109() {
+ // Regression test for #31109.
+ // Ensure the test produces a valid float with the expected bit pattern.
+ assert_float_result_bits_eq!(
+ 0x3fd5555555555555,
+ f64,
+ "0.3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333"
+ );
+}
+
+#[test]
+fn issue31407() {
+ // Regression test for #31407.
+ // Ensure the test produces a valid float with the expected bit pattern.
+ assert_float_result_bits_eq!(
+ 0x1752a64e34ba0d3,
+ f64,
+ "1234567890123456789012345678901234567890e-340"
+ );
+ assert_float_result_bits_eq!(
+ 0xfffffffffffff,
+ f64,
+ "2.225073858507201136057409796709131975934819546351645648023426109724822222021076945516529523908135087914149158913039621106870086438694594645527657207407820621743379988141063267329253552286881372149012981122451451889849057222307285255133155755015914397476397983411801999323962548289017107081850690630666655994938275772572015763062690663332647565300009245888316433037779791869612049497390377829704905051080609940730262937128958950003583799967207254304360284078895771796150945516748243471030702609144621572289880258182545180325707018860872113128079512233426288368622321503775666622503982534335974568884423900265498198385487948292206894721689831099698365846814022854243330660339850886445804001034933970427567186443383770486037861622771738545623065874679014086723327636718749999999999999999999999999999999999999e-308"
+ );
+ assert_float_result_bits_eq!(
+ 0x10000000000000,
+ f64,
+ "2.22507385850720113605740979670913197593481954635164564802342610972482222202107694551652952390813508791414915891303962110687008643869459464552765720740782062174337998814106326732925355228688137214901298112245145188984905722230728525513315575501591439747639798341180199932396254828901710708185069063066665599493827577257201576306269066333264756530000924588831643303777979186961204949739037782970490505108060994073026293712895895000358379996720725430436028407889577179615094551674824347103070260914462157228988025818254518032570701886087211312807951223342628836862232150377566662250398253433597456888442390026549819838548794829220689472168983109969836584681402285424333066033985088644580400103493397042756718644338377048603786162277173854562306587467901408672332763671875e-308"
+ );
+ assert_float_result_bits_eq!(
+ 0x10000000000000,
+ f64,
+ "0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000222507385850720138309023271733240406421921598046233183055332741688720443481391819585428315901251102056406733973103581100515243416155346010885601238537771882113077799353200233047961014744258363607192156504694250373420837525080665061665815894872049117996859163964850063590877011830487479978088775374994945158045160505091539985658247081864511353793580499211598108576605199243335211435239014879569960959128889160299264151106346631339366347758651302937176204732563178148566435087212282863764204484681140761391147706280168985324411002416144742161856716615054015428508471675290190316132277889672970737312333408698898317506783884692609277397797285865965494109136909540613646756870239867831529068098461721092462539672851562500000000000000001"
+ );
+ assert_float_result_bits_eq!(
+ 0x7fefffffffffffff,
+ f64,
+ "179769313486231580793728971405303415079934132710037826936173778980444968292764750946649017977587207096330286416692887910946555547851940402630657488671505820681908902000708383676273854845817711531764475730270069855571366959622842914819860834936475292719074168444365510704342711559699508093042880177904174497791.9999999999999999999999999999999999999999999999999999999999999999999999"
+ );
+ assert_float_result_bits_eq!(0x0, f64, "2.47032822920623272e-324");
+ assert_float_result_bits_eq!(
+ 0x8000000,
+ f64,
+ "6.631236871469758276785396630275967243399099947355303144249971758736286630139265439618068200788048744105960420552601852889715006376325666595539603330361800519107591783233358492337208057849499360899425128640718856616503093444922854759159988160304439909868291973931426625698663157749836252274523485312442358651207051292453083278116143932569727918709786004497872322193856150225415211997283078496319412124640111777216148110752815101775295719811974338451936095907419622417538473679495148632480391435931767981122396703443803335529756003353209830071832230689201383015598792184172909927924176339315507402234836120730914783168400715462440053817592702766213559042115986763819482654128770595766806872783349146967171293949598850675682115696218943412532098591327667236328125E-316"
+ );
+ assert_float_result_bits_eq!(
+ 0x10000,
+ f64,
+ "3.237883913302901289588352412501532174863037669423108059901297049552301970670676565786835742587799557860615776559838283435514391084153169252689190564396459577394618038928365305143463955100356696665629202017331344031730044369360205258345803431471660032699580731300954848363975548690010751530018881758184174569652173110473696022749934638425380623369774736560008997404060967498028389191878963968575439222206416981462690113342524002724385941651051293552601421155333430225237291523843322331326138431477823591142408800030775170625915670728657003151953664260769822494937951845801530895238439819708403389937873241463484205608000027270531106827387907791444918534771598750162812548862768493201518991668028251730299953143924168545708663913273994694463908672332763671875E-319"
+ );
+ assert_float_result_bits_eq!(
+ 0x800000000100,
+ f64,
+ "6.953355807847677105972805215521891690222119817145950754416205607980030131549636688806115726399441880065386399864028691275539539414652831584795668560082999889551357784961446896042113198284213107935110217162654939802416034676213829409720583759540476786936413816541621287843248433202369209916612249676005573022703244799714622116542188837770376022371172079559125853382801396219552418839469770514904192657627060319372847562301074140442660237844114174497210955449896389180395827191602886654488182452409583981389442783377001505462015745017848754574668342161759496661766020028752888783387074850773192997102997936619876226688096314989645766000479009083731736585750335262099860150896718774401964796827166283225641992040747894382698751809812609536720628966577351093292236328125E-310"
+ );
+ assert_float_result_bits_eq!(
+ 0x10800,
+ f64,
+ "3.339068557571188581835713701280943911923401916998521771655656997328440314559615318168849149074662609099998113009465566426808170378434065722991659642619467706034884424989741080790766778456332168200464651593995817371782125010668346652995912233993254584461125868481633343674905074271064409763090708017856584019776878812425312008812326260363035474811532236853359905334625575404216060622858633280744301892470300555678734689978476870369853549413277156622170245846166991655321535529623870646888786637528995592800436177901746286272273374471701452991433047257863864601424252024791567368195056077320885329384322332391564645264143400798619665040608077549162173963649264049738362290606875883456826586710961041737908872035803481241600376705491726170293986797332763671875E-319"
+ );
+ assert_float_result_bits_eq!(
+ 0x0,
+ f64,
+ "2.4703282292062327208828439643411068618252990130716238221279284125033775363510437593264991818081799618989828234772285886546332835517796989819938739800539093906315035659515570226392290858392449105184435931802849936536152500319370457678249219365623669863658480757001585769269903706311928279558551332927834338409351978015531246597263579574622766465272827220056374006485499977096599470454020828166226237857393450736339007967761930577506740176324673600968951340535537458516661134223766678604162159680461914467291840300530057530849048765391711386591646239524912623653881879636239373280423891018672348497668235089863388587925628302755995657524455507255189313690836254779186948667994968324049705821028513185451396213837722826145437693412532098591327667236328124999e-324"
+ );
+ assert_float_result_bits_eq!(
+ 0x0,
+ f64,
+ "2.4703282292062327208828439643411068618252990130716238221279284125033775363510437593264991818081799618989828234772285886546332835517796989819938739800539093906315035659515570226392290858392449105184435931802849936536152500319370457678249219365623669863658480757001585769269903706311928279558551332927834338409351978015531246597263579574622766465272827220056374006485499977096599470454020828166226237857393450736339007967761930577506740176324673600968951340535537458516661134223766678604162159680461914467291840300530057530849048765391711386591646239524912623653881879636239373280423891018672348497668235089863388587925628302755995657524455507255189313690836254779186948667994968324049705821028513185451396213837722826145437693412532098591327667236328125e-324"
+ );
+ assert_float_result_bits_eq!(
+ 0x1,
+ f64,
+ "2.4703282292062327208828439643411068618252990130716238221279284125033775363510437593264991818081799618989828234772285886546332835517796989819938739800539093906315035659515570226392290858392449105184435931802849936536152500319370457678249219365623669863658480757001585769269903706311928279558551332927834338409351978015531246597263579574622766465272827220056374006485499977096599470454020828166226237857393450736339007967761930577506740176324673600968951340535537458516661134223766678604162159680461914467291840300530057530849048765391711386591646239524912623653881879636239373280423891018672348497668235089863388587925628302755995657524455507255189313690836254779186948667994968324049705821028513185451396213837722826145437693412532098591327667236328125001e-324"
+ );
+ assert_float_result_bits_eq!(
+ 0x1,
+ f64,
+ "7.4109846876186981626485318930233205854758970392148714663837852375101326090531312779794975454245398856969484704316857659638998506553390969459816219401617281718945106978546710679176872575177347315553307795408549809608457500958111373034747658096871009590975442271004757307809711118935784838675653998783503015228055934046593739791790738723868299395818481660169122019456499931289798411362062484498678713572180352209017023903285791732520220528974020802906854021606612375549983402671300035812486479041385743401875520901590172592547146296175134159774938718574737870961645638908718119841271673056017045493004705269590165763776884908267986972573366521765567941072508764337560846003984904972149117463085539556354188641513168478436313080237596295773983001708984374999e-324"
+ );
+ assert_float_result_bits_eq!(
+ 0x2,
+ f64,
+ "7.4109846876186981626485318930233205854758970392148714663837852375101326090531312779794975454245398856969484704316857659638998506553390969459816219401617281718945106978546710679176872575177347315553307795408549809608457500958111373034747658096871009590975442271004757307809711118935784838675653998783503015228055934046593739791790738723868299395818481660169122019456499931289798411362062484498678713572180352209017023903285791732520220528974020802906854021606612375549983402671300035812486479041385743401875520901590172592547146296175134159774938718574737870961645638908718119841271673056017045493004705269590165763776884908267986972573366521765567941072508764337560846003984904972149117463085539556354188641513168478436313080237596295773983001708984375e-324"
+ );
+ assert_float_result_bits_eq!(
+ 0x2,
+ f64,
+ "7.4109846876186981626485318930233205854758970392148714663837852375101326090531312779794975454245398856969484704316857659638998506553390969459816219401617281718945106978546710679176872575177347315553307795408549809608457500958111373034747658096871009590975442271004757307809711118935784838675653998783503015228055934046593739791790738723868299395818481660169122019456499931289798411362062484498678713572180352209017023903285791732520220528974020802906854021606612375549983402671300035812486479041385743401875520901590172592547146296175134159774938718574737870961645638908718119841271673056017045493004705269590165763776884908267986972573366521765567941072508764337560846003984904972149117463085539556354188641513168478436313080237596295773983001708984375001e-324"
+ );
+ assert_float_result_bits_eq!(
+ 0x6c9a143590c14,
+ f64,
+ "94393431193180696942841837085033647913224148539854e-358"
+ );
+ assert_float_result_bits_eq!(
+ 0x7802665fd9600,
+ f64,
+ "104308485241983990666713401708072175773165034278685682646111762292409330928739751702404658197872319129036519947435319418387839758990478549477777586673075945844895981012024387992135617064532141489278815239849108105951619997829153633535314849999674266169258928940692239684771590065027025835804863585454872499320500023126142553932654370362024104462255244034053203998964360882487378334860197725139151265590832887433736189468858614521708567646743455601905935595381852723723645799866672558576993978025033590728687206296379801363024094048327273913079612469982585674824156000783167963081616214710691759864332339239688734656548790656486646106983450809073750535624894296242072010195710276073042036425579852459556183541199012652571123898996574563824424330960027873516082763671875e-1075"
+ );
+}
+
+#[test]
+fn many_digits() {
+ // Check large numbers of digits to ensure we have cases where significant
+ // digits (above Decimal::MAX_DIGITS) occurs.
+ assert_float_result_bits_eq!(
+ 0x7ffffe,
+ f32,
+ "1.175494140627517859246175898662808184331245864732796240031385942718174675986064769972472277004271745681762695312500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e-38"
+ );
+ assert_float_result_bits_eq!(
+ 0x7ffffe,
+ f32,
+ "1.175494140627517859246175898662808184331245864732796240031385942718174675986064769972472277004271745681762695312500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e-38"
+ );
+}
diff --git a/library/core/tests/num/flt2dec/estimator.rs b/library/core/tests/num/flt2dec/estimator.rs
new file mode 100644
index 000000000..da203b5f3
--- /dev/null
+++ b/library/core/tests/num/flt2dec/estimator.rs
@@ -0,0 +1,62 @@
+use core::num::flt2dec::estimator::*;
+
+#[test]
+fn test_estimate_scaling_factor() {
+ macro_rules! assert_almost_eq {
+ ($actual:expr, $expected:expr) => {{
+ let actual = $actual;
+ let expected = $expected;
+ println!(
+ "{} - {} = {} - {} = {}",
+ stringify!($expected),
+ stringify!($actual),
+ expected,
+ actual,
+ expected - actual
+ );
+ assert!(
+ expected == actual || expected == actual + 1,
+ "expected {}, actual {}",
+ expected,
+ actual
+ );
+ }};
+ }
+
+ assert_almost_eq!(estimate_scaling_factor(1, 0), 0);
+ assert_almost_eq!(estimate_scaling_factor(2, 0), 1);
+ assert_almost_eq!(estimate_scaling_factor(10, 0), 1);
+ assert_almost_eq!(estimate_scaling_factor(11, 0), 2);
+ assert_almost_eq!(estimate_scaling_factor(100, 0), 2);
+ assert_almost_eq!(estimate_scaling_factor(101, 0), 3);
+ assert_almost_eq!(estimate_scaling_factor(10000000000000000000, 0), 19);
+ assert_almost_eq!(estimate_scaling_factor(10000000000000000001, 0), 20);
+
+ // 1/2^20 = 0.00000095367...
+ assert_almost_eq!(estimate_scaling_factor(1 * 1048576 / 1000000, -20), -6);
+ assert_almost_eq!(estimate_scaling_factor(1 * 1048576 / 1000000 + 1, -20), -5);
+ assert_almost_eq!(estimate_scaling_factor(10 * 1048576 / 1000000, -20), -5);
+ assert_almost_eq!(estimate_scaling_factor(10 * 1048576 / 1000000 + 1, -20), -4);
+ assert_almost_eq!(estimate_scaling_factor(100 * 1048576 / 1000000, -20), -4);
+ assert_almost_eq!(estimate_scaling_factor(100 * 1048576 / 1000000 + 1, -20), -3);
+ assert_almost_eq!(estimate_scaling_factor(1048575, -20), 0);
+ assert_almost_eq!(estimate_scaling_factor(1048576, -20), 0);
+ assert_almost_eq!(estimate_scaling_factor(1048577, -20), 1);
+ assert_almost_eq!(estimate_scaling_factor(10485759999999999999, -20), 13);
+ assert_almost_eq!(estimate_scaling_factor(10485760000000000000, -20), 13);
+ assert_almost_eq!(estimate_scaling_factor(10485760000000000001, -20), 14);
+
+ // extreme values:
+ // 2^-1074 = 4.94065... * 10^-324
+ // (2^53-1) * 2^971 = 1.79763... * 10^308
+ assert_almost_eq!(estimate_scaling_factor(1, -1074), -323);
+ assert_almost_eq!(estimate_scaling_factor(0x1fffffffffffff, 971), 309);
+
+ // Miri is too slow
+ let step = if cfg!(miri) { 37 } else { 1 };
+
+ for i in (-1074..972).step_by(step) {
+ let expected = super::ldexp_f64(1.0, i).log10().ceil();
+ assert_almost_eq!(estimate_scaling_factor(1, i as i16), expected as i16);
+ }
+}
diff --git a/library/core/tests/num/flt2dec/mod.rs b/library/core/tests/num/flt2dec/mod.rs
new file mode 100644
index 000000000..798473bbd
--- /dev/null
+++ b/library/core/tests/num/flt2dec/mod.rs
@@ -0,0 +1,1172 @@
+use std::mem::MaybeUninit;
+use std::{fmt, str};
+
+use core::num::flt2dec::{decode, DecodableFloat, Decoded, FullDecoded};
+use core::num::flt2dec::{round_up, Sign, MAX_SIG_DIGITS};
+use core::num::flt2dec::{
+ to_exact_exp_str, to_exact_fixed_str, to_shortest_exp_str, to_shortest_str,
+};
+use core::num::fmt::{Formatted, Part};
+
+pub use test::Bencher;
+
+mod estimator;
+mod strategy {
+ mod dragon;
+ mod grisu;
+}
+mod random;
+
+pub fn decode_finite<T: DecodableFloat>(v: T) -> Decoded {
+ match decode(v).1 {
+ FullDecoded::Finite(decoded) => decoded,
+ full_decoded => panic!("expected finite, got {full_decoded:?} instead"),
+ }
+}
+
+macro_rules! check_shortest {
+ ($f:ident($v:expr) => $buf:expr, $exp:expr) => (
+ check_shortest!($f($v) => $buf, $exp;
+ "shortest mismatch for v={v}: actual {actual:?}, expected {expected:?}",
+ v = stringify!($v))
+ );
+
+ ($f:ident{$($k:ident: $v:expr),+} => $buf:expr, $exp:expr) => (
+ check_shortest!($f{$($k: $v),+} => $buf, $exp;
+ "shortest mismatch for {v:?}: actual {actual:?}, expected {expected:?}",
+ v = Decoded { $($k: $v),+ })
+ );
+
+ ($f:ident($v:expr) => $buf:expr, $exp:expr; $fmt:expr, $($key:ident = $val:expr),*) => ({
+ let mut buf = [MaybeUninit::new(b'_'); MAX_SIG_DIGITS];
+ let (buf, k) = $f(&decode_finite($v), &mut buf);
+ assert!((buf, k) == ($buf, $exp),
+ $fmt, actual = (str::from_utf8(buf).unwrap(), k),
+ expected = (str::from_utf8($buf).unwrap(), $exp),
+ $($key = $val),*);
+ });
+
+ ($f:ident{$($k:ident: $v:expr),+} => $buf:expr, $exp:expr;
+ $fmt:expr, $($key:ident = $val:expr),*) => ({
+ let mut buf = [MaybeUninit::new(b'_'); MAX_SIG_DIGITS];
+ let (buf, k) = $f(&Decoded { $($k: $v),+ }, &mut buf);
+ assert!((buf, k) == ($buf, $exp),
+ $fmt, actual = (str::from_utf8(buf).unwrap(), k),
+ expected = (str::from_utf8($buf).unwrap(), $exp),
+ $($key = $val),*);
+ })
+}
+
+macro_rules! try_exact {
+ ($f:ident($decoded:expr) => $buf:expr, $expected:expr, $expectedk:expr;
+ $fmt:expr, $($key:ident = $val:expr),*) => ({
+ let (buf, k) = $f($decoded, &mut $buf[..$expected.len()], i16::MIN);
+ assert!((buf, k) == ($expected, $expectedk),
+ $fmt, actual = (str::from_utf8(buf).unwrap(), k),
+ expected = (str::from_utf8($expected).unwrap(), $expectedk),
+ $($key = $val),*);
+ })
+}
+
+macro_rules! try_fixed {
+ ($f:ident($decoded:expr) => $buf:expr, $request:expr, $expected:expr, $expectedk:expr;
+ $fmt:expr, $($key:ident = $val:expr),*) => ({
+ let (buf, k) = $f($decoded, &mut $buf[..], $request);
+ assert!((buf, k) == ($expected, $expectedk),
+ $fmt, actual = (str::from_utf8(buf).unwrap(), k),
+ expected = (str::from_utf8($expected).unwrap(), $expectedk),
+ $($key = $val),*);
+ })
+}
+
+fn ldexp_f32(a: f32, b: i32) -> f32 {
+ ldexp_f64(a as f64, b) as f32
+}
+
+fn ldexp_f64(a: f64, b: i32) -> f64 {
+ extern "C" {
+ fn ldexp(x: f64, n: i32) -> f64;
+ }
+ // SAFETY: assuming a correct `ldexp` has been supplied, the given arguments cannot possibly
+ // cause undefined behavior
+ unsafe { ldexp(a, b) }
+}
+
+fn check_exact<F, T>(mut f: F, v: T, vstr: &str, expected: &[u8], expectedk: i16)
+where
+ T: DecodableFloat,
+ F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>], i16) -> (&'a [u8], i16),
+{
+ // use a large enough buffer
+ let mut buf = [MaybeUninit::new(b'_'); 1024];
+ let mut expected_ = [b'_'; 1024];
+
+ let decoded = decode_finite(v);
+ let cut = expected.iter().position(|&c| c == b' ');
+
+ // check significant digits
+ for i in 1..cut.unwrap_or(expected.len() - 1) {
+ expected_[..i].copy_from_slice(&expected[..i]);
+ let mut expectedk_ = expectedk;
+ if expected[i] >= b'5' {
+ // check if this is a rounding-to-even case.
+ // we avoid rounding ...x5000... (with infinite zeroes) to ...(x+1) when x is even.
+ if !(i + 1 < expected.len()
+ && expected[i - 1] & 1 == 0
+ && expected[i] == b'5'
+ && expected[i + 1] == b' ')
+ {
+ // if this returns true, expected_[..i] is all `9`s and being rounded up.
+ // we should always return `100..00` (`i` digits) instead, since that's
+ // what we can came up with `i` digits anyway. `round_up` assumes that
+ // the adjustment to the length is done by caller, which we simply ignore.
+ if let Some(_) = round_up(&mut expected_[..i]) {
+ expectedk_ += 1;
+ }
+ }
+ }
+
+ try_exact!(f(&decoded) => &mut buf, &expected_[..i], expectedk_;
+ "exact sigdigit mismatch for v={v}, i={i}: \
+ actual {actual:?}, expected {expected:?}",
+ v = vstr, i = i);
+ try_fixed!(f(&decoded) => &mut buf, expectedk_ - i as i16, &expected_[..i], expectedk_;
+ "fixed sigdigit mismatch for v={v}, i={i}: \
+ actual {actual:?}, expected {expected:?}",
+ v = vstr, i = i);
+ }
+
+ // check exact rounding for zero- and negative-width cases
+ let start;
+ if expected[0] >= b'5' {
+ try_fixed!(f(&decoded) => &mut buf, expectedk, b"1", expectedk + 1;
+ "zero-width rounding-up mismatch for v={v}: \
+ actual {actual:?}, expected {expected:?}",
+ v = vstr);
+ start = 1;
+ } else {
+ start = 0;
+ }
+ for i in start..-10 {
+ try_fixed!(f(&decoded) => &mut buf, expectedk - i, b"", expectedk;
+ "rounding-down mismatch for v={v}, i={i}: \
+ actual {actual:?}, expected {expected:?}",
+ v = vstr, i = -i);
+ }
+
+ // check infinite zero digits
+ if let Some(cut) = cut {
+ for i in cut..expected.len() - 1 {
+ expected_[..cut].copy_from_slice(&expected[..cut]);
+ for c in &mut expected_[cut..i] {
+ *c = b'0';
+ }
+
+ try_exact!(f(&decoded) => &mut buf, &expected_[..i], expectedk;
+ "exact infzero mismatch for v={v}, i={i}: \
+ actual {actual:?}, expected {expected:?}",
+ v = vstr, i = i);
+ try_fixed!(f(&decoded) => &mut buf, expectedk - i as i16, &expected_[..i], expectedk;
+ "fixed infzero mismatch for v={v}, i={i}: \
+ actual {actual:?}, expected {expected:?}",
+ v = vstr, i = i);
+ }
+ }
+}
+
+trait TestableFloat: DecodableFloat + fmt::Display {
+ /// Returns `x * 2^exp`. Almost same to `std::{f32,f64}::ldexp`.
+ /// This is used for testing.
+ fn ldexpi(f: i64, exp: isize) -> Self;
+}
+
+impl TestableFloat for f32 {
+ fn ldexpi(f: i64, exp: isize) -> Self {
+ f as Self * (exp as Self).exp2()
+ }
+}
+
+impl TestableFloat for f64 {
+ fn ldexpi(f: i64, exp: isize) -> Self {
+ f as Self * (exp as Self).exp2()
+ }
+}
+
+fn check_exact_one<F, T>(mut f: F, x: i64, e: isize, tstr: &str, expected: &[u8], expectedk: i16)
+where
+ T: TestableFloat,
+ F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>], i16) -> (&'a [u8], i16),
+{
+ // use a large enough buffer
+ let mut buf = [MaybeUninit::new(b'_'); 1024];
+ let v: T = TestableFloat::ldexpi(x, e);
+ let decoded = decode_finite(v);
+
+ try_exact!(f(&decoded) => &mut buf, &expected, expectedk;
+ "exact mismatch for v={x}p{e}{t}: actual {actual:?}, expected {expected:?}",
+ x = x, e = e, t = tstr);
+ try_fixed!(f(&decoded) => &mut buf, expectedk - expected.len() as i16, &expected, expectedk;
+ "fixed mismatch for v={x}p{e}{t}: actual {actual:?}, expected {expected:?}",
+ x = x, e = e, t = tstr);
+}
+
+macro_rules! check_exact {
+ ($f:ident($v:expr) => $buf:expr, $exp:expr) => {
+ check_exact(|d, b, k| $f(d, b, k), $v, stringify!($v), $buf, $exp)
+ };
+}
+
+macro_rules! check_exact_one {
+ ($f:ident($x:expr, $e:expr; $t:ty) => $buf:expr, $exp:expr) => {
+ check_exact_one::<_, $t>(|d, b, k| $f(d, b, k), $x, $e, stringify!($t), $buf, $exp)
+ };
+}
+
+// in the following comments, three numbers are spaced by 1 ulp apart,
+// and the second one is being formatted.
+//
+// some tests are derived from [1].
+//
+// [1] Vern Paxson, A Program for Testing IEEE Decimal-Binary Conversion
+// ftp://ftp.ee.lbl.gov/testbase-report.ps.Z
+
+pub fn f32_shortest_sanity_test<F>(mut f: F)
+where
+ F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>]) -> (&'a [u8], i16),
+{
+ // 0.0999999940395355224609375
+ // 0.100000001490116119384765625
+ // 0.10000000894069671630859375
+ check_shortest!(f(0.1f32) => b"1", 0);
+
+ // 0.333333313465118408203125
+ // 0.3333333432674407958984375 (1/3 in the default rounding)
+ // 0.33333337306976318359375
+ check_shortest!(f(1.0f32/3.0) => b"33333334", 0);
+
+ // 10^1 * 0.31415917873382568359375
+ // 10^1 * 0.31415920257568359375
+ // 10^1 * 0.31415922641754150390625
+ check_shortest!(f(3.141592f32) => b"3141592", 1);
+
+ // 10^18 * 0.31415916243714048
+ // 10^18 * 0.314159196796878848
+ // 10^18 * 0.314159231156617216
+ check_shortest!(f(3.141592e17f32) => b"3141592", 18);
+
+ // regression test for decoders
+ // 10^8 * 0.3355443
+ // 10^8 * 0.33554432
+ // 10^8 * 0.33554436
+ check_shortest!(f(ldexp_f32(1.0, 25)) => b"33554432", 8);
+
+ // 10^39 * 0.340282326356119256160033759537265639424
+ // 10^39 * 0.34028234663852885981170418348451692544
+ // 10^39 * 0.340282366920938463463374607431768211456
+ check_shortest!(f(f32::MAX) => b"34028235", 39);
+
+ // 10^-37 * 0.1175494210692441075487029444849287348827...
+ // 10^-37 * 0.1175494350822287507968736537222245677818...
+ // 10^-37 * 0.1175494490952133940450443629595204006810...
+ check_shortest!(f(f32::MIN_POSITIVE) => b"11754944", -37);
+
+ // 10^-44 * 0
+ // 10^-44 * 0.1401298464324817070923729583289916131280...
+ // 10^-44 * 0.2802596928649634141847459166579832262560...
+ let minf32 = ldexp_f32(1.0, -149);
+ check_shortest!(f(minf32) => b"1", -44);
+}
+
+pub fn f32_exact_sanity_test<F>(mut f: F)
+where
+ F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>], i16) -> (&'a [u8], i16),
+{
+ let minf32 = ldexp_f32(1.0, -149);
+
+ check_exact!(f(0.1f32) => b"100000001490116119384765625 ", 0);
+ check_exact!(f(0.5f32) => b"5 ", 0);
+ check_exact!(f(1.0f32/3.0) => b"3333333432674407958984375 ", 0);
+ check_exact!(f(3.141592f32) => b"31415920257568359375 ", 1);
+ check_exact!(f(3.141592e17f32) => b"314159196796878848 ", 18);
+ check_exact!(f(f32::MAX) => b"34028234663852885981170418348451692544 ", 39);
+ check_exact!(f(f32::MIN_POSITIVE) => b"1175494350822287507968736537222245677818", -37);
+ check_exact!(f(minf32) => b"1401298464324817070923729583289916131280", -44);
+
+ // [1], Table 16: Stress Inputs for Converting 24-bit Binary to Decimal, < 1/2 ULP
+ check_exact_one!(f(12676506, -102; f32) => b"2", -23);
+ check_exact_one!(f(12676506, -103; f32) => b"12", -23);
+ check_exact_one!(f(15445013, 86; f32) => b"119", 34);
+ check_exact_one!(f(13734123, -138; f32) => b"3941", -34);
+ check_exact_one!(f(12428269, -130; f32) => b"91308", -32);
+ check_exact_one!(f(15334037, -146; f32) => b"171900", -36);
+ check_exact_one!(f(11518287, -41; f32) => b"5237910", -5);
+ check_exact_one!(f(12584953, -145; f32) => b"28216440", -36);
+ check_exact_one!(f(15961084, -125; f32) => b"375243281", -30);
+ check_exact_one!(f(14915817, -146; f32) => b"1672120916", -36);
+ check_exact_one!(f(10845484, -102; f32) => b"21388945814", -23);
+ check_exact_one!(f(16431059, -61; f32) => b"712583594561", -11);
+
+ // [1], Table 17: Stress Inputs for Converting 24-bit Binary to Decimal, > 1/2 ULP
+ check_exact_one!(f(16093626, 69; f32) => b"1", 29);
+ check_exact_one!(f( 9983778, 25; f32) => b"34", 15);
+ check_exact_one!(f(12745034, 104; f32) => b"259", 39);
+ check_exact_one!(f(12706553, 72; f32) => b"6001", 29);
+ check_exact_one!(f(11005028, 45; f32) => b"38721", 21);
+ check_exact_one!(f(15059547, 71; f32) => b"355584", 29);
+ check_exact_one!(f(16015691, -99; f32) => b"2526831", -22);
+ check_exact_one!(f( 8667859, 56; f32) => b"62458507", 24);
+ check_exact_one!(f(14855922, -82; f32) => b"307213267", -17);
+ check_exact_one!(f(14855922, -83; f32) => b"1536066333", -17);
+ check_exact_one!(f(10144164, -110; f32) => b"78147796834", -26);
+ check_exact_one!(f(13248074, 95; f32) => b"524810279937", 36);
+}
+
+pub fn f64_shortest_sanity_test<F>(mut f: F)
+where
+ F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>]) -> (&'a [u8], i16),
+{
+ // 0.0999999999999999777955395074968691915273...
+ // 0.1000000000000000055511151231257827021181...
+ // 0.1000000000000000333066907387546962127089...
+ check_shortest!(f(0.1f64) => b"1", 0);
+
+ // this example is explicitly mentioned in the paper.
+ // 10^3 * 0.0999999999999999857891452847979962825775...
+ // 10^3 * 0.1 (exact)
+ // 10^3 * 0.1000000000000000142108547152020037174224...
+ check_shortest!(f(100.0f64) => b"1", 3);
+
+ // 0.3333333333333332593184650249895639717578...
+ // 0.3333333333333333148296162562473909929394... (1/3 in the default rounding)
+ // 0.3333333333333333703407674875052180141210...
+ check_shortest!(f(1.0f64/3.0) => b"3333333333333333", 0);
+
+ // explicit test case for equally closest representations.
+ // Dragon has its own tie-breaking rule; Grisu should fall back.
+ // 10^1 * 0.1000007629394531027955395074968691915273...
+ // 10^1 * 0.100000762939453125 (exact)
+ // 10^1 * 0.1000007629394531472044604925031308084726...
+ check_shortest!(f(1.00000762939453125f64) => b"10000076293945313", 1);
+
+ // 10^1 * 0.3141591999999999718085064159822650253772...
+ // 10^1 * 0.3141592000000000162174274009885266423225...
+ // 10^1 * 0.3141592000000000606263483859947882592678...
+ check_shortest!(f(3.141592f64) => b"3141592", 1);
+
+ // 10^18 * 0.314159199999999936
+ // 10^18 * 0.3141592 (exact)
+ // 10^18 * 0.314159200000000064
+ check_shortest!(f(3.141592e17f64) => b"3141592", 18);
+
+ // regression test for decoders
+ // 10^20 * 0.18446744073709549568
+ // 10^20 * 0.18446744073709551616
+ // 10^20 * 0.18446744073709555712
+ check_shortest!(f(ldexp_f64(1.0, 64)) => b"18446744073709552", 20);
+
+ // pathological case: high = 10^23 (exact). tie breaking should always prefer that.
+ // 10^24 * 0.099999999999999974834176
+ // 10^24 * 0.099999999999999991611392
+ // 10^24 * 0.100000000000000008388608
+ check_shortest!(f(1.0e23f64) => b"1", 24);
+
+ // 10^309 * 0.1797693134862315508561243283845062402343...
+ // 10^309 * 0.1797693134862315708145274237317043567980...
+ // 10^309 * 0.1797693134862315907729305190789024733617...
+ check_shortest!(f(f64::MAX) => b"17976931348623157", 309);
+
+ // 10^-307 * 0.2225073858507200889024586876085859887650...
+ // 10^-307 * 0.2225073858507201383090232717332404064219...
+ // 10^-307 * 0.2225073858507201877155878558578948240788...
+ check_shortest!(f(f64::MIN_POSITIVE) => b"22250738585072014", -307);
+
+ // 10^-323 * 0
+ // 10^-323 * 0.4940656458412465441765687928682213723650...
+ // 10^-323 * 0.9881312916824930883531375857364427447301...
+ let minf64 = ldexp_f64(1.0, -1074);
+ check_shortest!(f(minf64) => b"5", -323);
+}
+
+pub fn f64_exact_sanity_test<F>(mut f: F)
+where
+ F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>], i16) -> (&'a [u8], i16),
+{
+ let minf64 = ldexp_f64(1.0, -1074);
+
+ check_exact!(f(0.1f64) => b"1000000000000000055511151231257827021181", 0);
+ check_exact!(f(0.45f64) => b"4500000000000000111022302462515654042363", 0);
+ check_exact!(f(0.5f64) => b"5 ", 0);
+ check_exact!(f(0.95f64) => b"9499999999999999555910790149937383830547", 0);
+ check_exact!(f(100.0f64) => b"1 ", 3);
+ check_exact!(f(999.5f64) => b"9995000000000000000000000000000000000000", 3);
+ check_exact!(f(1.0f64/3.0) => b"3333333333333333148296162562473909929394", 0);
+ check_exact!(f(3.141592f64) => b"3141592000000000162174274009885266423225", 1);
+ check_exact!(f(3.141592e17f64) => b"3141592 ", 18);
+ check_exact!(f(1.0e23f64) => b"99999999999999991611392 ", 23);
+ check_exact!(f(f64::MAX) => b"1797693134862315708145274237317043567980", 309);
+ check_exact!(f(f64::MIN_POSITIVE) => b"2225073858507201383090232717332404064219", -307);
+ check_exact!(f(minf64) => b"4940656458412465441765687928682213723650\
+ 5980261432476442558568250067550727020875\
+ 1865299836361635992379796564695445717730\
+ 9266567103559397963987747960107818781263\
+ 0071319031140452784581716784898210368871\
+ 8636056998730723050006387409153564984387\
+ 3124733972731696151400317153853980741262\
+ 3856559117102665855668676818703956031062\
+ 4931945271591492455329305456544401127480\
+ 1297099995419319894090804165633245247571\
+ 4786901472678015935523861155013480352649\
+ 3472019379026810710749170333222684475333\
+ 5720832431936092382893458368060106011506\
+ 1698097530783422773183292479049825247307\
+ 7637592724787465608477820373446969953364\
+ 7017972677717585125660551199131504891101\
+ 4510378627381672509558373897335989936648\
+ 0994116420570263709027924276754456522908\
+ 7538682506419718265533447265625 ", -323);
+
+ // [1], Table 3: Stress Inputs for Converting 53-bit Binary to Decimal, < 1/2 ULP
+ check_exact_one!(f(8511030020275656, -342; f64) => b"9", -87);
+ check_exact_one!(f(5201988407066741, -824; f64) => b"46", -232);
+ check_exact_one!(f(6406892948269899, 237; f64) => b"141", 88);
+ check_exact_one!(f(8431154198732492, 72; f64) => b"3981", 38);
+ check_exact_one!(f(6475049196144587, 99; f64) => b"41040", 46);
+ check_exact_one!(f(8274307542972842, 726; f64) => b"292084", 235);
+ check_exact_one!(f(5381065484265332, -456; f64) => b"2891946", -121);
+ check_exact_one!(f(6761728585499734, -1057; f64) => b"43787718", -302);
+ check_exact_one!(f(7976538478610756, 376; f64) => b"122770163", 130);
+ check_exact_one!(f(5982403858958067, 377; f64) => b"1841552452", 130);
+ check_exact_one!(f(5536995190630837, 93; f64) => b"54835744350", 44);
+ check_exact_one!(f(7225450889282194, 710; f64) => b"389190181146", 230);
+ check_exact_one!(f(7225450889282194, 709; f64) => b"1945950905732", 230);
+ check_exact_one!(f(8703372741147379, 117; f64) => b"14460958381605", 52);
+ check_exact_one!(f(8944262675275217, -1001; f64) => b"417367747458531", -285);
+ check_exact_one!(f(7459803696087692, -707; f64) => b"1107950772878888", -196);
+ check_exact_one!(f(6080469016670379, -381; f64) => b"12345501366327440", -98);
+ check_exact_one!(f(8385515147034757, 721; f64) => b"925031711960365024", 233);
+ check_exact_one!(f(7514216811389786, -828; f64) => b"4198047150284889840", -233);
+ check_exact_one!(f(8397297803260511, -345; f64) => b"11716315319786511046", -87);
+ check_exact_one!(f(6733459239310543, 202; f64) => b"432810072844612493629", 77);
+ check_exact_one!(f(8091450587292794, -473; f64) => b"3317710118160031081518", -126);
+
+ // [1], Table 4: Stress Inputs for Converting 53-bit Binary to Decimal, > 1/2 ULP
+ check_exact_one!(f(6567258882077402, 952; f64) => b"3", 303);
+ check_exact_one!(f(6712731423444934, 535; f64) => b"76", 177);
+ check_exact_one!(f(6712731423444934, 534; f64) => b"378", 177);
+ check_exact_one!(f(5298405411573037, -957; f64) => b"4350", -272);
+ check_exact_one!(f(5137311167659507, -144; f64) => b"23037", -27);
+ check_exact_one!(f(6722280709661868, 363; f64) => b"126301", 126);
+ check_exact_one!(f(5344436398034927, -169; f64) => b"7142211", -35);
+ check_exact_one!(f(8369123604277281, -853; f64) => b"13934574", -240);
+ check_exact_one!(f(8995822108487663, -780; f64) => b"141463449", -218);
+ check_exact_one!(f(8942832835564782, -383; f64) => b"4539277920", -99);
+ check_exact_one!(f(8942832835564782, -384; f64) => b"22696389598", -99);
+ check_exact_one!(f(8942832835564782, -385; f64) => b"113481947988", -99);
+ check_exact_one!(f(6965949469487146, -249; f64) => b"7700366561890", -59);
+ check_exact_one!(f(6965949469487146, -250; f64) => b"38501832809448", -59);
+ check_exact_one!(f(6965949469487146, -251; f64) => b"192509164047238", -59);
+ check_exact_one!(f(7487252720986826, 548; f64) => b"6898586531774201", 181);
+ check_exact_one!(f(5592117679628511, 164; f64) => b"13076622631878654", 66);
+ check_exact_one!(f(8887055249355788, 665; f64) => b"136052020756121240", 217);
+ check_exact_one!(f(6994187472632449, 690; f64) => b"3592810217475959676", 224);
+ check_exact_one!(f(8797576579012143, 588; f64) => b"89125197712484551899", 193);
+ check_exact_one!(f(7363326733505337, 272; f64) => b"558769757362301140950", 98);
+ check_exact_one!(f(8549497411294502, -448; f64) => b"1176257830728540379990", -118);
+}
+
+pub fn more_shortest_sanity_test<F>(mut f: F)
+where
+ F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>]) -> (&'a [u8], i16),
+{
+ check_shortest!(f{mant: 99_999_999_999_999_999, minus: 1, plus: 1,
+ exp: 0, inclusive: true} => b"1", 18);
+ check_shortest!(f{mant: 99_999_999_999_999_999, minus: 1, plus: 1,
+ exp: 0, inclusive: false} => b"99999999999999999", 17);
+}
+
+fn to_string_with_parts<F>(mut f: F) -> String
+where
+ F: for<'a> FnMut(&'a mut [MaybeUninit<u8>], &'a mut [MaybeUninit<Part<'a>>]) -> Formatted<'a>,
+{
+ let mut buf = [MaybeUninit::new(0); 1024];
+ let mut parts = [MaybeUninit::new(Part::Zero(0)); 16];
+ let formatted = f(&mut buf, &mut parts);
+ let mut ret = vec![0; formatted.len()];
+ assert_eq!(formatted.write(&mut ret), Some(ret.len()));
+ String::from_utf8(ret).unwrap()
+}
+
+pub fn to_shortest_str_test<F>(mut f_: F)
+where
+ F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>]) -> (&'a [u8], i16),
+{
+ use core::num::flt2dec::Sign::*;
+
+ fn to_string<T, F>(f: &mut F, v: T, sign: Sign, frac_digits: usize) -> String
+ where
+ T: DecodableFloat,
+ F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>]) -> (&'a [u8], i16),
+ {
+ to_string_with_parts(|buf, parts| {
+ to_shortest_str(|d, b| f(d, b), v, sign, frac_digits, buf, parts)
+ })
+ }
+
+ let f = &mut f_;
+
+ assert_eq!(to_string(f, 0.0, Minus, 0), "0");
+ assert_eq!(to_string(f, 0.0, Minus, 0), "0");
+ assert_eq!(to_string(f, 0.0, MinusPlus, 0), "+0");
+ assert_eq!(to_string(f, -0.0, Minus, 0), "-0");
+ assert_eq!(to_string(f, -0.0, MinusPlus, 0), "-0");
+ assert_eq!(to_string(f, 0.0, Minus, 1), "0.0");
+ assert_eq!(to_string(f, 0.0, Minus, 1), "0.0");
+ assert_eq!(to_string(f, 0.0, MinusPlus, 1), "+0.0");
+ assert_eq!(to_string(f, -0.0, Minus, 8), "-0.00000000");
+ assert_eq!(to_string(f, -0.0, MinusPlus, 8), "-0.00000000");
+
+ assert_eq!(to_string(f, 1.0 / 0.0, Minus, 0), "inf");
+ assert_eq!(to_string(f, 1.0 / 0.0, Minus, 0), "inf");
+ assert_eq!(to_string(f, 1.0 / 0.0, MinusPlus, 0), "+inf");
+ assert_eq!(to_string(f, 0.0 / 0.0, Minus, 0), "NaN");
+ assert_eq!(to_string(f, 0.0 / 0.0, Minus, 1), "NaN");
+ assert_eq!(to_string(f, 0.0 / 0.0, MinusPlus, 64), "NaN");
+ assert_eq!(to_string(f, -1.0 / 0.0, Minus, 0), "-inf");
+ assert_eq!(to_string(f, -1.0 / 0.0, Minus, 1), "-inf");
+ assert_eq!(to_string(f, -1.0 / 0.0, MinusPlus, 64), "-inf");
+
+ assert_eq!(to_string(f, 3.14, Minus, 0), "3.14");
+ assert_eq!(to_string(f, 3.14, Minus, 0), "3.14");
+ assert_eq!(to_string(f, 3.14, MinusPlus, 0), "+3.14");
+ assert_eq!(to_string(f, -3.14, Minus, 0), "-3.14");
+ assert_eq!(to_string(f, -3.14, Minus, 0), "-3.14");
+ assert_eq!(to_string(f, -3.14, MinusPlus, 0), "-3.14");
+ assert_eq!(to_string(f, 3.14, Minus, 1), "3.14");
+ assert_eq!(to_string(f, 3.14, Minus, 2), "3.14");
+ assert_eq!(to_string(f, 3.14, MinusPlus, 4), "+3.1400");
+ assert_eq!(to_string(f, -3.14, Minus, 8), "-3.14000000");
+ assert_eq!(to_string(f, -3.14, Minus, 8), "-3.14000000");
+ assert_eq!(to_string(f, -3.14, MinusPlus, 8), "-3.14000000");
+
+ assert_eq!(to_string(f, 7.5e-11, Minus, 0), "0.000000000075");
+ assert_eq!(to_string(f, 7.5e-11, Minus, 3), "0.000000000075");
+ assert_eq!(to_string(f, 7.5e-11, Minus, 12), "0.000000000075");
+ assert_eq!(to_string(f, 7.5e-11, Minus, 13), "0.0000000000750");
+
+ assert_eq!(to_string(f, 1.9971e20, Minus, 0), "199710000000000000000");
+ assert_eq!(to_string(f, 1.9971e20, Minus, 1), "199710000000000000000.0");
+ assert_eq!(to_string(f, 1.9971e20, Minus, 8), "199710000000000000000.00000000");
+
+ assert_eq!(to_string(f, f32::MAX, Minus, 0), format!("34028235{:0>31}", ""));
+ assert_eq!(to_string(f, f32::MAX, Minus, 1), format!("34028235{:0>31}.0", ""));
+ assert_eq!(to_string(f, f32::MAX, Minus, 8), format!("34028235{:0>31}.00000000", ""));
+
+ let minf32 = ldexp_f32(1.0, -149);
+ assert_eq!(to_string(f, minf32, Minus, 0), format!("0.{:0>44}1", ""));
+ assert_eq!(to_string(f, minf32, Minus, 45), format!("0.{:0>44}1", ""));
+ assert_eq!(to_string(f, minf32, Minus, 46), format!("0.{:0>44}10", ""));
+
+ assert_eq!(to_string(f, f64::MAX, Minus, 0), format!("17976931348623157{:0>292}", ""));
+ assert_eq!(to_string(f, f64::MAX, Minus, 1), format!("17976931348623157{:0>292}.0", ""));
+ assert_eq!(to_string(f, f64::MAX, Minus, 8), format!("17976931348623157{:0>292}.00000000", ""));
+
+ let minf64 = ldexp_f64(1.0, -1074);
+ assert_eq!(to_string(f, minf64, Minus, 0), format!("0.{:0>323}5", ""));
+ assert_eq!(to_string(f, minf64, Minus, 324), format!("0.{:0>323}5", ""));
+ assert_eq!(to_string(f, minf64, Minus, 325), format!("0.{:0>323}50", ""));
+
+ if cfg!(miri) {
+ // Miri is too slow
+ return;
+ }
+
+ // very large output
+ assert_eq!(to_string(f, 1.1, Minus, 80000), format!("1.1{:0>79999}", ""));
+}
+
+pub fn to_shortest_exp_str_test<F>(mut f_: F)
+where
+ F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>]) -> (&'a [u8], i16),
+{
+ use core::num::flt2dec::Sign::*;
+
+ fn to_string<T, F>(f: &mut F, v: T, sign: Sign, exp_bounds: (i16, i16), upper: bool) -> String
+ where
+ T: DecodableFloat,
+ F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>]) -> (&'a [u8], i16),
+ {
+ to_string_with_parts(|buf, parts| {
+ to_shortest_exp_str(|d, b| f(d, b), v, sign, exp_bounds, upper, buf, parts)
+ })
+ }
+
+ let f = &mut f_;
+
+ assert_eq!(to_string(f, 0.0, Minus, (-4, 16), false), "0");
+ assert_eq!(to_string(f, 0.0, Minus, (-4, 16), false), "0");
+ assert_eq!(to_string(f, 0.0, MinusPlus, (-4, 16), false), "+0");
+ assert_eq!(to_string(f, -0.0, Minus, (-4, 16), false), "-0");
+ assert_eq!(to_string(f, -0.0, MinusPlus, (-4, 16), false), "-0");
+ assert_eq!(to_string(f, 0.0, Minus, (0, 0), true), "0E0");
+ assert_eq!(to_string(f, 0.0, Minus, (0, 0), false), "0e0");
+ assert_eq!(to_string(f, 0.0, MinusPlus, (5, 9), false), "+0e0");
+ assert_eq!(to_string(f, -0.0, Minus, (0, 0), true), "-0E0");
+ assert_eq!(to_string(f, -0.0, MinusPlus, (5, 9), false), "-0e0");
+
+ assert_eq!(to_string(f, 1.0 / 0.0, Minus, (-4, 16), false), "inf");
+ assert_eq!(to_string(f, 1.0 / 0.0, Minus, (-4, 16), true), "inf");
+ assert_eq!(to_string(f, 1.0 / 0.0, MinusPlus, (-4, 16), true), "+inf");
+ assert_eq!(to_string(f, 0.0 / 0.0, Minus, (0, 0), false), "NaN");
+ assert_eq!(to_string(f, 0.0 / 0.0, Minus, (0, 0), true), "NaN");
+ assert_eq!(to_string(f, 0.0 / 0.0, MinusPlus, (5, 9), true), "NaN");
+ assert_eq!(to_string(f, -1.0 / 0.0, Minus, (0, 0), false), "-inf");
+ assert_eq!(to_string(f, -1.0 / 0.0, Minus, (0, 0), true), "-inf");
+ assert_eq!(to_string(f, -1.0 / 0.0, MinusPlus, (5, 9), true), "-inf");
+
+ assert_eq!(to_string(f, 3.14, Minus, (-4, 16), false), "3.14");
+ assert_eq!(to_string(f, 3.14, MinusPlus, (-4, 16), false), "+3.14");
+ assert_eq!(to_string(f, -3.14, Minus, (-4, 16), false), "-3.14");
+ assert_eq!(to_string(f, -3.14, MinusPlus, (-4, 16), false), "-3.14");
+ assert_eq!(to_string(f, 3.14, Minus, (0, 0), true), "3.14E0");
+ assert_eq!(to_string(f, 3.14, Minus, (0, 0), false), "3.14e0");
+ assert_eq!(to_string(f, 3.14, MinusPlus, (5, 9), false), "+3.14e0");
+ assert_eq!(to_string(f, -3.14, Minus, (0, 0), true), "-3.14E0");
+ assert_eq!(to_string(f, -3.14, Minus, (0, 0), false), "-3.14e0");
+ assert_eq!(to_string(f, -3.14, MinusPlus, (5, 9), false), "-3.14e0");
+
+ assert_eq!(to_string(f, 0.1, Minus, (-4, 16), false), "0.1");
+ assert_eq!(to_string(f, 0.1, Minus, (-4, 16), false), "0.1");
+ assert_eq!(to_string(f, 0.1, MinusPlus, (-4, 16), false), "+0.1");
+ assert_eq!(to_string(f, -0.1, Minus, (-4, 16), false), "-0.1");
+ assert_eq!(to_string(f, -0.1, MinusPlus, (-4, 16), false), "-0.1");
+ assert_eq!(to_string(f, 0.1, Minus, (0, 0), true), "1E-1");
+ assert_eq!(to_string(f, 0.1, Minus, (0, 0), false), "1e-1");
+ assert_eq!(to_string(f, 0.1, MinusPlus, (5, 9), false), "+1e-1");
+ assert_eq!(to_string(f, -0.1, Minus, (0, 0), true), "-1E-1");
+ assert_eq!(to_string(f, -0.1, Minus, (0, 0), false), "-1e-1");
+ assert_eq!(to_string(f, -0.1, MinusPlus, (5, 9), false), "-1e-1");
+
+ assert_eq!(to_string(f, 7.5e-11, Minus, (-4, 16), false), "7.5e-11");
+ assert_eq!(to_string(f, 7.5e-11, Minus, (-11, 10), false), "0.000000000075");
+ assert_eq!(to_string(f, 7.5e-11, Minus, (-10, 11), false), "7.5e-11");
+
+ assert_eq!(to_string(f, 1.9971e20, Minus, (-4, 16), false), "1.9971e20");
+ assert_eq!(to_string(f, 1.9971e20, Minus, (-20, 21), false), "199710000000000000000");
+ assert_eq!(to_string(f, 1.9971e20, Minus, (-21, 20), false), "1.9971e20");
+
+ // the true value of 1.0e23f64 is less than 10^23, but that shouldn't matter here
+ assert_eq!(to_string(f, 1.0e23, Minus, (22, 23), false), "1e23");
+ assert_eq!(to_string(f, 1.0e23, Minus, (23, 24), false), "100000000000000000000000");
+ assert_eq!(to_string(f, 1.0e23, Minus, (24, 25), false), "1e23");
+
+ assert_eq!(to_string(f, f32::MAX, Minus, (-4, 16), false), "3.4028235e38");
+ assert_eq!(to_string(f, f32::MAX, Minus, (-39, 38), false), "3.4028235e38");
+ assert_eq!(to_string(f, f32::MAX, Minus, (-38, 39), false), format!("34028235{:0>31}", ""));
+
+ let minf32 = ldexp_f32(1.0, -149);
+ assert_eq!(to_string(f, minf32, Minus, (-4, 16), false), "1e-45");
+ assert_eq!(to_string(f, minf32, Minus, (-44, 45), false), "1e-45");
+ assert_eq!(to_string(f, minf32, Minus, (-45, 44), false), format!("0.{:0>44}1", ""));
+
+ assert_eq!(to_string(f, f64::MAX, Minus, (-4, 16), false), "1.7976931348623157e308");
+ assert_eq!(
+ to_string(f, f64::MAX, Minus, (-308, 309), false),
+ format!("17976931348623157{:0>292}", "")
+ );
+ assert_eq!(to_string(f, f64::MAX, Minus, (-309, 308), false), "1.7976931348623157e308");
+
+ let minf64 = ldexp_f64(1.0, -1074);
+ assert_eq!(to_string(f, minf64, Minus, (-4, 16), false), "5e-324");
+ assert_eq!(to_string(f, minf64, Minus, (-324, 323), false), format!("0.{:0>323}5", ""));
+ assert_eq!(to_string(f, minf64, Minus, (-323, 324), false), "5e-324");
+
+ assert_eq!(to_string(f, 1.1, Minus, (i16::MIN, i16::MAX), false), "1.1");
+}
+
+pub fn to_exact_exp_str_test<F>(mut f_: F)
+where
+ F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>], i16) -> (&'a [u8], i16),
+{
+ use core::num::flt2dec::Sign::*;
+
+ fn to_string<T, F>(f: &mut F, v: T, sign: Sign, ndigits: usize, upper: bool) -> String
+ where
+ T: DecodableFloat,
+ F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>], i16) -> (&'a [u8], i16),
+ {
+ to_string_with_parts(|buf, parts| {
+ to_exact_exp_str(|d, b, l| f(d, b, l), v, sign, ndigits, upper, buf, parts)
+ })
+ }
+
+ let f = &mut f_;
+
+ assert_eq!(to_string(f, 0.0, Minus, 1, true), "0E0");
+ assert_eq!(to_string(f, 0.0, Minus, 1, false), "0e0");
+ assert_eq!(to_string(f, 0.0, MinusPlus, 1, false), "+0e0");
+ assert_eq!(to_string(f, -0.0, Minus, 1, true), "-0E0");
+ assert_eq!(to_string(f, -0.0, MinusPlus, 1, false), "-0e0");
+ assert_eq!(to_string(f, 0.0, Minus, 2, true), "0.0E0");
+ assert_eq!(to_string(f, 0.0, Minus, 2, false), "0.0e0");
+ assert_eq!(to_string(f, 0.0, MinusPlus, 2, false), "+0.0e0");
+ assert_eq!(to_string(f, -0.0, Minus, 8, false), "-0.0000000e0");
+ assert_eq!(to_string(f, -0.0, MinusPlus, 8, false), "-0.0000000e0");
+
+ assert_eq!(to_string(f, 1.0 / 0.0, Minus, 1, false), "inf");
+ assert_eq!(to_string(f, 1.0 / 0.0, Minus, 1, true), "inf");
+ assert_eq!(to_string(f, 1.0 / 0.0, MinusPlus, 1, true), "+inf");
+ assert_eq!(to_string(f, 0.0 / 0.0, Minus, 8, false), "NaN");
+ assert_eq!(to_string(f, 0.0 / 0.0, Minus, 8, true), "NaN");
+ assert_eq!(to_string(f, 0.0 / 0.0, MinusPlus, 8, true), "NaN");
+ assert_eq!(to_string(f, -1.0 / 0.0, Minus, 64, false), "-inf");
+ assert_eq!(to_string(f, -1.0 / 0.0, Minus, 64, true), "-inf");
+ assert_eq!(to_string(f, -1.0 / 0.0, MinusPlus, 64, true), "-inf");
+
+ assert_eq!(to_string(f, 3.14, Minus, 1, true), "3E0");
+ assert_eq!(to_string(f, 3.14, Minus, 1, false), "3e0");
+ assert_eq!(to_string(f, 3.14, MinusPlus, 1, false), "+3e0");
+ assert_eq!(to_string(f, -3.14, Minus, 2, true), "-3.1E0");
+ assert_eq!(to_string(f, -3.14, Minus, 2, false), "-3.1e0");
+ assert_eq!(to_string(f, -3.14, MinusPlus, 2, false), "-3.1e0");
+ assert_eq!(to_string(f, 3.14, Minus, 3, true), "3.14E0");
+ assert_eq!(to_string(f, 3.14, Minus, 3, false), "3.14e0");
+ assert_eq!(to_string(f, 3.14, MinusPlus, 3, false), "+3.14e0");
+ assert_eq!(to_string(f, -3.14, Minus, 4, true), "-3.140E0");
+ assert_eq!(to_string(f, -3.14, Minus, 4, false), "-3.140e0");
+ assert_eq!(to_string(f, -3.14, MinusPlus, 4, false), "-3.140e0");
+
+ assert_eq!(to_string(f, 0.195, Minus, 1, false), "2e-1");
+ assert_eq!(to_string(f, 0.195, Minus, 1, true), "2E-1");
+ assert_eq!(to_string(f, 0.195, MinusPlus, 1, true), "+2E-1");
+ assert_eq!(to_string(f, -0.195, Minus, 2, false), "-2.0e-1");
+ assert_eq!(to_string(f, -0.195, Minus, 2, true), "-2.0E-1");
+ assert_eq!(to_string(f, -0.195, MinusPlus, 2, true), "-2.0E-1");
+ assert_eq!(to_string(f, 0.195, Minus, 3, false), "1.95e-1");
+ assert_eq!(to_string(f, 0.195, Minus, 3, true), "1.95E-1");
+ assert_eq!(to_string(f, 0.195, MinusPlus, 3, true), "+1.95E-1");
+ assert_eq!(to_string(f, -0.195, Minus, 4, false), "-1.950e-1");
+ assert_eq!(to_string(f, -0.195, Minus, 4, true), "-1.950E-1");
+ assert_eq!(to_string(f, -0.195, MinusPlus, 4, true), "-1.950E-1");
+
+ assert_eq!(to_string(f, 9.5, Minus, 1, false), "1e1");
+ assert_eq!(to_string(f, 9.5, Minus, 2, false), "9.5e0");
+ assert_eq!(to_string(f, 9.5, Minus, 3, false), "9.50e0");
+ assert_eq!(to_string(f, 9.5, Minus, 30, false), "9.50000000000000000000000000000e0");
+
+ assert_eq!(to_string(f, 1.0e25, Minus, 1, false), "1e25");
+ assert_eq!(to_string(f, 1.0e25, Minus, 2, false), "1.0e25");
+ assert_eq!(to_string(f, 1.0e25, Minus, 15, false), "1.00000000000000e25");
+ assert_eq!(to_string(f, 1.0e25, Minus, 16, false), "1.000000000000000e25");
+ assert_eq!(to_string(f, 1.0e25, Minus, 17, false), "1.0000000000000001e25");
+ assert_eq!(to_string(f, 1.0e25, Minus, 18, false), "1.00000000000000009e25");
+ assert_eq!(to_string(f, 1.0e25, Minus, 19, false), "1.000000000000000091e25");
+ assert_eq!(to_string(f, 1.0e25, Minus, 20, false), "1.0000000000000000906e25");
+ assert_eq!(to_string(f, 1.0e25, Minus, 21, false), "1.00000000000000009060e25");
+ assert_eq!(to_string(f, 1.0e25, Minus, 22, false), "1.000000000000000090597e25");
+ assert_eq!(to_string(f, 1.0e25, Minus, 23, false), "1.0000000000000000905970e25");
+ assert_eq!(to_string(f, 1.0e25, Minus, 24, false), "1.00000000000000009059697e25");
+ assert_eq!(to_string(f, 1.0e25, Minus, 25, false), "1.000000000000000090596966e25");
+ assert_eq!(to_string(f, 1.0e25, Minus, 26, false), "1.0000000000000000905969664e25");
+ assert_eq!(to_string(f, 1.0e25, Minus, 27, false), "1.00000000000000009059696640e25");
+ assert_eq!(to_string(f, 1.0e25, Minus, 30, false), "1.00000000000000009059696640000e25");
+
+ assert_eq!(to_string(f, 1.0e-6, Minus, 1, false), "1e-6");
+ assert_eq!(to_string(f, 1.0e-6, Minus, 2, false), "1.0e-6");
+ assert_eq!(to_string(f, 1.0e-6, Minus, 16, false), "1.000000000000000e-6");
+ assert_eq!(to_string(f, 1.0e-6, Minus, 17, false), "9.9999999999999995e-7");
+ assert_eq!(to_string(f, 1.0e-6, Minus, 18, false), "9.99999999999999955e-7");
+ assert_eq!(to_string(f, 1.0e-6, Minus, 19, false), "9.999999999999999547e-7");
+ assert_eq!(to_string(f, 1.0e-6, Minus, 20, false), "9.9999999999999995475e-7");
+ assert_eq!(to_string(f, 1.0e-6, Minus, 30, false), "9.99999999999999954748111825886e-7");
+ assert_eq!(
+ to_string(f, 1.0e-6, Minus, 40, false),
+ "9.999999999999999547481118258862586856139e-7"
+ );
+ assert_eq!(
+ to_string(f, 1.0e-6, Minus, 50, false),
+ "9.9999999999999995474811182588625868561393872369081e-7"
+ );
+ assert_eq!(
+ to_string(f, 1.0e-6, Minus, 60, false),
+ "9.99999999999999954748111825886258685613938723690807819366455e-7"
+ );
+ assert_eq!(
+ to_string(f, 1.0e-6, Minus, 70, false),
+ "9.999999999999999547481118258862586856139387236908078193664550781250000e-7"
+ );
+
+ assert_eq!(to_string(f, f32::MAX, Minus, 1, false), "3e38");
+ assert_eq!(to_string(f, f32::MAX, Minus, 2, false), "3.4e38");
+ assert_eq!(to_string(f, f32::MAX, Minus, 4, false), "3.403e38");
+ assert_eq!(to_string(f, f32::MAX, Minus, 8, false), "3.4028235e38");
+ assert_eq!(to_string(f, f32::MAX, Minus, 16, false), "3.402823466385289e38");
+ assert_eq!(to_string(f, f32::MAX, Minus, 32, false), "3.4028234663852885981170418348452e38");
+ assert_eq!(
+ to_string(f, f32::MAX, Minus, 64, false),
+ "3.402823466385288598117041834845169254400000000000000000000000000e38"
+ );
+
+ let minf32 = ldexp_f32(1.0, -149);
+ assert_eq!(to_string(f, minf32, Minus, 1, false), "1e-45");
+ assert_eq!(to_string(f, minf32, Minus, 2, false), "1.4e-45");
+ assert_eq!(to_string(f, minf32, Minus, 4, false), "1.401e-45");
+ assert_eq!(to_string(f, minf32, Minus, 8, false), "1.4012985e-45");
+ assert_eq!(to_string(f, minf32, Minus, 16, false), "1.401298464324817e-45");
+ assert_eq!(to_string(f, minf32, Minus, 32, false), "1.4012984643248170709237295832899e-45");
+ assert_eq!(
+ to_string(f, minf32, Minus, 64, false),
+ "1.401298464324817070923729583289916131280261941876515771757068284e-45"
+ );
+ assert_eq!(
+ to_string(f, minf32, Minus, 128, false),
+ "1.401298464324817070923729583289916131280261941876515771757068283\
+ 8897910826858606014866381883621215820312500000000000000000000000e-45"
+ );
+
+ if cfg!(miri) {
+ // Miri is too slow
+ return;
+ }
+
+ assert_eq!(to_string(f, f64::MAX, Minus, 1, false), "2e308");
+ assert_eq!(to_string(f, f64::MAX, Minus, 2, false), "1.8e308");
+ assert_eq!(to_string(f, f64::MAX, Minus, 4, false), "1.798e308");
+ assert_eq!(to_string(f, f64::MAX, Minus, 8, false), "1.7976931e308");
+ assert_eq!(to_string(f, f64::MAX, Minus, 16, false), "1.797693134862316e308");
+ assert_eq!(to_string(f, f64::MAX, Minus, 32, false), "1.7976931348623157081452742373170e308");
+ assert_eq!(
+ to_string(f, f64::MAX, Minus, 64, false),
+ "1.797693134862315708145274237317043567980705675258449965989174768e308"
+ );
+ assert_eq!(
+ to_string(f, f64::MAX, Minus, 128, false),
+ "1.797693134862315708145274237317043567980705675258449965989174768\
+ 0315726078002853876058955863276687817154045895351438246423432133e308"
+ );
+ assert_eq!(
+ to_string(f, f64::MAX, Minus, 256, false),
+ "1.797693134862315708145274237317043567980705675258449965989174768\
+ 0315726078002853876058955863276687817154045895351438246423432132\
+ 6889464182768467546703537516986049910576551282076245490090389328\
+ 9440758685084551339423045832369032229481658085593321233482747978e308"
+ );
+ assert_eq!(
+ to_string(f, f64::MAX, Minus, 512, false),
+ "1.797693134862315708145274237317043567980705675258449965989174768\
+ 0315726078002853876058955863276687817154045895351438246423432132\
+ 6889464182768467546703537516986049910576551282076245490090389328\
+ 9440758685084551339423045832369032229481658085593321233482747978\
+ 2620414472316873817718091929988125040402618412485836800000000000\
+ 0000000000000000000000000000000000000000000000000000000000000000\
+ 0000000000000000000000000000000000000000000000000000000000000000\
+ 0000000000000000000000000000000000000000000000000000000000000000e308"
+ );
+
+ // okay, this is becoming tough. fortunately for us, this is almost the worst case.
+ let minf64 = ldexp_f64(1.0, -1074);
+ assert_eq!(to_string(f, minf64, Minus, 1, false), "5e-324");
+ assert_eq!(to_string(f, minf64, Minus, 2, false), "4.9e-324");
+ assert_eq!(to_string(f, minf64, Minus, 4, false), "4.941e-324");
+ assert_eq!(to_string(f, minf64, Minus, 8, false), "4.9406565e-324");
+ assert_eq!(to_string(f, minf64, Minus, 16, false), "4.940656458412465e-324");
+ assert_eq!(to_string(f, minf64, Minus, 32, false), "4.9406564584124654417656879286822e-324");
+ assert_eq!(
+ to_string(f, minf64, Minus, 64, false),
+ "4.940656458412465441765687928682213723650598026143247644255856825e-324"
+ );
+ assert_eq!(
+ to_string(f, minf64, Minus, 128, false),
+ "4.940656458412465441765687928682213723650598026143247644255856825\
+ 0067550727020875186529983636163599237979656469544571773092665671e-324"
+ );
+ assert_eq!(
+ to_string(f, minf64, Minus, 256, false),
+ "4.940656458412465441765687928682213723650598026143247644255856825\
+ 0067550727020875186529983636163599237979656469544571773092665671\
+ 0355939796398774796010781878126300713190311404527845817167848982\
+ 1036887186360569987307230500063874091535649843873124733972731696e-324"
+ );
+ assert_eq!(
+ to_string(f, minf64, Minus, 512, false),
+ "4.940656458412465441765687928682213723650598026143247644255856825\
+ 0067550727020875186529983636163599237979656469544571773092665671\
+ 0355939796398774796010781878126300713190311404527845817167848982\
+ 1036887186360569987307230500063874091535649843873124733972731696\
+ 1514003171538539807412623856559117102665855668676818703956031062\
+ 4931945271591492455329305456544401127480129709999541931989409080\
+ 4165633245247571478690147267801593552386115501348035264934720193\
+ 7902681071074917033322268447533357208324319360923828934583680601e-324"
+ );
+ assert_eq!(
+ to_string(f, minf64, Minus, 1024, false),
+ "4.940656458412465441765687928682213723650598026143247644255856825\
+ 0067550727020875186529983636163599237979656469544571773092665671\
+ 0355939796398774796010781878126300713190311404527845817167848982\
+ 1036887186360569987307230500063874091535649843873124733972731696\
+ 1514003171538539807412623856559117102665855668676818703956031062\
+ 4931945271591492455329305456544401127480129709999541931989409080\
+ 4165633245247571478690147267801593552386115501348035264934720193\
+ 7902681071074917033322268447533357208324319360923828934583680601\
+ 0601150616980975307834227731832924790498252473077637592724787465\
+ 6084778203734469699533647017972677717585125660551199131504891101\
+ 4510378627381672509558373897335989936648099411642057026370902792\
+ 4276754456522908753868250641971826553344726562500000000000000000\
+ 0000000000000000000000000000000000000000000000000000000000000000\
+ 0000000000000000000000000000000000000000000000000000000000000000\
+ 0000000000000000000000000000000000000000000000000000000000000000\
+ 0000000000000000000000000000000000000000000000000000000000000000e-324"
+ );
+
+ // very large output
+ assert_eq!(to_string(f, 0.0, Minus, 80000, false), format!("0.{:0>79999}e0", ""));
+ assert_eq!(to_string(f, 1.0e1, Minus, 80000, false), format!("1.{:0>79999}e1", ""));
+ assert_eq!(to_string(f, 1.0e0, Minus, 80000, false), format!("1.{:0>79999}e0", ""));
+ assert_eq!(
+ to_string(f, 1.0e-1, Minus, 80000, false),
+ format!(
+ "1.000000000000000055511151231257827021181583404541015625{:0>79945}\
+ e-1",
+ ""
+ )
+ );
+ assert_eq!(
+ to_string(f, 1.0e-20, Minus, 80000, false),
+ format!(
+ "9.999999999999999451532714542095716517295037027873924471077157760\
+ 66783064379706047475337982177734375{:0>79901}e-21",
+ ""
+ )
+ );
+}
+
+pub fn to_exact_fixed_str_test<F>(mut f_: F)
+where
+ F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>], i16) -> (&'a [u8], i16),
+{
+ use core::num::flt2dec::Sign::*;
+
+ fn to_string<T, F>(f: &mut F, v: T, sign: Sign, frac_digits: usize) -> String
+ where
+ T: DecodableFloat,
+ F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>], i16) -> (&'a [u8], i16),
+ {
+ to_string_with_parts(|buf, parts| {
+ to_exact_fixed_str(|d, b, l| f(d, b, l), v, sign, frac_digits, buf, parts)
+ })
+ }
+
+ let f = &mut f_;
+
+ assert_eq!(to_string(f, 0.0, Minus, 0), "0");
+ assert_eq!(to_string(f, 0.0, MinusPlus, 0), "+0");
+ assert_eq!(to_string(f, -0.0, Minus, 0), "-0");
+ assert_eq!(to_string(f, -0.0, MinusPlus, 0), "-0");
+ assert_eq!(to_string(f, 0.0, Minus, 1), "0.0");
+ assert_eq!(to_string(f, 0.0, MinusPlus, 1), "+0.0");
+ assert_eq!(to_string(f, -0.0, Minus, 8), "-0.00000000");
+ assert_eq!(to_string(f, -0.0, MinusPlus, 8), "-0.00000000");
+
+ assert_eq!(to_string(f, 1.0 / 0.0, Minus, 0), "inf");
+ assert_eq!(to_string(f, 1.0 / 0.0, Minus, 1), "inf");
+ assert_eq!(to_string(f, 1.0 / 0.0, MinusPlus, 64), "+inf");
+ assert_eq!(to_string(f, 0.0 / 0.0, Minus, 0), "NaN");
+ assert_eq!(to_string(f, 0.0 / 0.0, Minus, 1), "NaN");
+ assert_eq!(to_string(f, 0.0 / 0.0, MinusPlus, 64), "NaN");
+ assert_eq!(to_string(f, -1.0 / 0.0, Minus, 0), "-inf");
+ assert_eq!(to_string(f, -1.0 / 0.0, Minus, 1), "-inf");
+ assert_eq!(to_string(f, -1.0 / 0.0, MinusPlus, 64), "-inf");
+
+ assert_eq!(to_string(f, 3.14, Minus, 0), "3");
+ assert_eq!(to_string(f, 3.14, Minus, 0), "3");
+ assert_eq!(to_string(f, 3.14, MinusPlus, 0), "+3");
+ assert_eq!(to_string(f, -3.14, Minus, 0), "-3");
+ assert_eq!(to_string(f, -3.14, Minus, 0), "-3");
+ assert_eq!(to_string(f, -3.14, MinusPlus, 0), "-3");
+ assert_eq!(to_string(f, 3.14, Minus, 1), "3.1");
+ assert_eq!(to_string(f, 3.14, Minus, 2), "3.14");
+ assert_eq!(to_string(f, 3.14, MinusPlus, 4), "+3.1400");
+ assert_eq!(to_string(f, -3.14, Minus, 8), "-3.14000000");
+ assert_eq!(to_string(f, -3.14, Minus, 8), "-3.14000000");
+ assert_eq!(to_string(f, -3.14, MinusPlus, 8), "-3.14000000");
+
+ assert_eq!(to_string(f, 0.195, Minus, 0), "0");
+ assert_eq!(to_string(f, 0.195, MinusPlus, 0), "+0");
+ assert_eq!(to_string(f, -0.195, Minus, 0), "-0");
+ assert_eq!(to_string(f, -0.195, Minus, 0), "-0");
+ assert_eq!(to_string(f, -0.195, MinusPlus, 0), "-0");
+ assert_eq!(to_string(f, 0.195, Minus, 1), "0.2");
+ assert_eq!(to_string(f, 0.195, Minus, 2), "0.20");
+ assert_eq!(to_string(f, 0.195, MinusPlus, 4), "+0.1950");
+ assert_eq!(to_string(f, -0.195, Minus, 5), "-0.19500");
+ assert_eq!(to_string(f, -0.195, Minus, 6), "-0.195000");
+ assert_eq!(to_string(f, -0.195, MinusPlus, 8), "-0.19500000");
+
+ assert_eq!(to_string(f, 999.5, Minus, 0), "1000");
+ assert_eq!(to_string(f, 999.5, Minus, 1), "999.5");
+ assert_eq!(to_string(f, 999.5, Minus, 2), "999.50");
+ assert_eq!(to_string(f, 999.5, Minus, 3), "999.500");
+ assert_eq!(to_string(f, 999.5, Minus, 30), "999.500000000000000000000000000000");
+
+ assert_eq!(to_string(f, 0.5, Minus, 0), "1");
+ assert_eq!(to_string(f, 0.5, Minus, 1), "0.5");
+ assert_eq!(to_string(f, 0.5, Minus, 2), "0.50");
+ assert_eq!(to_string(f, 0.5, Minus, 3), "0.500");
+
+ assert_eq!(to_string(f, 0.95, Minus, 0), "1");
+ assert_eq!(to_string(f, 0.95, Minus, 1), "0.9"); // because it really is less than 0.95
+ assert_eq!(to_string(f, 0.95, Minus, 2), "0.95");
+ assert_eq!(to_string(f, 0.95, Minus, 3), "0.950");
+ assert_eq!(to_string(f, 0.95, Minus, 10), "0.9500000000");
+ assert_eq!(to_string(f, 0.95, Minus, 30), "0.949999999999999955591079014994");
+
+ assert_eq!(to_string(f, 0.095, Minus, 0), "0");
+ assert_eq!(to_string(f, 0.095, Minus, 1), "0.1");
+ assert_eq!(to_string(f, 0.095, Minus, 2), "0.10");
+ assert_eq!(to_string(f, 0.095, Minus, 3), "0.095");
+ assert_eq!(to_string(f, 0.095, Minus, 4), "0.0950");
+ assert_eq!(to_string(f, 0.095, Minus, 10), "0.0950000000");
+ assert_eq!(to_string(f, 0.095, Minus, 30), "0.095000000000000001110223024625");
+
+ assert_eq!(to_string(f, 0.0095, Minus, 0), "0");
+ assert_eq!(to_string(f, 0.0095, Minus, 1), "0.0");
+ assert_eq!(to_string(f, 0.0095, Minus, 2), "0.01");
+ assert_eq!(to_string(f, 0.0095, Minus, 3), "0.009"); // really is less than 0.0095
+ assert_eq!(to_string(f, 0.0095, Minus, 4), "0.0095");
+ assert_eq!(to_string(f, 0.0095, Minus, 5), "0.00950");
+ assert_eq!(to_string(f, 0.0095, Minus, 10), "0.0095000000");
+ assert_eq!(to_string(f, 0.0095, Minus, 30), "0.009499999999999999764077607267");
+
+ assert_eq!(to_string(f, 7.5e-11, Minus, 0), "0");
+ assert_eq!(to_string(f, 7.5e-11, Minus, 3), "0.000");
+ assert_eq!(to_string(f, 7.5e-11, Minus, 10), "0.0000000001");
+ assert_eq!(to_string(f, 7.5e-11, Minus, 11), "0.00000000007"); // ditto
+ assert_eq!(to_string(f, 7.5e-11, Minus, 12), "0.000000000075");
+ assert_eq!(to_string(f, 7.5e-11, Minus, 13), "0.0000000000750");
+ assert_eq!(to_string(f, 7.5e-11, Minus, 20), "0.00000000007500000000");
+ assert_eq!(to_string(f, 7.5e-11, Minus, 30), "0.000000000074999999999999999501");
+
+ assert_eq!(to_string(f, 1.0e25, Minus, 0), "10000000000000000905969664");
+ assert_eq!(to_string(f, 1.0e25, Minus, 1), "10000000000000000905969664.0");
+ assert_eq!(to_string(f, 1.0e25, Minus, 3), "10000000000000000905969664.000");
+
+ assert_eq!(to_string(f, 1.0e-6, Minus, 0), "0");
+ assert_eq!(to_string(f, 1.0e-6, Minus, 3), "0.000");
+ assert_eq!(to_string(f, 1.0e-6, Minus, 6), "0.000001");
+ assert_eq!(to_string(f, 1.0e-6, Minus, 9), "0.000001000");
+ assert_eq!(to_string(f, 1.0e-6, Minus, 12), "0.000001000000");
+ assert_eq!(to_string(f, 1.0e-6, Minus, 22), "0.0000010000000000000000");
+ assert_eq!(to_string(f, 1.0e-6, Minus, 23), "0.00000099999999999999995");
+ assert_eq!(to_string(f, 1.0e-6, Minus, 24), "0.000000999999999999999955");
+ assert_eq!(to_string(f, 1.0e-6, Minus, 25), "0.0000009999999999999999547");
+ assert_eq!(to_string(f, 1.0e-6, Minus, 35), "0.00000099999999999999995474811182589");
+ assert_eq!(to_string(f, 1.0e-6, Minus, 45), "0.000000999999999999999954748111825886258685614");
+ assert_eq!(
+ to_string(f, 1.0e-6, Minus, 55),
+ "0.0000009999999999999999547481118258862586856139387236908"
+ );
+ assert_eq!(
+ to_string(f, 1.0e-6, Minus, 65),
+ "0.00000099999999999999995474811182588625868561393872369080781936646"
+ );
+ assert_eq!(
+ to_string(f, 1.0e-6, Minus, 75),
+ "0.000000999999999999999954748111825886258685613938723690807819366455078125000"
+ );
+
+ assert_eq!(to_string(f, f32::MAX, Minus, 0), "340282346638528859811704183484516925440");
+ assert_eq!(to_string(f, f32::MAX, Minus, 1), "340282346638528859811704183484516925440.0");
+ assert_eq!(to_string(f, f32::MAX, Minus, 2), "340282346638528859811704183484516925440.00");
+
+ if cfg!(miri) {
+ // Miri is too slow
+ return;
+ }
+
+ let minf32 = ldexp_f32(1.0, -149);
+ assert_eq!(to_string(f, minf32, Minus, 0), "0");
+ assert_eq!(to_string(f, minf32, Minus, 1), "0.0");
+ assert_eq!(to_string(f, minf32, Minus, 2), "0.00");
+ assert_eq!(to_string(f, minf32, Minus, 4), "0.0000");
+ assert_eq!(to_string(f, minf32, Minus, 8), "0.00000000");
+ assert_eq!(to_string(f, minf32, Minus, 16), "0.0000000000000000");
+ assert_eq!(to_string(f, minf32, Minus, 32), "0.00000000000000000000000000000000");
+ assert_eq!(
+ to_string(f, minf32, Minus, 64),
+ "0.0000000000000000000000000000000000000000000014012984643248170709"
+ );
+ assert_eq!(
+ to_string(f, minf32, Minus, 128),
+ "0.0000000000000000000000000000000000000000000014012984643248170709\
+ 2372958328991613128026194187651577175706828388979108268586060149"
+ );
+ assert_eq!(
+ to_string(f, minf32, Minus, 256),
+ "0.0000000000000000000000000000000000000000000014012984643248170709\
+ 2372958328991613128026194187651577175706828388979108268586060148\
+ 6638188362121582031250000000000000000000000000000000000000000000\
+ 0000000000000000000000000000000000000000000000000000000000000000"
+ );
+
+ assert_eq!(
+ to_string(f, f64::MAX, Minus, 0),
+ "1797693134862315708145274237317043567980705675258449965989174768\
+ 0315726078002853876058955863276687817154045895351438246423432132\
+ 6889464182768467546703537516986049910576551282076245490090389328\
+ 9440758685084551339423045832369032229481658085593321233482747978\
+ 26204144723168738177180919299881250404026184124858368"
+ );
+ assert_eq!(
+ to_string(f, f64::MAX, Minus, 10),
+ "1797693134862315708145274237317043567980705675258449965989174768\
+ 0315726078002853876058955863276687817154045895351438246423432132\
+ 6889464182768467546703537516986049910576551282076245490090389328\
+ 9440758685084551339423045832369032229481658085593321233482747978\
+ 26204144723168738177180919299881250404026184124858368.0000000000"
+ );
+
+ let minf64 = ldexp_f64(1.0, -1074);
+ assert_eq!(to_string(f, minf64, Minus, 0), "0");
+ assert_eq!(to_string(f, minf64, Minus, 1), "0.0");
+ assert_eq!(to_string(f, minf64, Minus, 10), "0.0000000000");
+ assert_eq!(
+ to_string(f, minf64, Minus, 100),
+ "0.0000000000000000000000000000000000000000000000000000000000000000\
+ 000000000000000000000000000000000000"
+ );
+ assert_eq!(
+ to_string(f, minf64, Minus, 1000),
+ "0.0000000000000000000000000000000000000000000000000000000000000000\
+ 0000000000000000000000000000000000000000000000000000000000000000\
+ 0000000000000000000000000000000000000000000000000000000000000000\
+ 0000000000000000000000000000000000000000000000000000000000000000\
+ 0000000000000000000000000000000000000000000000000000000000000000\
+ 0004940656458412465441765687928682213723650598026143247644255856\
+ 8250067550727020875186529983636163599237979656469544571773092665\
+ 6710355939796398774796010781878126300713190311404527845817167848\
+ 9821036887186360569987307230500063874091535649843873124733972731\
+ 6961514003171538539807412623856559117102665855668676818703956031\
+ 0624931945271591492455329305456544401127480129709999541931989409\
+ 0804165633245247571478690147267801593552386115501348035264934720\
+ 1937902681071074917033322268447533357208324319360923828934583680\
+ 6010601150616980975307834227731832924790498252473077637592724787\
+ 4656084778203734469699533647017972677717585125660551199131504891\
+ 1014510378627381672509558373897335989937"
+ );
+
+ // very large output
+ assert_eq!(to_string(f, 0.0, Minus, 80000), format!("0.{:0>80000}", ""));
+ assert_eq!(to_string(f, 1.0e1, Minus, 80000), format!("10.{:0>80000}", ""));
+ assert_eq!(to_string(f, 1.0e0, Minus, 80000), format!("1.{:0>80000}", ""));
+ assert_eq!(
+ to_string(f, 1.0e-1, Minus, 80000),
+ format!("0.1000000000000000055511151231257827021181583404541015625{:0>79945}", "")
+ );
+ assert_eq!(
+ to_string(f, 1.0e-20, Minus, 80000),
+ format!(
+ "0.0000000000000000000099999999999999994515327145420957165172950370\
+ 2787392447107715776066783064379706047475337982177734375{:0>79881}",
+ ""
+ )
+ );
+}
diff --git a/library/core/tests/num/flt2dec/random.rs b/library/core/tests/num/flt2dec/random.rs
new file mode 100644
index 000000000..d09500393
--- /dev/null
+++ b/library/core/tests/num/flt2dec/random.rs
@@ -0,0 +1,202 @@
+#![cfg(not(target_arch = "wasm32"))]
+
+use std::mem::MaybeUninit;
+use std::str;
+
+use core::num::flt2dec::strategy::grisu::format_exact_opt;
+use core::num::flt2dec::strategy::grisu::format_shortest_opt;
+use core::num::flt2dec::MAX_SIG_DIGITS;
+use core::num::flt2dec::{decode, DecodableFloat, Decoded, FullDecoded};
+
+use rand::distributions::{Distribution, Uniform};
+use rand::rngs::StdRng;
+use rand::SeedableRng;
+
+pub fn decode_finite<T: DecodableFloat>(v: T) -> Decoded {
+ match decode(v).1 {
+ FullDecoded::Finite(decoded) => decoded,
+ full_decoded => panic!("expected finite, got {full_decoded:?} instead"),
+ }
+}
+
+fn iterate<F, G, V>(func: &str, k: usize, n: usize, mut f: F, mut g: G, mut v: V) -> (usize, usize)
+where
+ F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>]) -> Option<(&'a [u8], i16)>,
+ G: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>]) -> (&'a [u8], i16),
+ V: FnMut(usize) -> Decoded,
+{
+ assert!(k <= 1024);
+
+ let mut npassed = 0; // f(x) = Some(g(x))
+ let mut nignored = 0; // f(x) = None
+
+ for i in 0..n {
+ if (i & 0xfffff) == 0 {
+ println!(
+ "in progress, {:x}/{:x} (ignored={} passed={} failed={})",
+ i,
+ n,
+ nignored,
+ npassed,
+ i - nignored - npassed
+ );
+ }
+
+ let decoded = v(i);
+ let mut buf1 = [MaybeUninit::new(0); 1024];
+ if let Some((buf1, e1)) = f(&decoded, &mut buf1[..k]) {
+ let mut buf2 = [MaybeUninit::new(0); 1024];
+ let (buf2, e2) = g(&decoded, &mut buf2[..k]);
+ if e1 == e2 && buf1 == buf2 {
+ npassed += 1;
+ } else {
+ println!(
+ "equivalence test failed, {:x}/{:x}: {:?} f(i)={}e{} g(i)={}e{}",
+ i,
+ n,
+ decoded,
+ str::from_utf8(buf1).unwrap(),
+ e1,
+ str::from_utf8(buf2).unwrap(),
+ e2
+ );
+ }
+ } else {
+ nignored += 1;
+ }
+ }
+ println!(
+ "{}({}): done, ignored={} passed={} failed={}",
+ func,
+ k,
+ nignored,
+ npassed,
+ n - nignored - npassed
+ );
+ assert!(
+ nignored + npassed == n,
+ "{}({}): {} out of {} values returns an incorrect value!",
+ func,
+ k,
+ n - nignored - npassed,
+ n
+ );
+ (npassed, nignored)
+}
+
+pub fn f32_random_equivalence_test<F, G>(f: F, g: G, k: usize, n: usize)
+where
+ F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>]) -> Option<(&'a [u8], i16)>,
+ G: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>]) -> (&'a [u8], i16),
+{
+ if cfg!(target_os = "emscripten") {
+ return; // using rng pulls in i128 support, which doesn't work
+ }
+ let mut rng = StdRng::from_entropy();
+ let f32_range = Uniform::new(0x0000_0001u32, 0x7f80_0000);
+ iterate("f32_random_equivalence_test", k, n, f, g, |_| {
+ let x = f32::from_bits(f32_range.sample(&mut rng));
+ decode_finite(x)
+ });
+}
+
+pub fn f64_random_equivalence_test<F, G>(f: F, g: G, k: usize, n: usize)
+where
+ F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>]) -> Option<(&'a [u8], i16)>,
+ G: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>]) -> (&'a [u8], i16),
+{
+ if cfg!(target_os = "emscripten") {
+ return; // using rng pulls in i128 support, which doesn't work
+ }
+ let mut rng = StdRng::from_entropy();
+ let f64_range = Uniform::new(0x0000_0000_0000_0001u64, 0x7ff0_0000_0000_0000);
+ iterate("f64_random_equivalence_test", k, n, f, g, |_| {
+ let x = f64::from_bits(f64_range.sample(&mut rng));
+ decode_finite(x)
+ });
+}
+
+pub fn f32_exhaustive_equivalence_test<F, G>(f: F, g: G, k: usize)
+where
+ F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>]) -> Option<(&'a [u8], i16)>,
+ G: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>]) -> (&'a [u8], i16),
+{
+ // we have only 2^23 * (2^8 - 1) - 1 = 2,139,095,039 positive finite f32 values,
+ // so why not simply testing all of them?
+ //
+ // this is of course very stressful (and thus should be behind an `#[ignore]` attribute),
+ // but with `-C opt-level=3 -C lto` this only takes about an hour or so.
+
+ // iterate from 0x0000_0001 to 0x7f7f_ffff, i.e., all finite ranges
+ let (npassed, nignored) =
+ iterate("f32_exhaustive_equivalence_test", k, 0x7f7f_ffff, f, g, |i: usize| {
+ let x = f32::from_bits(i as u32 + 1);
+ decode_finite(x)
+ });
+ assert_eq!((npassed, nignored), (2121451881, 17643158));
+}
+
+#[test]
+fn shortest_random_equivalence_test() {
+ use core::num::flt2dec::strategy::dragon::format_shortest as fallback;
+ // Miri is too slow
+ let n = if cfg!(miri) { 10 } else { 10_000 };
+
+ f64_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, n);
+ f32_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, n);
+}
+
+#[test]
+#[ignore] // it is too expensive
+fn shortest_f32_exhaustive_equivalence_test() {
+ // it is hard to directly test the optimality of the output, but we can at least test if
+ // two different algorithms agree to each other.
+ //
+ // this reports the progress and the number of f32 values returned `None`.
+ // with `--nocapture` (and plenty of time and appropriate rustc flags), this should print:
+ // `done, ignored=17643158 passed=2121451881 failed=0`.
+
+ use core::num::flt2dec::strategy::dragon::format_shortest as fallback;
+ f32_exhaustive_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS);
+}
+
+#[test]
+#[ignore] // it is too expensive
+fn shortest_f64_hard_random_equivalence_test() {
+ // this again probably has to use appropriate rustc flags.
+
+ use core::num::flt2dec::strategy::dragon::format_shortest as fallback;
+ f64_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, 100_000_000);
+}
+
+#[test]
+fn exact_f32_random_equivalence_test() {
+ use core::num::flt2dec::strategy::dragon::format_exact as fallback;
+ // Miri is too slow
+ let n = if cfg!(miri) { 3 } else { 1_000 };
+
+ for k in 1..21 {
+ f32_random_equivalence_test(
+ |d, buf| format_exact_opt(d, buf, i16::MIN),
+ |d, buf| fallback(d, buf, i16::MIN),
+ k,
+ n,
+ );
+ }
+}
+
+#[test]
+fn exact_f64_random_equivalence_test() {
+ use core::num::flt2dec::strategy::dragon::format_exact as fallback;
+ // Miri is too slow
+ let n = if cfg!(miri) { 2 } else { 1_000 };
+
+ for k in 1..21 {
+ f64_random_equivalence_test(
+ |d, buf| format_exact_opt(d, buf, i16::MIN),
+ |d, buf| fallback(d, buf, i16::MIN),
+ k,
+ n,
+ );
+ }
+}
diff --git a/library/core/tests/num/flt2dec/strategy/dragon.rs b/library/core/tests/num/flt2dec/strategy/dragon.rs
new file mode 100644
index 000000000..fc2e724a2
--- /dev/null
+++ b/library/core/tests/num/flt2dec/strategy/dragon.rs
@@ -0,0 +1,63 @@
+use super::super::*;
+use core::num::bignum::Big32x40 as Big;
+use core::num::flt2dec::strategy::dragon::*;
+
+#[test]
+fn test_mul_pow10() {
+ let mut prevpow10 = Big::from_small(1);
+ for i in 1..340 {
+ let mut curpow10 = Big::from_small(1);
+ mul_pow10(&mut curpow10, i);
+ assert_eq!(curpow10, *prevpow10.clone().mul_small(10));
+ prevpow10 = curpow10;
+ }
+}
+
+#[test]
+fn shortest_sanity_test() {
+ f64_shortest_sanity_test(format_shortest);
+ f32_shortest_sanity_test(format_shortest);
+ more_shortest_sanity_test(format_shortest);
+}
+
+#[test]
+#[cfg_attr(miri, ignore)] // Miri is too slow
+fn exact_sanity_test() {
+ // This test ends up running what I can only assume is some corner-ish case
+ // of the `exp2` library function, defined in whatever C runtime we're
+ // using. In VS 2013 this function apparently had a bug as this test fails
+ // when linked, but with VS 2015 the bug appears fixed as the test runs just
+ // fine.
+ //
+ // The bug seems to be a difference in return value of `exp2(-1057)`, where
+ // in VS 2013 it returns a double with the bit pattern 0x2 and in VS 2015 it
+ // returns 0x20000.
+ //
+ // For now just ignore this test entirely on MSVC as it's tested elsewhere
+ // anyway and we're not super interested in testing each platform's exp2
+ // implementation.
+ if !cfg!(target_env = "msvc") {
+ f64_exact_sanity_test(format_exact);
+ }
+ f32_exact_sanity_test(format_exact);
+}
+
+#[test]
+fn test_to_shortest_str() {
+ to_shortest_str_test(format_shortest);
+}
+
+#[test]
+fn test_to_shortest_exp_str() {
+ to_shortest_exp_str_test(format_shortest);
+}
+
+#[test]
+fn test_to_exact_exp_str() {
+ to_exact_exp_str_test(format_exact);
+}
+
+#[test]
+fn test_to_exact_fixed_str() {
+ to_exact_fixed_str_test(format_exact);
+}
diff --git a/library/core/tests/num/flt2dec/strategy/grisu.rs b/library/core/tests/num/flt2dec/strategy/grisu.rs
new file mode 100644
index 000000000..b59a3b9b7
--- /dev/null
+++ b/library/core/tests/num/flt2dec/strategy/grisu.rs
@@ -0,0 +1,72 @@
+use super::super::*;
+use core::num::flt2dec::strategy::grisu::*;
+
+#[test]
+#[cfg_attr(miri, ignore)] // Miri is too slow
+fn test_cached_power() {
+ assert_eq!(CACHED_POW10.first().unwrap().1, CACHED_POW10_FIRST_E);
+ assert_eq!(CACHED_POW10.last().unwrap().1, CACHED_POW10_LAST_E);
+
+ for e in -1137..961 {
+ // full range for f64
+ let low = ALPHA - e - 64;
+ let high = GAMMA - e - 64;
+ let (_k, cached) = cached_power(low, high);
+ assert!(
+ low <= cached.e && cached.e <= high,
+ "cached_power({}, {}) = {:?} is incorrect",
+ low,
+ high,
+ cached
+ );
+ }
+}
+
+#[test]
+fn test_max_pow10_no_more_than() {
+ let mut prevtenk = 1;
+ for k in 1..10 {
+ let tenk = prevtenk * 10;
+ assert_eq!(max_pow10_no_more_than(tenk - 1), (k - 1, prevtenk));
+ assert_eq!(max_pow10_no_more_than(tenk), (k, tenk));
+ prevtenk = tenk;
+ }
+}
+
+#[test]
+fn shortest_sanity_test() {
+ f64_shortest_sanity_test(format_shortest);
+ f32_shortest_sanity_test(format_shortest);
+ more_shortest_sanity_test(format_shortest);
+}
+
+#[test]
+#[cfg_attr(miri, ignore)] // Miri is too slow
+fn exact_sanity_test() {
+ // See comments in dragon.rs's exact_sanity_test for why this test is
+ // ignored on MSVC
+ if !cfg!(target_env = "msvc") {
+ f64_exact_sanity_test(format_exact);
+ }
+ f32_exact_sanity_test(format_exact);
+}
+
+#[test]
+fn test_to_shortest_str() {
+ to_shortest_str_test(format_shortest);
+}
+
+#[test]
+fn test_to_shortest_exp_str() {
+ to_shortest_exp_str_test(format_shortest);
+}
+
+#[test]
+fn test_to_exact_exp_str() {
+ to_exact_exp_str_test(format_exact);
+}
+
+#[test]
+fn test_to_exact_fixed_str() {
+ to_exact_fixed_str_test(format_exact);
+}
diff --git a/library/core/tests/num/i128.rs b/library/core/tests/num/i128.rs
new file mode 100644
index 000000000..1ddd20f33
--- /dev/null
+++ b/library/core/tests/num/i128.rs
@@ -0,0 +1 @@
+int_module!(i128);
diff --git a/library/core/tests/num/i16.rs b/library/core/tests/num/i16.rs
new file mode 100644
index 000000000..c7aa9fff9
--- /dev/null
+++ b/library/core/tests/num/i16.rs
@@ -0,0 +1 @@
+int_module!(i16);
diff --git a/library/core/tests/num/i32.rs b/library/core/tests/num/i32.rs
new file mode 100644
index 000000000..efd5b1596
--- /dev/null
+++ b/library/core/tests/num/i32.rs
@@ -0,0 +1,30 @@
+int_module!(i32);
+
+#[test]
+fn test_arith_operation() {
+ let a: isize = 10;
+ assert_eq!(a * (a - 1), 90);
+ let i32_a: isize = 10;
+ assert_eq!(i32_a, 10);
+ assert_eq!(i32_a - 10, 0);
+ assert_eq!(i32_a / 10, 1);
+ assert_eq!(i32_a - 20, -10);
+ assert_eq!(i32_a << 10, 10240);
+ assert_eq!(i32_a << 16, 655360);
+ assert_eq!(i32_a * 16, 160);
+ assert_eq!(i32_a * i32_a * i32_a, 1000);
+ assert_eq!(i32_a * i32_a * i32_a * i32_a, 10000);
+ assert_eq!(i32_a * i32_a / i32_a * i32_a, 100);
+ assert_eq!(i32_a * (i32_a - 1) << (2 + i32_a as usize), 368640);
+ let i32_b: isize = 0x10101010;
+ assert_eq!(i32_b + 1 - 1, i32_b);
+ assert_eq!(i32_b << 1, i32_b << 1);
+ assert_eq!(i32_b >> 1, i32_b >> 1);
+ assert_eq!(i32_b & i32_b << 1, 0);
+ assert_eq!(i32_b | i32_b << 1, 0x30303030);
+ let i32_c: isize = 0x10101010;
+ assert_eq!(
+ i32_c + i32_c * 2 / 3 * 2 + (i32_c - 7 % 3),
+ i32_c + i32_c * 2 / 3 * 2 + (i32_c - 7 % 3)
+ );
+}
diff --git a/library/core/tests/num/i64.rs b/library/core/tests/num/i64.rs
new file mode 100644
index 000000000..93d23c10a
--- /dev/null
+++ b/library/core/tests/num/i64.rs
@@ -0,0 +1 @@
+int_module!(i64);
diff --git a/library/core/tests/num/i8.rs b/library/core/tests/num/i8.rs
new file mode 100644
index 000000000..887d4f17d
--- /dev/null
+++ b/library/core/tests/num/i8.rs
@@ -0,0 +1 @@
+int_module!(i8);
diff --git a/library/core/tests/num/ieee754.rs b/library/core/tests/num/ieee754.rs
new file mode 100644
index 000000000..f6e5dfc98
--- /dev/null
+++ b/library/core/tests/num/ieee754.rs
@@ -0,0 +1,158 @@
+//! IEEE 754 floating point compliance tests
+//!
+//! To understand IEEE 754's requirements on a programming language, one must understand that the
+//! requirements of IEEE 754 rest on the total programming environment, and not entirely on any
+//! one component. That means the hardware, language, and even libraries are considered part of
+//! conforming floating point support in a programming environment.
+//!
+//! A programming language's duty, accordingly, is:
+//! 1. offer access to the hardware where the hardware offers support
+//! 2. provide operations that fulfill the remaining requirements of the standard
+//! 3. provide the ability to write additional software that can fulfill those requirements
+//!
+//! This may be fulfilled in any combination that the language sees fit. However, to claim that
+//! a language supports IEEE 754 is to suggest that it has fulfilled requirements 1 and 2, without
+//! deferring minimum requirements to libraries. This is because support for IEEE 754 is defined
+//! as complete support for at least one specified floating point type as an "arithmetic" and
+//! "interchange" format, plus specified type conversions to "external character sequences" and
+//! integer types.
+//!
+//! For our purposes,
+//! "interchange format" => f32, f64
+//! "arithmetic format" => f32, f64, and any "soft floats"
+//! "external character sequence" => str from any float
+//! "integer format" => {i,u}{8,16,32,64,128}
+//!
+//! None of these tests are against Rust's own implementation. They are only tests against the
+//! standard. That is why they accept wildly diverse inputs or may seem to duplicate other tests.
+//! Please consider this carefully when adding, removing, or reorganizing these tests. They are
+//! here so that it is clear what tests are required by the standard and what can be changed.
+use ::core::str::FromStr;
+
+// IEEE 754 for many tests is applied to specific bit patterns.
+// These generally are not applicable to NaN, however.
+macro_rules! assert_biteq {
+ ($lhs:expr, $rhs:expr) => {
+ assert_eq!($lhs.to_bits(), $rhs.to_bits())
+ };
+}
+
+// ToString uses the default fmt::Display impl without special concerns, and bypasses other parts
+// of the formatting infrastructure, which makes it ideal for testing here.
+#[allow(unused_macros)]
+macro_rules! roundtrip {
+ ($f:expr => $t:ty) => {
+ ($f).to_string().parse::<$t>().unwrap()
+ };
+}
+
+macro_rules! assert_floats_roundtrip {
+ ($f:ident) => {
+ assert_biteq!(f32::$f, roundtrip!(f32::$f => f32));
+ assert_biteq!(f64::$f, roundtrip!(f64::$f => f64));
+ };
+ ($f:expr) => {
+ assert_biteq!($f as f32, roundtrip!($f => f32));
+ assert_biteq!($f as f64, roundtrip!($f => f64));
+ }
+}
+
+macro_rules! assert_floats_bitne {
+ ($lhs:ident, $rhs:ident) => {
+ assert_ne!(f32::$lhs.to_bits(), f32::$rhs.to_bits());
+ assert_ne!(f64::$lhs.to_bits(), f64::$rhs.to_bits());
+ };
+ ($lhs:expr, $rhs:expr) => {
+ assert_ne!(f32::to_bits($lhs), f32::to_bits($rhs));
+ assert_ne!(f64::to_bits($lhs), f64::to_bits($rhs));
+ };
+}
+
+// We must preserve signs on all numbers. That includes zero.
+// -0 and 0 are == normally, so test bit equality.
+#[test]
+fn preserve_signed_zero() {
+ assert_floats_roundtrip!(-0.0);
+ assert_floats_roundtrip!(0.0);
+ assert_floats_bitne!(0.0, -0.0);
+}
+
+#[test]
+fn preserve_signed_infinity() {
+ assert_floats_roundtrip!(INFINITY);
+ assert_floats_roundtrip!(NEG_INFINITY);
+ assert_floats_bitne!(INFINITY, NEG_INFINITY);
+}
+
+#[test]
+fn infinity_to_str() {
+ assert!(match f32::INFINITY.to_string().to_lowercase().as_str() {
+ "+infinity" | "infinity" => true,
+ "+inf" | "inf" => true,
+ _ => false,
+ });
+ assert!(
+ match f64::INFINITY.to_string().to_lowercase().as_str() {
+ "+infinity" | "infinity" => true,
+ "+inf" | "inf" => true,
+ _ => false,
+ },
+ "Infinity must write to a string as some casing of inf or infinity, with an optional +."
+ );
+}
+
+#[test]
+fn neg_infinity_to_str() {
+ assert!(match f32::NEG_INFINITY.to_string().to_lowercase().as_str() {
+ "-infinity" | "-inf" => true,
+ _ => false,
+ });
+ assert!(
+ match f64::NEG_INFINITY.to_string().to_lowercase().as_str() {
+ "-infinity" | "-inf" => true,
+ _ => false,
+ },
+ "Negative Infinity must write to a string as some casing of -inf or -infinity"
+ )
+}
+
+#[test]
+fn nan_to_str() {
+ assert!(
+ match f32::NAN.to_string().to_lowercase().as_str() {
+ "nan" | "+nan" | "-nan" => true,
+ _ => false,
+ },
+ "NaNs must write to a string as some casing of nan."
+ )
+}
+
+// "+"?("inf"|"infinity") in any case => Infinity
+#[test]
+fn infinity_from_str() {
+ assert_biteq!(f32::INFINITY, f32::from_str("infinity").unwrap());
+ assert_biteq!(f32::INFINITY, f32::from_str("inf").unwrap());
+ assert_biteq!(f32::INFINITY, f32::from_str("+infinity").unwrap());
+ assert_biteq!(f32::INFINITY, f32::from_str("+inf").unwrap());
+ // yes! this means you are weLcOmE tO mY iNfInItElY tWiStEd MiNd
+ assert_biteq!(f32::INFINITY, f32::from_str("+iNfInItY").unwrap());
+}
+
+// "-inf"|"-infinity" in any case => Negative Infinity
+#[test]
+fn neg_infinity_from_str() {
+ assert_biteq!(f32::NEG_INFINITY, f32::from_str("-infinity").unwrap());
+ assert_biteq!(f32::NEG_INFINITY, f32::from_str("-inf").unwrap());
+ assert_biteq!(f32::NEG_INFINITY, f32::from_str("-INF").unwrap());
+ assert_biteq!(f32::NEG_INFINITY, f32::from_str("-INFinity").unwrap());
+}
+
+// ("+"|"-"")?"s"?"nan" in any case => qNaN
+#[test]
+fn qnan_from_str() {
+ assert!("nan".parse::<f32>().unwrap().is_nan());
+ assert!("-nan".parse::<f32>().unwrap().is_nan());
+ assert!("+nan".parse::<f32>().unwrap().is_nan());
+ assert!("+NAN".parse::<f32>().unwrap().is_nan());
+ assert!("-NaN".parse::<f32>().unwrap().is_nan());
+}
diff --git a/library/core/tests/num/int_log.rs b/library/core/tests/num/int_log.rs
new file mode 100644
index 000000000..dc3092e14
--- /dev/null
+++ b/library/core/tests/num/int_log.rs
@@ -0,0 +1,166 @@
+//! This tests the `Integer::{log,log2,log10}` methods. These tests are in a
+//! separate file because there's both a large number of them, and not all tests
+//! can be run on Android. This is because in Android `log2` uses an imprecise
+//! approximation:https://github.com/rust-lang/rust/blob/4825e12fc9c79954aa0fe18f5521efa6c19c7539/src/libstd/sys/unix/android.rs#L27-L53
+
+#[test]
+fn checked_log() {
+ assert_eq!(999u32.checked_log(10), Some(2));
+ assert_eq!(1000u32.checked_log(10), Some(3));
+ assert_eq!(555u32.checked_log(13), Some(2));
+ assert_eq!(63u32.checked_log(4), Some(2));
+ assert_eq!(64u32.checked_log(4), Some(3));
+ assert_eq!(10460353203u64.checked_log(3), Some(21));
+ assert_eq!(10460353202u64.checked_log(3), Some(20));
+ assert_eq!(147808829414345923316083210206383297601u128.checked_log(3), Some(80));
+ assert_eq!(147808829414345923316083210206383297600u128.checked_log(3), Some(79));
+ assert_eq!(22528399544939174411840147874772641u128.checked_log(19683), Some(8));
+ assert_eq!(22528399544939174411840147874772631i128.checked_log(19683), Some(7));
+
+ assert_eq!(0u8.checked_log(4), None);
+ assert_eq!(0u16.checked_log(4), None);
+ assert_eq!(0i8.checked_log(4), None);
+ assert_eq!(0i16.checked_log(4), None);
+
+ #[cfg(not(miri))] // Miri is too slow
+ for i in i16::MIN..=0 {
+ assert_eq!(i.checked_log(4), None);
+ }
+ #[cfg(not(miri))] // Miri is too slow
+ for i in 1..=i16::MAX {
+ assert_eq!(i.checked_log(13), Some((i as f32).log(13.0) as u32));
+ }
+ #[cfg(not(miri))] // Miri is too slow
+ for i in 1..=u16::MAX {
+ assert_eq!(i.checked_log(13), Some((i as f32).log(13.0) as u32));
+ }
+}
+
+#[test]
+fn checked_log2() {
+ assert_eq!(5u32.checked_log2(), Some(2));
+ assert_eq!(0u64.checked_log2(), None);
+ assert_eq!(128i32.checked_log2(), Some(7));
+ assert_eq!((-55i16).checked_log2(), None);
+
+ assert_eq!(0u8.checked_log2(), None);
+ assert_eq!(0u16.checked_log2(), None);
+ assert_eq!(0i8.checked_log2(), None);
+ assert_eq!(0i16.checked_log2(), None);
+
+ for i in 1..=u8::MAX {
+ assert_eq!(i.checked_log2(), Some((i as f32).log2() as u32));
+ }
+ #[cfg(not(miri))] // Miri is too slow
+ for i in 1..=u16::MAX {
+ // Guard against Android's imprecise f32::log2 implementation.
+ if i != 8192 && i != 32768 {
+ assert_eq!(i.checked_log2(), Some((i as f32).log2() as u32));
+ }
+ }
+ for i in i8::MIN..=0 {
+ assert_eq!(i.checked_log2(), None);
+ }
+ for i in 1..=i8::MAX {
+ assert_eq!(i.checked_log2(), Some((i as f32).log2() as u32));
+ }
+ #[cfg(not(miri))] // Miri is too slow
+ for i in i16::MIN..=0 {
+ assert_eq!(i.checked_log2(), None);
+ }
+ #[cfg(not(miri))] // Miri is too slow
+ for i in 1..=i16::MAX {
+ // Guard against Android's imprecise f32::log2 implementation.
+ if i != 8192 {
+ assert_eq!(i.checked_log2(), Some((i as f32).log2() as u32));
+ }
+ }
+}
+
+// Validate cases that fail on Android's imprecise float log2 implementation.
+#[test]
+#[cfg(not(target_os = "android"))]
+fn checked_log2_not_android() {
+ assert_eq!(8192u16.checked_log2(), Some((8192f32).log2() as u32));
+ assert_eq!(32768u16.checked_log2(), Some((32768f32).log2() as u32));
+ assert_eq!(8192i16.checked_log2(), Some((8192f32).log2() as u32));
+}
+
+#[test]
+fn checked_log10() {
+ assert_eq!(0u8.checked_log10(), None);
+ assert_eq!(0u16.checked_log10(), None);
+ assert_eq!(0i8.checked_log10(), None);
+ assert_eq!(0i16.checked_log10(), None);
+
+ #[cfg(not(miri))] // Miri is too slow
+ for i in i16::MIN..=0 {
+ assert_eq!(i.checked_log10(), None);
+ }
+ #[cfg(not(miri))] // Miri is too slow
+ for i in 1..=i16::MAX {
+ assert_eq!(i.checked_log10(), Some((i as f32).log10() as u32));
+ }
+ #[cfg(not(miri))] // Miri is too slow
+ for i in 1..=u16::MAX {
+ assert_eq!(i.checked_log10(), Some((i as f32).log10() as u32));
+ }
+ #[cfg(not(miri))] // Miri is too slow
+ for i in 1..=100_000u32 {
+ assert_eq!(i.checked_log10(), Some((i as f32).log10() as u32));
+ }
+}
+
+macro_rules! log10_loop {
+ ($T:ty, $log10_max:expr) => {
+ assert_eq!(<$T>::MAX.log10(), $log10_max);
+ for i in 0..=$log10_max {
+ let p = (10 as $T).pow(i as u32);
+ if p >= 10 {
+ assert_eq!((p - 9).log10(), i - 1);
+ assert_eq!((p - 1).log10(), i - 1);
+ }
+ assert_eq!(p.log10(), i);
+ assert_eq!((p + 1).log10(), i);
+ if p >= 10 {
+ assert_eq!((p + 9).log10(), i);
+ }
+
+ // also check `x.log(10)`
+ if p >= 10 {
+ assert_eq!((p - 9).log(10), i - 1);
+ assert_eq!((p - 1).log(10), i - 1);
+ }
+ assert_eq!(p.log(10), i);
+ assert_eq!((p + 1).log(10), i);
+ if p >= 10 {
+ assert_eq!((p + 9).log(10), i);
+ }
+ }
+ };
+}
+
+#[test]
+fn log10_u8() {
+ log10_loop! { u8, 2 }
+}
+
+#[test]
+fn log10_u16() {
+ log10_loop! { u16, 4 }
+}
+
+#[test]
+fn log10_u32() {
+ log10_loop! { u32, 9 }
+}
+
+#[test]
+fn log10_u64() {
+ log10_loop! { u64, 19 }
+}
+
+#[test]
+fn log10_u128() {
+ log10_loop! { u128, 38 }
+}
diff --git a/library/core/tests/num/int_macros.rs b/library/core/tests/num/int_macros.rs
new file mode 100644
index 000000000..8b84a78e6
--- /dev/null
+++ b/library/core/tests/num/int_macros.rs
@@ -0,0 +1,343 @@
+macro_rules! int_module {
+ ($T:ident) => {
+ #[cfg(test)]
+ mod tests {
+ use core::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr};
+ use core::$T::*;
+
+ use crate::num;
+
+ #[test]
+ fn test_overflows() {
+ assert!(MAX > 0);
+ assert!(MIN <= 0);
+ assert_eq!(MIN + MAX + 1, 0);
+ }
+
+ #[test]
+ fn test_num() {
+ num::test_num(10 as $T, 2 as $T);
+ }
+
+ #[test]
+ fn test_rem_euclid() {
+ assert_eq!((-1 as $T).rem_euclid(MIN), MAX);
+ }
+
+ #[test]
+ pub fn test_abs() {
+ assert_eq!((1 as $T).abs(), 1 as $T);
+ assert_eq!((0 as $T).abs(), 0 as $T);
+ assert_eq!((-1 as $T).abs(), 1 as $T);
+ }
+
+ #[test]
+ fn test_signum() {
+ assert_eq!((1 as $T).signum(), 1 as $T);
+ assert_eq!((0 as $T).signum(), 0 as $T);
+ assert_eq!((-0 as $T).signum(), 0 as $T);
+ assert_eq!((-1 as $T).signum(), -1 as $T);
+ }
+
+ #[test]
+ fn test_is_positive() {
+ assert!((1 as $T).is_positive());
+ assert!(!(0 as $T).is_positive());
+ assert!(!(-0 as $T).is_positive());
+ assert!(!(-1 as $T).is_positive());
+ }
+
+ #[test]
+ fn test_is_negative() {
+ assert!(!(1 as $T).is_negative());
+ assert!(!(0 as $T).is_negative());
+ assert!(!(-0 as $T).is_negative());
+ assert!((-1 as $T).is_negative());
+ }
+
+ #[test]
+ fn test_bitwise_operators() {
+ assert_eq!(0b1110 as $T, (0b1100 as $T).bitor(0b1010 as $T));
+ assert_eq!(0b1000 as $T, (0b1100 as $T).bitand(0b1010 as $T));
+ assert_eq!(0b0110 as $T, (0b1100 as $T).bitxor(0b1010 as $T));
+ assert_eq!(0b1110 as $T, (0b0111 as $T).shl(1));
+ assert_eq!(0b0111 as $T, (0b1110 as $T).shr(1));
+ assert_eq!(-(0b11 as $T) - (1 as $T), (0b11 as $T).not());
+ }
+
+ const A: $T = 0b0101100;
+ const B: $T = 0b0100001;
+ const C: $T = 0b1111001;
+
+ const _0: $T = 0;
+ const _1: $T = !0;
+
+ #[test]
+ fn test_count_ones() {
+ assert_eq!(A.count_ones(), 3);
+ assert_eq!(B.count_ones(), 2);
+ assert_eq!(C.count_ones(), 5);
+ }
+
+ #[test]
+ fn test_count_zeros() {
+ assert_eq!(A.count_zeros(), $T::BITS - 3);
+ assert_eq!(B.count_zeros(), $T::BITS - 2);
+ assert_eq!(C.count_zeros(), $T::BITS - 5);
+ }
+
+ #[test]
+ fn test_leading_trailing_ones() {
+ let a: $T = 0b0101_1111;
+ assert_eq!(a.trailing_ones(), 5);
+ assert_eq!((!a).leading_ones(), $T::BITS - 7);
+
+ assert_eq!(a.reverse_bits().leading_ones(), 5);
+
+ assert_eq!(_1.leading_ones(), $T::BITS);
+ assert_eq!(_1.trailing_ones(), $T::BITS);
+
+ assert_eq!((_1 << 1).trailing_ones(), 0);
+ assert_eq!(MAX.leading_ones(), 0);
+
+ assert_eq!((_1 << 1).leading_ones(), $T::BITS - 1);
+ assert_eq!(MAX.trailing_ones(), $T::BITS - 1);
+
+ assert_eq!(_0.leading_ones(), 0);
+ assert_eq!(_0.trailing_ones(), 0);
+
+ let x: $T = 0b0010_1100;
+ assert_eq!(x.leading_ones(), 0);
+ assert_eq!(x.trailing_ones(), 0);
+ }
+
+ #[test]
+ fn test_rotate() {
+ assert_eq!(A.rotate_left(6).rotate_right(2).rotate_right(4), A);
+ assert_eq!(B.rotate_left(3).rotate_left(2).rotate_right(5), B);
+ assert_eq!(C.rotate_left(6).rotate_right(2).rotate_right(4), C);
+
+ // Rotating these should make no difference
+ //
+ // We test using 124 bits because to ensure that overlong bit shifts do
+ // not cause undefined behaviour. See #10183.
+ assert_eq!(_0.rotate_left(124), _0);
+ assert_eq!(_1.rotate_left(124), _1);
+ assert_eq!(_0.rotate_right(124), _0);
+ assert_eq!(_1.rotate_right(124), _1);
+
+ // Rotating by 0 should have no effect
+ assert_eq!(A.rotate_left(0), A);
+ assert_eq!(B.rotate_left(0), B);
+ assert_eq!(C.rotate_left(0), C);
+ // Rotating by a multiple of word size should also have no effect
+ assert_eq!(A.rotate_left(128), A);
+ assert_eq!(B.rotate_left(128), B);
+ assert_eq!(C.rotate_left(128), C);
+ }
+
+ #[test]
+ fn test_swap_bytes() {
+ assert_eq!(A.swap_bytes().swap_bytes(), A);
+ assert_eq!(B.swap_bytes().swap_bytes(), B);
+ assert_eq!(C.swap_bytes().swap_bytes(), C);
+
+ // Swapping these should make no difference
+ assert_eq!(_0.swap_bytes(), _0);
+ assert_eq!(_1.swap_bytes(), _1);
+ }
+
+ #[test]
+ fn test_le() {
+ assert_eq!($T::from_le(A.to_le()), A);
+ assert_eq!($T::from_le(B.to_le()), B);
+ assert_eq!($T::from_le(C.to_le()), C);
+ assert_eq!($T::from_le(_0), _0);
+ assert_eq!($T::from_le(_1), _1);
+ assert_eq!(_0.to_le(), _0);
+ assert_eq!(_1.to_le(), _1);
+ }
+
+ #[test]
+ fn test_be() {
+ assert_eq!($T::from_be(A.to_be()), A);
+ assert_eq!($T::from_be(B.to_be()), B);
+ assert_eq!($T::from_be(C.to_be()), C);
+ assert_eq!($T::from_be(_0), _0);
+ assert_eq!($T::from_be(_1), _1);
+ assert_eq!(_0.to_be(), _0);
+ assert_eq!(_1.to_be(), _1);
+ }
+
+ #[test]
+ fn test_signed_checked_div() {
+ assert_eq!((10 as $T).checked_div(2), Some(5));
+ assert_eq!((5 as $T).checked_div(0), None);
+ assert_eq!(isize::MIN.checked_div(-1), None);
+ }
+
+ #[test]
+ fn test_saturating_abs() {
+ assert_eq!((0 as $T).saturating_abs(), 0);
+ assert_eq!((123 as $T).saturating_abs(), 123);
+ assert_eq!((-123 as $T).saturating_abs(), 123);
+ assert_eq!((MAX - 2).saturating_abs(), MAX - 2);
+ assert_eq!((MAX - 1).saturating_abs(), MAX - 1);
+ assert_eq!(MAX.saturating_abs(), MAX);
+ assert_eq!((MIN + 2).saturating_abs(), MAX - 1);
+ assert_eq!((MIN + 1).saturating_abs(), MAX);
+ assert_eq!(MIN.saturating_abs(), MAX);
+ }
+
+ #[test]
+ fn test_saturating_neg() {
+ assert_eq!((0 as $T).saturating_neg(), 0);
+ assert_eq!((123 as $T).saturating_neg(), -123);
+ assert_eq!((-123 as $T).saturating_neg(), 123);
+ assert_eq!((MAX - 2).saturating_neg(), MIN + 3);
+ assert_eq!((MAX - 1).saturating_neg(), MIN + 2);
+ assert_eq!(MAX.saturating_neg(), MIN + 1);
+ assert_eq!((MIN + 2).saturating_neg(), MAX - 1);
+ assert_eq!((MIN + 1).saturating_neg(), MAX);
+ assert_eq!(MIN.saturating_neg(), MAX);
+ }
+
+ #[test]
+ fn test_from_str() {
+ fn from_str<T: std::str::FromStr>(t: &str) -> Option<T> {
+ std::str::FromStr::from_str(t).ok()
+ }
+ assert_eq!(from_str::<$T>("0"), Some(0 as $T));
+ assert_eq!(from_str::<$T>("3"), Some(3 as $T));
+ assert_eq!(from_str::<$T>("10"), Some(10 as $T));
+ assert_eq!(from_str::<i32>("123456789"), Some(123456789 as i32));
+ assert_eq!(from_str::<$T>("00100"), Some(100 as $T));
+
+ assert_eq!(from_str::<$T>("-1"), Some(-1 as $T));
+ assert_eq!(from_str::<$T>("-3"), Some(-3 as $T));
+ assert_eq!(from_str::<$T>("-10"), Some(-10 as $T));
+ assert_eq!(from_str::<i32>("-123456789"), Some(-123456789 as i32));
+ assert_eq!(from_str::<$T>("-00100"), Some(-100 as $T));
+
+ assert_eq!(from_str::<$T>(""), None);
+ assert_eq!(from_str::<$T>(" "), None);
+ assert_eq!(from_str::<$T>("x"), None);
+ }
+
+ #[test]
+ fn test_from_str_radix() {
+ assert_eq!($T::from_str_radix("123", 10), Ok(123 as $T));
+ assert_eq!($T::from_str_radix("1001", 2), Ok(9 as $T));
+ assert_eq!($T::from_str_radix("123", 8), Ok(83 as $T));
+ assert_eq!(i32::from_str_radix("123", 16), Ok(291 as i32));
+ assert_eq!(i32::from_str_radix("ffff", 16), Ok(65535 as i32));
+ assert_eq!(i32::from_str_radix("FFFF", 16), Ok(65535 as i32));
+ assert_eq!($T::from_str_radix("z", 36), Ok(35 as $T));
+ assert_eq!($T::from_str_radix("Z", 36), Ok(35 as $T));
+
+ assert_eq!($T::from_str_radix("-123", 10), Ok(-123 as $T));
+ assert_eq!($T::from_str_radix("-1001", 2), Ok(-9 as $T));
+ assert_eq!($T::from_str_radix("-123", 8), Ok(-83 as $T));
+ assert_eq!(i32::from_str_radix("-123", 16), Ok(-291 as i32));
+ assert_eq!(i32::from_str_radix("-ffff", 16), Ok(-65535 as i32));
+ assert_eq!(i32::from_str_radix("-FFFF", 16), Ok(-65535 as i32));
+ assert_eq!($T::from_str_radix("-z", 36), Ok(-35 as $T));
+ assert_eq!($T::from_str_radix("-Z", 36), Ok(-35 as $T));
+
+ assert_eq!($T::from_str_radix("Z", 35).ok(), None::<$T>);
+ assert_eq!($T::from_str_radix("-9", 2).ok(), None::<$T>);
+ }
+
+ #[test]
+ fn test_pow() {
+ let mut r = 2 as $T;
+ assert_eq!(r.pow(2), 4 as $T);
+ assert_eq!(r.pow(0), 1 as $T);
+ assert_eq!(r.wrapping_pow(2), 4 as $T);
+ assert_eq!(r.wrapping_pow(0), 1 as $T);
+ assert_eq!(r.checked_pow(2), Some(4 as $T));
+ assert_eq!(r.checked_pow(0), Some(1 as $T));
+ assert_eq!(r.overflowing_pow(2), (4 as $T, false));
+ assert_eq!(r.overflowing_pow(0), (1 as $T, false));
+ assert_eq!(r.saturating_pow(2), 4 as $T);
+ assert_eq!(r.saturating_pow(0), 1 as $T);
+
+ r = MAX;
+ // use `^` to represent .pow() with no overflow.
+ // if itest::MAX == 2^j-1, then itest is a `j` bit int,
+ // so that `itest::MAX*itest::MAX == 2^(2*j)-2^(j+1)+1`,
+ // thussaturating_pow the overflowing result is exactly 1.
+ assert_eq!(r.wrapping_pow(2), 1 as $T);
+ assert_eq!(r.checked_pow(2), None);
+ assert_eq!(r.overflowing_pow(2), (1 as $T, true));
+ assert_eq!(r.saturating_pow(2), MAX);
+ //test for negative exponent.
+ r = -2 as $T;
+ assert_eq!(r.pow(2), 4 as $T);
+ assert_eq!(r.pow(3), -8 as $T);
+ assert_eq!(r.pow(0), 1 as $T);
+ assert_eq!(r.wrapping_pow(2), 4 as $T);
+ assert_eq!(r.wrapping_pow(3), -8 as $T);
+ assert_eq!(r.wrapping_pow(0), 1 as $T);
+ assert_eq!(r.checked_pow(2), Some(4 as $T));
+ assert_eq!(r.checked_pow(3), Some(-8 as $T));
+ assert_eq!(r.checked_pow(0), Some(1 as $T));
+ assert_eq!(r.overflowing_pow(2), (4 as $T, false));
+ assert_eq!(r.overflowing_pow(3), (-8 as $T, false));
+ assert_eq!(r.overflowing_pow(0), (1 as $T, false));
+ assert_eq!(r.saturating_pow(2), 4 as $T);
+ assert_eq!(r.saturating_pow(3), -8 as $T);
+ assert_eq!(r.saturating_pow(0), 1 as $T);
+ }
+
+ #[test]
+ fn test_div_floor() {
+ let a: $T = 8;
+ let b = 3;
+ assert_eq!(a.div_floor(b), 2);
+ assert_eq!(a.div_floor(-b), -3);
+ assert_eq!((-a).div_floor(b), -3);
+ assert_eq!((-a).div_floor(-b), 2);
+ }
+
+ #[test]
+ fn test_div_ceil() {
+ let a: $T = 8;
+ let b = 3;
+ assert_eq!(a.div_ceil(b), 3);
+ assert_eq!(a.div_ceil(-b), -2);
+ assert_eq!((-a).div_ceil(b), -2);
+ assert_eq!((-a).div_ceil(-b), 3);
+ }
+
+ #[test]
+ fn test_next_multiple_of() {
+ assert_eq!((16 as $T).next_multiple_of(8), 16);
+ assert_eq!((23 as $T).next_multiple_of(8), 24);
+ assert_eq!((16 as $T).next_multiple_of(-8), 16);
+ assert_eq!((23 as $T).next_multiple_of(-8), 16);
+ assert_eq!((-16 as $T).next_multiple_of(8), -16);
+ assert_eq!((-23 as $T).next_multiple_of(8), -16);
+ assert_eq!((-16 as $T).next_multiple_of(-8), -16);
+ assert_eq!((-23 as $T).next_multiple_of(-8), -24);
+ assert_eq!(MIN.next_multiple_of(-1), MIN);
+ }
+
+ #[test]
+ fn test_checked_next_multiple_of() {
+ assert_eq!((16 as $T).checked_next_multiple_of(8), Some(16));
+ assert_eq!((23 as $T).checked_next_multiple_of(8), Some(24));
+ assert_eq!((16 as $T).checked_next_multiple_of(-8), Some(16));
+ assert_eq!((23 as $T).checked_next_multiple_of(-8), Some(16));
+ assert_eq!((-16 as $T).checked_next_multiple_of(8), Some(-16));
+ assert_eq!((-23 as $T).checked_next_multiple_of(8), Some(-16));
+ assert_eq!((-16 as $T).checked_next_multiple_of(-8), Some(-16));
+ assert_eq!((-23 as $T).checked_next_multiple_of(-8), Some(-24));
+ assert_eq!((1 as $T).checked_next_multiple_of(0), None);
+ assert_eq!(MAX.checked_next_multiple_of(2), None);
+ assert_eq!(MIN.checked_next_multiple_of(-3), None);
+ assert_eq!(MIN.checked_next_multiple_of(-1), Some(MIN));
+ }
+ }
+ };
+}
diff --git a/library/core/tests/num/mod.rs b/library/core/tests/num/mod.rs
new file mode 100644
index 000000000..49580cdcc
--- /dev/null
+++ b/library/core/tests/num/mod.rs
@@ -0,0 +1,871 @@
+use core::cmp::PartialEq;
+use core::convert::{TryFrom, TryInto};
+use core::fmt::Debug;
+use core::marker::Copy;
+use core::num::{can_not_overflow, IntErrorKind, ParseIntError, TryFromIntError};
+use core::ops::{Add, Div, Mul, Rem, Sub};
+use core::option::Option;
+use core::option::Option::None;
+use core::str::FromStr;
+
+#[macro_use]
+mod int_macros;
+
+mod i128;
+mod i16;
+mod i32;
+mod i64;
+mod i8;
+
+#[macro_use]
+mod uint_macros;
+
+mod u128;
+mod u16;
+mod u32;
+mod u64;
+mod u8;
+
+mod bignum;
+
+mod const_from;
+mod dec2flt;
+mod flt2dec;
+mod int_log;
+mod ops;
+mod wrapping;
+
+mod ieee754;
+mod nan;
+
+/// Adds the attribute to all items in the block.
+macro_rules! cfg_block {
+ ($(#[$attr:meta]{$($it:item)*})*) => {$($(
+ #[$attr]
+ $it
+ )*)*}
+}
+
+/// Groups items that assume the pointer width is either 16/32/64, and has to be altered if
+/// support for larger/smaller pointer widths are added in the future.
+macro_rules! assume_usize_width {
+ {$($it:item)*} => {#[cfg(not(any(
+ target_pointer_width = "16", target_pointer_width = "32", target_pointer_width = "64")))]
+ compile_error!("The current tests of try_from on usize/isize assume that \
+ the pointer width is either 16, 32, or 64");
+ $($it)*
+ }
+}
+
+/// Helper function for testing numeric operations
+pub fn test_num<T>(ten: T, two: T)
+where
+ T: PartialEq
+ + Add<Output = T>
+ + Sub<Output = T>
+ + Mul<Output = T>
+ + Div<Output = T>
+ + Rem<Output = T>
+ + Debug
+ + Copy,
+{
+ assert_eq!(ten.add(two), ten + two);
+ assert_eq!(ten.sub(two), ten - two);
+ assert_eq!(ten.mul(two), ten * two);
+ assert_eq!(ten.div(two), ten / two);
+ assert_eq!(ten.rem(two), ten % two);
+}
+
+/// Helper function for asserting number parsing returns a specific error
+fn test_parse<T>(num_str: &str, expected: Result<T, IntErrorKind>)
+where
+ T: FromStr<Err = ParseIntError>,
+ Result<T, IntErrorKind>: PartialEq + Debug,
+{
+ assert_eq!(num_str.parse::<T>().map_err(|e| e.kind().clone()), expected)
+}
+
+#[test]
+fn from_str_issue7588() {
+ let u: Option<u8> = u8::from_str_radix("1000", 10).ok();
+ assert_eq!(u, None);
+ let s: Option<i16> = i16::from_str_radix("80000", 10).ok();
+ assert_eq!(s, None);
+}
+
+#[test]
+fn test_int_from_str_overflow() {
+ test_parse::<i8>("127", Ok(127));
+ test_parse::<i8>("128", Err(IntErrorKind::PosOverflow));
+
+ test_parse::<i8>("-128", Ok(-128));
+ test_parse::<i8>("-129", Err(IntErrorKind::NegOverflow));
+
+ test_parse::<i16>("32767", Ok(32_767));
+ test_parse::<i16>("32768", Err(IntErrorKind::PosOverflow));
+
+ test_parse::<i16>("-32768", Ok(-32_768));
+ test_parse::<i16>("-32769", Err(IntErrorKind::NegOverflow));
+
+ test_parse::<i32>("2147483647", Ok(2_147_483_647));
+ test_parse::<i32>("2147483648", Err(IntErrorKind::PosOverflow));
+
+ test_parse::<i32>("-2147483648", Ok(-2_147_483_648));
+ test_parse::<i32>("-2147483649", Err(IntErrorKind::NegOverflow));
+
+ test_parse::<i64>("9223372036854775807", Ok(9_223_372_036_854_775_807));
+ test_parse::<i64>("9223372036854775808", Err(IntErrorKind::PosOverflow));
+
+ test_parse::<i64>("-9223372036854775808", Ok(-9_223_372_036_854_775_808));
+ test_parse::<i64>("-9223372036854775809", Err(IntErrorKind::NegOverflow));
+}
+
+#[test]
+fn test_can_not_overflow() {
+ fn can_overflow<T>(radix: u32, input: &str) -> bool
+ where
+ T: std::convert::TryFrom<i8>,
+ {
+ !can_not_overflow::<T>(radix, T::try_from(-1_i8).is_ok(), input.as_bytes())
+ }
+
+ // Positive tests:
+ assert!(!can_overflow::<i8>(16, "F"));
+ assert!(!can_overflow::<u8>(16, "FF"));
+
+ assert!(!can_overflow::<i8>(10, "9"));
+ assert!(!can_overflow::<u8>(10, "99"));
+
+ // Negative tests:
+
+ // Not currently in std lib (issue: #27728)
+ fn format_radix<T>(mut x: T, radix: T) -> String
+ where
+ T: std::ops::Rem<Output = T>,
+ T: std::ops::Div<Output = T>,
+ T: std::cmp::PartialEq,
+ T: std::default::Default,
+ T: Copy,
+ T: Default,
+ u32: TryFrom<T>,
+ {
+ let mut result = vec![];
+
+ loop {
+ let m = x % radix;
+ x = x / radix;
+ result.push(
+ std::char::from_digit(m.try_into().ok().unwrap(), radix.try_into().ok().unwrap())
+ .unwrap(),
+ );
+ if x == T::default() {
+ break;
+ }
+ }
+ result.into_iter().rev().collect()
+ }
+
+ macro_rules! check {
+ ($($t:ty)*) => ($(
+ for base in 2..=36 {
+ let num = (<$t>::MAX as u128) + 1;
+
+ // Calcutate the string length for the smallest overflowing number:
+ let max_len_string = format_radix(num, base as u128);
+ // Ensure that that string length is deemed to potentially overflow:
+ assert!(can_overflow::<$t>(base, &max_len_string));
+ }
+ )*)
+ }
+
+ check! { i8 i16 i32 i64 i128 isize usize u8 u16 u32 u64 }
+
+ // Check u128 separately:
+ for base in 2..=36 {
+ let num = u128::MAX as u128;
+ let max_len_string = format_radix(num, base as u128);
+ // base 16 fits perfectly for u128 and won't overflow:
+ assert_eq!(can_overflow::<u128>(base, &max_len_string), base != 16);
+ }
+}
+
+#[test]
+fn test_leading_plus() {
+ test_parse::<u8>("+127", Ok(127));
+ test_parse::<i64>("+9223372036854775807", Ok(9223372036854775807));
+}
+
+#[test]
+fn test_invalid() {
+ test_parse::<i8>("--129", Err(IntErrorKind::InvalidDigit));
+ test_parse::<i8>("++129", Err(IntErrorKind::InvalidDigit));
+ test_parse::<u8>("Съешь", Err(IntErrorKind::InvalidDigit));
+ test_parse::<u8>("123Hello", Err(IntErrorKind::InvalidDigit));
+ test_parse::<i8>("--", Err(IntErrorKind::InvalidDigit));
+ test_parse::<i8>("-", Err(IntErrorKind::InvalidDigit));
+ test_parse::<i8>("+", Err(IntErrorKind::InvalidDigit));
+ test_parse::<u8>("-1", Err(IntErrorKind::InvalidDigit));
+}
+
+#[test]
+fn test_empty() {
+ test_parse::<u8>("", Err(IntErrorKind::Empty));
+}
+
+#[test]
+fn test_infallible_try_from_int_error() {
+ let func = |x: i8| -> Result<i32, TryFromIntError> { Ok(x.try_into()?) };
+
+ assert!(func(0).is_ok());
+}
+
+macro_rules! test_impl_from {
+ ($fn_name:ident, bool, $target: ty) => {
+ #[test]
+ fn $fn_name() {
+ let one: $target = 1;
+ let zero: $target = 0;
+ assert_eq!(one, <$target>::from(true));
+ assert_eq!(zero, <$target>::from(false));
+ }
+ };
+ ($fn_name: ident, $Small: ty, $Large: ty) => {
+ #[test]
+ fn $fn_name() {
+ let small_max = <$Small>::MAX;
+ let small_min = <$Small>::MIN;
+ let large_max: $Large = small_max.into();
+ let large_min: $Large = small_min.into();
+ assert_eq!(large_max as $Small, small_max);
+ assert_eq!(large_min as $Small, small_min);
+ }
+ };
+}
+
+// Unsigned -> Unsigned
+test_impl_from! { test_u8u16, u8, u16 }
+test_impl_from! { test_u8u32, u8, u32 }
+test_impl_from! { test_u8u64, u8, u64 }
+test_impl_from! { test_u8usize, u8, usize }
+test_impl_from! { test_u16u32, u16, u32 }
+test_impl_from! { test_u16u64, u16, u64 }
+test_impl_from! { test_u32u64, u32, u64 }
+
+// Signed -> Signed
+test_impl_from! { test_i8i16, i8, i16 }
+test_impl_from! { test_i8i32, i8, i32 }
+test_impl_from! { test_i8i64, i8, i64 }
+test_impl_from! { test_i8isize, i8, isize }
+test_impl_from! { test_i16i32, i16, i32 }
+test_impl_from! { test_i16i64, i16, i64 }
+test_impl_from! { test_i32i64, i32, i64 }
+
+// Unsigned -> Signed
+test_impl_from! { test_u8i16, u8, i16 }
+test_impl_from! { test_u8i32, u8, i32 }
+test_impl_from! { test_u8i64, u8, i64 }
+test_impl_from! { test_u16i32, u16, i32 }
+test_impl_from! { test_u16i64, u16, i64 }
+test_impl_from! { test_u32i64, u32, i64 }
+
+// Bool -> Integer
+test_impl_from! { test_boolu8, bool, u8 }
+test_impl_from! { test_boolu16, bool, u16 }
+test_impl_from! { test_boolu32, bool, u32 }
+test_impl_from! { test_boolu64, bool, u64 }
+test_impl_from! { test_boolu128, bool, u128 }
+test_impl_from! { test_booli8, bool, i8 }
+test_impl_from! { test_booli16, bool, i16 }
+test_impl_from! { test_booli32, bool, i32 }
+test_impl_from! { test_booli64, bool, i64 }
+test_impl_from! { test_booli128, bool, i128 }
+
+// Signed -> Float
+test_impl_from! { test_i8f32, i8, f32 }
+test_impl_from! { test_i8f64, i8, f64 }
+test_impl_from! { test_i16f32, i16, f32 }
+test_impl_from! { test_i16f64, i16, f64 }
+test_impl_from! { test_i32f64, i32, f64 }
+
+// Unsigned -> Float
+test_impl_from! { test_u8f32, u8, f32 }
+test_impl_from! { test_u8f64, u8, f64 }
+test_impl_from! { test_u16f32, u16, f32 }
+test_impl_from! { test_u16f64, u16, f64 }
+test_impl_from! { test_u32f64, u32, f64 }
+
+// Float -> Float
+#[test]
+fn test_f32f64() {
+ let max: f64 = f32::MAX.into();
+ assert_eq!(max as f32, f32::MAX);
+ assert!(max.is_normal());
+
+ let min: f64 = f32::MIN.into();
+ assert_eq!(min as f32, f32::MIN);
+ assert!(min.is_normal());
+
+ let min_positive: f64 = f32::MIN_POSITIVE.into();
+ assert_eq!(min_positive as f32, f32::MIN_POSITIVE);
+ assert!(min_positive.is_normal());
+
+ let epsilon: f64 = f32::EPSILON.into();
+ assert_eq!(epsilon as f32, f32::EPSILON);
+ assert!(epsilon.is_normal());
+
+ let zero: f64 = (0.0f32).into();
+ assert_eq!(zero as f32, 0.0f32);
+ assert!(zero.is_sign_positive());
+
+ let neg_zero: f64 = (-0.0f32).into();
+ assert_eq!(neg_zero as f32, -0.0f32);
+ assert!(neg_zero.is_sign_negative());
+
+ let infinity: f64 = f32::INFINITY.into();
+ assert_eq!(infinity as f32, f32::INFINITY);
+ assert!(infinity.is_infinite());
+ assert!(infinity.is_sign_positive());
+
+ let neg_infinity: f64 = f32::NEG_INFINITY.into();
+ assert_eq!(neg_infinity as f32, f32::NEG_INFINITY);
+ assert!(neg_infinity.is_infinite());
+ assert!(neg_infinity.is_sign_negative());
+
+ let nan: f64 = f32::NAN.into();
+ assert!(nan.is_nan());
+}
+
+/// Conversions where the full width of $source can be represented as $target
+macro_rules! test_impl_try_from_always_ok {
+ ($fn_name:ident, $source:ty, $target: ty) => {
+ #[test]
+ fn $fn_name() {
+ let max = <$source>::MAX;
+ let min = <$source>::MIN;
+ let zero: $source = 0;
+ assert_eq!(<$target as TryFrom<$source>>::try_from(max).unwrap(), max as $target);
+ assert_eq!(<$target as TryFrom<$source>>::try_from(min).unwrap(), min as $target);
+ assert_eq!(<$target as TryFrom<$source>>::try_from(zero).unwrap(), zero as $target);
+ }
+ };
+}
+
+test_impl_try_from_always_ok! { test_try_u8u8, u8, u8 }
+test_impl_try_from_always_ok! { test_try_u8u16, u8, u16 }
+test_impl_try_from_always_ok! { test_try_u8u32, u8, u32 }
+test_impl_try_from_always_ok! { test_try_u8u64, u8, u64 }
+test_impl_try_from_always_ok! { test_try_u8u128, u8, u128 }
+test_impl_try_from_always_ok! { test_try_u8i16, u8, i16 }
+test_impl_try_from_always_ok! { test_try_u8i32, u8, i32 }
+test_impl_try_from_always_ok! { test_try_u8i64, u8, i64 }
+test_impl_try_from_always_ok! { test_try_u8i128, u8, i128 }
+
+test_impl_try_from_always_ok! { test_try_u16u16, u16, u16 }
+test_impl_try_from_always_ok! { test_try_u16u32, u16, u32 }
+test_impl_try_from_always_ok! { test_try_u16u64, u16, u64 }
+test_impl_try_from_always_ok! { test_try_u16u128, u16, u128 }
+test_impl_try_from_always_ok! { test_try_u16i32, u16, i32 }
+test_impl_try_from_always_ok! { test_try_u16i64, u16, i64 }
+test_impl_try_from_always_ok! { test_try_u16i128, u16, i128 }
+
+test_impl_try_from_always_ok! { test_try_u32u32, u32, u32 }
+test_impl_try_from_always_ok! { test_try_u32u64, u32, u64 }
+test_impl_try_from_always_ok! { test_try_u32u128, u32, u128 }
+test_impl_try_from_always_ok! { test_try_u32i64, u32, i64 }
+test_impl_try_from_always_ok! { test_try_u32i128, u32, i128 }
+
+test_impl_try_from_always_ok! { test_try_u64u64, u64, u64 }
+test_impl_try_from_always_ok! { test_try_u64u128, u64, u128 }
+test_impl_try_from_always_ok! { test_try_u64i128, u64, i128 }
+
+test_impl_try_from_always_ok! { test_try_u128u128, u128, u128 }
+
+test_impl_try_from_always_ok! { test_try_i8i8, i8, i8 }
+test_impl_try_from_always_ok! { test_try_i8i16, i8, i16 }
+test_impl_try_from_always_ok! { test_try_i8i32, i8, i32 }
+test_impl_try_from_always_ok! { test_try_i8i64, i8, i64 }
+test_impl_try_from_always_ok! { test_try_i8i128, i8, i128 }
+
+test_impl_try_from_always_ok! { test_try_i16i16, i16, i16 }
+test_impl_try_from_always_ok! { test_try_i16i32, i16, i32 }
+test_impl_try_from_always_ok! { test_try_i16i64, i16, i64 }
+test_impl_try_from_always_ok! { test_try_i16i128, i16, i128 }
+
+test_impl_try_from_always_ok! { test_try_i32i32, i32, i32 }
+test_impl_try_from_always_ok! { test_try_i32i64, i32, i64 }
+test_impl_try_from_always_ok! { test_try_i32i128, i32, i128 }
+
+test_impl_try_from_always_ok! { test_try_i64i64, i64, i64 }
+test_impl_try_from_always_ok! { test_try_i64i128, i64, i128 }
+
+test_impl_try_from_always_ok! { test_try_i128i128, i128, i128 }
+
+test_impl_try_from_always_ok! { test_try_usizeusize, usize, usize }
+test_impl_try_from_always_ok! { test_try_isizeisize, isize, isize }
+
+assume_usize_width! {
+ test_impl_try_from_always_ok! { test_try_u8usize, u8, usize }
+ test_impl_try_from_always_ok! { test_try_u8isize, u8, isize }
+ test_impl_try_from_always_ok! { test_try_i8isize, i8, isize }
+
+ test_impl_try_from_always_ok! { test_try_u16usize, u16, usize }
+ test_impl_try_from_always_ok! { test_try_i16isize, i16, isize }
+
+ test_impl_try_from_always_ok! { test_try_usizeu64, usize, u64 }
+ test_impl_try_from_always_ok! { test_try_usizeu128, usize, u128 }
+ test_impl_try_from_always_ok! { test_try_usizei128, usize, i128 }
+
+ test_impl_try_from_always_ok! { test_try_isizei64, isize, i64 }
+ test_impl_try_from_always_ok! { test_try_isizei128, isize, i128 }
+
+ cfg_block!(
+ #[cfg(target_pointer_width = "16")] {
+ test_impl_try_from_always_ok! { test_try_usizeu16, usize, u16 }
+ test_impl_try_from_always_ok! { test_try_isizei16, isize, i16 }
+ test_impl_try_from_always_ok! { test_try_usizeu32, usize, u32 }
+ test_impl_try_from_always_ok! { test_try_usizei32, usize, i32 }
+ test_impl_try_from_always_ok! { test_try_isizei32, isize, i32 }
+ test_impl_try_from_always_ok! { test_try_usizei64, usize, i64 }
+ }
+
+ #[cfg(target_pointer_width = "32")] {
+ test_impl_try_from_always_ok! { test_try_u16isize, u16, isize }
+ test_impl_try_from_always_ok! { test_try_usizeu32, usize, u32 }
+ test_impl_try_from_always_ok! { test_try_isizei32, isize, i32 }
+ test_impl_try_from_always_ok! { test_try_u32usize, u32, usize }
+ test_impl_try_from_always_ok! { test_try_i32isize, i32, isize }
+ test_impl_try_from_always_ok! { test_try_usizei64, usize, i64 }
+ }
+
+ #[cfg(target_pointer_width = "64")] {
+ test_impl_try_from_always_ok! { test_try_u16isize, u16, isize }
+ test_impl_try_from_always_ok! { test_try_u32usize, u32, usize }
+ test_impl_try_from_always_ok! { test_try_u32isize, u32, isize }
+ test_impl_try_from_always_ok! { test_try_i32isize, i32, isize }
+ test_impl_try_from_always_ok! { test_try_u64usize, u64, usize }
+ test_impl_try_from_always_ok! { test_try_i64isize, i64, isize }
+ }
+ );
+}
+
+/// Conversions where max of $source can be represented as $target,
+macro_rules! test_impl_try_from_signed_to_unsigned_upper_ok {
+ ($fn_name:ident, $source:ty, $target:ty) => {
+ #[test]
+ fn $fn_name() {
+ let max = <$source>::MAX;
+ let min = <$source>::MIN;
+ let zero: $source = 0;
+ let neg_one: $source = -1;
+ assert_eq!(<$target as TryFrom<$source>>::try_from(max).unwrap(), max as $target);
+ assert!(<$target as TryFrom<$source>>::try_from(min).is_err());
+ assert_eq!(<$target as TryFrom<$source>>::try_from(zero).unwrap(), zero as $target);
+ assert!(<$target as TryFrom<$source>>::try_from(neg_one).is_err());
+ }
+ };
+}
+
+test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i8u8, i8, u8 }
+test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i8u16, i8, u16 }
+test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i8u32, i8, u32 }
+test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i8u64, i8, u64 }
+test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i8u128, i8, u128 }
+
+test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i16u16, i16, u16 }
+test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i16u32, i16, u32 }
+test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i16u64, i16, u64 }
+test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i16u128, i16, u128 }
+
+test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i32u32, i32, u32 }
+test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i32u64, i32, u64 }
+test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i32u128, i32, u128 }
+
+test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i64u64, i64, u64 }
+test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i64u128, i64, u128 }
+
+test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i128u128, i128, u128 }
+
+assume_usize_width! {
+ test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i8usize, i8, usize }
+ test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i16usize, i16, usize }
+
+ test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu64, isize, u64 }
+ test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu128, isize, u128 }
+ test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeusize, isize, usize }
+
+ cfg_block!(
+ #[cfg(target_pointer_width = "16")] {
+ test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu16, isize, u16 }
+ test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu32, isize, u32 }
+ }
+
+ #[cfg(target_pointer_width = "32")] {
+ test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu32, isize, u32 }
+
+ test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i32usize, i32, usize }
+ }
+
+ #[cfg(target_pointer_width = "64")] {
+ test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i32usize, i32, usize }
+ test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i64usize, i64, usize }
+ }
+ );
+}
+
+/// Conversions where max of $source can not be represented as $target,
+/// but min can.
+macro_rules! test_impl_try_from_unsigned_to_signed_upper_err {
+ ($fn_name:ident, $source:ty, $target:ty) => {
+ #[test]
+ fn $fn_name() {
+ let max = <$source>::MAX;
+ let min = <$source>::MIN;
+ let zero: $source = 0;
+ assert!(<$target as TryFrom<$source>>::try_from(max).is_err());
+ assert_eq!(<$target as TryFrom<$source>>::try_from(min).unwrap(), min as $target);
+ assert_eq!(<$target as TryFrom<$source>>::try_from(zero).unwrap(), zero as $target);
+ }
+ };
+}
+
+test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u8i8, u8, i8 }
+
+test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u16i8, u16, i8 }
+test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u16i16, u16, i16 }
+
+test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u32i8, u32, i8 }
+test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u32i16, u32, i16 }
+test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u32i32, u32, i32 }
+
+test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u64i8, u64, i8 }
+test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u64i16, u64, i16 }
+test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u64i32, u64, i32 }
+test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u64i64, u64, i64 }
+
+test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u128i8, u128, i8 }
+test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u128i16, u128, i16 }
+test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u128i32, u128, i32 }
+test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u128i64, u128, i64 }
+test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u128i128, u128, i128 }
+
+assume_usize_width! {
+ test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u64isize, u64, isize }
+ test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u128isize, u128, isize }
+
+ test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei8, usize, i8 }
+ test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei16, usize, i16 }
+ test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizeisize, usize, isize }
+
+ cfg_block!(
+ #[cfg(target_pointer_width = "16")] {
+ test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u16isize, u16, isize }
+ test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u32isize, u32, isize }
+ }
+
+ #[cfg(target_pointer_width = "32")] {
+ test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u32isize, u32, isize }
+ test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei32, usize, i32 }
+ }
+
+ #[cfg(target_pointer_width = "64")] {
+ test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei32, usize, i32 }
+ test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei64, usize, i64 }
+ }
+ );
+}
+
+/// Conversions where min/max of $source can not be represented as $target.
+macro_rules! test_impl_try_from_same_sign_err {
+ ($fn_name:ident, $source:ty, $target:ty) => {
+ #[test]
+ fn $fn_name() {
+ let max = <$source>::MAX;
+ let min = <$source>::MIN;
+ let zero: $source = 0;
+ let t_max = <$target>::MAX;
+ let t_min = <$target>::MIN;
+ assert!(<$target as TryFrom<$source>>::try_from(max).is_err());
+ if min != 0 {
+ assert!(<$target as TryFrom<$source>>::try_from(min).is_err());
+ }
+ assert_eq!(<$target as TryFrom<$source>>::try_from(zero).unwrap(), zero as $target);
+ assert_eq!(
+ <$target as TryFrom<$source>>::try_from(t_max as $source).unwrap(),
+ t_max as $target
+ );
+ assert_eq!(
+ <$target as TryFrom<$source>>::try_from(t_min as $source).unwrap(),
+ t_min as $target
+ );
+ }
+ };
+}
+
+test_impl_try_from_same_sign_err! { test_try_u16u8, u16, u8 }
+
+test_impl_try_from_same_sign_err! { test_try_u32u8, u32, u8 }
+test_impl_try_from_same_sign_err! { test_try_u32u16, u32, u16 }
+
+test_impl_try_from_same_sign_err! { test_try_u64u8, u64, u8 }
+test_impl_try_from_same_sign_err! { test_try_u64u16, u64, u16 }
+test_impl_try_from_same_sign_err! { test_try_u64u32, u64, u32 }
+
+test_impl_try_from_same_sign_err! { test_try_u128u8, u128, u8 }
+test_impl_try_from_same_sign_err! { test_try_u128u16, u128, u16 }
+test_impl_try_from_same_sign_err! { test_try_u128u32, u128, u32 }
+test_impl_try_from_same_sign_err! { test_try_u128u64, u128, u64 }
+
+test_impl_try_from_same_sign_err! { test_try_i16i8, i16, i8 }
+test_impl_try_from_same_sign_err! { test_try_isizei8, isize, i8 }
+
+test_impl_try_from_same_sign_err! { test_try_i32i8, i32, i8 }
+test_impl_try_from_same_sign_err! { test_try_i32i16, i32, i16 }
+
+test_impl_try_from_same_sign_err! { test_try_i64i8, i64, i8 }
+test_impl_try_from_same_sign_err! { test_try_i64i16, i64, i16 }
+test_impl_try_from_same_sign_err! { test_try_i64i32, i64, i32 }
+
+test_impl_try_from_same_sign_err! { test_try_i128i8, i128, i8 }
+test_impl_try_from_same_sign_err! { test_try_i128i16, i128, i16 }
+test_impl_try_from_same_sign_err! { test_try_i128i32, i128, i32 }
+test_impl_try_from_same_sign_err! { test_try_i128i64, i128, i64 }
+
+assume_usize_width! {
+ test_impl_try_from_same_sign_err! { test_try_usizeu8, usize, u8 }
+ test_impl_try_from_same_sign_err! { test_try_u128usize, u128, usize }
+ test_impl_try_from_same_sign_err! { test_try_i128isize, i128, isize }
+
+ cfg_block!(
+ #[cfg(target_pointer_width = "16")] {
+ test_impl_try_from_same_sign_err! { test_try_u32usize, u32, usize }
+ test_impl_try_from_same_sign_err! { test_try_u64usize, u64, usize }
+
+ test_impl_try_from_same_sign_err! { test_try_i32isize, i32, isize }
+ test_impl_try_from_same_sign_err! { test_try_i64isize, i64, isize }
+ }
+
+ #[cfg(target_pointer_width = "32")] {
+ test_impl_try_from_same_sign_err! { test_try_u64usize, u64, usize }
+ test_impl_try_from_same_sign_err! { test_try_usizeu16, usize, u16 }
+
+ test_impl_try_from_same_sign_err! { test_try_i64isize, i64, isize }
+ test_impl_try_from_same_sign_err! { test_try_isizei16, isize, i16 }
+ }
+
+ #[cfg(target_pointer_width = "64")] {
+ test_impl_try_from_same_sign_err! { test_try_usizeu16, usize, u16 }
+ test_impl_try_from_same_sign_err! { test_try_usizeu32, usize, u32 }
+
+ test_impl_try_from_same_sign_err! { test_try_isizei16, isize, i16 }
+ test_impl_try_from_same_sign_err! { test_try_isizei32, isize, i32 }
+ }
+ );
+}
+
+/// Conversions where neither the min nor the max of $source can be represented by
+/// $target, but max/min of the target can be represented by the source.
+macro_rules! test_impl_try_from_signed_to_unsigned_err {
+ ($fn_name:ident, $source:ty, $target:ty) => {
+ #[test]
+ fn $fn_name() {
+ let max = <$source>::MAX;
+ let min = <$source>::MIN;
+ let zero: $source = 0;
+ let t_max = <$target>::MAX;
+ let t_min = <$target>::MIN;
+ assert!(<$target as TryFrom<$source>>::try_from(max).is_err());
+ assert!(<$target as TryFrom<$source>>::try_from(min).is_err());
+ assert_eq!(<$target as TryFrom<$source>>::try_from(zero).unwrap(), zero as $target);
+ assert_eq!(
+ <$target as TryFrom<$source>>::try_from(t_max as $source).unwrap(),
+ t_max as $target
+ );
+ assert_eq!(
+ <$target as TryFrom<$source>>::try_from(t_min as $source).unwrap(),
+ t_min as $target
+ );
+ }
+ };
+}
+
+test_impl_try_from_signed_to_unsigned_err! { test_try_i16u8, i16, u8 }
+
+test_impl_try_from_signed_to_unsigned_err! { test_try_i32u8, i32, u8 }
+test_impl_try_from_signed_to_unsigned_err! { test_try_i32u16, i32, u16 }
+
+test_impl_try_from_signed_to_unsigned_err! { test_try_i64u8, i64, u8 }
+test_impl_try_from_signed_to_unsigned_err! { test_try_i64u16, i64, u16 }
+test_impl_try_from_signed_to_unsigned_err! { test_try_i64u32, i64, u32 }
+
+test_impl_try_from_signed_to_unsigned_err! { test_try_i128u8, i128, u8 }
+test_impl_try_from_signed_to_unsigned_err! { test_try_i128u16, i128, u16 }
+test_impl_try_from_signed_to_unsigned_err! { test_try_i128u32, i128, u32 }
+test_impl_try_from_signed_to_unsigned_err! { test_try_i128u64, i128, u64 }
+
+assume_usize_width! {
+ test_impl_try_from_signed_to_unsigned_err! { test_try_isizeu8, isize, u8 }
+ test_impl_try_from_signed_to_unsigned_err! { test_try_i128usize, i128, usize }
+
+ cfg_block! {
+ #[cfg(target_pointer_width = "16")] {
+ test_impl_try_from_signed_to_unsigned_err! { test_try_i32usize, i32, usize }
+ test_impl_try_from_signed_to_unsigned_err! { test_try_i64usize, i64, usize }
+ }
+ #[cfg(target_pointer_width = "32")] {
+ test_impl_try_from_signed_to_unsigned_err! { test_try_i64usize, i64, usize }
+
+ test_impl_try_from_signed_to_unsigned_err! { test_try_isizeu16, isize, u16 }
+ }
+ #[cfg(target_pointer_width = "64")] {
+ test_impl_try_from_signed_to_unsigned_err! { test_try_isizeu16, isize, u16 }
+ test_impl_try_from_signed_to_unsigned_err! { test_try_isizeu32, isize, u32 }
+ }
+ }
+}
+
+macro_rules! test_float {
+ ($modname: ident, $fty: ty, $inf: expr, $neginf: expr, $nan: expr) => {
+ mod $modname {
+ #[test]
+ fn min() {
+ assert_eq!((0.0 as $fty).min(0.0), 0.0);
+ assert!((0.0 as $fty).min(0.0).is_sign_positive());
+ assert_eq!((-0.0 as $fty).min(-0.0), -0.0);
+ assert!((-0.0 as $fty).min(-0.0).is_sign_negative());
+ assert_eq!((9.0 as $fty).min(9.0), 9.0);
+ assert_eq!((-9.0 as $fty).min(0.0), -9.0);
+ assert_eq!((0.0 as $fty).min(9.0), 0.0);
+ assert!((0.0 as $fty).min(9.0).is_sign_positive());
+ assert_eq!((-0.0 as $fty).min(9.0), -0.0);
+ assert!((-0.0 as $fty).min(9.0).is_sign_negative());
+ assert_eq!((-0.0 as $fty).min(-9.0), -9.0);
+ assert_eq!(($inf as $fty).min(9.0), 9.0);
+ assert_eq!((9.0 as $fty).min($inf), 9.0);
+ assert_eq!(($inf as $fty).min(-9.0), -9.0);
+ assert_eq!((-9.0 as $fty).min($inf), -9.0);
+ assert_eq!(($neginf as $fty).min(9.0), $neginf);
+ assert_eq!((9.0 as $fty).min($neginf), $neginf);
+ assert_eq!(($neginf as $fty).min(-9.0), $neginf);
+ assert_eq!((-9.0 as $fty).min($neginf), $neginf);
+ assert_eq!(($nan as $fty).min(9.0), 9.0);
+ assert_eq!(($nan as $fty).min(-9.0), -9.0);
+ assert_eq!((9.0 as $fty).min($nan), 9.0);
+ assert_eq!((-9.0 as $fty).min($nan), -9.0);
+ assert!(($nan as $fty).min($nan).is_nan());
+ }
+ #[test]
+ fn max() {
+ assert_eq!((0.0 as $fty).max(0.0), 0.0);
+ assert!((0.0 as $fty).max(0.0).is_sign_positive());
+ assert_eq!((-0.0 as $fty).max(-0.0), -0.0);
+ assert!((-0.0 as $fty).max(-0.0).is_sign_negative());
+ assert_eq!((9.0 as $fty).max(9.0), 9.0);
+ assert_eq!((-9.0 as $fty).max(0.0), 0.0);
+ assert!((-9.0 as $fty).max(0.0).is_sign_positive());
+ assert_eq!((-9.0 as $fty).max(-0.0), -0.0);
+ assert!((-9.0 as $fty).max(-0.0).is_sign_negative());
+ assert_eq!((0.0 as $fty).max(9.0), 9.0);
+ assert_eq!((0.0 as $fty).max(-9.0), 0.0);
+ assert!((0.0 as $fty).max(-9.0).is_sign_positive());
+ assert_eq!((-0.0 as $fty).max(-9.0), -0.0);
+ assert!((-0.0 as $fty).max(-9.0).is_sign_negative());
+ assert_eq!(($inf as $fty).max(9.0), $inf);
+ assert_eq!((9.0 as $fty).max($inf), $inf);
+ assert_eq!(($inf as $fty).max(-9.0), $inf);
+ assert_eq!((-9.0 as $fty).max($inf), $inf);
+ assert_eq!(($neginf as $fty).max(9.0), 9.0);
+ assert_eq!((9.0 as $fty).max($neginf), 9.0);
+ assert_eq!(($neginf as $fty).max(-9.0), -9.0);
+ assert_eq!((-9.0 as $fty).max($neginf), -9.0);
+ assert_eq!(($nan as $fty).max(9.0), 9.0);
+ assert_eq!(($nan as $fty).max(-9.0), -9.0);
+ assert_eq!((9.0 as $fty).max($nan), 9.0);
+ assert_eq!((-9.0 as $fty).max($nan), -9.0);
+ assert!(($nan as $fty).max($nan).is_nan());
+ }
+ #[test]
+ fn minimum() {
+ assert_eq!((0.0 as $fty).minimum(0.0), 0.0);
+ assert!((0.0 as $fty).minimum(0.0).is_sign_positive());
+ assert_eq!((-0.0 as $fty).minimum(0.0), -0.0);
+ assert!((-0.0 as $fty).minimum(0.0).is_sign_negative());
+ assert_eq!((-0.0 as $fty).minimum(-0.0), -0.0);
+ assert!((-0.0 as $fty).minimum(-0.0).is_sign_negative());
+ assert_eq!((9.0 as $fty).minimum(9.0), 9.0);
+ assert_eq!((-9.0 as $fty).minimum(0.0), -9.0);
+ assert_eq!((0.0 as $fty).minimum(9.0), 0.0);
+ assert!((0.0 as $fty).minimum(9.0).is_sign_positive());
+ assert_eq!((-0.0 as $fty).minimum(9.0), -0.0);
+ assert!((-0.0 as $fty).minimum(9.0).is_sign_negative());
+ assert_eq!((-0.0 as $fty).minimum(-9.0), -9.0);
+ assert_eq!(($inf as $fty).minimum(9.0), 9.0);
+ assert_eq!((9.0 as $fty).minimum($inf), 9.0);
+ assert_eq!(($inf as $fty).minimum(-9.0), -9.0);
+ assert_eq!((-9.0 as $fty).minimum($inf), -9.0);
+ assert_eq!(($neginf as $fty).minimum(9.0), $neginf);
+ assert_eq!((9.0 as $fty).minimum($neginf), $neginf);
+ assert_eq!(($neginf as $fty).minimum(-9.0), $neginf);
+ assert_eq!((-9.0 as $fty).minimum($neginf), $neginf);
+ assert!(($nan as $fty).minimum(9.0).is_nan());
+ assert!(($nan as $fty).minimum(-9.0).is_nan());
+ assert!((9.0 as $fty).minimum($nan).is_nan());
+ assert!((-9.0 as $fty).minimum($nan).is_nan());
+ assert!(($nan as $fty).minimum($nan).is_nan());
+ }
+ #[test]
+ fn maximum() {
+ assert_eq!((0.0 as $fty).maximum(0.0), 0.0);
+ assert!((0.0 as $fty).maximum(0.0).is_sign_positive());
+ assert_eq!((-0.0 as $fty).maximum(0.0), 0.0);
+ assert!((-0.0 as $fty).maximum(0.0).is_sign_positive());
+ assert_eq!((-0.0 as $fty).maximum(-0.0), -0.0);
+ assert!((-0.0 as $fty).maximum(-0.0).is_sign_negative());
+ assert_eq!((9.0 as $fty).maximum(9.0), 9.0);
+ assert_eq!((-9.0 as $fty).maximum(0.0), 0.0);
+ assert!((-9.0 as $fty).maximum(0.0).is_sign_positive());
+ assert_eq!((-9.0 as $fty).maximum(-0.0), -0.0);
+ assert!((-9.0 as $fty).maximum(-0.0).is_sign_negative());
+ assert_eq!((0.0 as $fty).maximum(9.0), 9.0);
+ assert_eq!((0.0 as $fty).maximum(-9.0), 0.0);
+ assert!((0.0 as $fty).maximum(-9.0).is_sign_positive());
+ assert_eq!((-0.0 as $fty).maximum(-9.0), -0.0);
+ assert!((-0.0 as $fty).maximum(-9.0).is_sign_negative());
+ assert_eq!(($inf as $fty).maximum(9.0), $inf);
+ assert_eq!((9.0 as $fty).maximum($inf), $inf);
+ assert_eq!(($inf as $fty).maximum(-9.0), $inf);
+ assert_eq!((-9.0 as $fty).maximum($inf), $inf);
+ assert_eq!(($neginf as $fty).maximum(9.0), 9.0);
+ assert_eq!((9.0 as $fty).maximum($neginf), 9.0);
+ assert_eq!(($neginf as $fty).maximum(-9.0), -9.0);
+ assert_eq!((-9.0 as $fty).maximum($neginf), -9.0);
+ assert!(($nan as $fty).maximum(9.0).is_nan());
+ assert!(($nan as $fty).maximum(-9.0).is_nan());
+ assert!((9.0 as $fty).maximum($nan).is_nan());
+ assert!((-9.0 as $fty).maximum($nan).is_nan());
+ assert!(($nan as $fty).maximum($nan).is_nan());
+ }
+ #[test]
+ fn rem_euclid() {
+ let a: $fty = 42.0;
+ assert!($inf.rem_euclid(a).is_nan());
+ assert_eq!(a.rem_euclid($inf), a);
+ assert!(a.rem_euclid($nan).is_nan());
+ assert!($inf.rem_euclid($inf).is_nan());
+ assert!($inf.rem_euclid($nan).is_nan());
+ assert!($nan.rem_euclid($inf).is_nan());
+ }
+ #[test]
+ fn div_euclid() {
+ let a: $fty = 42.0;
+ assert_eq!(a.div_euclid($inf), 0.0);
+ assert!(a.div_euclid($nan).is_nan());
+ assert!($inf.div_euclid($inf).is_nan());
+ assert!($inf.div_euclid($nan).is_nan());
+ assert!($nan.div_euclid($inf).is_nan());
+ }
+ }
+ };
+}
+
+test_float!(f32, f32, f32::INFINITY, f32::NEG_INFINITY, f32::NAN);
+test_float!(f64, f64, f64::INFINITY, f64::NEG_INFINITY, f64::NAN);
diff --git a/library/core/tests/num/nan.rs b/library/core/tests/num/nan.rs
new file mode 100644
index 000000000..ef81988c9
--- /dev/null
+++ b/library/core/tests/num/nan.rs
@@ -0,0 +1,7 @@
+#[test]
+fn test_nan() {
+ let x = "NaN".to_string();
+ assert_eq!(format!("{}", f64::NAN), x);
+ assert_eq!(format!("{:e}", f64::NAN), x);
+ assert_eq!(format!("{:E}", f64::NAN), x);
+}
diff --git a/library/core/tests/num/ops.rs b/library/core/tests/num/ops.rs
new file mode 100644
index 000000000..ae8b93825
--- /dev/null
+++ b/library/core/tests/num/ops.rs
@@ -0,0 +1,232 @@
+use core::ops::*;
+
+// For types L and R, checks that a trait implementation exists for
+// * binary ops: L op R, L op &R, &L op R and &L op &R
+// * assign ops: &mut L op R, &mut L op &R
+macro_rules! impl_defined {
+ ($op:ident, $method:ident($lhs:literal, $rhs:literal), $result:literal, $lt:ty, $rt:ty) => {
+ let lhs = $lhs as $lt;
+ let rhs = $rhs as $rt;
+ assert_eq!($result as $lt, $op::$method(lhs, rhs));
+ assert_eq!($result as $lt, $op::$method(lhs, &rhs));
+ assert_eq!($result as $lt, $op::$method(&lhs, rhs));
+ assert_eq!($result as $lt, $op::$method(&lhs, &rhs));
+ };
+ ($op:ident, $method:ident(&mut $lhs:literal, $rhs:literal), $result:literal, $lt:ty, $rt:ty) => {
+ let rhs = $rhs as $rt;
+ let mut lhs = $lhs as $lt;
+ $op::$method(&mut lhs, rhs);
+ assert_eq!($result as $lt, lhs);
+
+ let mut lhs = $lhs as $lt;
+ $op::$method(&mut lhs, &rhs);
+ assert_eq!($result as $lt, lhs);
+ };
+}
+
+// For all specified types T, checks that a trait implementation exists for
+// * binary ops: T op T, T op &T, &T op T and &T op &T
+// * assign ops: &mut T op T, &mut T op &T
+// * unary ops: op T and op &T
+macro_rules! impls_defined {
+ ($op:ident, $method:ident($lhs:literal, $rhs:literal), $result:literal, $($t:ty),+) => {$(
+ impl_defined!($op, $method($lhs, $rhs), $result, $t, $t);
+ )+};
+ ($op:ident, $method:ident(&mut $lhs:literal, $rhs:literal), $result:literal, $($t:ty),+) => {$(
+ impl_defined!($op, $method(&mut $lhs, $rhs), $result, $t, $t);
+ )+};
+ ($op:ident, $method:ident($operand:literal), $result:literal, $($t:ty),+) => {$(
+ let operand = $operand as $t;
+ assert_eq!($result as $t, $op::$method(operand));
+ assert_eq!($result as $t, $op::$method(&operand));
+ )+};
+}
+
+macro_rules! test_op {
+ ($fn_name:ident, $op:ident::$method:ident($lhs:literal), $result:literal, $($t:ty),+) => {
+ #[test]
+ fn $fn_name() {
+ impls_defined!($op, $method($lhs), $result, $($t),+);
+ }
+ };
+}
+
+test_op!(test_neg_defined, Neg::neg(0), 0, i8, i16, i32, i64, f32, f64);
+#[cfg(not(target_os = "emscripten"))]
+test_op!(test_neg_defined_128, Neg::neg(0), 0, i128);
+
+test_op!(test_not_defined_bool, Not::not(true), false, bool);
+
+macro_rules! test_arith_op {
+ ($fn_name:ident, $op:ident::$method:ident($lhs:literal, $rhs:literal)) => {
+ #[test]
+ fn $fn_name() {
+ impls_defined!(
+ $op,
+ $method($lhs, $rhs),
+ 0,
+ i8,
+ i16,
+ i32,
+ i64,
+ isize,
+ u8,
+ u16,
+ u32,
+ u64,
+ usize,
+ f32,
+ f64
+ );
+ #[cfg(not(target_os = "emscripten"))]
+ impls_defined!($op, $method($lhs, $rhs), 0, i128, u128);
+ }
+ };
+ ($fn_name:ident, $op:ident::$method:ident(&mut $lhs:literal, $rhs:literal)) => {
+ #[test]
+ fn $fn_name() {
+ impls_defined!(
+ $op,
+ $method(&mut $lhs, $rhs),
+ 0,
+ i8,
+ i16,
+ i32,
+ i64,
+ isize,
+ u8,
+ u16,
+ u32,
+ u64,
+ usize,
+ f32,
+ f64
+ );
+ #[cfg(not(target_os = "emscripten"))]
+ impls_defined!($op, $method(&mut $lhs, $rhs), 0, i128, u128);
+ }
+ };
+}
+
+test_arith_op!(test_add_defined, Add::add(0, 0));
+test_arith_op!(test_add_assign_defined, AddAssign::add_assign(&mut 0, 0));
+test_arith_op!(test_sub_defined, Sub::sub(0, 0));
+test_arith_op!(test_sub_assign_defined, SubAssign::sub_assign(&mut 0, 0));
+test_arith_op!(test_mul_defined, Mul::mul(0, 0));
+test_arith_op!(test_mul_assign_defined, MulAssign::mul_assign(&mut 0, 0));
+test_arith_op!(test_div_defined, Div::div(0, 1));
+test_arith_op!(test_div_assign_defined, DivAssign::div_assign(&mut 0, 1));
+test_arith_op!(test_rem_defined, Rem::rem(0, 1));
+test_arith_op!(test_rem_assign_defined, RemAssign::rem_assign(&mut 0, 1));
+
+macro_rules! test_bitop {
+ ($test_name:ident, $op:ident::$method:ident) => {
+ #[test]
+ fn $test_name() {
+ impls_defined!(
+ $op,
+ $method(0, 0),
+ 0,
+ i8,
+ i16,
+ i32,
+ i64,
+ isize,
+ u8,
+ u16,
+ u32,
+ u64,
+ usize
+ );
+ #[cfg(not(target_os = "emscripten"))]
+ impls_defined!($op, $method(0, 0), 0, i128, u128);
+ impls_defined!($op, $method(false, false), false, bool);
+ }
+ };
+}
+macro_rules! test_bitop_assign {
+ ($test_name:ident, $op:ident::$method:ident) => {
+ #[test]
+ fn $test_name() {
+ impls_defined!(
+ $op,
+ $method(&mut 0, 0),
+ 0,
+ i8,
+ i16,
+ i32,
+ i64,
+ isize,
+ u8,
+ u16,
+ u32,
+ u64,
+ usize
+ );
+ #[cfg(not(target_os = "emscripten"))]
+ impls_defined!($op, $method(&mut 0, 0), 0, i128, u128);
+ impls_defined!($op, $method(&mut false, false), false, bool);
+ }
+ };
+}
+
+test_bitop!(test_bitand_defined, BitAnd::bitand);
+test_bitop_assign!(test_bitand_assign_defined, BitAndAssign::bitand_assign);
+test_bitop!(test_bitor_defined, BitOr::bitor);
+test_bitop_assign!(test_bitor_assign_defined, BitOrAssign::bitor_assign);
+test_bitop!(test_bitxor_defined, BitXor::bitxor);
+test_bitop_assign!(test_bitxor_assign_defined, BitXorAssign::bitxor_assign);
+
+macro_rules! test_shift_inner {
+ ($op:ident::$method:ident, $lt:ty, $($rt:ty),+) => {
+ $(impl_defined!($op, $method(0,0), 0, $lt, $rt);)+
+ };
+ ($op:ident::$method:ident, $lt:ty) => {
+ test_shift_inner!($op::$method, $lt, i8, i16, i32, i64, isize, u8, u16, u32, u64, usize);
+ #[cfg(not(target_os = "emscripten"))]
+ test_shift_inner!($op::$method, $lt, i128, u128);
+ };
+}
+
+macro_rules! test_shift {
+ ($op:ident::$method:ident, $($lt:ty),+) => {
+ $(test_shift_inner!($op::$method, $lt);)+
+ };
+ ($test_name:ident, $op:ident::$method:ident) => {
+ #[test]
+ fn $test_name() {
+ test_shift!($op::$method, i8, i16, i32, i64, isize, u8, u16, u32, u64, usize);
+ #[cfg(not(target_os = "emscripten"))]
+ test_shift!($op::$method, i128, u128);
+ }
+ };
+}
+
+macro_rules! test_shift_assign_inner {
+ ($op:ident::$method:ident, $lt:ty, $($rt:ty),+) => {
+ $(impl_defined!($op, $method(&mut 0,0), 0, $lt, $rt);)+
+ };
+ ($op:ident::$method:ident, $lt:ty) => {
+ test_shift_assign_inner!($op::$method, $lt, i8, i16, i32, i64, isize, u8, u16, u32, u64, usize);
+ #[cfg(not(target_os = "emscripten"))]
+ test_shift_assign_inner!($op::$method, $lt, i128, u128);
+ };
+}
+
+macro_rules! test_shift_assign {
+ ($op:ident::$method:ident, $($lt:ty),+) => {
+ $(test_shift_assign_inner!($op::$method, $lt);)+
+ };
+ ($test_name:ident, $op:ident::$method:ident) => {
+ #[test]
+ fn $test_name() {
+ test_shift_assign!($op::$method, i8, i16, i32, i64, isize, u8, u16, u32, u64, usize);
+ #[cfg(not(target_os = "emscripten"))]
+ test_shift_assign!($op::$method, i128, u128);
+ }
+ };
+}
+test_shift!(test_shl_defined, Shl::shl);
+test_shift_assign!(test_shl_assign_defined, ShlAssign::shl_assign);
+test_shift!(test_shr_defined, Shr::shr);
+test_shift_assign!(test_shr_assign_defined, ShrAssign::shr_assign);
diff --git a/library/core/tests/num/u128.rs b/library/core/tests/num/u128.rs
new file mode 100644
index 000000000..a7b0f9eff
--- /dev/null
+++ b/library/core/tests/num/u128.rs
@@ -0,0 +1 @@
+uint_module!(u128);
diff --git a/library/core/tests/num/u16.rs b/library/core/tests/num/u16.rs
new file mode 100644
index 000000000..010596a34
--- /dev/null
+++ b/library/core/tests/num/u16.rs
@@ -0,0 +1 @@
+uint_module!(u16);
diff --git a/library/core/tests/num/u32.rs b/library/core/tests/num/u32.rs
new file mode 100644
index 000000000..687d3bbaa
--- /dev/null
+++ b/library/core/tests/num/u32.rs
@@ -0,0 +1 @@
+uint_module!(u32);
diff --git a/library/core/tests/num/u64.rs b/library/core/tests/num/u64.rs
new file mode 100644
index 000000000..ee55071e9
--- /dev/null
+++ b/library/core/tests/num/u64.rs
@@ -0,0 +1 @@
+uint_module!(u64);
diff --git a/library/core/tests/num/u8.rs b/library/core/tests/num/u8.rs
new file mode 100644
index 000000000..12b038ce0
--- /dev/null
+++ b/library/core/tests/num/u8.rs
@@ -0,0 +1 @@
+uint_module!(u8);
diff --git a/library/core/tests/num/uint_macros.rs b/library/core/tests/num/uint_macros.rs
new file mode 100644
index 000000000..93ae620c2
--- /dev/null
+++ b/library/core/tests/num/uint_macros.rs
@@ -0,0 +1,235 @@
+macro_rules! uint_module {
+ ($T:ident) => {
+ #[cfg(test)]
+ mod tests {
+ use core::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr};
+ use core::$T::*;
+ use std::str::FromStr;
+
+ use crate::num;
+
+ #[test]
+ fn test_overflows() {
+ assert!(MAX > 0);
+ assert!(MIN <= 0);
+ assert!((MIN + MAX).wrapping_add(1) == 0);
+ }
+
+ #[test]
+ fn test_num() {
+ num::test_num(10 as $T, 2 as $T);
+ }
+
+ #[test]
+ fn test_bitwise_operators() {
+ assert!(0b1110 as $T == (0b1100 as $T).bitor(0b1010 as $T));
+ assert!(0b1000 as $T == (0b1100 as $T).bitand(0b1010 as $T));
+ assert!(0b0110 as $T == (0b1100 as $T).bitxor(0b1010 as $T));
+ assert!(0b1110 as $T == (0b0111 as $T).shl(1));
+ assert!(0b0111 as $T == (0b1110 as $T).shr(1));
+ assert!(MAX - (0b1011 as $T) == (0b1011 as $T).not());
+ }
+
+ const A: $T = 0b0101100;
+ const B: $T = 0b0100001;
+ const C: $T = 0b1111001;
+
+ const _0: $T = 0;
+ const _1: $T = !0;
+
+ #[test]
+ fn test_count_ones() {
+ assert!(A.count_ones() == 3);
+ assert!(B.count_ones() == 2);
+ assert!(C.count_ones() == 5);
+ }
+
+ #[test]
+ fn test_count_zeros() {
+ assert!(A.count_zeros() == $T::BITS - 3);
+ assert!(B.count_zeros() == $T::BITS - 2);
+ assert!(C.count_zeros() == $T::BITS - 5);
+ }
+
+ #[test]
+ fn test_leading_trailing_ones() {
+ let a: $T = 0b0101_1111;
+ assert_eq!(a.trailing_ones(), 5);
+ assert_eq!((!a).leading_ones(), $T::BITS - 7);
+
+ assert_eq!(a.reverse_bits().leading_ones(), 5);
+
+ assert_eq!(_1.leading_ones(), $T::BITS);
+ assert_eq!(_1.trailing_ones(), $T::BITS);
+
+ assert_eq!((_1 << 1).trailing_ones(), 0);
+ assert_eq!((_1 >> 1).leading_ones(), 0);
+
+ assert_eq!((_1 << 1).leading_ones(), $T::BITS - 1);
+ assert_eq!((_1 >> 1).trailing_ones(), $T::BITS - 1);
+
+ assert_eq!(_0.leading_ones(), 0);
+ assert_eq!(_0.trailing_ones(), 0);
+
+ let x: $T = 0b0010_1100;
+ assert_eq!(x.leading_ones(), 0);
+ assert_eq!(x.trailing_ones(), 0);
+ }
+
+ #[test]
+ fn test_rotate() {
+ assert_eq!(A.rotate_left(6).rotate_right(2).rotate_right(4), A);
+ assert_eq!(B.rotate_left(3).rotate_left(2).rotate_right(5), B);
+ assert_eq!(C.rotate_left(6).rotate_right(2).rotate_right(4), C);
+
+ // Rotating these should make no difference
+ //
+ // We test using 124 bits because to ensure that overlong bit shifts do
+ // not cause undefined behaviour. See #10183.
+ assert_eq!(_0.rotate_left(124), _0);
+ assert_eq!(_1.rotate_left(124), _1);
+ assert_eq!(_0.rotate_right(124), _0);
+ assert_eq!(_1.rotate_right(124), _1);
+
+ // Rotating by 0 should have no effect
+ assert_eq!(A.rotate_left(0), A);
+ assert_eq!(B.rotate_left(0), B);
+ assert_eq!(C.rotate_left(0), C);
+ // Rotating by a multiple of word size should also have no effect
+ assert_eq!(A.rotate_left(128), A);
+ assert_eq!(B.rotate_left(128), B);
+ assert_eq!(C.rotate_left(128), C);
+ }
+
+ #[test]
+ fn test_swap_bytes() {
+ assert_eq!(A.swap_bytes().swap_bytes(), A);
+ assert_eq!(B.swap_bytes().swap_bytes(), B);
+ assert_eq!(C.swap_bytes().swap_bytes(), C);
+
+ // Swapping these should make no difference
+ assert_eq!(_0.swap_bytes(), _0);
+ assert_eq!(_1.swap_bytes(), _1);
+ }
+
+ #[test]
+ fn test_reverse_bits() {
+ assert_eq!(A.reverse_bits().reverse_bits(), A);
+ assert_eq!(B.reverse_bits().reverse_bits(), B);
+ assert_eq!(C.reverse_bits().reverse_bits(), C);
+
+ // Swapping these should make no difference
+ assert_eq!(_0.reverse_bits(), _0);
+ assert_eq!(_1.reverse_bits(), _1);
+ }
+
+ #[test]
+ fn test_le() {
+ assert_eq!($T::from_le(A.to_le()), A);
+ assert_eq!($T::from_le(B.to_le()), B);
+ assert_eq!($T::from_le(C.to_le()), C);
+ assert_eq!($T::from_le(_0), _0);
+ assert_eq!($T::from_le(_1), _1);
+ assert_eq!(_0.to_le(), _0);
+ assert_eq!(_1.to_le(), _1);
+ }
+
+ #[test]
+ fn test_be() {
+ assert_eq!($T::from_be(A.to_be()), A);
+ assert_eq!($T::from_be(B.to_be()), B);
+ assert_eq!($T::from_be(C.to_be()), C);
+ assert_eq!($T::from_be(_0), _0);
+ assert_eq!($T::from_be(_1), _1);
+ assert_eq!(_0.to_be(), _0);
+ assert_eq!(_1.to_be(), _1);
+ }
+
+ #[test]
+ fn test_unsigned_checked_div() {
+ assert!((10 as $T).checked_div(2) == Some(5));
+ assert!((5 as $T).checked_div(0) == None);
+ }
+
+ fn from_str<T: FromStr>(t: &str) -> Option<T> {
+ FromStr::from_str(t).ok()
+ }
+
+ #[test]
+ pub fn test_from_str() {
+ assert_eq!(from_str::<$T>("0"), Some(0 as $T));
+ assert_eq!(from_str::<$T>("3"), Some(3 as $T));
+ assert_eq!(from_str::<$T>("10"), Some(10 as $T));
+ assert_eq!(from_str::<u32>("123456789"), Some(123456789 as u32));
+ assert_eq!(from_str::<$T>("00100"), Some(100 as $T));
+
+ assert_eq!(from_str::<$T>(""), None);
+ assert_eq!(from_str::<$T>(" "), None);
+ assert_eq!(from_str::<$T>("x"), None);
+ }
+
+ #[test]
+ pub fn test_parse_bytes() {
+ assert_eq!($T::from_str_radix("123", 10), Ok(123 as $T));
+ assert_eq!($T::from_str_radix("1001", 2), Ok(9 as $T));
+ assert_eq!($T::from_str_radix("123", 8), Ok(83 as $T));
+ assert_eq!(u16::from_str_radix("123", 16), Ok(291 as u16));
+ assert_eq!(u16::from_str_radix("ffff", 16), Ok(65535 as u16));
+ assert_eq!($T::from_str_radix("z", 36), Ok(35 as $T));
+
+ assert_eq!($T::from_str_radix("Z", 10).ok(), None::<$T>);
+ assert_eq!($T::from_str_radix("_", 2).ok(), None::<$T>);
+ }
+
+ #[test]
+ fn test_pow() {
+ let mut r = 2 as $T;
+ assert_eq!(r.pow(2), 4 as $T);
+ assert_eq!(r.pow(0), 1 as $T);
+ assert_eq!(r.wrapping_pow(2), 4 as $T);
+ assert_eq!(r.wrapping_pow(0), 1 as $T);
+ assert_eq!(r.checked_pow(2), Some(4 as $T));
+ assert_eq!(r.checked_pow(0), Some(1 as $T));
+ assert_eq!(r.overflowing_pow(2), (4 as $T, false));
+ assert_eq!(r.overflowing_pow(0), (1 as $T, false));
+ assert_eq!(r.saturating_pow(2), 4 as $T);
+ assert_eq!(r.saturating_pow(0), 1 as $T);
+
+ r = MAX;
+ // use `^` to represent .pow() with no overflow.
+ // if itest::MAX == 2^j-1, then itest is a `j` bit int,
+ // so that `itest::MAX*itest::MAX == 2^(2*j)-2^(j+1)+1`,
+ // thussaturating_pow the overflowing result is exactly 1.
+ assert_eq!(r.wrapping_pow(2), 1 as $T);
+ assert_eq!(r.checked_pow(2), None);
+ assert_eq!(r.overflowing_pow(2), (1 as $T, true));
+ assert_eq!(r.saturating_pow(2), MAX);
+ }
+
+ #[test]
+ fn test_div_floor() {
+ assert_eq!((8 as $T).div_floor(3), 2);
+ }
+
+ #[test]
+ fn test_div_ceil() {
+ assert_eq!((8 as $T).div_ceil(3), 3);
+ }
+
+ #[test]
+ fn test_next_multiple_of() {
+ assert_eq!((16 as $T).next_multiple_of(8), 16);
+ assert_eq!((23 as $T).next_multiple_of(8), 24);
+ assert_eq!(MAX.next_multiple_of(1), MAX);
+ }
+
+ #[test]
+ fn test_checked_next_multiple_of() {
+ assert_eq!((16 as $T).checked_next_multiple_of(8), Some(16));
+ assert_eq!((23 as $T).checked_next_multiple_of(8), Some(24));
+ assert_eq!((1 as $T).checked_next_multiple_of(0), None);
+ assert_eq!(MAX.checked_next_multiple_of(2), None);
+ }
+ }
+ };
+}
diff --git a/library/core/tests/num/wrapping.rs b/library/core/tests/num/wrapping.rs
new file mode 100644
index 000000000..8ded139a1
--- /dev/null
+++ b/library/core/tests/num/wrapping.rs
@@ -0,0 +1,320 @@
+use core::num::Wrapping;
+
+macro_rules! wrapping_operation {
+ ($result:expr, $lhs:ident $op:tt $rhs:expr) => {
+ assert_eq!($result, $lhs $op $rhs);
+ assert_eq!($result, &$lhs $op $rhs);
+ assert_eq!($result, $lhs $op &$rhs);
+ assert_eq!($result, &$lhs $op &$rhs);
+ };
+ ($result:expr, $op:tt $expr:expr) => {
+ assert_eq!($result, $op $expr);
+ assert_eq!($result, $op &$expr);
+ };
+}
+
+macro_rules! wrapping_assignment {
+ ($result:expr, $lhs:ident $op:tt $rhs:expr) => {
+ let mut lhs1 = $lhs;
+ lhs1 $op $rhs;
+ assert_eq!($result, lhs1);
+
+ let mut lhs2 = $lhs;
+ lhs2 $op &$rhs;
+ assert_eq!($result, lhs2);
+ };
+}
+
+macro_rules! wrapping_test {
+ ($fn_name:ident, $type:ty, $min:expr, $max:expr) => {
+ #[test]
+ fn $fn_name() {
+ let zero: Wrapping<$type> = Wrapping(0);
+ let one: Wrapping<$type> = Wrapping(1);
+ let min: Wrapping<$type> = Wrapping($min);
+ let max: Wrapping<$type> = Wrapping($max);
+
+ wrapping_operation!(min, max + one);
+ wrapping_assignment!(min, max += one);
+ wrapping_operation!(max, min - one);
+ wrapping_assignment!(max, min -= one);
+ wrapping_operation!(max, max * one);
+ wrapping_assignment!(max, max *= one);
+ wrapping_operation!(max, max / one);
+ wrapping_assignment!(max, max /= one);
+ wrapping_operation!(zero, max % one);
+ wrapping_assignment!(zero, max %= one);
+ wrapping_operation!(zero, zero & max);
+ wrapping_assignment!(zero, zero &= max);
+ wrapping_operation!(max, zero | max);
+ wrapping_assignment!(max, zero |= max);
+ wrapping_operation!(zero, max ^ max);
+ wrapping_assignment!(zero, max ^= max);
+ wrapping_operation!(zero, zero << 1usize);
+ wrapping_assignment!(zero, zero <<= 1usize);
+ wrapping_operation!(zero, zero >> 1usize);
+ wrapping_assignment!(zero, zero >>= 1usize);
+ wrapping_operation!(zero, -zero);
+ wrapping_operation!(max, !min);
+ }
+ };
+}
+
+wrapping_test!(test_wrapping_i8, i8, i8::MIN, i8::MAX);
+wrapping_test!(test_wrapping_i16, i16, i16::MIN, i16::MAX);
+wrapping_test!(test_wrapping_i32, i32, i32::MIN, i32::MAX);
+wrapping_test!(test_wrapping_i64, i64, i64::MIN, i64::MAX);
+#[cfg(not(target_os = "emscripten"))]
+wrapping_test!(test_wrapping_i128, i128, i128::MIN, i128::MAX);
+wrapping_test!(test_wrapping_isize, isize, isize::MIN, isize::MAX);
+wrapping_test!(test_wrapping_u8, u8, u8::MIN, u8::MAX);
+wrapping_test!(test_wrapping_u16, u16, u16::MIN, u16::MAX);
+wrapping_test!(test_wrapping_u32, u32, u32::MIN, u32::MAX);
+wrapping_test!(test_wrapping_u64, u64, u64::MIN, u64::MAX);
+#[cfg(not(target_os = "emscripten"))]
+wrapping_test!(test_wrapping_u128, u128, u128::MIN, u128::MAX);
+wrapping_test!(test_wrapping_usize, usize, usize::MIN, usize::MAX);
+
+// Don't warn about overflowing ops on 32-bit platforms
+#[cfg_attr(target_pointer_width = "32", allow(const_err))]
+#[test]
+fn wrapping_int_api() {
+ assert_eq!(i8::MAX.wrapping_add(1), i8::MIN);
+ assert_eq!(i16::MAX.wrapping_add(1), i16::MIN);
+ assert_eq!(i32::MAX.wrapping_add(1), i32::MIN);
+ assert_eq!(i64::MAX.wrapping_add(1), i64::MIN);
+ assert_eq!(isize::MAX.wrapping_add(1), isize::MIN);
+
+ assert_eq!(i8::MIN.wrapping_sub(1), i8::MAX);
+ assert_eq!(i16::MIN.wrapping_sub(1), i16::MAX);
+ assert_eq!(i32::MIN.wrapping_sub(1), i32::MAX);
+ assert_eq!(i64::MIN.wrapping_sub(1), i64::MAX);
+ assert_eq!(isize::MIN.wrapping_sub(1), isize::MAX);
+
+ assert_eq!(u8::MAX.wrapping_add(1), u8::MIN);
+ assert_eq!(u16::MAX.wrapping_add(1), u16::MIN);
+ assert_eq!(u32::MAX.wrapping_add(1), u32::MIN);
+ assert_eq!(u64::MAX.wrapping_add(1), u64::MIN);
+ assert_eq!(usize::MAX.wrapping_add(1), usize::MIN);
+
+ assert_eq!(u8::MIN.wrapping_sub(1), u8::MAX);
+ assert_eq!(u16::MIN.wrapping_sub(1), u16::MAX);
+ assert_eq!(u32::MIN.wrapping_sub(1), u32::MAX);
+ assert_eq!(u64::MIN.wrapping_sub(1), u64::MAX);
+ assert_eq!(usize::MIN.wrapping_sub(1), usize::MAX);
+
+ assert_eq!((0xfe_u8 as i8).wrapping_mul(16), (0xe0_u8 as i8));
+ assert_eq!((0xfedc_u16 as i16).wrapping_mul(16), (0xedc0_u16 as i16));
+ assert_eq!((0xfedc_ba98_u32 as i32).wrapping_mul(16), (0xedcb_a980_u32 as i32));
+ assert_eq!(
+ (0xfedc_ba98_7654_3217_u64 as i64).wrapping_mul(16),
+ (0xedcb_a987_6543_2170_u64 as i64)
+ );
+
+ match () {
+ #[cfg(target_pointer_width = "32")]
+ () => {
+ assert_eq!((0xfedc_ba98_u32 as isize).wrapping_mul(16), (0xedcb_a980_u32 as isize));
+ }
+ #[cfg(target_pointer_width = "64")]
+ () => {
+ assert_eq!(
+ (0xfedc_ba98_7654_3217_u64 as isize).wrapping_mul(16),
+ (0xedcb_a987_6543_2170_u64 as isize)
+ );
+ }
+ }
+
+ assert_eq!((0xfe as u8).wrapping_mul(16), (0xe0 as u8));
+ assert_eq!((0xfedc as u16).wrapping_mul(16), (0xedc0 as u16));
+ assert_eq!((0xfedc_ba98 as u32).wrapping_mul(16), (0xedcb_a980 as u32));
+ assert_eq!((0xfedc_ba98_7654_3217 as u64).wrapping_mul(16), (0xedcb_a987_6543_2170 as u64));
+
+ match () {
+ #[cfg(target_pointer_width = "32")]
+ () => {
+ assert_eq!((0xfedc_ba98 as usize).wrapping_mul(16), (0xedcb_a980 as usize));
+ }
+ #[cfg(target_pointer_width = "64")]
+ () => {
+ assert_eq!(
+ (0xfedc_ba98_7654_3217 as usize).wrapping_mul(16),
+ (0xedcb_a987_6543_2170 as usize)
+ );
+ }
+ }
+
+ macro_rules! check_mul_no_wrap {
+ ($e:expr, $f:expr) => {
+ assert_eq!(($e).wrapping_mul($f), ($e) * $f);
+ };
+ }
+ macro_rules! check_mul_wraps {
+ ($e:expr, $f:expr) => {
+ assert_eq!(($e).wrapping_mul($f), $e);
+ };
+ }
+
+ check_mul_no_wrap!(0xfe_u8 as i8, -1);
+ check_mul_no_wrap!(0xfedc_u16 as i16, -1);
+ check_mul_no_wrap!(0xfedc_ba98_u32 as i32, -1);
+ check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -1);
+ check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -1);
+
+ check_mul_no_wrap!(0xfe_u8 as i8, -2);
+ check_mul_no_wrap!(0xfedc_u16 as i16, -2);
+ check_mul_no_wrap!(0xfedc_ba98_u32 as i32, -2);
+ check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -2);
+ check_mul_no_wrap!(0xfedc_ba98_fedc_ba98_u64 as u64 as isize, -2);
+
+ check_mul_no_wrap!(0xfe_u8 as i8, 2);
+ check_mul_no_wrap!(0xfedc_u16 as i16, 2);
+ check_mul_no_wrap!(0xfedc_ba98_u32 as i32, 2);
+ check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, 2);
+ check_mul_no_wrap!(0xfedc_ba98_fedc_ba98_u64 as u64 as isize, 2);
+
+ check_mul_wraps!(0x80_u8 as i8, -1);
+ check_mul_wraps!(0x8000_u16 as i16, -1);
+ check_mul_wraps!(0x8000_0000_u32 as i32, -1);
+ check_mul_wraps!(0x8000_0000_0000_0000_u64 as i64, -1);
+ match () {
+ #[cfg(target_pointer_width = "32")]
+ () => {
+ check_mul_wraps!(0x8000_0000_u32 as isize, -1);
+ }
+ #[cfg(target_pointer_width = "64")]
+ () => {
+ check_mul_wraps!(0x8000_0000_0000_0000_u64 as isize, -1);
+ }
+ }
+
+ macro_rules! check_div_no_wrap {
+ ($e:expr, $f:expr) => {
+ assert_eq!(($e).wrapping_div($f), ($e) / $f);
+ };
+ }
+ macro_rules! check_div_wraps {
+ ($e:expr, $f:expr) => {
+ assert_eq!(($e).wrapping_div($f), $e);
+ };
+ }
+
+ check_div_no_wrap!(0xfe_u8 as i8, -1);
+ check_div_no_wrap!(0xfedc_u16 as i16, -1);
+ check_div_no_wrap!(0xfedc_ba98_u32 as i32, -1);
+ check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -1);
+ check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -1);
+
+ check_div_no_wrap!(0xfe_u8 as i8, -2);
+ check_div_no_wrap!(0xfedc_u16 as i16, -2);
+ check_div_no_wrap!(0xfedc_ba98_u32 as i32, -2);
+ check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -2);
+ check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -2);
+
+ check_div_no_wrap!(0xfe_u8 as i8, 2);
+ check_div_no_wrap!(0xfedc_u16 as i16, 2);
+ check_div_no_wrap!(0xfedc_ba98_u32 as i32, 2);
+ check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, 2);
+ check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, 2);
+
+ check_div_wraps!(-128 as i8, -1);
+ check_div_wraps!(0x8000_u16 as i16, -1);
+ check_div_wraps!(0x8000_0000_u32 as i32, -1);
+ check_div_wraps!(0x8000_0000_0000_0000_u64 as i64, -1);
+ match () {
+ #[cfg(target_pointer_width = "32")]
+ () => {
+ check_div_wraps!(0x8000_0000_u32 as isize, -1);
+ }
+ #[cfg(target_pointer_width = "64")]
+ () => {
+ check_div_wraps!(0x8000_0000_0000_0000_u64 as isize, -1);
+ }
+ }
+
+ macro_rules! check_rem_no_wrap {
+ ($e:expr, $f:expr) => {
+ assert_eq!(($e).wrapping_rem($f), ($e) % $f);
+ };
+ }
+ macro_rules! check_rem_wraps {
+ ($e:expr, $f:expr) => {
+ assert_eq!(($e).wrapping_rem($f), 0);
+ };
+ }
+
+ check_rem_no_wrap!(0xfe_u8 as i8, -1);
+ check_rem_no_wrap!(0xfedc_u16 as i16, -1);
+ check_rem_no_wrap!(0xfedc_ba98_u32 as i32, -1);
+ check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -1);
+ check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -1);
+
+ check_rem_no_wrap!(0xfe_u8 as i8, -2);
+ check_rem_no_wrap!(0xfedc_u16 as i16, -2);
+ check_rem_no_wrap!(0xfedc_ba98_u32 as i32, -2);
+ check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -2);
+ check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -2);
+
+ check_rem_no_wrap!(0xfe_u8 as i8, 2);
+ check_rem_no_wrap!(0xfedc_u16 as i16, 2);
+ check_rem_no_wrap!(0xfedc_ba98_u32 as i32, 2);
+ check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, 2);
+ check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, 2);
+
+ check_rem_wraps!(0x80_u8 as i8, -1);
+ check_rem_wraps!(0x8000_u16 as i16, -1);
+ check_rem_wraps!(0x8000_0000_u32 as i32, -1);
+ check_rem_wraps!(0x8000_0000_0000_0000_u64 as i64, -1);
+ match () {
+ #[cfg(target_pointer_width = "32")]
+ () => {
+ check_rem_wraps!(0x8000_0000_u32 as isize, -1);
+ }
+ #[cfg(target_pointer_width = "64")]
+ () => {
+ check_rem_wraps!(0x8000_0000_0000_0000_u64 as isize, -1);
+ }
+ }
+
+ macro_rules! check_neg_no_wrap {
+ ($e:expr) => {
+ assert_eq!(($e).wrapping_neg(), -($e));
+ };
+ }
+ macro_rules! check_neg_wraps {
+ ($e:expr) => {
+ assert_eq!(($e).wrapping_neg(), ($e));
+ };
+ }
+
+ check_neg_no_wrap!(0xfe_u8 as i8);
+ check_neg_no_wrap!(0xfedc_u16 as i16);
+ check_neg_no_wrap!(0xfedc_ba98_u32 as i32);
+ check_neg_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64);
+ check_neg_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize);
+
+ check_neg_wraps!(0x80_u8 as i8);
+ check_neg_wraps!(0x8000_u16 as i16);
+ check_neg_wraps!(0x8000_0000_u32 as i32);
+ check_neg_wraps!(0x8000_0000_0000_0000_u64 as i64);
+ match () {
+ #[cfg(target_pointer_width = "32")]
+ () => {
+ check_neg_wraps!(0x8000_0000_u32 as isize);
+ }
+ #[cfg(target_pointer_width = "64")]
+ () => {
+ check_neg_wraps!(0x8000_0000_0000_0000_u64 as isize);
+ }
+ }
+}
+
+#[test]
+fn wrapping_const() {
+ // Specifically the wrapping behavior of division and remainder is subtle,
+ // see https://github.com/rust-lang/rust/pull/94512.
+ const _: () = {
+ assert!(i32::MIN.wrapping_div(-1) == i32::MIN);
+ assert!(i32::MIN.wrapping_rem(-1) == 0);
+ };
+}
diff --git a/library/core/tests/ops.rs b/library/core/tests/ops.rs
new file mode 100644
index 000000000..0c81cba35
--- /dev/null
+++ b/library/core/tests/ops.rs
@@ -0,0 +1,240 @@
+mod control_flow;
+
+use core::ops::{Bound, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive};
+use core::ops::{Deref, DerefMut};
+
+// Test the Range structs and syntax.
+
+#[test]
+fn test_range() {
+ let r = Range { start: 2, end: 10 };
+ let mut count = 0;
+ for (i, ri) in r.enumerate() {
+ assert_eq!(ri, i + 2);
+ assert!(ri >= 2 && ri < 10);
+ count += 1;
+ }
+ assert_eq!(count, 8);
+}
+
+#[test]
+fn test_range_from() {
+ let r = RangeFrom { start: 2 };
+ let mut count = 0;
+ for (i, ri) in r.take(10).enumerate() {
+ assert_eq!(ri, i + 2);
+ assert!(ri >= 2 && ri < 12);
+ count += 1;
+ }
+ assert_eq!(count, 10);
+}
+
+#[test]
+fn test_range_to() {
+ // Not much to test.
+ let _ = RangeTo { end: 42 };
+}
+
+#[test]
+fn test_full_range() {
+ // Not much to test.
+ let _ = RangeFull;
+}
+
+#[test]
+fn test_range_inclusive() {
+ let mut r = RangeInclusive::new(1i8, 2);
+ assert_eq!(r.next(), Some(1));
+ assert_eq!(r.next(), Some(2));
+ assert_eq!(r.next(), None);
+
+ r = RangeInclusive::new(127i8, 127);
+ assert_eq!(r.next(), Some(127));
+ assert_eq!(r.next(), None);
+
+ r = RangeInclusive::new(-128i8, -128);
+ assert_eq!(r.next_back(), Some(-128));
+ assert_eq!(r.next_back(), None);
+
+ // degenerate
+ r = RangeInclusive::new(1, -1);
+ assert_eq!(r.size_hint(), (0, Some(0)));
+ assert_eq!(r.next(), None);
+}
+
+#[test]
+fn test_range_to_inclusive() {
+ // Not much to test.
+ let _ = RangeToInclusive { end: 42 };
+}
+
+#[test]
+fn test_range_is_empty() {
+ assert!(!(0.0..10.0).is_empty());
+ assert!((-0.0..0.0).is_empty());
+ assert!((10.0..0.0).is_empty());
+
+ assert!(!(f32::NEG_INFINITY..f32::INFINITY).is_empty());
+ assert!((f32::EPSILON..f32::NAN).is_empty());
+ assert!((f32::NAN..f32::EPSILON).is_empty());
+ assert!((f32::NAN..f32::NAN).is_empty());
+
+ assert!(!(0.0..=10.0).is_empty());
+ assert!(!(-0.0..=0.0).is_empty());
+ assert!((10.0..=0.0).is_empty());
+
+ assert!(!(f32::NEG_INFINITY..=f32::INFINITY).is_empty());
+ assert!((f32::EPSILON..=f32::NAN).is_empty());
+ assert!((f32::NAN..=f32::EPSILON).is_empty());
+ assert!((f32::NAN..=f32::NAN).is_empty());
+}
+
+#[test]
+fn test_bound_cloned_unbounded() {
+ assert_eq!(Bound::<&u32>::Unbounded.cloned(), Bound::Unbounded);
+}
+
+#[test]
+fn test_bound_cloned_included() {
+ assert_eq!(Bound::Included(&3).cloned(), Bound::Included(3));
+}
+
+#[test]
+fn test_bound_cloned_excluded() {
+ assert_eq!(Bound::Excluded(&3).cloned(), Bound::Excluded(3));
+}
+
+#[test]
+#[allow(unused_comparisons)]
+#[allow(unused_mut)]
+fn test_range_syntax() {
+ let mut count = 0;
+ for i in 0_usize..10 {
+ assert!(i >= 0 && i < 10);
+ count += i;
+ }
+ assert_eq!(count, 45);
+
+ let mut count = 0;
+ let mut range = 0_usize..10;
+ for i in range {
+ assert!(i >= 0 && i < 10);
+ count += i;
+ }
+ assert_eq!(count, 45);
+
+ let mut count = 0;
+ let mut rf = 3_usize..;
+ for i in rf.take(10) {
+ assert!(i >= 3 && i < 13);
+ count += i;
+ }
+ assert_eq!(count, 75);
+
+ let _ = 0_usize..4 + 4 - 3;
+
+ fn foo() -> isize {
+ 42
+ }
+ let _ = 0..foo();
+
+ let _ = { &42..&100 }; // references to literals are OK
+ let _ = ..42_usize;
+
+ // Test we can use two different types with a common supertype.
+ let x = &42;
+ {
+ let y = 42;
+ let _ = x..&y;
+ }
+}
+
+#[test]
+#[allow(dead_code)]
+fn test_range_syntax_in_return_statement() {
+ fn return_range_to() -> RangeTo<i32> {
+ return ..1;
+ }
+ fn return_full_range() -> RangeFull {
+ return ..;
+ }
+ // Not much to test.
+}
+
+#[test]
+fn range_structural_match() {
+ // test that all range types can be structurally matched upon
+
+ const RANGE: Range<usize> = 0..1000;
+ match RANGE {
+ RANGE => {}
+ _ => unreachable!(),
+ }
+
+ const RANGE_FROM: RangeFrom<usize> = 0..;
+ match RANGE_FROM {
+ RANGE_FROM => {}
+ _ => unreachable!(),
+ }
+
+ const RANGE_FULL: RangeFull = ..;
+ match RANGE_FULL {
+ RANGE_FULL => {}
+ }
+
+ const RANGE_INCLUSIVE: RangeInclusive<usize> = 0..=999;
+ match RANGE_INCLUSIVE {
+ RANGE_INCLUSIVE => {}
+ _ => unreachable!(),
+ }
+
+ const RANGE_TO: RangeTo<usize> = ..1000;
+ match RANGE_TO {
+ RANGE_TO => {}
+ _ => unreachable!(),
+ }
+
+ const RANGE_TO_INCLUSIVE: RangeToInclusive<usize> = ..=999;
+ match RANGE_TO_INCLUSIVE {
+ RANGE_TO_INCLUSIVE => {}
+ _ => unreachable!(),
+ }
+}
+
+// Test Deref implementations
+
+#[test]
+fn deref_mut_on_ref() {
+ // Test that `&mut T` implements `DerefMut<T>`
+
+ fn inc<T: Deref<Target = isize> + DerefMut>(mut t: T) {
+ *t += 1;
+ }
+
+ let mut x: isize = 5;
+ inc(&mut x);
+ assert_eq!(x, 6);
+}
+
+#[test]
+fn deref_on_ref() {
+ // Test that `&T` and `&mut T` implement `Deref<T>`
+
+ fn deref<U: Copy, T: Deref<Target = U>>(t: T) -> U {
+ *t
+ }
+
+ let x: isize = 3;
+ let y = deref(&x);
+ assert_eq!(y, 3);
+
+ let mut x: isize = 4;
+ let y = deref(&mut x);
+ assert_eq!(y, 4);
+}
+
+#[test]
+#[allow(unreachable_code)]
+fn test_not_never() {
+ if !return () {}
+}
diff --git a/library/core/tests/ops/control_flow.rs b/library/core/tests/ops/control_flow.rs
new file mode 100644
index 000000000..eacfd63a6
--- /dev/null
+++ b/library/core/tests/ops/control_flow.rs
@@ -0,0 +1,18 @@
+use core::intrinsics::discriminant_value;
+use core::ops::ControlFlow;
+
+#[test]
+fn control_flow_discriminants_match_result() {
+ // This isn't stable surface area, but helps keep `?` cheap between them,
+ // even if LLVM can't always take advantage of it right now.
+ // (Sadly Result and Option are inconsistent, so ControlFlow can't match both.)
+
+ assert_eq!(
+ discriminant_value(&ControlFlow::<i32, i32>::Break(3)),
+ discriminant_value(&Result::<i32, i32>::Err(3)),
+ );
+ assert_eq!(
+ discriminant_value(&ControlFlow::<i32, i32>::Continue(3)),
+ discriminant_value(&Result::<i32, i32>::Ok(3)),
+ );
+}
diff --git a/library/core/tests/option.rs b/library/core/tests/option.rs
new file mode 100644
index 000000000..9f5e537dc
--- /dev/null
+++ b/library/core/tests/option.rs
@@ -0,0 +1,555 @@
+use core::cell::Cell;
+use core::clone::Clone;
+use core::mem;
+use core::ops::DerefMut;
+use core::option::*;
+
+#[test]
+fn test_get_ptr() {
+ unsafe {
+ let x: Box<_> = Box::new(0);
+ let addr_x: *const isize = mem::transmute(&*x);
+ let opt = Some(x);
+ let y = opt.unwrap();
+ let addr_y: *const isize = mem::transmute(&*y);
+ assert_eq!(addr_x, addr_y);
+ }
+}
+
+#[test]
+fn test_get_str() {
+ let x = "test".to_string();
+ let addr_x = x.as_ptr();
+ let opt = Some(x);
+ let y = opt.unwrap();
+ let addr_y = y.as_ptr();
+ assert_eq!(addr_x, addr_y);
+}
+
+#[test]
+fn test_get_resource() {
+ use core::cell::RefCell;
+ use std::rc::Rc;
+
+ struct R {
+ i: Rc<RefCell<isize>>,
+ }
+
+ impl Drop for R {
+ fn drop(&mut self) {
+ let ii = &*self.i;
+ let i = *ii.borrow();
+ *ii.borrow_mut() = i + 1;
+ }
+ }
+
+ fn r(i: Rc<RefCell<isize>>) -> R {
+ R { i }
+ }
+
+ let i = Rc::new(RefCell::new(0));
+ {
+ let x = r(i.clone());
+ let opt = Some(x);
+ let _y = opt.unwrap();
+ }
+ assert_eq!(*i.borrow(), 1);
+}
+
+#[test]
+fn test_option_dance() {
+ let x = Some(());
+ let mut y = Some(5);
+ let mut y2 = 0;
+ for _x in x {
+ y2 = y.take().unwrap();
+ }
+ assert_eq!(y2, 5);
+ assert!(y.is_none());
+}
+
+#[test]
+#[should_panic]
+fn test_option_too_much_dance() {
+ struct A;
+ let mut y = Some(A);
+ let _y2 = y.take().unwrap();
+ let _y3 = y.take().unwrap();
+}
+
+#[test]
+fn test_and() {
+ let x: Option<isize> = Some(1);
+ assert_eq!(x.and(Some(2)), Some(2));
+ assert_eq!(x.and(None::<isize>), None);
+
+ let x: Option<isize> = None;
+ assert_eq!(x.and(Some(2)), None);
+ assert_eq!(x.and(None::<isize>), None);
+
+ const FOO: Option<isize> = Some(1);
+ const A: Option<isize> = FOO.and(Some(2));
+ const B: Option<isize> = FOO.and(None);
+ assert_eq!(A, Some(2));
+ assert_eq!(B, None);
+
+ const BAR: Option<isize> = None;
+ const C: Option<isize> = BAR.and(Some(2));
+ const D: Option<isize> = BAR.and(None);
+ assert_eq!(C, None);
+ assert_eq!(D, None);
+}
+
+#[test]
+fn test_and_then() {
+ const fn plus_one(x: isize) -> Option<isize> {
+ Some(x + 1)
+ }
+
+ const fn none(_: isize) -> Option<isize> {
+ None
+ }
+
+ let x: Option<isize> = Some(1);
+ assert_eq!(x.and_then(plus_one), Some(2));
+ assert_eq!(x.and_then(none), None);
+
+ let x: Option<isize> = None;
+ assert_eq!(x.and_then(plus_one), None);
+ assert_eq!(x.and_then(none), None);
+
+ const FOO: Option<isize> = Some(1);
+ const A: Option<isize> = FOO.and_then(plus_one);
+ const B: Option<isize> = FOO.and_then(none);
+ assert_eq!(A, Some(2));
+ assert_eq!(B, None);
+
+ const BAR: Option<isize> = None;
+ const C: Option<isize> = BAR.and_then(plus_one);
+ const D: Option<isize> = BAR.and_then(none);
+ assert_eq!(C, None);
+ assert_eq!(D, None);
+}
+
+#[test]
+fn test_or() {
+ let x: Option<isize> = Some(1);
+ assert_eq!(x.or(Some(2)), Some(1));
+ assert_eq!(x.or(None), Some(1));
+
+ let x: Option<isize> = None;
+ assert_eq!(x.or(Some(2)), Some(2));
+ assert_eq!(x.or(None), None);
+
+ const FOO: Option<isize> = Some(1);
+ const A: Option<isize> = FOO.or(Some(2));
+ const B: Option<isize> = FOO.or(None);
+ assert_eq!(A, Some(1));
+ assert_eq!(B, Some(1));
+
+ const BAR: Option<isize> = None;
+ const C: Option<isize> = BAR.or(Some(2));
+ const D: Option<isize> = BAR.or(None);
+ assert_eq!(C, Some(2));
+ assert_eq!(D, None);
+}
+
+#[test]
+fn test_or_else() {
+ const fn two() -> Option<isize> {
+ Some(2)
+ }
+
+ const fn none() -> Option<isize> {
+ None
+ }
+
+ let x: Option<isize> = Some(1);
+ assert_eq!(x.or_else(two), Some(1));
+ assert_eq!(x.or_else(none), Some(1));
+
+ let x: Option<isize> = None;
+ assert_eq!(x.or_else(two), Some(2));
+ assert_eq!(x.or_else(none), None);
+
+ const FOO: Option<isize> = Some(1);
+ const A: Option<isize> = FOO.or_else(two);
+ const B: Option<isize> = FOO.or_else(none);
+ assert_eq!(A, Some(1));
+ assert_eq!(B, Some(1));
+
+ const BAR: Option<isize> = None;
+ const C: Option<isize> = BAR.or_else(two);
+ const D: Option<isize> = BAR.or_else(none);
+ assert_eq!(C, Some(2));
+ assert_eq!(D, None);
+}
+
+#[test]
+fn test_unwrap() {
+ assert_eq!(Some(1).unwrap(), 1);
+ let s = Some("hello".to_string()).unwrap();
+ assert_eq!(s, "hello");
+}
+
+#[test]
+#[should_panic]
+fn test_unwrap_panic1() {
+ let x: Option<isize> = None;
+ x.unwrap();
+}
+
+#[test]
+#[should_panic]
+fn test_unwrap_panic2() {
+ let x: Option<String> = None;
+ x.unwrap();
+}
+
+#[test]
+fn test_unwrap_or() {
+ let x: Option<isize> = Some(1);
+ assert_eq!(x.unwrap_or(2), 1);
+
+ let x: Option<isize> = None;
+ assert_eq!(x.unwrap_or(2), 2);
+
+ const A: isize = Some(1).unwrap_or(2);
+ const B: isize = None.unwrap_or(2);
+ assert_eq!(A, 1);
+ assert_eq!(B, 2);
+}
+
+#[test]
+fn test_unwrap_or_else() {
+ const fn two() -> isize {
+ 2
+ }
+
+ let x: Option<isize> = Some(1);
+ assert_eq!(x.unwrap_or_else(two), 1);
+
+ let x: Option<isize> = None;
+ assert_eq!(x.unwrap_or_else(two), 2);
+
+ const A: isize = Some(1).unwrap_or_else(two);
+ const B: isize = None.unwrap_or_else(two);
+ assert_eq!(A, 1);
+ assert_eq!(B, 2);
+}
+
+#[test]
+fn test_unwrap_unchecked() {
+ assert_eq!(unsafe { Some(1).unwrap_unchecked() }, 1);
+ let s = unsafe { Some("hello".to_string()).unwrap_unchecked() };
+ assert_eq!(s, "hello");
+}
+
+#[test]
+fn test_iter() {
+ let val = 5;
+
+ let x = Some(val);
+ let mut it = x.iter();
+
+ assert_eq!(it.size_hint(), (1, Some(1)));
+ assert_eq!(it.next(), Some(&val));
+ assert_eq!(it.size_hint(), (0, Some(0)));
+ assert!(it.next().is_none());
+
+ let mut it = (&x).into_iter();
+ assert_eq!(it.next(), Some(&val));
+}
+
+#[test]
+fn test_mut_iter() {
+ let mut val = 5;
+ let new_val = 11;
+
+ let mut x = Some(val);
+ {
+ let mut it = x.iter_mut();
+
+ assert_eq!(it.size_hint(), (1, Some(1)));
+
+ match it.next() {
+ Some(interior) => {
+ assert_eq!(*interior, val);
+ *interior = new_val;
+ }
+ None => assert!(false),
+ }
+
+ assert_eq!(it.size_hint(), (0, Some(0)));
+ assert!(it.next().is_none());
+ }
+ assert_eq!(x, Some(new_val));
+
+ let mut y = Some(val);
+ let mut it = (&mut y).into_iter();
+ assert_eq!(it.next(), Some(&mut val));
+}
+
+#[test]
+fn test_ord() {
+ let small = Some(1.0f64);
+ let big = Some(5.0f64);
+ let nan = Some(0.0f64 / 0.0);
+ assert!(!(nan < big));
+ assert!(!(nan > big));
+ assert!(small < big);
+ assert!(None < big);
+ assert!(big > None);
+}
+
+#[test]
+fn test_collect() {
+ let v: Option<Vec<isize>> = (0..0).map(|_| Some(0)).collect();
+ assert!(v == Some(vec![]));
+
+ let v: Option<Vec<isize>> = (0..3).map(|x| Some(x)).collect();
+ assert!(v == Some(vec![0, 1, 2]));
+
+ let v: Option<Vec<isize>> = (0..3).map(|x| if x > 1 { None } else { Some(x) }).collect();
+ assert!(v == None);
+
+ // test that it does not take more elements than it needs
+ let mut functions: [Box<dyn Fn() -> Option<()>>; 3] =
+ [Box::new(|| Some(())), Box::new(|| None), Box::new(|| panic!())];
+
+ let v: Option<Vec<()>> = functions.iter_mut().map(|f| (*f)()).collect();
+
+ assert!(v == None);
+}
+
+#[test]
+fn test_copied() {
+ let val = 1;
+ let val_ref = &val;
+ let opt_none: Option<&'static u32> = None;
+ let opt_ref = Some(&val);
+ let opt_ref_ref = Some(&val_ref);
+
+ // None works
+ assert_eq!(opt_none.clone(), None);
+ assert_eq!(opt_none.copied(), None);
+
+ // Immutable ref works
+ assert_eq!(opt_ref.clone(), Some(&val));
+ assert_eq!(opt_ref.copied(), Some(1));
+
+ // Double Immutable ref works
+ assert_eq!(opt_ref_ref.clone(), Some(&val_ref));
+ assert_eq!(opt_ref_ref.clone().copied(), Some(&val));
+ assert_eq!(opt_ref_ref.copied().copied(), Some(1));
+}
+
+#[test]
+fn test_cloned() {
+ let val = 1;
+ let val_ref = &val;
+ let opt_none: Option<&'static u32> = None;
+ let opt_ref = Some(&val);
+ let opt_ref_ref = Some(&val_ref);
+
+ // None works
+ assert_eq!(opt_none.clone(), None);
+ assert_eq!(opt_none.cloned(), None);
+
+ // Immutable ref works
+ assert_eq!(opt_ref.clone(), Some(&val));
+ assert_eq!(opt_ref.cloned(), Some(1));
+
+ // Double Immutable ref works
+ assert_eq!(opt_ref_ref.clone(), Some(&val_ref));
+ assert_eq!(opt_ref_ref.clone().cloned(), Some(&val));
+ assert_eq!(opt_ref_ref.cloned().cloned(), Some(1));
+}
+
+#[test]
+fn test_try() {
+ fn try_option_some() -> Option<u8> {
+ let val = Some(1)?;
+ Some(val)
+ }
+ assert_eq!(try_option_some(), Some(1));
+
+ fn try_option_none() -> Option<u8> {
+ let val = None?;
+ Some(val)
+ }
+ assert_eq!(try_option_none(), None);
+}
+
+#[test]
+fn test_option_as_deref() {
+ // Some: &Option<T: Deref>::Some(T) -> Option<&T::Deref::Target>::Some(&*T)
+ let ref_option = &Some(&42);
+ assert_eq!(ref_option.as_deref(), Some(&42));
+
+ let ref_option = &Some(String::from("a result"));
+ assert_eq!(ref_option.as_deref(), Some("a result"));
+
+ let ref_option = &Some(vec![1, 2, 3, 4, 5]);
+ assert_eq!(ref_option.as_deref(), Some([1, 2, 3, 4, 5].as_slice()));
+
+ // None: &Option<T: Deref>>::None -> None
+ let ref_option: &Option<&i32> = &None;
+ assert_eq!(ref_option.as_deref(), None);
+}
+
+#[test]
+fn test_option_as_deref_mut() {
+ // Some: &mut Option<T: Deref>::Some(T) -> Option<&mut T::Deref::Target>::Some(&mut *T)
+ let mut val = 42;
+ let ref_option = &mut Some(&mut val);
+ assert_eq!(ref_option.as_deref_mut(), Some(&mut 42));
+
+ let ref_option = &mut Some(String::from("a result"));
+ assert_eq!(ref_option.as_deref_mut(), Some(String::from("a result").deref_mut()));
+
+ let ref_option = &mut Some(vec![1, 2, 3, 4, 5]);
+ assert_eq!(ref_option.as_deref_mut(), Some([1, 2, 3, 4, 5].as_mut_slice()));
+
+ // None: &mut Option<T: Deref>>::None -> None
+ let ref_option: &mut Option<&mut i32> = &mut None;
+ assert_eq!(ref_option.as_deref_mut(), None);
+}
+
+#[test]
+fn test_replace() {
+ let mut x = Some(2);
+ let old = x.replace(5);
+
+ assert_eq!(x, Some(5));
+ assert_eq!(old, Some(2));
+
+ let mut x = None;
+ let old = x.replace(3);
+
+ assert_eq!(x, Some(3));
+ assert_eq!(old, None);
+}
+
+#[test]
+fn option_const() {
+ // test that the methods of `Option` are usable in a const context
+
+ const OPTION: Option<usize> = Some(32);
+ assert_eq!(OPTION, Some(32));
+
+ const OPTION_FROM: Option<usize> = Option::from(32);
+ assert_eq!(OPTION_FROM, Some(32));
+
+ const REF: Option<&usize> = OPTION.as_ref();
+ assert_eq!(REF, Some(&32));
+
+ const REF_FROM: Option<&usize> = Option::from(&OPTION);
+ assert_eq!(REF_FROM, Some(&32));
+
+ const IS_SOME: bool = OPTION.is_some();
+ assert!(IS_SOME);
+
+ const IS_NONE: bool = OPTION.is_none();
+ assert!(!IS_NONE);
+
+ const COPIED: Option<usize> = OPTION.as_ref().copied();
+ assert_eq!(COPIED, OPTION);
+}
+
+#[test]
+const fn option_const_mut() {
+ // test that the methods of `Option` that take mutable references are usable in a const context
+
+ let mut option: Option<usize> = Some(32);
+
+ let _take = option.take();
+ let _replace = option.replace(42);
+
+ {
+ let as_mut = option.as_mut();
+ match as_mut {
+ Some(v) => *v = 32,
+ None => unreachable!(),
+ }
+ }
+
+ {
+ let as_mut: Option<&mut usize> = Option::from(&mut option);
+ match as_mut {
+ Some(v) => *v = 42,
+ None => unreachable!(),
+ }
+ }
+}
+
+#[test]
+fn test_unwrap_drop() {
+ struct Dtor<'a> {
+ x: &'a Cell<isize>,
+ }
+
+ impl<'a> std::ops::Drop for Dtor<'a> {
+ fn drop(&mut self) {
+ self.x.set(self.x.get() - 1);
+ }
+ }
+
+ fn unwrap<T>(o: Option<T>) -> T {
+ match o {
+ Some(v) => v,
+ None => panic!(),
+ }
+ }
+
+ let x = &Cell::new(1);
+
+ {
+ let b = Some(Dtor { x });
+ let _c = unwrap(b);
+ }
+
+ assert_eq!(x.get(), 0);
+}
+
+#[test]
+fn option_ext() {
+ let thing = "{{ f }}";
+ let f = thing.find("{{");
+
+ if f.is_none() {
+ println!("None!");
+ }
+}
+
+#[test]
+fn zip_options() {
+ let x = Some(10);
+ let y = Some("foo");
+ let z: Option<usize> = None;
+
+ assert_eq!(x.zip(y), Some((10, "foo")));
+ assert_eq!(x.zip(z), None);
+ assert_eq!(z.zip(x), None);
+}
+
+#[test]
+fn unzip_options() {
+ let x = Some((10, "foo"));
+ let y = None::<(bool, i32)>;
+
+ assert_eq!(x.unzip(), (Some(10), Some("foo")));
+ assert_eq!(y.unzip(), (None, None));
+}
+
+#[test]
+fn zip_unzip_roundtrip() {
+ let x = Some(10);
+ let y = Some("foo");
+
+ let z = x.zip(y);
+ assert_eq!(z, Some((10, "foo")));
+
+ let a = z.unzip();
+ assert_eq!(a, (x, y));
+}
diff --git a/library/core/tests/pattern.rs b/library/core/tests/pattern.rs
new file mode 100644
index 000000000..d4bec996d
--- /dev/null
+++ b/library/core/tests/pattern.rs
@@ -0,0 +1,503 @@
+use std::str::pattern::*;
+
+// This macro makes it easier to write
+// tests that do a series of iterations
+macro_rules! search_asserts {
+ ($haystack:expr, $needle:expr, $testname:expr, [$($func:ident),*], $result:expr) => {
+ let mut searcher = $needle.into_searcher($haystack);
+ let arr = [$( Step::from(searcher.$func()) ),*];
+ assert_eq!(&arr[..], &$result, $testname);
+ }
+}
+
+/// Combined enum for the results of next() and next_match()/next_reject()
+#[derive(Debug, PartialEq, Eq)]
+enum Step {
+ // variant names purposely chosen to
+ // be the same length for easy alignment
+ Matches(usize, usize),
+ Rejects(usize, usize),
+ InRange(usize, usize),
+ Done,
+}
+
+use self::Step::*;
+
+impl From<SearchStep> for Step {
+ fn from(x: SearchStep) -> Self {
+ match x {
+ SearchStep::Match(a, b) => Matches(a, b),
+ SearchStep::Reject(a, b) => Rejects(a, b),
+ SearchStep::Done => Done,
+ }
+ }
+}
+
+impl From<Option<(usize, usize)>> for Step {
+ fn from(x: Option<(usize, usize)>) -> Self {
+ match x {
+ Some((a, b)) => InRange(a, b),
+ None => Done,
+ }
+ }
+}
+
+// FIXME(Manishearth) these tests focus on single-character searching (CharSearcher)
+// and on next()/next_match(), not next_reject(). This is because
+// the memchr changes make next_match() for single chars complex, but next_reject()
+// continues to use next() under the hood. We should add more test cases for all
+// of these, as well as tests for StrSearcher and higher level tests for str::find() (etc)
+
+#[test]
+fn test_simple_iteration() {
+ search_asserts!(
+ "abcdeabcd",
+ 'a',
+ "forward iteration for ASCII string",
+ // a b c d e a b c d EOF
+ [next, next, next, next, next, next, next, next, next, next],
+ [
+ Matches(0, 1),
+ Rejects(1, 2),
+ Rejects(2, 3),
+ Rejects(3, 4),
+ Rejects(4, 5),
+ Matches(5, 6),
+ Rejects(6, 7),
+ Rejects(7, 8),
+ Rejects(8, 9),
+ Done
+ ]
+ );
+
+ search_asserts!(
+ "abcdeabcd",
+ 'a',
+ "reverse iteration for ASCII string",
+ // d c b a e d c b a EOF
+ [
+ next_back, next_back, next_back, next_back, next_back, next_back, next_back, next_back,
+ next_back, next_back
+ ],
+ [
+ Rejects(8, 9),
+ Rejects(7, 8),
+ Rejects(6, 7),
+ Matches(5, 6),
+ Rejects(4, 5),
+ Rejects(3, 4),
+ Rejects(2, 3),
+ Rejects(1, 2),
+ Matches(0, 1),
+ Done
+ ]
+ );
+
+ search_asserts!(
+ "我爱我的猫",
+ '我',
+ "forward iteration for Chinese string",
+ // 我 愛 我 的 貓 EOF
+ [next, next, next, next, next, next],
+ [Matches(0, 3), Rejects(3, 6), Matches(6, 9), Rejects(9, 12), Rejects(12, 15), Done]
+ );
+
+ search_asserts!(
+ "我的猫说meow",
+ 'm',
+ "forward iteration for mixed string",
+ // 我 的 猫 说 m e o w EOF
+ [next, next, next, next, next, next, next, next, next],
+ [
+ Rejects(0, 3),
+ Rejects(3, 6),
+ Rejects(6, 9),
+ Rejects(9, 12),
+ Matches(12, 13),
+ Rejects(13, 14),
+ Rejects(14, 15),
+ Rejects(15, 16),
+ Done
+ ]
+ );
+
+ search_asserts!(
+ "我的猫说meow",
+ '猫',
+ "reverse iteration for mixed string",
+ // w o e m 说 猫 的 我 EOF
+ [
+ next_back, next_back, next_back, next_back, next_back, next_back, next_back, next_back,
+ next_back
+ ],
+ [
+ Rejects(15, 16),
+ Rejects(14, 15),
+ Rejects(13, 14),
+ Rejects(12, 13),
+ Rejects(9, 12),
+ Matches(6, 9),
+ Rejects(3, 6),
+ Rejects(0, 3),
+ Done
+ ]
+ );
+}
+
+#[test]
+fn test_simple_search() {
+ search_asserts!(
+ "abcdeabcdeabcde",
+ 'a',
+ "next_match for ASCII string",
+ [next_match, next_match, next_match, next_match],
+ [InRange(0, 1), InRange(5, 6), InRange(10, 11), Done]
+ );
+
+ search_asserts!(
+ "abcdeabcdeabcde",
+ 'a',
+ "next_match_back for ASCII string",
+ [next_match_back, next_match_back, next_match_back, next_match_back],
+ [InRange(10, 11), InRange(5, 6), InRange(0, 1), Done]
+ );
+
+ search_asserts!(
+ "abcdeab",
+ 'a',
+ "next_reject for ASCII string",
+ [next_reject, next_reject, next_match, next_reject, next_reject],
+ [InRange(1, 2), InRange(2, 3), InRange(5, 6), InRange(6, 7), Done]
+ );
+
+ search_asserts!(
+ "abcdeabcdeabcde",
+ 'a',
+ "next_reject_back for ASCII string",
+ [
+ next_reject_back,
+ next_reject_back,
+ next_match_back,
+ next_reject_back,
+ next_reject_back,
+ next_reject_back
+ ],
+ [
+ InRange(14, 15),
+ InRange(13, 14),
+ InRange(10, 11),
+ InRange(9, 10),
+ InRange(8, 9),
+ InRange(7, 8)
+ ]
+ );
+}
+
+// Á, 각, ก, 😀 all end in 0x81
+// 🁀, ᘀ do not end in 0x81 but contain the byte
+// ꁁ has 0x81 as its second and third bytes.
+//
+// The memchr-using implementation of next_match
+// and next_match_back temporarily violate
+// the property that the search is always on a unicode boundary,
+// which is fine as long as this never reaches next() or next_back().
+// So we test if next() is correct after each next_match() as well.
+const STRESS: &str = "Áa🁀bÁꁁfg😁각กᘀ각aÁ각ꁁก😁a";
+
+#[test]
+fn test_stress_indices() {
+ // this isn't really a test, more of documentation on the indices of each character in the stresstest string
+
+ search_asserts!(
+ STRESS,
+ 'x',
+ "Indices of characters in stress test",
+ [
+ next, next, next, next, next, next, next, next, next, next, next, next, next, next,
+ next, next, next, next, next, next, next
+ ],
+ [
+ Rejects(0, 2), // Á
+ Rejects(2, 3), // a
+ Rejects(3, 7), // 🁀
+ Rejects(7, 8), // b
+ Rejects(8, 10), // Á
+ Rejects(10, 13), // ꁁ
+ Rejects(13, 14), // f
+ Rejects(14, 15), // g
+ Rejects(15, 19), // 😀
+ Rejects(19, 22), // 각
+ Rejects(22, 25), // ก
+ Rejects(25, 28), // ᘀ
+ Rejects(28, 31), // 각
+ Rejects(31, 32), // a
+ Rejects(32, 34), // Á
+ Rejects(34, 37), // 각
+ Rejects(37, 40), // ꁁ
+ Rejects(40, 43), // ก
+ Rejects(43, 47), // 😀
+ Rejects(47, 48), // a
+ Done
+ ]
+ );
+}
+
+#[test]
+fn test_forward_search_shared_bytes() {
+ search_asserts!(
+ STRESS,
+ 'Á',
+ "Forward search for two-byte Latin character",
+ [next_match, next_match, next_match, next_match],
+ [InRange(0, 2), InRange(8, 10), InRange(32, 34), Done]
+ );
+
+ search_asserts!(
+ STRESS,
+ 'Á',
+ "Forward search for two-byte Latin character; check if next() still works",
+ [next_match, next, next_match, next, next_match, next, next_match],
+ [
+ InRange(0, 2),
+ Rejects(2, 3),
+ InRange(8, 10),
+ Rejects(10, 13),
+ InRange(32, 34),
+ Rejects(34, 37),
+ Done
+ ]
+ );
+
+ search_asserts!(
+ STRESS,
+ '각',
+ "Forward search for three-byte Hangul character",
+ [next_match, next, next_match, next_match, next_match],
+ [InRange(19, 22), Rejects(22, 25), InRange(28, 31), InRange(34, 37), Done]
+ );
+
+ search_asserts!(
+ STRESS,
+ '각',
+ "Forward search for three-byte Hangul character; check if next() still works",
+ [next_match, next, next_match, next, next_match, next, next_match],
+ [
+ InRange(19, 22),
+ Rejects(22, 25),
+ InRange(28, 31),
+ Rejects(31, 32),
+ InRange(34, 37),
+ Rejects(37, 40),
+ Done
+ ]
+ );
+
+ search_asserts!(
+ STRESS,
+ 'ก',
+ "Forward search for three-byte Thai character",
+ [next_match, next, next_match, next, next_match],
+ [InRange(22, 25), Rejects(25, 28), InRange(40, 43), Rejects(43, 47), Done]
+ );
+
+ search_asserts!(
+ STRESS,
+ 'ก',
+ "Forward search for three-byte Thai character; check if next() still works",
+ [next_match, next, next_match, next, next_match],
+ [InRange(22, 25), Rejects(25, 28), InRange(40, 43), Rejects(43, 47), Done]
+ );
+
+ search_asserts!(
+ STRESS,
+ '😁',
+ "Forward search for four-byte emoji",
+ [next_match, next, next_match, next, next_match],
+ [InRange(15, 19), Rejects(19, 22), InRange(43, 47), Rejects(47, 48), Done]
+ );
+
+ search_asserts!(
+ STRESS,
+ '😁',
+ "Forward search for four-byte emoji; check if next() still works",
+ [next_match, next, next_match, next, next_match],
+ [InRange(15, 19), Rejects(19, 22), InRange(43, 47), Rejects(47, 48), Done]
+ );
+
+ search_asserts!(
+ STRESS,
+ 'ꁁ',
+ "Forward search for three-byte Yi character with repeated bytes",
+ [next_match, next, next_match, next, next_match],
+ [InRange(10, 13), Rejects(13, 14), InRange(37, 40), Rejects(40, 43), Done]
+ );
+
+ search_asserts!(
+ STRESS,
+ 'ꁁ',
+ "Forward search for three-byte Yi character with repeated bytes; check if next() still works",
+ [next_match, next, next_match, next, next_match],
+ [InRange(10, 13), Rejects(13, 14), InRange(37, 40), Rejects(40, 43), Done]
+ );
+}
+
+#[test]
+fn test_reverse_search_shared_bytes() {
+ search_asserts!(
+ STRESS,
+ 'Á',
+ "Reverse search for two-byte Latin character",
+ [next_match_back, next_match_back, next_match_back, next_match_back],
+ [InRange(32, 34), InRange(8, 10), InRange(0, 2), Done]
+ );
+
+ search_asserts!(
+ STRESS,
+ 'Á',
+ "Reverse search for two-byte Latin character; check if next_back() still works",
+ [next_match_back, next_back, next_match_back, next_back, next_match_back, next_back],
+ [InRange(32, 34), Rejects(31, 32), InRange(8, 10), Rejects(7, 8), InRange(0, 2), Done]
+ );
+
+ search_asserts!(
+ STRESS,
+ '각',
+ "Reverse search for three-byte Hangul character",
+ [next_match_back, next_back, next_match_back, next_match_back, next_match_back],
+ [InRange(34, 37), Rejects(32, 34), InRange(28, 31), InRange(19, 22), Done]
+ );
+
+ search_asserts!(
+ STRESS,
+ '각',
+ "Reverse search for three-byte Hangul character; check if next_back() still works",
+ [
+ next_match_back,
+ next_back,
+ next_match_back,
+ next_back,
+ next_match_back,
+ next_back,
+ next_match_back
+ ],
+ [
+ InRange(34, 37),
+ Rejects(32, 34),
+ InRange(28, 31),
+ Rejects(25, 28),
+ InRange(19, 22),
+ Rejects(15, 19),
+ Done
+ ]
+ );
+
+ search_asserts!(
+ STRESS,
+ 'ก',
+ "Reverse search for three-byte Thai character",
+ [next_match_back, next_back, next_match_back, next_back, next_match_back],
+ [InRange(40, 43), Rejects(37, 40), InRange(22, 25), Rejects(19, 22), Done]
+ );
+
+ search_asserts!(
+ STRESS,
+ 'ก',
+ "Reverse search for three-byte Thai character; check if next_back() still works",
+ [next_match_back, next_back, next_match_back, next_back, next_match_back],
+ [InRange(40, 43), Rejects(37, 40), InRange(22, 25), Rejects(19, 22), Done]
+ );
+
+ search_asserts!(
+ STRESS,
+ '😁',
+ "Reverse search for four-byte emoji",
+ [next_match_back, next_back, next_match_back, next_back, next_match_back],
+ [InRange(43, 47), Rejects(40, 43), InRange(15, 19), Rejects(14, 15), Done]
+ );
+
+ search_asserts!(
+ STRESS,
+ '😁',
+ "Reverse search for four-byte emoji; check if next_back() still works",
+ [next_match_back, next_back, next_match_back, next_back, next_match_back],
+ [InRange(43, 47), Rejects(40, 43), InRange(15, 19), Rejects(14, 15), Done]
+ );
+
+ search_asserts!(
+ STRESS,
+ 'ꁁ',
+ "Reverse search for three-byte Yi character with repeated bytes",
+ [next_match_back, next_back, next_match_back, next_back, next_match_back],
+ [InRange(37, 40), Rejects(34, 37), InRange(10, 13), Rejects(8, 10), Done]
+ );
+
+ search_asserts!(
+ STRESS,
+ 'ꁁ',
+ "Reverse search for three-byte Yi character with repeated bytes; check if next_back() still works",
+ [next_match_back, next_back, next_match_back, next_back, next_match_back],
+ [InRange(37, 40), Rejects(34, 37), InRange(10, 13), Rejects(8, 10), Done]
+ );
+}
+
+#[test]
+fn double_ended_regression_test() {
+ // https://github.com/rust-lang/rust/issues/47175
+ // Ensures that double ended searching comes to a convergence
+ search_asserts!(
+ "abcdeabcdeabcde",
+ 'a',
+ "alternating double ended search",
+ [next_match, next_match_back, next_match, next_match_back],
+ [InRange(0, 1), InRange(10, 11), InRange(5, 6), Done]
+ );
+ search_asserts!(
+ "abcdeabcdeabcde",
+ 'a',
+ "triple double ended search for a",
+ [next_match, next_match_back, next_match_back, next_match_back],
+ [InRange(0, 1), InRange(10, 11), InRange(5, 6), Done]
+ );
+ search_asserts!(
+ "abcdeabcdeabcde",
+ 'd',
+ "triple double ended search for d",
+ [next_match, next_match_back, next_match_back, next_match_back],
+ [InRange(3, 4), InRange(13, 14), InRange(8, 9), Done]
+ );
+ search_asserts!(
+ STRESS,
+ 'Á',
+ "Double ended search for two-byte Latin character",
+ [next_match, next_match_back, next_match, next_match_back],
+ [InRange(0, 2), InRange(32, 34), InRange(8, 10), Done]
+ );
+ search_asserts!(
+ STRESS,
+ '각',
+ "Reverse double ended search for three-byte Hangul character",
+ [next_match_back, next_back, next_match, next, next_match_back, next_match],
+ [InRange(34, 37), Rejects(32, 34), InRange(19, 22), Rejects(22, 25), InRange(28, 31), Done]
+ );
+ search_asserts!(
+ STRESS,
+ 'ก',
+ "Double ended search for three-byte Thai character",
+ [next_match, next_back, next, next_match_back, next_match],
+ [InRange(22, 25), Rejects(47, 48), Rejects(25, 28), InRange(40, 43), Done]
+ );
+ search_asserts!(
+ STRESS,
+ '😁',
+ "Double ended search for four-byte emoji",
+ [next_match_back, next, next_match, next_back, next_match],
+ [InRange(43, 47), Rejects(0, 2), InRange(15, 19), Rejects(40, 43), Done]
+ );
+ search_asserts!(
+ STRESS,
+ 'ꁁ',
+ "Double ended search for three-byte Yi character with repeated bytes",
+ [next_match, next, next_match_back, next_back, next_match],
+ [InRange(10, 13), Rejects(13, 14), InRange(37, 40), Rejects(34, 37), Done]
+ );
+}
diff --git a/library/core/tests/pin.rs b/library/core/tests/pin.rs
new file mode 100644
index 000000000..6f617c8d0
--- /dev/null
+++ b/library/core/tests/pin.rs
@@ -0,0 +1,31 @@
+use core::pin::Pin;
+
+#[test]
+fn pin_const() {
+ // test that the methods of `Pin` are usable in a const context
+
+ const POINTER: &'static usize = &2;
+
+ const PINNED: Pin<&'static usize> = Pin::new(POINTER);
+ const PINNED_UNCHECKED: Pin<&'static usize> = unsafe { Pin::new_unchecked(POINTER) };
+ assert_eq!(PINNED_UNCHECKED, PINNED);
+
+ const INNER: &'static usize = Pin::into_inner(PINNED);
+ assert_eq!(INNER, POINTER);
+
+ const INNER_UNCHECKED: &'static usize = unsafe { Pin::into_inner_unchecked(PINNED) };
+ assert_eq!(INNER_UNCHECKED, POINTER);
+
+ const REF: &'static usize = PINNED.get_ref();
+ assert_eq!(REF, POINTER);
+
+ // Note: `pin_mut_const` tests that the methods of `Pin<&mut T>` are usable in a const context.
+ // A const fn is used because `&mut` is not (yet) usable in constants.
+ const fn pin_mut_const() {
+ let _ = Pin::new(&mut 2).into_ref();
+ let _ = Pin::new(&mut 2).get_mut();
+ let _ = unsafe { Pin::new(&mut 2).get_unchecked_mut() };
+ }
+
+ pin_mut_const();
+}
diff --git a/library/core/tests/pin_macro.rs b/library/core/tests/pin_macro.rs
new file mode 100644
index 000000000..79c8c166c
--- /dev/null
+++ b/library/core/tests/pin_macro.rs
@@ -0,0 +1,33 @@
+// edition:2021
+use core::{
+ marker::PhantomPinned,
+ mem::{drop as stuff, transmute},
+ pin::{pin, Pin},
+};
+
+#[test]
+fn basic() {
+ let it: Pin<&mut PhantomPinned> = pin!(PhantomPinned);
+ stuff(it);
+}
+
+#[test]
+fn extension_works_through_block() {
+ let it: Pin<&mut PhantomPinned> = { pin!(PhantomPinned) };
+ stuff(it);
+}
+
+#[test]
+fn extension_works_through_unsafe_block() {
+ // "retro-type-inference" works as well.
+ let it: Pin<&mut PhantomPinned> = unsafe { pin!(transmute(())) };
+ stuff(it);
+}
+
+#[test]
+fn unsize_coercion() {
+ let slice: Pin<&mut [PhantomPinned]> = pin!([PhantomPinned; 2]);
+ stuff(slice);
+ let dyn_obj: Pin<&mut dyn Send> = pin!([PhantomPinned; 2]);
+ stuff(dyn_obj);
+}
diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs
new file mode 100644
index 000000000..12861794c
--- /dev/null
+++ b/library/core/tests/ptr.rs
@@ -0,0 +1,855 @@
+use core::cell::RefCell;
+use core::mem::{self, MaybeUninit};
+use core::num::NonZeroUsize;
+use core::ptr;
+use core::ptr::*;
+use std::fmt::{Debug, Display};
+
+#[test]
+fn test_const_from_raw_parts() {
+ const SLICE: &[u8] = &[1, 2, 3, 4];
+ const FROM_RAW: &[u8] = unsafe { &*slice_from_raw_parts(SLICE.as_ptr(), SLICE.len()) };
+ assert_eq!(SLICE, FROM_RAW);
+
+ let slice = &[1, 2, 3, 4, 5];
+ let from_raw = unsafe { &*slice_from_raw_parts(slice.as_ptr(), 2) };
+ assert_eq!(&slice[..2], from_raw);
+}
+
+#[test]
+fn test() {
+ unsafe {
+ #[repr(C)]
+ struct Pair {
+ fst: isize,
+ snd: isize,
+ }
+ let mut p = Pair { fst: 10, snd: 20 };
+ let pptr: *mut Pair = &mut p;
+ let iptr: *mut isize = pptr as *mut isize;
+ assert_eq!(*iptr, 10);
+ *iptr = 30;
+ assert_eq!(*iptr, 30);
+ assert_eq!(p.fst, 30);
+
+ *pptr = Pair { fst: 50, snd: 60 };
+ assert_eq!(*iptr, 50);
+ assert_eq!(p.fst, 50);
+ assert_eq!(p.snd, 60);
+
+ let v0 = vec![32000u16, 32001u16, 32002u16];
+ let mut v1 = vec![0u16, 0u16, 0u16];
+
+ copy(v0.as_ptr().offset(1), v1.as_mut_ptr().offset(1), 1);
+ assert!((v1[0] == 0u16 && v1[1] == 32001u16 && v1[2] == 0u16));
+ copy(v0.as_ptr().offset(2), v1.as_mut_ptr(), 1);
+ assert!((v1[0] == 32002u16 && v1[1] == 32001u16 && v1[2] == 0u16));
+ copy(v0.as_ptr(), v1.as_mut_ptr().offset(2), 1);
+ assert!((v1[0] == 32002u16 && v1[1] == 32001u16 && v1[2] == 32000u16));
+ }
+}
+
+#[test]
+fn test_is_null() {
+ let p: *const isize = null();
+ assert!(p.is_null());
+
+ let q = p.wrapping_offset(1);
+ assert!(!q.is_null());
+
+ let mp: *mut isize = null_mut();
+ assert!(mp.is_null());
+
+ let mq = mp.wrapping_offset(1);
+ assert!(!mq.is_null());
+
+ // Pointers to unsized types -- slices
+ let s: &mut [u8] = &mut [1, 2, 3];
+ let cs: *const [u8] = s;
+ assert!(!cs.is_null());
+
+ let ms: *mut [u8] = s;
+ assert!(!ms.is_null());
+
+ let cz: *const [u8] = &[];
+ assert!(!cz.is_null());
+
+ let mz: *mut [u8] = &mut [];
+ assert!(!mz.is_null());
+
+ let ncs: *const [u8] = null::<[u8; 3]>();
+ assert!(ncs.is_null());
+
+ let nms: *mut [u8] = null_mut::<[u8; 3]>();
+ assert!(nms.is_null());
+
+ // Pointers to unsized types -- trait objects
+ let ci: *const dyn ToString = &3;
+ assert!(!ci.is_null());
+
+ let mi: *mut dyn ToString = &mut 3;
+ assert!(!mi.is_null());
+
+ let nci: *const dyn ToString = null::<isize>();
+ assert!(nci.is_null());
+
+ let nmi: *mut dyn ToString = null_mut::<isize>();
+ assert!(nmi.is_null());
+
+ extern "C" {
+ type Extern;
+ }
+ let ec: *const Extern = null::<Extern>();
+ assert!(ec.is_null());
+
+ let em: *mut Extern = null_mut::<Extern>();
+ assert!(em.is_null());
+}
+
+#[test]
+fn test_as_ref() {
+ unsafe {
+ let p: *const isize = null();
+ assert_eq!(p.as_ref(), None);
+
+ let q: *const isize = &2;
+ assert_eq!(q.as_ref().unwrap(), &2);
+
+ let p: *mut isize = null_mut();
+ assert_eq!(p.as_ref(), None);
+
+ let q: *mut isize = &mut 2;
+ assert_eq!(q.as_ref().unwrap(), &2);
+
+ // Lifetime inference
+ let u = 2isize;
+ {
+ let p = &u as *const isize;
+ assert_eq!(p.as_ref().unwrap(), &2);
+ }
+
+ // Pointers to unsized types -- slices
+ let s: &mut [u8] = &mut [1, 2, 3];
+ let cs: *const [u8] = s;
+ assert_eq!(cs.as_ref(), Some(&*s));
+
+ let ms: *mut [u8] = s;
+ assert_eq!(ms.as_ref(), Some(&*s));
+
+ let cz: *const [u8] = &[];
+ assert_eq!(cz.as_ref(), Some(&[][..]));
+
+ let mz: *mut [u8] = &mut [];
+ assert_eq!(mz.as_ref(), Some(&[][..]));
+
+ let ncs: *const [u8] = null::<[u8; 3]>();
+ assert_eq!(ncs.as_ref(), None);
+
+ let nms: *mut [u8] = null_mut::<[u8; 3]>();
+ assert_eq!(nms.as_ref(), None);
+
+ // Pointers to unsized types -- trait objects
+ let ci: *const dyn ToString = &3;
+ assert!(ci.as_ref().is_some());
+
+ let mi: *mut dyn ToString = &mut 3;
+ assert!(mi.as_ref().is_some());
+
+ let nci: *const dyn ToString = null::<isize>();
+ assert!(nci.as_ref().is_none());
+
+ let nmi: *mut dyn ToString = null_mut::<isize>();
+ assert!(nmi.as_ref().is_none());
+ }
+}
+
+#[test]
+fn test_as_mut() {
+ unsafe {
+ let p: *mut isize = null_mut();
+ assert!(p.as_mut() == None);
+
+ let q: *mut isize = &mut 2;
+ assert!(q.as_mut().unwrap() == &mut 2);
+
+ // Lifetime inference
+ let mut u = 2isize;
+ {
+ let p = &mut u as *mut isize;
+ assert!(p.as_mut().unwrap() == &mut 2);
+ }
+
+ // Pointers to unsized types -- slices
+ let s: &mut [u8] = &mut [1, 2, 3];
+ let ms: *mut [u8] = s;
+ assert_eq!(ms.as_mut(), Some(&mut [1, 2, 3][..]));
+
+ let mz: *mut [u8] = &mut [];
+ assert_eq!(mz.as_mut(), Some(&mut [][..]));
+
+ let nms: *mut [u8] = null_mut::<[u8; 3]>();
+ assert_eq!(nms.as_mut(), None);
+
+ // Pointers to unsized types -- trait objects
+ let mi: *mut dyn ToString = &mut 3;
+ assert!(mi.as_mut().is_some());
+
+ let nmi: *mut dyn ToString = null_mut::<isize>();
+ assert!(nmi.as_mut().is_none());
+ }
+}
+
+#[test]
+fn test_ptr_addition() {
+ unsafe {
+ let xs = vec![5; 16];
+ let mut ptr = xs.as_ptr();
+ let end = ptr.offset(16);
+
+ while ptr < end {
+ assert_eq!(*ptr, 5);
+ ptr = ptr.offset(1);
+ }
+
+ let mut xs_mut = xs;
+ let mut m_ptr = xs_mut.as_mut_ptr();
+ let m_end = m_ptr.offset(16);
+
+ while m_ptr < m_end {
+ *m_ptr += 5;
+ m_ptr = m_ptr.offset(1);
+ }
+
+ assert!(xs_mut == vec![10; 16]);
+ }
+}
+
+#[test]
+fn test_ptr_subtraction() {
+ unsafe {
+ let xs = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
+ let mut idx = 9;
+ let ptr = xs.as_ptr();
+
+ while idx >= 0 {
+ assert_eq!(*(ptr.offset(idx as isize)), idx as isize);
+ idx = idx - 1;
+ }
+
+ let mut xs_mut = xs;
+ let m_start = xs_mut.as_mut_ptr();
+ let mut m_ptr = m_start.offset(9);
+
+ loop {
+ *m_ptr += *m_ptr;
+ if m_ptr == m_start {
+ break;
+ }
+ m_ptr = m_ptr.offset(-1);
+ }
+
+ assert_eq!(xs_mut, [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]);
+ }
+}
+
+#[test]
+fn test_set_memory() {
+ let mut xs = [0u8; 20];
+ let ptr = xs.as_mut_ptr();
+ unsafe {
+ write_bytes(ptr, 5u8, xs.len());
+ }
+ assert!(xs == [5u8; 20]);
+}
+
+#[test]
+fn test_set_memory_const() {
+ const XS: [u8; 20] = {
+ let mut xs = [0u8; 20];
+ let ptr = xs.as_mut_ptr();
+ unsafe {
+ ptr.write_bytes(5u8, xs.len());
+ }
+ xs
+ };
+
+ assert!(XS == [5u8; 20]);
+}
+
+#[test]
+fn test_unsized_nonnull() {
+ let xs: &[i32] = &[1, 2, 3];
+ let ptr = unsafe { NonNull::new_unchecked(xs as *const [i32] as *mut [i32]) };
+ let ys = unsafe { ptr.as_ref() };
+ let zs: &[i32] = &[1, 2, 3];
+ assert!(ys == zs);
+}
+
+#[test]
+fn test_const_nonnull_new() {
+ const {
+ assert!(NonNull::new(core::ptr::null_mut::<()>()).is_none());
+
+ let value = &mut 0u32;
+ let mut ptr = NonNull::new(value).unwrap();
+ unsafe { *ptr.as_mut() = 42 };
+
+ let reference = unsafe { &*ptr.as_ref() };
+ assert!(*reference == *value);
+ assert!(*reference == 42);
+ };
+}
+
+#[test]
+#[cfg(unix)] // printf may not be available on other platforms
+#[allow(deprecated)] // For SipHasher
+pub fn test_variadic_fnptr() {
+ use core::ffi;
+ use core::hash::{Hash, SipHasher};
+ extern "C" {
+ // This needs to use the correct function signature even though it isn't called as some
+ // codegen backends make it UB to declare a function with multiple conflicting signatures
+ // (like LLVM) while others straight up return an error (like Cranelift).
+ fn printf(_: *const ffi::c_char, ...) -> ffi::c_int;
+ }
+ let p: unsafe extern "C" fn(*const ffi::c_char, ...) -> ffi::c_int = printf;
+ let q = p.clone();
+ assert_eq!(p, q);
+ assert!(!(p < q));
+ let mut s = SipHasher::new();
+ assert_eq!(p.hash(&mut s), q.hash(&mut s));
+}
+
+#[test]
+fn write_unaligned_drop() {
+ thread_local! {
+ static DROPS: RefCell<Vec<u32>> = RefCell::new(Vec::new());
+ }
+
+ struct Dropper(u32);
+
+ impl Drop for Dropper {
+ fn drop(&mut self) {
+ DROPS.with(|d| d.borrow_mut().push(self.0));
+ }
+ }
+
+ {
+ let c = Dropper(0);
+ let mut t = Dropper(1);
+ unsafe {
+ write_unaligned(&mut t, c);
+ }
+ }
+ DROPS.with(|d| assert_eq!(*d.borrow(), [0]));
+}
+
+#[test]
+fn align_offset_zst() {
+ // For pointers of stride = 0, the pointer is already aligned or it cannot be aligned at
+ // all, because no amount of elements will align the pointer.
+ let mut p = 1;
+ while p < 1024 {
+ assert_eq!(ptr::invalid::<()>(p).align_offset(p), 0);
+ if p != 1 {
+ assert_eq!(ptr::invalid::<()>(p + 1).align_offset(p), !0);
+ }
+ p = (p + 1).next_power_of_two();
+ }
+}
+
+#[test]
+fn align_offset_stride_one() {
+ // For pointers of stride = 1, the pointer can always be aligned. The offset is equal to
+ // number of bytes.
+ let mut align = 1;
+ while align < 1024 {
+ for ptr in 1..2 * align {
+ let expected = ptr % align;
+ let offset = if expected == 0 { 0 } else { align - expected };
+ assert_eq!(
+ ptr::invalid::<u8>(ptr).align_offset(align),
+ offset,
+ "ptr = {}, align = {}, size = 1",
+ ptr,
+ align
+ );
+ }
+ align = (align + 1).next_power_of_two();
+ }
+}
+
+#[test]
+fn align_offset_various_strides() {
+ unsafe fn test_stride<T>(ptr: *const T, align: usize) -> bool {
+ let numptr = ptr as usize;
+ let mut expected = usize::MAX;
+ // Naive but definitely correct way to find the *first* aligned element of stride::<T>.
+ for el in 0..align {
+ if (numptr + el * ::std::mem::size_of::<T>()) % align == 0 {
+ expected = el;
+ break;
+ }
+ }
+ let got = ptr.align_offset(align);
+ if got != expected {
+ eprintln!(
+ "aligning {:p} (with stride of {}) to {}, expected {}, got {}",
+ ptr,
+ ::std::mem::size_of::<T>(),
+ align,
+ expected,
+ got
+ );
+ return true;
+ }
+ return false;
+ }
+
+ // For pointers of stride != 1, we verify the algorithm against the naivest possible
+ // implementation
+ let mut align = 1;
+ let mut x = false;
+ // Miri is too slow
+ let limit = if cfg!(miri) { 32 } else { 1024 };
+ while align < limit {
+ for ptr in 1usize..4 * align {
+ unsafe {
+ #[repr(packed)]
+ struct A3(u16, u8);
+ x |= test_stride::<A3>(ptr::invalid::<A3>(ptr), align);
+
+ struct A4(u32);
+ x |= test_stride::<A4>(ptr::invalid::<A4>(ptr), align);
+
+ #[repr(packed)]
+ struct A5(u32, u8);
+ x |= test_stride::<A5>(ptr::invalid::<A5>(ptr), align);
+
+ #[repr(packed)]
+ struct A6(u32, u16);
+ x |= test_stride::<A6>(ptr::invalid::<A6>(ptr), align);
+
+ #[repr(packed)]
+ struct A7(u32, u16, u8);
+ x |= test_stride::<A7>(ptr::invalid::<A7>(ptr), align);
+
+ #[repr(packed)]
+ struct A8(u32, u32);
+ x |= test_stride::<A8>(ptr::invalid::<A8>(ptr), align);
+
+ #[repr(packed)]
+ struct A9(u32, u32, u8);
+ x |= test_stride::<A9>(ptr::invalid::<A9>(ptr), align);
+
+ #[repr(packed)]
+ struct A10(u32, u32, u16);
+ x |= test_stride::<A10>(ptr::invalid::<A10>(ptr), align);
+
+ x |= test_stride::<u32>(ptr::invalid::<u32>(ptr), align);
+ x |= test_stride::<u128>(ptr::invalid::<u128>(ptr), align);
+ }
+ }
+ align = (align + 1).next_power_of_two();
+ }
+ assert!(!x);
+}
+
+#[test]
+fn offset_from() {
+ let mut a = [0; 5];
+ let ptr1: *mut i32 = &mut a[1];
+ let ptr2: *mut i32 = &mut a[3];
+ unsafe {
+ assert_eq!(ptr2.offset_from(ptr1), 2);
+ assert_eq!(ptr1.offset_from(ptr2), -2);
+ assert_eq!(ptr1.offset(2), ptr2);
+ assert_eq!(ptr2.offset(-2), ptr1);
+ }
+}
+
+#[test]
+fn ptr_metadata() {
+ struct Unit;
+ struct Pair<A, B: ?Sized>(A, B);
+ extern "C" {
+ type Extern;
+ }
+ let () = metadata(&());
+ let () = metadata(&Unit);
+ let () = metadata(&4_u32);
+ let () = metadata(&String::new());
+ let () = metadata(&Some(4_u32));
+ let () = metadata(&ptr_metadata);
+ let () = metadata(&|| {});
+ let () = metadata(&[4, 7]);
+ let () = metadata(&(4, String::new()));
+ let () = metadata(&Pair(4, String::new()));
+ let () = metadata(ptr::null::<()>() as *const Extern);
+ let () = metadata(ptr::null::<()>() as *const <&u32 as std::ops::Deref>::Target);
+
+ assert_eq!(metadata("foo"), 3_usize);
+ assert_eq!(metadata(&[4, 7][..]), 2_usize);
+
+ let dst_tuple: &(bool, [u8]) = &(true, [0x66, 0x6F, 0x6F]);
+ let dst_struct: &Pair<bool, [u8]> = &Pair(true, [0x66, 0x6F, 0x6F]);
+ assert_eq!(metadata(dst_tuple), 3_usize);
+ assert_eq!(metadata(dst_struct), 3_usize);
+ unsafe {
+ let dst_tuple: &(bool, str) = std::mem::transmute(dst_tuple);
+ let dst_struct: &Pair<bool, str> = std::mem::transmute(dst_struct);
+ assert_eq!(&dst_tuple.1, "foo");
+ assert_eq!(&dst_struct.1, "foo");
+ assert_eq!(metadata(dst_tuple), 3_usize);
+ assert_eq!(metadata(dst_struct), 3_usize);
+ }
+
+ let vtable_1: DynMetadata<dyn Debug> = metadata(&4_u16 as &dyn Debug);
+ let vtable_2: DynMetadata<dyn Display> = metadata(&4_u16 as &dyn Display);
+ let vtable_3: DynMetadata<dyn Display> = metadata(&4_u32 as &dyn Display);
+ let vtable_4: DynMetadata<dyn Display> = metadata(&(true, 7_u32) as &(bool, dyn Display));
+ let vtable_5: DynMetadata<dyn Display> =
+ metadata(&Pair(true, 7_u32) as &Pair<bool, dyn Display>);
+ unsafe {
+ let address_1: *const () = std::mem::transmute(vtable_1);
+ let address_2: *const () = std::mem::transmute(vtable_2);
+ let address_3: *const () = std::mem::transmute(vtable_3);
+ let address_4: *const () = std::mem::transmute(vtable_4);
+ let address_5: *const () = std::mem::transmute(vtable_5);
+ // Different trait => different vtable pointer
+ assert_ne!(address_1, address_2);
+ // Different erased type => different vtable pointer
+ assert_ne!(address_2, address_3);
+ // Same erased type and same trait => same vtable pointer
+ assert_eq!(address_3, address_4);
+ assert_eq!(address_3, address_5);
+ }
+}
+
+#[test]
+fn ptr_metadata_bounds() {
+ fn metadata_eq_method_address<T: ?Sized>() -> usize {
+ // The `Metadata` associated type has an `Ord` bound, so this is valid:
+ <<T as Pointee>::Metadata as PartialEq>::eq as usize
+ }
+ // "Synthetic" trait impls generated by the compiler like those of `Pointee`
+ // are not checked for bounds of associated type.
+ // So with a buggy libcore we could have both:
+ // * `<dyn Display as Pointee>::Metadata == DynMetadata`
+ // * `DynMetadata: !PartialEq`
+ // … and cause an ICE here:
+ metadata_eq_method_address::<dyn Display>();
+
+ // For this reason, let’s check here that bounds are satisfied:
+
+ let _ = static_assert_expected_bounds_for_metadata::<()>;
+ let _ = static_assert_expected_bounds_for_metadata::<usize>;
+ let _ = static_assert_expected_bounds_for_metadata::<DynMetadata<dyn Display>>;
+ fn _static_assert_associated_type<T: ?Sized>() {
+ let _ = static_assert_expected_bounds_for_metadata::<<T as Pointee>::Metadata>;
+ }
+
+ fn static_assert_expected_bounds_for_metadata<Meta>()
+ where
+ // Keep this in sync with the associated type in `library/core/src/ptr/metadata.rs`
+ Meta: Copy + Send + Sync + Ord + std::hash::Hash + Unpin,
+ {
+ }
+}
+
+#[test]
+fn dyn_metadata() {
+ #[derive(Debug)]
+ #[repr(align(32))]
+ struct Something([u8; 47]);
+
+ let value = Something([0; 47]);
+ let trait_object: &dyn Debug = &value;
+ let meta = metadata(trait_object);
+
+ assert_eq!(meta.size_of(), 64);
+ assert_eq!(meta.size_of(), std::mem::size_of::<Something>());
+ assert_eq!(meta.align_of(), 32);
+ assert_eq!(meta.align_of(), std::mem::align_of::<Something>());
+ assert_eq!(meta.layout(), std::alloc::Layout::new::<Something>());
+
+ assert!(format!("{meta:?}").starts_with("DynMetadata(0x"));
+}
+
+#[test]
+fn from_raw_parts() {
+ let mut value = 5_u32;
+ let address = &mut value as *mut _ as *mut ();
+ let trait_object: &dyn Display = &mut value;
+ let vtable = metadata(trait_object);
+ let trait_object = NonNull::from(trait_object);
+
+ assert_eq!(ptr::from_raw_parts(address, vtable), trait_object.as_ptr());
+ assert_eq!(ptr::from_raw_parts_mut(address, vtable), trait_object.as_ptr());
+ assert_eq!(NonNull::from_raw_parts(NonNull::new(address).unwrap(), vtable), trait_object);
+
+ let mut array = [5_u32, 5, 5, 5, 5];
+ let address = &mut array as *mut _ as *mut ();
+ let array_ptr = NonNull::from(&mut array);
+ let slice_ptr = NonNull::from(&mut array[..]);
+
+ assert_eq!(ptr::from_raw_parts(address, ()), array_ptr.as_ptr());
+ assert_eq!(ptr::from_raw_parts_mut(address, ()), array_ptr.as_ptr());
+ assert_eq!(NonNull::from_raw_parts(NonNull::new(address).unwrap(), ()), array_ptr);
+
+ assert_eq!(ptr::from_raw_parts(address, 5), slice_ptr.as_ptr());
+ assert_eq!(ptr::from_raw_parts_mut(address, 5), slice_ptr.as_ptr());
+ assert_eq!(NonNull::from_raw_parts(NonNull::new(address).unwrap(), 5), slice_ptr);
+}
+
+#[test]
+fn thin_box() {
+ let foo = ThinBox::<dyn Display>::new(4);
+ assert_eq!(foo.to_string(), "4");
+ drop(foo);
+ let bar = ThinBox::<dyn Display>::new(7);
+ assert_eq!(bar.to_string(), "7");
+
+ // A slightly more interesting library that could be built on top of metadata APIs.
+ //
+ // * It could be generalized to any `T: ?Sized` (not just trait object)
+ // if `{size,align}_of_for_meta<T: ?Sized>(T::Metadata)` are added.
+ // * Constructing a `ThinBox` without consuming and deallocating a `Box`
+ // requires either the unstable `Unsize` marker trait,
+ // or the unstable `unsized_locals` language feature,
+ // or taking `&dyn T` and restricting to `T: Copy`.
+
+ use std::alloc::*;
+ use std::marker::PhantomData;
+
+ struct ThinBox<T>
+ where
+ T: ?Sized + Pointee<Metadata = DynMetadata<T>>,
+ {
+ ptr: NonNull<DynMetadata<T>>,
+ phantom: PhantomData<T>,
+ }
+
+ impl<T> ThinBox<T>
+ where
+ T: ?Sized + Pointee<Metadata = DynMetadata<T>>,
+ {
+ pub fn new<Value: std::marker::Unsize<T>>(value: Value) -> Self {
+ let unsized_: &T = &value;
+ let meta = metadata(unsized_);
+ let meta_layout = Layout::for_value(&meta);
+ let value_layout = Layout::for_value(&value);
+ let (layout, offset) = meta_layout.extend(value_layout).unwrap();
+ // `DynMetadata` is pointer-sized:
+ assert!(layout.size() > 0);
+ // If `ThinBox<T>` is generalized to any `T: ?Sized`,
+ // handle ZSTs with a dangling pointer without going through `alloc()`,
+ // like `Box<T>` does.
+ unsafe {
+ let ptr = NonNull::new(alloc(layout))
+ .unwrap_or_else(|| handle_alloc_error(layout))
+ .cast::<DynMetadata<T>>();
+ ptr.as_ptr().write(meta);
+ ptr.cast::<u8>().as_ptr().add(offset).cast::<Value>().write(value);
+ Self { ptr, phantom: PhantomData }
+ }
+ }
+
+ fn meta(&self) -> DynMetadata<T> {
+ unsafe { *self.ptr.as_ref() }
+ }
+
+ fn layout(&self) -> (Layout, usize) {
+ let meta = self.meta();
+ Layout::for_value(&meta).extend(meta.layout()).unwrap()
+ }
+
+ fn value_ptr(&self) -> *const T {
+ let (_, offset) = self.layout();
+ let data_ptr = unsafe { self.ptr.cast::<u8>().as_ptr().add(offset) };
+ ptr::from_raw_parts(data_ptr.cast(), self.meta())
+ }
+
+ fn value_mut_ptr(&mut self) -> *mut T {
+ let (_, offset) = self.layout();
+ // FIXME: can this line be shared with the same in `value_ptr()`
+ // without upsetting Stacked Borrows?
+ let data_ptr = unsafe { self.ptr.cast::<u8>().as_ptr().add(offset) };
+ from_raw_parts_mut(data_ptr.cast(), self.meta())
+ }
+ }
+
+ impl<T> std::ops::Deref for ThinBox<T>
+ where
+ T: ?Sized + Pointee<Metadata = DynMetadata<T>>,
+ {
+ type Target = T;
+
+ fn deref(&self) -> &T {
+ unsafe { &*self.value_ptr() }
+ }
+ }
+
+ impl<T> std::ops::DerefMut for ThinBox<T>
+ where
+ T: ?Sized + Pointee<Metadata = DynMetadata<T>>,
+ {
+ fn deref_mut(&mut self) -> &mut T {
+ unsafe { &mut *self.value_mut_ptr() }
+ }
+ }
+
+ impl<T> std::ops::Drop for ThinBox<T>
+ where
+ T: ?Sized + Pointee<Metadata = DynMetadata<T>>,
+ {
+ fn drop(&mut self) {
+ let (layout, _) = self.layout();
+ unsafe {
+ drop_in_place::<T>(&mut **self);
+ dealloc(self.ptr.cast().as_ptr(), layout);
+ }
+ }
+ }
+}
+
+#[test]
+fn nonnull_tagged_pointer_with_provenance() {
+ let raw_pointer = Box::into_raw(Box::new(10));
+
+ let mut p = TaggedPointer::new(raw_pointer).unwrap();
+ assert_eq!(p.tag(), 0);
+
+ p.set_tag(1);
+ assert_eq!(p.tag(), 1);
+ assert_eq!(unsafe { *p.pointer().as_ptr() }, 10);
+
+ p.set_tag(3);
+ assert_eq!(p.tag(), 3);
+ assert_eq!(unsafe { *p.pointer().as_ptr() }, 10);
+
+ unsafe { Box::from_raw(p.pointer().as_ptr()) };
+
+ /// A non-null pointer type which carries several bits of metadata and maintains provenance.
+ #[repr(transparent)]
+ pub struct TaggedPointer<T>(NonNull<T>);
+
+ impl<T> Clone for TaggedPointer<T> {
+ fn clone(&self) -> Self {
+ Self(self.0)
+ }
+ }
+
+ impl<T> Copy for TaggedPointer<T> {}
+
+ impl<T> TaggedPointer<T> {
+ /// The ABI-required minimum alignment of the `P` type.
+ pub const ALIGNMENT: usize = core::mem::align_of::<T>();
+ /// A mask for data-carrying bits of the address.
+ pub const DATA_MASK: usize = !Self::ADDRESS_MASK;
+ /// Number of available bits of storage in the address.
+ pub const NUM_BITS: u32 = Self::ALIGNMENT.trailing_zeros();
+ /// A mask for the non-data-carrying bits of the address.
+ pub const ADDRESS_MASK: usize = usize::MAX << Self::NUM_BITS;
+
+ /// Create a new tagged pointer from a possibly null pointer.
+ pub fn new(pointer: *mut T) -> Option<TaggedPointer<T>> {
+ Some(TaggedPointer(NonNull::new(pointer)?))
+ }
+
+ /// Consume this tagged pointer and produce a raw mutable pointer to the
+ /// memory location.
+ pub fn pointer(self) -> NonNull<T> {
+ // SAFETY: The `addr` guaranteed to have bits set in the Self::ADDRESS_MASK, so the result will be non-null.
+ self.0.map_addr(|addr| unsafe {
+ NonZeroUsize::new_unchecked(addr.get() & Self::ADDRESS_MASK)
+ })
+ }
+
+ /// Consume this tagged pointer and produce the data it carries.
+ pub fn tag(&self) -> usize {
+ self.0.addr().get() & Self::DATA_MASK
+ }
+
+ /// Update the data this tagged pointer carries to a new value.
+ pub fn set_tag(&mut self, data: usize) {
+ assert_eq!(
+ data & Self::ADDRESS_MASK,
+ 0,
+ "cannot set more data beyond the lowest NUM_BITS"
+ );
+ let data = data & Self::DATA_MASK;
+
+ // SAFETY: This value will always be non-zero because the upper bits (from
+ // ADDRESS_MASK) will always be non-zero. This a property of the type and its
+ // construction.
+ self.0 = self.0.map_addr(|addr| unsafe {
+ NonZeroUsize::new_unchecked((addr.get() & Self::ADDRESS_MASK) | data)
+ })
+ }
+ }
+}
+
+#[test]
+fn swap_copy_untyped() {
+ // We call `{swap,copy}{,_nonoverlapping}` at `bool` type on data that is not a valid bool.
+ // These should all do untyped copies, so this should work fine.
+ let mut x = 5u8;
+ let mut y = 6u8;
+
+ let ptr1 = &mut x as *mut u8 as *mut bool;
+ let ptr2 = &mut y as *mut u8 as *mut bool;
+
+ unsafe {
+ ptr::swap(ptr1, ptr2);
+ ptr::swap_nonoverlapping(ptr1, ptr2, 1);
+ }
+ assert_eq!(x, 5);
+ assert_eq!(y, 6);
+
+ unsafe {
+ ptr::copy(ptr1, ptr2, 1);
+ ptr::copy_nonoverlapping(ptr1, ptr2, 1);
+ }
+ assert_eq!(x, 5);
+ assert_eq!(y, 5);
+}
+
+#[test]
+fn test_const_copy() {
+ const {
+ let ptr1 = &1;
+ let mut ptr2 = &666;
+
+ // Copy ptr1 to ptr2, bytewise.
+ unsafe {
+ ptr::copy(
+ &ptr1 as *const _ as *const MaybeUninit<u8>,
+ &mut ptr2 as *mut _ as *mut MaybeUninit<u8>,
+ mem::size_of::<&i32>(),
+ );
+ }
+
+ // Make sure they still work.
+ assert!(*ptr1 == 1);
+ assert!(*ptr2 == 1);
+ };
+
+ const {
+ let ptr1 = &1;
+ let mut ptr2 = &666;
+
+ // Copy ptr1 to ptr2, bytewise.
+ unsafe {
+ ptr::copy_nonoverlapping(
+ &ptr1 as *const _ as *const MaybeUninit<u8>,
+ &mut ptr2 as *mut _ as *mut MaybeUninit<u8>,
+ mem::size_of::<&i32>(),
+ );
+ }
+
+ // Make sure they still work.
+ assert!(*ptr1 == 1);
+ assert!(*ptr2 == 1);
+ };
+}
diff --git a/library/core/tests/result.rs b/library/core/tests/result.rs
new file mode 100644
index 000000000..103e8cc3a
--- /dev/null
+++ b/library/core/tests/result.rs
@@ -0,0 +1,427 @@
+use core::ops::DerefMut;
+use core::option::*;
+
+fn op1() -> Result<isize, &'static str> {
+ Ok(666)
+}
+fn op2() -> Result<isize, &'static str> {
+ Err("sadface")
+}
+
+#[test]
+fn test_and() {
+ assert_eq!(op1().and(Ok(667)).unwrap(), 667);
+ assert_eq!(op1().and(Err::<i32, &'static str>("bad")).unwrap_err(), "bad");
+
+ assert_eq!(op2().and(Ok(667)).unwrap_err(), "sadface");
+ assert_eq!(op2().and(Err::<i32, &'static str>("bad")).unwrap_err(), "sadface");
+}
+
+#[test]
+fn test_and_then() {
+ assert_eq!(op1().and_then(|i| Ok::<isize, &'static str>(i + 1)).unwrap(), 667);
+ assert_eq!(op1().and_then(|_| Err::<isize, &'static str>("bad")).unwrap_err(), "bad");
+
+ assert_eq!(op2().and_then(|i| Ok::<isize, &'static str>(i + 1)).unwrap_err(), "sadface");
+ assert_eq!(op2().and_then(|_| Err::<isize, &'static str>("bad")).unwrap_err(), "sadface");
+}
+
+#[test]
+fn test_or() {
+ assert_eq!(op1().or(Ok::<_, &'static str>(667)).unwrap(), 666);
+ assert_eq!(op1().or(Err("bad")).unwrap(), 666);
+
+ assert_eq!(op2().or(Ok::<_, &'static str>(667)).unwrap(), 667);
+ assert_eq!(op2().or(Err("bad")).unwrap_err(), "bad");
+}
+
+#[test]
+fn test_or_else() {
+ assert_eq!(op1().or_else(|_| Ok::<isize, &'static str>(667)).unwrap(), 666);
+ assert_eq!(op1().or_else(|e| Err::<isize, &'static str>(e)).unwrap(), 666);
+
+ assert_eq!(op2().or_else(|_| Ok::<isize, &'static str>(667)).unwrap(), 667);
+ assert_eq!(op2().or_else(|e| Err::<isize, &'static str>(e)).unwrap_err(), "sadface");
+}
+
+#[test]
+fn test_impl_map() {
+ assert!(Ok::<isize, isize>(1).map(|x| x + 1) == Ok(2));
+ assert!(Err::<isize, isize>(1).map(|x| x + 1) == Err(1));
+}
+
+#[test]
+fn test_impl_map_err() {
+ assert!(Ok::<isize, isize>(1).map_err(|x| x + 1) == Ok(1));
+ assert!(Err::<isize, isize>(1).map_err(|x| x + 1) == Err(2));
+}
+
+#[test]
+fn test_collect() {
+ let v: Result<Vec<isize>, ()> = (0..0).map(|_| Ok::<isize, ()>(0)).collect();
+ assert!(v == Ok(vec![]));
+
+ let v: Result<Vec<isize>, ()> = (0..3).map(|x| Ok::<isize, ()>(x)).collect();
+ assert!(v == Ok(vec![0, 1, 2]));
+
+ let v: Result<Vec<isize>, isize> = (0..3).map(|x| if x > 1 { Err(x) } else { Ok(x) }).collect();
+ assert!(v == Err(2));
+
+ // test that it does not take more elements than it needs
+ let mut functions: [Box<dyn Fn() -> Result<(), isize>>; 3] =
+ [Box::new(|| Ok(())), Box::new(|| Err(1)), Box::new(|| panic!())];
+
+ let v: Result<Vec<()>, isize> = functions.iter_mut().map(|f| (*f)()).collect();
+ assert!(v == Err(1));
+}
+
+#[test]
+fn test_fmt_default() {
+ let ok: Result<isize, &'static str> = Ok(100);
+ let err: Result<isize, &'static str> = Err("Err");
+
+ let s = format!("{ok:?}");
+ assert_eq!(s, "Ok(100)");
+ let s = format!("{err:?}");
+ assert_eq!(s, "Err(\"Err\")");
+}
+
+#[test]
+fn test_unwrap_or() {
+ let ok: Result<isize, &'static str> = Ok(100);
+ let ok_err: Result<isize, &'static str> = Err("Err");
+
+ assert_eq!(ok.unwrap_or(50), 100);
+ assert_eq!(ok_err.unwrap_or(50), 50);
+}
+
+#[test]
+fn test_ok_or_err() {
+ let ok: Result<isize, isize> = Ok(100);
+ let err: Result<isize, isize> = Err(200);
+
+ assert_eq!(ok.into_ok_or_err(), 100);
+ assert_eq!(err.into_ok_or_err(), 200);
+}
+
+#[test]
+fn test_unwrap_or_else() {
+ fn handler(msg: &'static str) -> isize {
+ if msg == "I got this." { 50 } else { panic!("BadBad") }
+ }
+
+ let ok: Result<isize, &'static str> = Ok(100);
+ let ok_err: Result<isize, &'static str> = Err("I got this.");
+
+ assert_eq!(ok.unwrap_or_else(handler), 100);
+ assert_eq!(ok_err.unwrap_or_else(handler), 50);
+}
+
+#[test]
+#[should_panic]
+pub fn test_unwrap_or_else_panic() {
+ fn handler(msg: &'static str) -> isize {
+ if msg == "I got this." { 50 } else { panic!("BadBad") }
+ }
+
+ let bad_err: Result<isize, &'static str> = Err("Unrecoverable mess.");
+ let _: isize = bad_err.unwrap_or_else(handler);
+}
+
+#[test]
+fn test_unwrap_unchecked() {
+ let ok: Result<isize, &'static str> = Ok(100);
+ assert_eq!(unsafe { ok.unwrap_unchecked() }, 100);
+}
+
+#[test]
+fn test_unwrap_err_unchecked() {
+ let ok_err: Result<isize, &'static str> = Err("Err");
+ assert_eq!(unsafe { ok_err.unwrap_err_unchecked() }, "Err");
+}
+
+#[test]
+pub fn test_expect_ok() {
+ let ok: Result<isize, &'static str> = Ok(100);
+ assert_eq!(ok.expect("Unexpected error"), 100);
+}
+#[test]
+#[should_panic(expected = "Got expected error: \"All good\"")]
+pub fn test_expect_err() {
+ let err: Result<isize, &'static str> = Err("All good");
+ err.expect("Got expected error");
+}
+
+#[test]
+pub fn test_expect_err_err() {
+ let ok: Result<&'static str, isize> = Err(100);
+ assert_eq!(ok.expect_err("Unexpected ok"), 100);
+}
+#[test]
+#[should_panic(expected = "Got expected ok: \"All good\"")]
+pub fn test_expect_err_ok() {
+ let err: Result<&'static str, isize> = Ok("All good");
+ err.expect_err("Got expected ok");
+}
+
+#[test]
+pub fn test_iter() {
+ let ok: Result<isize, &'static str> = Ok(100);
+ let mut it = ok.iter();
+ assert_eq!(it.size_hint(), (1, Some(1)));
+ assert_eq!(it.next(), Some(&100));
+ assert_eq!(it.size_hint(), (0, Some(0)));
+ assert!(it.next().is_none());
+ assert_eq!((&ok).into_iter().next(), Some(&100));
+
+ let err: Result<isize, &'static str> = Err("error");
+ assert_eq!(err.iter().next(), None);
+}
+
+#[test]
+pub fn test_iter_mut() {
+ let mut ok: Result<isize, &'static str> = Ok(100);
+ for loc in ok.iter_mut() {
+ *loc = 200;
+ }
+ assert_eq!(ok, Ok(200));
+ for loc in &mut ok {
+ *loc = 300;
+ }
+ assert_eq!(ok, Ok(300));
+
+ let mut err: Result<isize, &'static str> = Err("error");
+ for loc in err.iter_mut() {
+ *loc = 200;
+ }
+ assert_eq!(err, Err("error"));
+}
+
+#[test]
+pub fn test_unwrap_or_default() {
+ assert_eq!(op1().unwrap_or_default(), 666);
+ assert_eq!(op2().unwrap_or_default(), 0);
+}
+
+#[test]
+pub fn test_into_ok() {
+ fn infallible_op() -> Result<isize, !> {
+ Ok(666)
+ }
+
+ assert_eq!(infallible_op().into_ok(), 666);
+
+ enum MyNeverToken {}
+ impl From<MyNeverToken> for ! {
+ fn from(never: MyNeverToken) -> ! {
+ match never {}
+ }
+ }
+
+ fn infallible_op2() -> Result<isize, MyNeverToken> {
+ Ok(667)
+ }
+
+ assert_eq!(infallible_op2().into_ok(), 667);
+}
+
+#[test]
+pub fn test_into_err() {
+ fn until_error_op() -> Result<!, isize> {
+ Err(666)
+ }
+
+ assert_eq!(until_error_op().into_err(), 666);
+
+ enum MyNeverToken {}
+ impl From<MyNeverToken> for ! {
+ fn from(never: MyNeverToken) -> ! {
+ match never {}
+ }
+ }
+
+ fn until_error_op2() -> Result<MyNeverToken, isize> {
+ Err(667)
+ }
+
+ assert_eq!(until_error_op2().into_err(), 667);
+}
+
+#[test]
+fn test_try() {
+ fn try_result_ok() -> Result<u8, u32> {
+ let result: Result<u8, u8> = Ok(1);
+ let val = result?;
+ Ok(val)
+ }
+ assert_eq!(try_result_ok(), Ok(1));
+
+ fn try_result_err() -> Result<u8, u32> {
+ let result: Result<u8, u8> = Err(1);
+ let val = result?;
+ Ok(val)
+ }
+ assert_eq!(try_result_err(), Err(1));
+}
+
+#[test]
+fn test_result_as_deref() {
+ // &Result<T: Deref, E>::Ok(T).as_deref() ->
+ // Result<&T::Deref::Target, &E>::Ok(&*T)
+ let ref_ok = &Result::Ok::<&i32, u8>(&42);
+ let expected_result = Result::Ok::<&i32, &u8>(&42);
+ assert_eq!(ref_ok.as_deref(), expected_result);
+
+ let ref_ok = &Result::Ok::<String, u32>(String::from("a result"));
+ let expected_result = Result::Ok::<&str, &u32>("a result");
+ assert_eq!(ref_ok.as_deref(), expected_result);
+
+ let ref_ok = &Result::Ok::<Vec<i32>, u32>(vec![1, 2, 3, 4, 5]);
+ let expected_result = Result::Ok::<&[i32], &u32>([1, 2, 3, 4, 5].as_slice());
+ assert_eq!(ref_ok.as_deref(), expected_result);
+
+ // &Result<T: Deref, E>::Err(T).as_deref() ->
+ // Result<&T::Deref::Target, &E>::Err(&*E)
+ let val = 41;
+ let ref_err = &Result::Err::<&u8, i32>(val);
+ let expected_result = Result::Err::<&u8, &i32>(&val);
+ assert_eq!(ref_err.as_deref(), expected_result);
+
+ let s = String::from("an error");
+ let ref_err = &Result::Err::<&u32, String>(s.clone());
+ let expected_result = Result::Err::<&u32, &String>(&s);
+ assert_eq!(ref_err.as_deref(), expected_result);
+
+ let v = vec![5, 4, 3, 2, 1];
+ let ref_err = &Result::Err::<&u32, Vec<i32>>(v.clone());
+ let expected_result = Result::Err::<&u32, &Vec<i32>>(&v);
+ assert_eq!(ref_err.as_deref(), expected_result);
+}
+
+#[test]
+fn test_result_as_deref_mut() {
+ // &mut Result<T: DerefMut, E>::Ok(T).as_deref_mut() ->
+ // Result<&mut T::DerefMut::Target, &mut E>::Ok(&mut *T)
+ let mut val = 42;
+ let mut expected_val = 42;
+ let mut_ok = &mut Result::Ok::<&mut i32, u8>(&mut val);
+ let expected_result = Result::Ok::<&mut i32, &mut u8>(&mut expected_val);
+ assert_eq!(mut_ok.as_deref_mut(), expected_result);
+
+ let mut expected_string = String::from("a result");
+ let mut_ok = &mut Result::Ok::<String, u32>(expected_string.clone());
+ let expected_result = Result::Ok::<&mut str, &mut u32>(expected_string.deref_mut());
+ assert_eq!(mut_ok.as_deref_mut(), expected_result);
+
+ let mut expected_vec = vec![1, 2, 3, 4, 5];
+ let mut_ok = &mut Result::Ok::<Vec<i32>, u32>(expected_vec.clone());
+ let expected_result = Result::Ok::<&mut [i32], &mut u32>(expected_vec.as_mut_slice());
+ assert_eq!(mut_ok.as_deref_mut(), expected_result);
+
+ // &mut Result<T: DerefMut, E>::Err(T).as_deref_mut() ->
+ // Result<&mut T, &mut E>::Err(&mut *E)
+ let mut val = 41;
+ let mut_err = &mut Result::Err::<&mut u8, i32>(val);
+ let expected_result = Result::Err::<&mut u8, &mut i32>(&mut val);
+ assert_eq!(mut_err.as_deref_mut(), expected_result);
+
+ let mut expected_string = String::from("an error");
+ let mut_err = &mut Result::Err::<&mut u32, String>(expected_string.clone());
+ let expected_result = Result::Err::<&mut u32, &mut String>(&mut expected_string);
+ assert_eq!(mut_err.as_deref_mut(), expected_result);
+
+ let mut expected_vec = vec![5, 4, 3, 2, 1];
+ let mut_err = &mut Result::Err::<&mut u32, Vec<i32>>(expected_vec.clone());
+ let expected_result = Result::Err::<&mut u32, &mut Vec<i32>>(&mut expected_vec);
+ assert_eq!(mut_err.as_deref_mut(), expected_result);
+}
+
+#[test]
+fn result_const() {
+ // test that the methods of `Result` are usable in a const context
+
+ const RESULT: Result<usize, bool> = Ok(32);
+
+ const REF: Result<&usize, &bool> = RESULT.as_ref();
+ assert_eq!(REF, Ok(&32));
+
+ const IS_OK: bool = RESULT.is_ok();
+ assert!(IS_OK);
+
+ const IS_ERR: bool = RESULT.is_err();
+ assert!(!IS_ERR)
+}
+
+#[test]
+const fn result_const_mut() {
+ let mut result: Result<usize, bool> = Ok(32);
+
+ {
+ let as_mut = result.as_mut();
+ match as_mut {
+ Ok(v) => *v = 42,
+ Err(_) => unreachable!(),
+ }
+ }
+
+ let mut result_err: Result<usize, bool> = Err(false);
+
+ {
+ let as_mut = result_err.as_mut();
+ match as_mut {
+ Ok(_) => unreachable!(),
+ Err(v) => *v = true,
+ }
+ }
+}
+
+#[test]
+fn result_opt_conversions() {
+ #[derive(Copy, Clone, Debug, PartialEq)]
+ struct BadNumErr;
+
+ fn try_num(x: i32) -> Result<i32, BadNumErr> {
+ if x <= 5 { Ok(x + 1) } else { Err(BadNumErr) }
+ }
+
+ type ResOpt = Result<Option<i32>, BadNumErr>;
+ type OptRes = Option<Result<i32, BadNumErr>>;
+
+ let mut x: ResOpt = Ok(Some(5));
+ let mut y: OptRes = Some(Ok(5));
+ assert_eq!(x, y.transpose());
+ assert_eq!(x.transpose(), y);
+
+ x = Ok(None);
+ y = None;
+ assert_eq!(x, y.transpose());
+ assert_eq!(x.transpose(), y);
+
+ x = Err(BadNumErr);
+ y = Some(Err(BadNumErr));
+ assert_eq!(x, y.transpose());
+ assert_eq!(x.transpose(), y);
+
+ let res: Result<Vec<i32>, BadNumErr> = (0..10)
+ .map(|x| {
+ let y = try_num(x)?;
+ Ok(if y % 2 == 0 { Some(y - 1) } else { None })
+ })
+ .filter_map(Result::transpose)
+ .collect();
+
+ assert_eq!(res, Err(BadNumErr))
+}
+
+#[test]
+fn result_try_trait_v2_branch() {
+ use core::num::NonZeroU32;
+ use core::ops::{ControlFlow::*, Try};
+ assert_eq!(Ok::<i32, i32>(4).branch(), Continue(4));
+ assert_eq!(Err::<i32, i32>(4).branch(), Break(Err(4)));
+ let one = NonZeroU32::new(1).unwrap();
+ assert_eq!(Ok::<(), NonZeroU32>(()).branch(), Continue(()));
+ assert_eq!(Err::<(), NonZeroU32>(one).branch(), Break(Err(one)));
+ assert_eq!(Ok::<NonZeroU32, ()>(one).branch(), Continue(one));
+ assert_eq!(Err::<NonZeroU32, ()>(()).branch(), Break(Err(())));
+}
diff --git a/library/core/tests/simd.rs b/library/core/tests/simd.rs
new file mode 100644
index 000000000..565c8975e
--- /dev/null
+++ b/library/core/tests/simd.rs
@@ -0,0 +1,14 @@
+use core::simd::f32x4;
+use core::simd::SimdFloat;
+
+#[test]
+fn testing() {
+ let x = f32x4::from_array([1.0, 1.0, 1.0, 1.0]);
+ let y = -x;
+
+ let h = x * f32x4::splat(0.5);
+
+ let r = y.abs();
+ assert_eq!(x, r);
+ assert_eq!(h, f32x4::splat(0.5));
+}
diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs
new file mode 100644
index 000000000..0656109e9
--- /dev/null
+++ b/library/core/tests/slice.rs
@@ -0,0 +1,2597 @@
+use core::cell::Cell;
+use core::cmp::Ordering;
+use core::mem::MaybeUninit;
+use core::result::Result::{Err, Ok};
+use core::slice;
+
+#[test]
+fn test_position() {
+ let b = [1, 2, 3, 5, 5];
+ assert_eq!(b.iter().position(|&v| v == 9), None);
+ assert_eq!(b.iter().position(|&v| v == 5), Some(3));
+ assert_eq!(b.iter().position(|&v| v == 3), Some(2));
+ assert_eq!(b.iter().position(|&v| v == 0), None);
+}
+
+#[test]
+fn test_rposition() {
+ let b = [1, 2, 3, 5, 5];
+ assert_eq!(b.iter().rposition(|&v| v == 9), None);
+ assert_eq!(b.iter().rposition(|&v| v == 5), Some(4));
+ assert_eq!(b.iter().rposition(|&v| v == 3), Some(2));
+ assert_eq!(b.iter().rposition(|&v| v == 0), None);
+}
+
+#[test]
+fn test_binary_search() {
+ let b: [i32; 0] = [];
+ assert_eq!(b.binary_search(&5), Err(0));
+
+ let b = [4];
+ assert_eq!(b.binary_search(&3), Err(0));
+ assert_eq!(b.binary_search(&4), Ok(0));
+ assert_eq!(b.binary_search(&5), Err(1));
+
+ let b = [1, 2, 4, 6, 8, 9];
+ assert_eq!(b.binary_search(&5), Err(3));
+ assert_eq!(b.binary_search(&6), Ok(3));
+ assert_eq!(b.binary_search(&7), Err(4));
+ assert_eq!(b.binary_search(&8), Ok(4));
+
+ let b = [1, 2, 4, 5, 6, 8];
+ assert_eq!(b.binary_search(&9), Err(6));
+
+ let b = [1, 2, 4, 6, 7, 8, 9];
+ assert_eq!(b.binary_search(&6), Ok(3));
+ assert_eq!(b.binary_search(&5), Err(3));
+ assert_eq!(b.binary_search(&8), Ok(5));
+
+ let b = [1, 2, 4, 5, 6, 8, 9];
+ assert_eq!(b.binary_search(&7), Err(5));
+ assert_eq!(b.binary_search(&0), Err(0));
+
+ let b = [1, 3, 3, 3, 7];
+ assert_eq!(b.binary_search(&0), Err(0));
+ assert_eq!(b.binary_search(&1), Ok(0));
+ assert_eq!(b.binary_search(&2), Err(1));
+ assert!(match b.binary_search(&3) {
+ Ok(1..=3) => true,
+ _ => false,
+ });
+ assert!(match b.binary_search(&3) {
+ Ok(1..=3) => true,
+ _ => false,
+ });
+ assert_eq!(b.binary_search(&4), Err(4));
+ assert_eq!(b.binary_search(&5), Err(4));
+ assert_eq!(b.binary_search(&6), Err(4));
+ assert_eq!(b.binary_search(&7), Ok(4));
+ assert_eq!(b.binary_search(&8), Err(5));
+
+ let b = [(); usize::MAX];
+ assert_eq!(b.binary_search(&()), Ok(usize::MAX / 2));
+}
+
+#[test]
+fn test_binary_search_by_overflow() {
+ let b = [(); usize::MAX];
+ assert_eq!(b.binary_search_by(|_| Ordering::Equal), Ok(usize::MAX / 2));
+ assert_eq!(b.binary_search_by(|_| Ordering::Greater), Err(0));
+ assert_eq!(b.binary_search_by(|_| Ordering::Less), Err(usize::MAX));
+}
+
+#[test]
+// Test implementation specific behavior when finding equivalent elements.
+// It is ok to break this test but when you do a crater run is highly advisable.
+fn test_binary_search_implementation_details() {
+ let b = [1, 1, 2, 2, 3, 3, 3];
+ assert_eq!(b.binary_search(&1), Ok(1));
+ assert_eq!(b.binary_search(&2), Ok(3));
+ assert_eq!(b.binary_search(&3), Ok(5));
+ let b = [1, 1, 1, 1, 1, 3, 3, 3, 3];
+ assert_eq!(b.binary_search(&1), Ok(4));
+ assert_eq!(b.binary_search(&3), Ok(7));
+ let b = [1, 1, 1, 1, 3, 3, 3, 3, 3];
+ assert_eq!(b.binary_search(&1), Ok(2));
+ assert_eq!(b.binary_search(&3), Ok(4));
+}
+
+#[test]
+fn test_partition_point() {
+ let b: [i32; 0] = [];
+ assert_eq!(b.partition_point(|&x| x < 5), 0);
+
+ let b = [4];
+ assert_eq!(b.partition_point(|&x| x < 3), 0);
+ assert_eq!(b.partition_point(|&x| x < 4), 0);
+ assert_eq!(b.partition_point(|&x| x < 5), 1);
+
+ let b = [1, 2, 4, 6, 8, 9];
+ assert_eq!(b.partition_point(|&x| x < 5), 3);
+ assert_eq!(b.partition_point(|&x| x < 6), 3);
+ assert_eq!(b.partition_point(|&x| x < 7), 4);
+ assert_eq!(b.partition_point(|&x| x < 8), 4);
+
+ let b = [1, 2, 4, 5, 6, 8];
+ assert_eq!(b.partition_point(|&x| x < 9), 6);
+
+ let b = [1, 2, 4, 6, 7, 8, 9];
+ assert_eq!(b.partition_point(|&x| x < 6), 3);
+ assert_eq!(b.partition_point(|&x| x < 5), 3);
+ assert_eq!(b.partition_point(|&x| x < 8), 5);
+
+ let b = [1, 2, 4, 5, 6, 8, 9];
+ assert_eq!(b.partition_point(|&x| x < 7), 5);
+ assert_eq!(b.partition_point(|&x| x < 0), 0);
+
+ let b = [1, 3, 3, 3, 7];
+ assert_eq!(b.partition_point(|&x| x < 0), 0);
+ assert_eq!(b.partition_point(|&x| x < 1), 0);
+ assert_eq!(b.partition_point(|&x| x < 2), 1);
+ assert_eq!(b.partition_point(|&x| x < 3), 1);
+ assert_eq!(b.partition_point(|&x| x < 4), 4);
+ assert_eq!(b.partition_point(|&x| x < 5), 4);
+ assert_eq!(b.partition_point(|&x| x < 6), 4);
+ assert_eq!(b.partition_point(|&x| x < 7), 4);
+ assert_eq!(b.partition_point(|&x| x < 8), 5);
+}
+
+#[test]
+fn test_iterator_advance_by() {
+ let v = &[0, 1, 2, 3, 4];
+
+ for i in 0..=v.len() {
+ let mut iter = v.iter();
+ iter.advance_by(i).unwrap();
+ assert_eq!(iter.as_slice(), &v[i..]);
+ }
+
+ let mut iter = v.iter();
+ assert_eq!(iter.advance_by(v.len() + 1), Err(v.len()));
+ assert_eq!(iter.as_slice(), &[]);
+
+ let mut iter = v.iter();
+ iter.advance_by(3).unwrap();
+ assert_eq!(iter.as_slice(), &v[3..]);
+ iter.advance_by(2).unwrap();
+ assert_eq!(iter.as_slice(), &[]);
+ iter.advance_by(0).unwrap();
+}
+
+#[test]
+fn test_iterator_advance_back_by() {
+ let v = &[0, 1, 2, 3, 4];
+
+ for i in 0..=v.len() {
+ let mut iter = v.iter();
+ iter.advance_back_by(i).unwrap();
+ assert_eq!(iter.as_slice(), &v[..v.len() - i]);
+ }
+
+ let mut iter = v.iter();
+ assert_eq!(iter.advance_back_by(v.len() + 1), Err(v.len()));
+ assert_eq!(iter.as_slice(), &[]);
+
+ let mut iter = v.iter();
+ iter.advance_back_by(3).unwrap();
+ assert_eq!(iter.as_slice(), &v[..v.len() - 3]);
+ iter.advance_back_by(2).unwrap();
+ assert_eq!(iter.as_slice(), &[]);
+ iter.advance_back_by(0).unwrap();
+}
+
+#[test]
+fn test_iterator_nth() {
+ let v: &[_] = &[0, 1, 2, 3, 4];
+ for i in 0..v.len() {
+ assert_eq!(v.iter().nth(i).unwrap(), &v[i]);
+ }
+ assert_eq!(v.iter().nth(v.len()), None);
+
+ let mut iter = v.iter();
+ assert_eq!(iter.nth(2).unwrap(), &v[2]);
+ assert_eq!(iter.nth(1).unwrap(), &v[4]);
+}
+
+#[test]
+fn test_iterator_nth_back() {
+ let v: &[_] = &[0, 1, 2, 3, 4];
+ for i in 0..v.len() {
+ assert_eq!(v.iter().nth_back(i).unwrap(), &v[v.len() - i - 1]);
+ }
+ assert_eq!(v.iter().nth_back(v.len()), None);
+
+ let mut iter = v.iter();
+ assert_eq!(iter.nth_back(2).unwrap(), &v[2]);
+ assert_eq!(iter.nth_back(1).unwrap(), &v[0]);
+}
+
+#[test]
+fn test_iterator_last() {
+ let v: &[_] = &[0, 1, 2, 3, 4];
+ assert_eq!(v.iter().last().unwrap(), &4);
+ assert_eq!(v[..1].iter().last().unwrap(), &0);
+}
+
+#[test]
+fn test_iterator_count() {
+ let v: &[_] = &[0, 1, 2, 3, 4];
+ assert_eq!(v.iter().count(), 5);
+
+ let mut iter2 = v.iter();
+ iter2.next();
+ iter2.next();
+ assert_eq!(iter2.count(), 3);
+}
+
+#[test]
+fn test_chunks_count() {
+ let v: &[i32] = &[0, 1, 2, 3, 4, 5];
+ let c = v.chunks(3);
+ assert_eq!(c.count(), 2);
+
+ let v2: &[i32] = &[0, 1, 2, 3, 4];
+ let c2 = v2.chunks(2);
+ assert_eq!(c2.count(), 3);
+
+ let v3: &[i32] = &[];
+ let c3 = v3.chunks(2);
+ assert_eq!(c3.count(), 0);
+}
+
+#[test]
+fn test_chunks_nth() {
+ let v: &[i32] = &[0, 1, 2, 3, 4, 5];
+ let mut c = v.chunks(2);
+ assert_eq!(c.nth(1).unwrap(), &[2, 3]);
+ assert_eq!(c.next().unwrap(), &[4, 5]);
+
+ let v2: &[i32] = &[0, 1, 2, 3, 4];
+ let mut c2 = v2.chunks(3);
+ assert_eq!(c2.nth(1).unwrap(), &[3, 4]);
+ assert_eq!(c2.next(), None);
+}
+
+#[test]
+fn test_chunks_next() {
+ let v = [0, 1, 2, 3, 4, 5];
+ let mut c = v.chunks(2);
+ assert_eq!(c.next().unwrap(), &[0, 1]);
+ assert_eq!(c.next().unwrap(), &[2, 3]);
+ assert_eq!(c.next().unwrap(), &[4, 5]);
+ assert_eq!(c.next(), None);
+
+ let v = [0, 1, 2, 3, 4, 5, 6, 7];
+ let mut c = v.chunks(3);
+ assert_eq!(c.next().unwrap(), &[0, 1, 2]);
+ assert_eq!(c.next().unwrap(), &[3, 4, 5]);
+ assert_eq!(c.next().unwrap(), &[6, 7]);
+ assert_eq!(c.next(), None);
+}
+
+#[test]
+fn test_chunks_next_back() {
+ let v = [0, 1, 2, 3, 4, 5];
+ let mut c = v.chunks(2);
+ assert_eq!(c.next_back().unwrap(), &[4, 5]);
+ assert_eq!(c.next_back().unwrap(), &[2, 3]);
+ assert_eq!(c.next_back().unwrap(), &[0, 1]);
+ assert_eq!(c.next_back(), None);
+
+ let v = [0, 1, 2, 3, 4, 5, 6, 7];
+ let mut c = v.chunks(3);
+ assert_eq!(c.next_back().unwrap(), &[6, 7]);
+ assert_eq!(c.next_back().unwrap(), &[3, 4, 5]);
+ assert_eq!(c.next_back().unwrap(), &[0, 1, 2]);
+ assert_eq!(c.next_back(), None);
+}
+
+#[test]
+fn test_chunks_nth_back() {
+ let v: &[i32] = &[0, 1, 2, 3, 4, 5];
+ let mut c = v.chunks(2);
+ assert_eq!(c.nth_back(1).unwrap(), &[2, 3]);
+ assert_eq!(c.next().unwrap(), &[0, 1]);
+ assert_eq!(c.next(), None);
+
+ let v2: &[i32] = &[0, 1, 2, 3, 4];
+ let mut c2 = v2.chunks(3);
+ assert_eq!(c2.nth_back(1).unwrap(), &[0, 1, 2]);
+ assert_eq!(c2.next(), None);
+ assert_eq!(c2.next_back(), None);
+
+ let v3: &[i32] = &[0, 1, 2, 3, 4];
+ let mut c3 = v3.chunks(10);
+ assert_eq!(c3.nth_back(0).unwrap(), &[0, 1, 2, 3, 4]);
+ assert_eq!(c3.next(), None);
+
+ let v4: &[i32] = &[0, 1, 2];
+ let mut c4 = v4.chunks(10);
+ assert_eq!(c4.nth_back(1_000_000_000usize), None);
+}
+
+#[test]
+fn test_chunks_last() {
+ let v: &[i32] = &[0, 1, 2, 3, 4, 5];
+ let c = v.chunks(2);
+ assert_eq!(c.last().unwrap()[1], 5);
+
+ let v2: &[i32] = &[0, 1, 2, 3, 4];
+ let c2 = v2.chunks(2);
+ assert_eq!(c2.last().unwrap()[0], 4);
+}
+
+#[test]
+fn test_chunks_zip() {
+ let v1: &[i32] = &[0, 1, 2, 3, 4];
+ let v2: &[i32] = &[6, 7, 8, 9, 10];
+
+ let res = v1
+ .chunks(2)
+ .zip(v2.chunks(2))
+ .map(|(a, b)| a.iter().sum::<i32>() + b.iter().sum::<i32>())
+ .collect::<Vec<_>>();
+ assert_eq!(res, vec![14, 22, 14]);
+}
+
+#[test]
+fn test_chunks_mut_count() {
+ let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
+ let c = v.chunks_mut(3);
+ assert_eq!(c.count(), 2);
+
+ let v2: &mut [i32] = &mut [0, 1, 2, 3, 4];
+ let c2 = v2.chunks_mut(2);
+ assert_eq!(c2.count(), 3);
+
+ let v3: &mut [i32] = &mut [];
+ let c3 = v3.chunks_mut(2);
+ assert_eq!(c3.count(), 0);
+}
+
+#[test]
+fn test_chunks_mut_nth() {
+ let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
+ let mut c = v.chunks_mut(2);
+ assert_eq!(c.nth(1).unwrap(), &[2, 3]);
+ assert_eq!(c.next().unwrap(), &[4, 5]);
+
+ let v2: &mut [i32] = &mut [0, 1, 2, 3, 4];
+ let mut c2 = v2.chunks_mut(3);
+ assert_eq!(c2.nth(1).unwrap(), &[3, 4]);
+ assert_eq!(c2.next(), None);
+}
+
+#[test]
+fn test_chunks_mut_nth_back() {
+ let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
+ let mut c = v.chunks_mut(2);
+ assert_eq!(c.nth_back(1).unwrap(), &[2, 3]);
+ assert_eq!(c.next().unwrap(), &[0, 1]);
+
+ let v1: &mut [i32] = &mut [0, 1, 2, 3, 4];
+ let mut c1 = v1.chunks_mut(3);
+ assert_eq!(c1.nth_back(1).unwrap(), &[0, 1, 2]);
+ assert_eq!(c1.next(), None);
+
+ let v3: &mut [i32] = &mut [0, 1, 2, 3, 4];
+ let mut c3 = v3.chunks_mut(10);
+ assert_eq!(c3.nth_back(0).unwrap(), &[0, 1, 2, 3, 4]);
+ assert_eq!(c3.next(), None);
+
+ let v4: &mut [i32] = &mut [0, 1, 2];
+ let mut c4 = v4.chunks_mut(10);
+ assert_eq!(c4.nth_back(1_000_000_000usize), None);
+}
+
+#[test]
+fn test_chunks_mut_last() {
+ let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
+ let c = v.chunks_mut(2);
+ assert_eq!(c.last().unwrap(), &[4, 5]);
+
+ let v2: &mut [i32] = &mut [0, 1, 2, 3, 4];
+ let c2 = v2.chunks_mut(2);
+ assert_eq!(c2.last().unwrap(), &[4]);
+}
+
+#[test]
+fn test_chunks_mut_zip() {
+ let v1: &mut [i32] = &mut [0, 1, 2, 3, 4];
+ let v2: &[i32] = &[6, 7, 8, 9, 10];
+
+ for (a, b) in v1.chunks_mut(2).zip(v2.chunks(2)) {
+ let sum = b.iter().sum::<i32>();
+ for v in a {
+ *v += sum;
+ }
+ }
+ assert_eq!(v1, [13, 14, 19, 20, 14]);
+}
+
+#[test]
+fn test_chunks_mut_zip_aliasing() {
+ let v1: &mut [i32] = &mut [0, 1, 2, 3, 4];
+ let v2: &[i32] = &[6, 7, 8, 9, 10];
+
+ let mut it = v1.chunks_mut(2).zip(v2.chunks(2));
+ let first = it.next().unwrap();
+ let _ = it.next().unwrap();
+ assert_eq!(first, (&mut [0, 1][..], &[6, 7][..]));
+}
+
+#[test]
+fn test_chunks_exact_mut_zip_aliasing() {
+ let v1: &mut [i32] = &mut [0, 1, 2, 3, 4];
+ let v2: &[i32] = &[6, 7, 8, 9, 10];
+
+ let mut it = v1.chunks_exact_mut(2).zip(v2.chunks(2));
+ let first = it.next().unwrap();
+ let _ = it.next().unwrap();
+ assert_eq!(first, (&mut [0, 1][..], &[6, 7][..]));
+}
+
+#[test]
+fn test_rchunks_mut_zip_aliasing() {
+ let v1: &mut [i32] = &mut [0, 1, 2, 3, 4];
+ let v2: &[i32] = &[6, 7, 8, 9, 10];
+
+ let mut it = v1.rchunks_mut(2).zip(v2.chunks(2));
+ let first = it.next().unwrap();
+ let _ = it.next().unwrap();
+ assert_eq!(first, (&mut [3, 4][..], &[6, 7][..]));
+}
+
+#[test]
+fn test_rchunks_exact_mut_zip_aliasing() {
+ let v1: &mut [i32] = &mut [0, 1, 2, 3, 4];
+ let v2: &[i32] = &[6, 7, 8, 9, 10];
+
+ let mut it = v1.rchunks_exact_mut(2).zip(v2.chunks(2));
+ let first = it.next().unwrap();
+ let _ = it.next().unwrap();
+ assert_eq!(first, (&mut [3, 4][..], &[6, 7][..]));
+}
+
+#[test]
+fn test_chunks_exact_count() {
+ let v: &[i32] = &[0, 1, 2, 3, 4, 5];
+ let c = v.chunks_exact(3);
+ assert_eq!(c.count(), 2);
+
+ let v2: &[i32] = &[0, 1, 2, 3, 4];
+ let c2 = v2.chunks_exact(2);
+ assert_eq!(c2.count(), 2);
+
+ let v3: &[i32] = &[];
+ let c3 = v3.chunks_exact(2);
+ assert_eq!(c3.count(), 0);
+}
+
+#[test]
+fn test_chunks_exact_nth() {
+ let v: &[i32] = &[0, 1, 2, 3, 4, 5];
+ let mut c = v.chunks_exact(2);
+ assert_eq!(c.nth(1).unwrap(), &[2, 3]);
+ assert_eq!(c.next().unwrap(), &[4, 5]);
+
+ let v2: &[i32] = &[0, 1, 2, 3, 4, 5, 6];
+ let mut c2 = v2.chunks_exact(3);
+ assert_eq!(c2.nth(1).unwrap(), &[3, 4, 5]);
+ assert_eq!(c2.next(), None);
+}
+
+#[test]
+fn test_chunks_exact_nth_back() {
+ let v: &[i32] = &[0, 1, 2, 3, 4, 5];
+ let mut c = v.chunks_exact(2);
+ assert_eq!(c.nth_back(1).unwrap(), &[2, 3]);
+ assert_eq!(c.next().unwrap(), &[0, 1]);
+ assert_eq!(c.next(), None);
+
+ let v2: &[i32] = &[0, 1, 2, 3, 4];
+ let mut c2 = v2.chunks_exact(3);
+ assert_eq!(c2.nth_back(0).unwrap(), &[0, 1, 2]);
+ assert_eq!(c2.next(), None);
+ assert_eq!(c2.next_back(), None);
+
+ let v3: &[i32] = &[0, 1, 2, 3, 4];
+ let mut c3 = v3.chunks_exact(10);
+ assert_eq!(c3.nth_back(0), None);
+}
+
+#[test]
+fn test_chunks_exact_last() {
+ let v: &[i32] = &[0, 1, 2, 3, 4, 5];
+ let c = v.chunks_exact(2);
+ assert_eq!(c.last().unwrap(), &[4, 5]);
+
+ let v2: &[i32] = &[0, 1, 2, 3, 4];
+ let c2 = v2.chunks_exact(2);
+ assert_eq!(c2.last().unwrap(), &[2, 3]);
+}
+
+#[test]
+fn test_chunks_exact_remainder() {
+ let v: &[i32] = &[0, 1, 2, 3, 4];
+ let c = v.chunks_exact(2);
+ assert_eq!(c.remainder(), &[4]);
+}
+
+#[test]
+fn test_chunks_exact_zip() {
+ let v1: &[i32] = &[0, 1, 2, 3, 4];
+ let v2: &[i32] = &[6, 7, 8, 9, 10];
+
+ let res = v1
+ .chunks_exact(2)
+ .zip(v2.chunks_exact(2))
+ .map(|(a, b)| a.iter().sum::<i32>() + b.iter().sum::<i32>())
+ .collect::<Vec<_>>();
+ assert_eq!(res, vec![14, 22]);
+}
+
+#[test]
+fn test_chunks_exact_mut_count() {
+ let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
+ let c = v.chunks_exact_mut(3);
+ assert_eq!(c.count(), 2);
+
+ let v2: &mut [i32] = &mut [0, 1, 2, 3, 4];
+ let c2 = v2.chunks_exact_mut(2);
+ assert_eq!(c2.count(), 2);
+
+ let v3: &mut [i32] = &mut [];
+ let c3 = v3.chunks_exact_mut(2);
+ assert_eq!(c3.count(), 0);
+}
+
+#[test]
+fn test_chunks_exact_mut_nth() {
+ let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
+ let mut c = v.chunks_exact_mut(2);
+ assert_eq!(c.nth(1).unwrap(), &[2, 3]);
+ assert_eq!(c.next().unwrap(), &[4, 5]);
+
+ let v2: &mut [i32] = &mut [0, 1, 2, 3, 4, 5, 6];
+ let mut c2 = v2.chunks_exact_mut(3);
+ assert_eq!(c2.nth(1).unwrap(), &[3, 4, 5]);
+ assert_eq!(c2.next(), None);
+}
+
+#[test]
+fn test_chunks_exact_mut_nth_back() {
+ let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
+ let mut c = v.chunks_exact_mut(2);
+ assert_eq!(c.nth_back(1).unwrap(), &[2, 3]);
+ assert_eq!(c.next().unwrap(), &[0, 1]);
+ assert_eq!(c.next(), None);
+
+ let v2: &mut [i32] = &mut [0, 1, 2, 3, 4];
+ let mut c2 = v2.chunks_exact_mut(3);
+ assert_eq!(c2.nth_back(0).unwrap(), &[0, 1, 2]);
+ assert_eq!(c2.next(), None);
+ assert_eq!(c2.next_back(), None);
+
+ let v3: &mut [i32] = &mut [0, 1, 2, 3, 4];
+ let mut c3 = v3.chunks_exact_mut(10);
+ assert_eq!(c3.nth_back(0), None);
+}
+
+#[test]
+fn test_chunks_exact_mut_last() {
+ let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
+ let c = v.chunks_exact_mut(2);
+ assert_eq!(c.last().unwrap(), &[4, 5]);
+
+ let v2: &mut [i32] = &mut [0, 1, 2, 3, 4];
+ let c2 = v2.chunks_exact_mut(2);
+ assert_eq!(c2.last().unwrap(), &[2, 3]);
+}
+
+#[test]
+fn test_chunks_exact_mut_remainder() {
+ let v: &mut [i32] = &mut [0, 1, 2, 3, 4];
+ let c = v.chunks_exact_mut(2);
+ assert_eq!(c.into_remainder(), &[4]);
+}
+
+#[test]
+fn test_chunks_exact_mut_zip() {
+ let v1: &mut [i32] = &mut [0, 1, 2, 3, 4];
+ let v2: &[i32] = &[6, 7, 8, 9, 10];
+
+ for (a, b) in v1.chunks_exact_mut(2).zip(v2.chunks_exact(2)) {
+ let sum = b.iter().sum::<i32>();
+ for v in a {
+ *v += sum;
+ }
+ }
+ assert_eq!(v1, [13, 14, 19, 20, 4]);
+}
+
+#[test]
+fn test_array_chunks_infer() {
+ let v: &[i32] = &[0, 1, 2, 3, 4, -4];
+ let c = v.array_chunks();
+ for &[a, b, c] in c {
+ assert_eq!(a + b + c, 3);
+ }
+
+ let v2: &[i32] = &[0, 1, 2, 3, 4, 5, 6];
+ let total = v2.array_chunks().map(|&[a, b]| a * b).sum::<i32>();
+ assert_eq!(total, 2 * 3 + 4 * 5);
+}
+
+#[test]
+fn test_array_chunks_count() {
+ let v: &[i32] = &[0, 1, 2, 3, 4, 5];
+ let c = v.array_chunks::<3>();
+ assert_eq!(c.count(), 2);
+
+ let v2: &[i32] = &[0, 1, 2, 3, 4];
+ let c2 = v2.array_chunks::<2>();
+ assert_eq!(c2.count(), 2);
+
+ let v3: &[i32] = &[];
+ let c3 = v3.array_chunks::<2>();
+ assert_eq!(c3.count(), 0);
+}
+
+#[test]
+fn test_array_chunks_nth() {
+ let v: &[i32] = &[0, 1, 2, 3, 4, 5];
+ let mut c = v.array_chunks::<2>();
+ assert_eq!(c.nth(1).unwrap(), &[2, 3]);
+ assert_eq!(c.next().unwrap(), &[4, 5]);
+
+ let v2: &[i32] = &[0, 1, 2, 3, 4, 5, 6];
+ let mut c2 = v2.array_chunks::<3>();
+ assert_eq!(c2.nth(1).unwrap(), &[3, 4, 5]);
+ assert_eq!(c2.next(), None);
+}
+
+#[test]
+fn test_array_chunks_nth_back() {
+ let v: &[i32] = &[0, 1, 2, 3, 4, 5];
+ let mut c = v.array_chunks::<2>();
+ assert_eq!(c.nth_back(1).unwrap(), &[2, 3]);
+ assert_eq!(c.next().unwrap(), &[0, 1]);
+ assert_eq!(c.next(), None);
+
+ let v2: &[i32] = &[0, 1, 2, 3, 4];
+ let mut c2 = v2.array_chunks::<3>();
+ assert_eq!(c2.nth_back(0).unwrap(), &[0, 1, 2]);
+ assert_eq!(c2.next(), None);
+ assert_eq!(c2.next_back(), None);
+
+ let v3: &[i32] = &[0, 1, 2, 3, 4];
+ let mut c3 = v3.array_chunks::<10>();
+ assert_eq!(c3.nth_back(0), None);
+}
+
+#[test]
+fn test_array_chunks_last() {
+ let v: &[i32] = &[0, 1, 2, 3, 4, 5];
+ let c = v.array_chunks::<2>();
+ assert_eq!(c.last().unwrap(), &[4, 5]);
+
+ let v2: &[i32] = &[0, 1, 2, 3, 4];
+ let c2 = v2.array_chunks::<2>();
+ assert_eq!(c2.last().unwrap(), &[2, 3]);
+}
+
+#[test]
+fn test_array_chunks_remainder() {
+ let v: &[i32] = &[0, 1, 2, 3, 4];
+ let c = v.array_chunks::<2>();
+ assert_eq!(c.remainder(), &[4]);
+}
+
+#[test]
+fn test_array_chunks_zip() {
+ let v1: &[i32] = &[0, 1, 2, 3, 4];
+ let v2: &[i32] = &[6, 7, 8, 9, 10];
+
+ let res = v1
+ .array_chunks::<2>()
+ .zip(v2.array_chunks::<2>())
+ .map(|(a, b)| a.iter().sum::<i32>() + b.iter().sum::<i32>())
+ .collect::<Vec<_>>();
+ assert_eq!(res, vec![14, 22]);
+}
+
+#[test]
+fn test_array_chunks_mut_infer() {
+ let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5, 6];
+ for a in v.array_chunks_mut() {
+ let sum = a.iter().sum::<i32>();
+ *a = [sum; 3];
+ }
+ assert_eq!(v, &[3, 3, 3, 12, 12, 12, 6]);
+
+ let v2: &mut [i32] = &mut [0, 1, 2, 3, 4, 5, 6];
+ v2.array_chunks_mut().for_each(|[a, b]| core::mem::swap(a, b));
+ assert_eq!(v2, &[1, 0, 3, 2, 5, 4, 6]);
+}
+
+#[test]
+fn test_array_chunks_mut_count() {
+ let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
+ let c = v.array_chunks_mut::<3>();
+ assert_eq!(c.count(), 2);
+
+ let v2: &mut [i32] = &mut [0, 1, 2, 3, 4];
+ let c2 = v2.array_chunks_mut::<2>();
+ assert_eq!(c2.count(), 2);
+
+ let v3: &mut [i32] = &mut [];
+ let c3 = v3.array_chunks_mut::<2>();
+ assert_eq!(c3.count(), 0);
+}
+
+#[test]
+fn test_array_chunks_mut_nth() {
+ let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
+ let mut c = v.array_chunks_mut::<2>();
+ assert_eq!(c.nth(1).unwrap(), &[2, 3]);
+ assert_eq!(c.next().unwrap(), &[4, 5]);
+
+ let v2: &mut [i32] = &mut [0, 1, 2, 3, 4, 5, 6];
+ let mut c2 = v2.array_chunks_mut::<3>();
+ assert_eq!(c2.nth(1).unwrap(), &[3, 4, 5]);
+ assert_eq!(c2.next(), None);
+}
+
+#[test]
+fn test_array_chunks_mut_nth_back() {
+ let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
+ let mut c = v.array_chunks_mut::<2>();
+ assert_eq!(c.nth_back(1).unwrap(), &[2, 3]);
+ assert_eq!(c.next().unwrap(), &[0, 1]);
+ assert_eq!(c.next(), None);
+
+ let v2: &mut [i32] = &mut [0, 1, 2, 3, 4];
+ let mut c2 = v2.array_chunks_mut::<3>();
+ assert_eq!(c2.nth_back(0).unwrap(), &[0, 1, 2]);
+ assert_eq!(c2.next(), None);
+ assert_eq!(c2.next_back(), None);
+
+ let v3: &mut [i32] = &mut [0, 1, 2, 3, 4];
+ let mut c3 = v3.array_chunks_mut::<10>();
+ assert_eq!(c3.nth_back(0), None);
+}
+
+#[test]
+fn test_array_chunks_mut_last() {
+ let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
+ let c = v.array_chunks_mut::<2>();
+ assert_eq!(c.last().unwrap(), &[4, 5]);
+
+ let v2: &mut [i32] = &mut [0, 1, 2, 3, 4];
+ let c2 = v2.array_chunks_mut::<2>();
+ assert_eq!(c2.last().unwrap(), &[2, 3]);
+}
+
+#[test]
+fn test_array_chunks_mut_remainder() {
+ let v: &mut [i32] = &mut [0, 1, 2, 3, 4];
+ let c = v.array_chunks_mut::<2>();
+ assert_eq!(c.into_remainder(), &[4]);
+}
+
+#[test]
+fn test_array_chunks_mut_zip() {
+ let v1: &mut [i32] = &mut [0, 1, 2, 3, 4];
+ let v2: &[i32] = &[6, 7, 8, 9, 10];
+
+ for (a, b) in v1.array_chunks_mut::<2>().zip(v2.array_chunks::<2>()) {
+ let sum = b.iter().sum::<i32>();
+ for v in a {
+ *v += sum;
+ }
+ }
+ assert_eq!(v1, [13, 14, 19, 20, 4]);
+}
+
+#[test]
+fn test_array_windows_infer() {
+ let v: &[i32] = &[0, 1, 0, 1];
+ assert_eq!(v.array_windows::<2>().count(), 3);
+ let c = v.array_windows();
+ for &[a, b] in c {
+ assert_eq!(a + b, 1);
+ }
+
+ let v2: &[i32] = &[0, 1, 2, 3, 4, 5, 6];
+ let total = v2.array_windows().map(|&[a, b, c]| a + b + c).sum::<i32>();
+ assert_eq!(total, 3 + 6 + 9 + 12 + 15);
+}
+
+#[test]
+fn test_array_windows_count() {
+ let v: &[i32] = &[0, 1, 2, 3, 4, 5];
+ let c = v.array_windows::<3>();
+ assert_eq!(c.count(), 4);
+
+ let v2: &[i32] = &[0, 1, 2, 3, 4];
+ let c2 = v2.array_windows::<6>();
+ assert_eq!(c2.count(), 0);
+
+ let v3: &[i32] = &[];
+ let c3 = v3.array_windows::<2>();
+ assert_eq!(c3.count(), 0);
+
+ let v4: &[()] = &[(); usize::MAX];
+ let c4 = v4.array_windows::<1>();
+ assert_eq!(c4.count(), usize::MAX);
+}
+
+#[test]
+fn test_array_windows_nth() {
+ let v: &[i32] = &[0, 1, 2, 3, 4, 5];
+ let snd = v.array_windows::<4>().nth(1);
+ assert_eq!(snd, Some(&[1, 2, 3, 4]));
+ let mut arr_windows = v.array_windows::<2>();
+ assert_ne!(arr_windows.nth(0), arr_windows.nth(0));
+ let last = v.array_windows::<3>().last();
+ assert_eq!(last, Some(&[3, 4, 5]));
+}
+
+#[test]
+fn test_array_windows_nth_back() {
+ let v: &[i32] = &[0, 1, 2, 3, 4, 5];
+ let snd = v.array_windows::<4>().nth_back(1);
+ assert_eq!(snd, Some(&[1, 2, 3, 4]));
+ let mut arr_windows = v.array_windows::<2>();
+ assert_ne!(arr_windows.nth_back(0), arr_windows.nth_back(0));
+}
+
+#[test]
+fn test_rchunks_count() {
+ let v: &[i32] = &[0, 1, 2, 3, 4, 5];
+ let c = v.rchunks(3);
+ assert_eq!(c.count(), 2);
+
+ let v2: &[i32] = &[0, 1, 2, 3, 4];
+ let c2 = v2.rchunks(2);
+ assert_eq!(c2.count(), 3);
+
+ let v3: &[i32] = &[];
+ let c3 = v3.rchunks(2);
+ assert_eq!(c3.count(), 0);
+}
+
+#[test]
+fn test_rchunks_nth() {
+ let v: &[i32] = &[0, 1, 2, 3, 4, 5];
+ let mut c = v.rchunks(2);
+ assert_eq!(c.nth(1).unwrap(), &[2, 3]);
+ assert_eq!(c.next().unwrap(), &[0, 1]);
+
+ let v2: &[i32] = &[0, 1, 2, 3, 4];
+ let mut c2 = v2.rchunks(3);
+ assert_eq!(c2.nth(1).unwrap(), &[0, 1]);
+ assert_eq!(c2.next(), None);
+}
+
+#[test]
+fn test_rchunks_nth_back() {
+ let v: &[i32] = &[0, 1, 2, 3, 4, 5];
+ let mut c = v.rchunks(2);
+ assert_eq!(c.nth_back(1).unwrap(), &[2, 3]);
+ assert_eq!(c.next_back().unwrap(), &[4, 5]);
+
+ let v2: &[i32] = &[0, 1, 2, 3, 4];
+ let mut c2 = v2.rchunks(3);
+ assert_eq!(c2.nth_back(1).unwrap(), &[2, 3, 4]);
+ assert_eq!(c2.next_back(), None);
+}
+
+#[test]
+fn test_rchunks_next() {
+ let v = [0, 1, 2, 3, 4, 5];
+ let mut c = v.rchunks(2);
+ assert_eq!(c.next().unwrap(), &[4, 5]);
+ assert_eq!(c.next().unwrap(), &[2, 3]);
+ assert_eq!(c.next().unwrap(), &[0, 1]);
+ assert_eq!(c.next(), None);
+
+ let v = [0, 1, 2, 3, 4, 5, 6, 7];
+ let mut c = v.rchunks(3);
+ assert_eq!(c.next().unwrap(), &[5, 6, 7]);
+ assert_eq!(c.next().unwrap(), &[2, 3, 4]);
+ assert_eq!(c.next().unwrap(), &[0, 1]);
+ assert_eq!(c.next(), None);
+}
+
+#[test]
+fn test_rchunks_next_back() {
+ let v = [0, 1, 2, 3, 4, 5];
+ let mut c = v.rchunks(2);
+ assert_eq!(c.next_back().unwrap(), &[0, 1]);
+ assert_eq!(c.next_back().unwrap(), &[2, 3]);
+ assert_eq!(c.next_back().unwrap(), &[4, 5]);
+ assert_eq!(c.next_back(), None);
+
+ let v = [0, 1, 2, 3, 4, 5, 6, 7];
+ let mut c = v.rchunks(3);
+ assert_eq!(c.next_back().unwrap(), &[0, 1]);
+ assert_eq!(c.next_back().unwrap(), &[2, 3, 4]);
+ assert_eq!(c.next_back().unwrap(), &[5, 6, 7]);
+ assert_eq!(c.next_back(), None);
+}
+
+#[test]
+fn test_rchunks_last() {
+ let v: &[i32] = &[0, 1, 2, 3, 4, 5];
+ let c = v.rchunks(2);
+ assert_eq!(c.last().unwrap()[1], 1);
+
+ let v2: &[i32] = &[0, 1, 2, 3, 4];
+ let c2 = v2.rchunks(2);
+ assert_eq!(c2.last().unwrap()[0], 0);
+}
+
+#[test]
+fn test_rchunks_zip() {
+ let v1: &[i32] = &[0, 1, 2, 3, 4];
+ let v2: &[i32] = &[6, 7, 8, 9, 10];
+
+ let res = v1
+ .rchunks(2)
+ .zip(v2.rchunks(2))
+ .map(|(a, b)| a.iter().sum::<i32>() + b.iter().sum::<i32>())
+ .collect::<Vec<_>>();
+ assert_eq!(res, vec![26, 18, 6]);
+}
+
+#[test]
+fn test_rchunks_mut_count() {
+ let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
+ let c = v.rchunks_mut(3);
+ assert_eq!(c.count(), 2);
+
+ let v2: &mut [i32] = &mut [0, 1, 2, 3, 4];
+ let c2 = v2.rchunks_mut(2);
+ assert_eq!(c2.count(), 3);
+
+ let v3: &mut [i32] = &mut [];
+ let c3 = v3.rchunks_mut(2);
+ assert_eq!(c3.count(), 0);
+}
+
+#[test]
+fn test_rchunks_mut_nth() {
+ let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
+ let mut c = v.rchunks_mut(2);
+ assert_eq!(c.nth(1).unwrap(), &[2, 3]);
+ assert_eq!(c.next().unwrap(), &[0, 1]);
+
+ let v2: &mut [i32] = &mut [0, 1, 2, 3, 4];
+ let mut c2 = v2.rchunks_mut(3);
+ assert_eq!(c2.nth(1).unwrap(), &[0, 1]);
+ assert_eq!(c2.next(), None);
+}
+
+#[test]
+fn test_rchunks_mut_nth_back() {
+ let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
+ let mut c = v.rchunks_mut(2);
+ assert_eq!(c.nth_back(1).unwrap(), &[2, 3]);
+ assert_eq!(c.next_back().unwrap(), &[4, 5]);
+
+ let v2: &mut [i32] = &mut [0, 1, 2, 3, 4];
+ let mut c2 = v2.rchunks_mut(3);
+ assert_eq!(c2.nth_back(1).unwrap(), &[2, 3, 4]);
+ assert_eq!(c2.next_back(), None);
+}
+
+#[test]
+fn test_rchunks_mut_next() {
+ let mut v = [0, 1, 2, 3, 4, 5];
+ let mut c = v.rchunks_mut(2);
+ assert_eq!(c.next().unwrap(), &mut [4, 5]);
+ assert_eq!(c.next().unwrap(), &mut [2, 3]);
+ assert_eq!(c.next().unwrap(), &mut [0, 1]);
+ assert_eq!(c.next(), None);
+
+ let mut v = [0, 1, 2, 3, 4, 5, 6, 7];
+ let mut c = v.rchunks_mut(3);
+ assert_eq!(c.next().unwrap(), &mut [5, 6, 7]);
+ assert_eq!(c.next().unwrap(), &mut [2, 3, 4]);
+ assert_eq!(c.next().unwrap(), &mut [0, 1]);
+ assert_eq!(c.next(), None);
+}
+
+#[test]
+fn test_rchunks_mut_next_back() {
+ let mut v = [0, 1, 2, 3, 4, 5];
+ let mut c = v.rchunks_mut(2);
+ assert_eq!(c.next_back().unwrap(), &mut [0, 1]);
+ assert_eq!(c.next_back().unwrap(), &mut [2, 3]);
+ assert_eq!(c.next_back().unwrap(), &mut [4, 5]);
+ assert_eq!(c.next_back(), None);
+
+ let mut v = [0, 1, 2, 3, 4, 5, 6, 7];
+ let mut c = v.rchunks_mut(3);
+ assert_eq!(c.next_back().unwrap(), &mut [0, 1]);
+ assert_eq!(c.next_back().unwrap(), &mut [2, 3, 4]);
+ assert_eq!(c.next_back().unwrap(), &mut [5, 6, 7]);
+ assert_eq!(c.next_back(), None);
+}
+
+#[test]
+fn test_rchunks_mut_last() {
+ let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
+ let c = v.rchunks_mut(2);
+ assert_eq!(c.last().unwrap(), &[0, 1]);
+
+ let v2: &mut [i32] = &mut [0, 1, 2, 3, 4];
+ let c2 = v2.rchunks_mut(2);
+ assert_eq!(c2.last().unwrap(), &[0]);
+}
+
+#[test]
+fn test_rchunks_mut_zip() {
+ let v1: &mut [i32] = &mut [0, 1, 2, 3, 4];
+ let v2: &[i32] = &[6, 7, 8, 9, 10];
+
+ for (a, b) in v1.rchunks_mut(2).zip(v2.rchunks(2)) {
+ let sum = b.iter().sum::<i32>();
+ for v in a {
+ *v += sum;
+ }
+ }
+ assert_eq!(v1, [6, 16, 17, 22, 23]);
+}
+
+#[test]
+fn test_rchunks_exact_count() {
+ let v: &[i32] = &[0, 1, 2, 3, 4, 5];
+ let c = v.rchunks_exact(3);
+ assert_eq!(c.count(), 2);
+
+ let v2: &[i32] = &[0, 1, 2, 3, 4];
+ let c2 = v2.rchunks_exact(2);
+ assert_eq!(c2.count(), 2);
+
+ let v3: &[i32] = &[];
+ let c3 = v3.rchunks_exact(2);
+ assert_eq!(c3.count(), 0);
+}
+
+#[test]
+fn test_rchunks_exact_nth() {
+ let v: &[i32] = &[0, 1, 2, 3, 4, 5];
+ let mut c = v.rchunks_exact(2);
+ assert_eq!(c.nth(1).unwrap(), &[2, 3]);
+ assert_eq!(c.next().unwrap(), &[0, 1]);
+
+ let v2: &[i32] = &[0, 1, 2, 3, 4, 5, 6];
+ let mut c2 = v2.rchunks_exact(3);
+ assert_eq!(c2.nth(1).unwrap(), &[1, 2, 3]);
+ assert_eq!(c2.next(), None);
+}
+
+#[test]
+fn test_rchunks_exact_nth_back() {
+ let v: &[i32] = &[0, 1, 2, 3, 4, 5];
+ let mut c = v.rchunks_exact(2);
+ assert_eq!(c.nth_back(1).unwrap(), &[2, 3]);
+ assert_eq!(c.next_back().unwrap(), &[4, 5]);
+
+ let v2: &[i32] = &[0, 1, 2, 3, 4, 5, 6];
+ let mut c2 = v2.rchunks_exact(3);
+ assert_eq!(c2.nth_back(1).unwrap(), &[4, 5, 6]);
+ assert_eq!(c2.next(), None);
+}
+
+#[test]
+fn test_rchunks_exact_last() {
+ let v: &[i32] = &[0, 1, 2, 3, 4, 5];
+ let c = v.rchunks_exact(2);
+ assert_eq!(c.last().unwrap(), &[0, 1]);
+
+ let v2: &[i32] = &[0, 1, 2, 3, 4];
+ let c2 = v2.rchunks_exact(2);
+ assert_eq!(c2.last().unwrap(), &[1, 2]);
+}
+
+#[test]
+fn test_rchunks_exact_remainder() {
+ let v: &[i32] = &[0, 1, 2, 3, 4];
+ let c = v.rchunks_exact(2);
+ assert_eq!(c.remainder(), &[0]);
+}
+
+#[test]
+fn test_rchunks_exact_zip() {
+ let v1: &[i32] = &[0, 1, 2, 3, 4];
+ let v2: &[i32] = &[6, 7, 8, 9, 10];
+
+ let res = v1
+ .rchunks_exact(2)
+ .zip(v2.rchunks_exact(2))
+ .map(|(a, b)| a.iter().sum::<i32>() + b.iter().sum::<i32>())
+ .collect::<Vec<_>>();
+ assert_eq!(res, vec![26, 18]);
+}
+
+#[test]
+fn test_rchunks_exact_mut_count() {
+ let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
+ let c = v.rchunks_exact_mut(3);
+ assert_eq!(c.count(), 2);
+
+ let v2: &mut [i32] = &mut [0, 1, 2, 3, 4];
+ let c2 = v2.rchunks_exact_mut(2);
+ assert_eq!(c2.count(), 2);
+
+ let v3: &mut [i32] = &mut [];
+ let c3 = v3.rchunks_exact_mut(2);
+ assert_eq!(c3.count(), 0);
+}
+
+#[test]
+fn test_rchunks_exact_mut_nth() {
+ let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
+ let mut c = v.rchunks_exact_mut(2);
+ assert_eq!(c.nth(1).unwrap(), &[2, 3]);
+ assert_eq!(c.next().unwrap(), &[0, 1]);
+
+ let v2: &mut [i32] = &mut [0, 1, 2, 3, 4, 5, 6];
+ let mut c2 = v2.rchunks_exact_mut(3);
+ assert_eq!(c2.nth(1).unwrap(), &[1, 2, 3]);
+ assert_eq!(c2.next(), None);
+}
+
+#[test]
+fn test_rchunks_exact_mut_nth_back() {
+ let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
+ let mut c = v.rchunks_exact_mut(2);
+ assert_eq!(c.nth_back(1).unwrap(), &[2, 3]);
+ assert_eq!(c.next_back().unwrap(), &[4, 5]);
+
+ let v2: &mut [i32] = &mut [0, 1, 2, 3, 4, 5, 6];
+ let mut c2 = v2.rchunks_exact_mut(3);
+ assert_eq!(c2.nth_back(1).unwrap(), &[4, 5, 6]);
+ assert_eq!(c2.next(), None);
+}
+
+#[test]
+fn test_rchunks_exact_mut_last() {
+ let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
+ let c = v.rchunks_exact_mut(2);
+ assert_eq!(c.last().unwrap(), &[0, 1]);
+
+ let v2: &mut [i32] = &mut [0, 1, 2, 3, 4];
+ let c2 = v2.rchunks_exact_mut(2);
+ assert_eq!(c2.last().unwrap(), &[1, 2]);
+}
+
+#[test]
+fn test_rchunks_exact_mut_remainder() {
+ let v: &mut [i32] = &mut [0, 1, 2, 3, 4];
+ let c = v.rchunks_exact_mut(2);
+ assert_eq!(c.into_remainder(), &[0]);
+}
+
+#[test]
+fn test_rchunks_exact_mut_zip() {
+ let v1: &mut [i32] = &mut [0, 1, 2, 3, 4];
+ let v2: &[i32] = &[6, 7, 8, 9, 10];
+
+ for (a, b) in v1.rchunks_exact_mut(2).zip(v2.rchunks_exact(2)) {
+ let sum = b.iter().sum::<i32>();
+ for v in a {
+ *v += sum;
+ }
+ }
+ assert_eq!(v1, [0, 16, 17, 22, 23]);
+}
+
+#[test]
+fn chunks_mut_are_send_and_sync() {
+ use std::cell::Cell;
+ use std::slice::{ChunksExactMut, ChunksMut, RChunksExactMut, RChunksMut};
+ use std::sync::MutexGuard;
+
+ #[allow(unused)]
+ fn assert_send_and_sync()
+ where
+ ChunksMut<'static, Cell<i32>>: Send,
+ ChunksMut<'static, MutexGuard<'static, u32>>: Sync,
+ ChunksExactMut<'static, Cell<i32>>: Send,
+ ChunksExactMut<'static, MutexGuard<'static, u32>>: Sync,
+ RChunksMut<'static, Cell<i32>>: Send,
+ RChunksMut<'static, MutexGuard<'static, u32>>: Sync,
+ RChunksExactMut<'static, Cell<i32>>: Send,
+ RChunksExactMut<'static, MutexGuard<'static, u32>>: Sync,
+ {
+ }
+}
+
+#[test]
+fn test_windows_count() {
+ let v: &[i32] = &[0, 1, 2, 3, 4, 5];
+ let c = v.windows(3);
+ assert_eq!(c.count(), 4);
+
+ let v2: &[i32] = &[0, 1, 2, 3, 4];
+ let c2 = v2.windows(6);
+ assert_eq!(c2.count(), 0);
+
+ let v3: &[i32] = &[];
+ let c3 = v3.windows(2);
+ assert_eq!(c3.count(), 0);
+
+ let v4 = &[(); usize::MAX];
+ let c4 = v4.windows(1);
+ assert_eq!(c4.count(), usize::MAX);
+}
+
+#[test]
+fn test_windows_nth() {
+ let v: &[i32] = &[0, 1, 2, 3, 4, 5];
+ let mut c = v.windows(2);
+ assert_eq!(c.nth(2).unwrap()[1], 3);
+ assert_eq!(c.next().unwrap()[0], 3);
+
+ let v2: &[i32] = &[0, 1, 2, 3, 4];
+ let mut c2 = v2.windows(4);
+ assert_eq!(c2.nth(1).unwrap()[1], 2);
+ assert_eq!(c2.next(), None);
+}
+
+#[test]
+fn test_windows_nth_back() {
+ let v: &[i32] = &[0, 1, 2, 3, 4, 5];
+ let mut c = v.windows(2);
+ assert_eq!(c.nth_back(2).unwrap()[0], 2);
+ assert_eq!(c.next_back().unwrap()[1], 2);
+
+ let v2: &[i32] = &[0, 1, 2, 3, 4];
+ let mut c2 = v2.windows(4);
+ assert_eq!(c2.nth_back(1).unwrap()[1], 1);
+ assert_eq!(c2.next_back(), None);
+}
+
+#[test]
+fn test_windows_last() {
+ let v: &[i32] = &[0, 1, 2, 3, 4, 5];
+ let c = v.windows(2);
+ assert_eq!(c.last().unwrap()[1], 5);
+
+ let v2: &[i32] = &[0, 1, 2, 3, 4];
+ let c2 = v2.windows(2);
+ assert_eq!(c2.last().unwrap()[0], 3);
+}
+
+#[test]
+fn test_windows_zip() {
+ let v1: &[i32] = &[0, 1, 2, 3, 4];
+ let v2: &[i32] = &[6, 7, 8, 9, 10];
+
+ let res = v1
+ .windows(2)
+ .zip(v2.windows(2))
+ .map(|(a, b)| a.iter().sum::<i32>() + b.iter().sum::<i32>())
+ .collect::<Vec<_>>();
+
+ assert_eq!(res, [14, 18, 22, 26]);
+}
+
+#[test]
+#[allow(const_err)]
+fn test_iter_ref_consistency() {
+ use std::fmt::Debug;
+
+ fn test<T: Copy + Debug + PartialEq>(x: T) {
+ let v: &[T] = &[x, x, x];
+ let v_ptrs: [*const T; 3] = match v {
+ [ref v1, ref v2, ref v3] => [v1 as *const _, v2 as *const _, v3 as *const _],
+ _ => unreachable!(),
+ };
+ let len = v.len();
+
+ // nth(i)
+ for i in 0..len {
+ assert_eq!(&v[i] as *const _, v_ptrs[i]); // check the v_ptrs array, just to be sure
+ let nth = v.iter().nth(i).unwrap();
+ assert_eq!(nth as *const _, v_ptrs[i]);
+ }
+ assert_eq!(v.iter().nth(len), None, "nth(len) should return None");
+
+ // stepping through with nth(0)
+ {
+ let mut it = v.iter();
+ for i in 0..len {
+ let next = it.nth(0).unwrap();
+ assert_eq!(next as *const _, v_ptrs[i]);
+ }
+ assert_eq!(it.nth(0), None);
+ }
+
+ // next()
+ {
+ let mut it = v.iter();
+ for i in 0..len {
+ let remaining = len - i;
+ assert_eq!(it.size_hint(), (remaining, Some(remaining)));
+
+ let next = it.next().unwrap();
+ assert_eq!(next as *const _, v_ptrs[i]);
+ }
+ assert_eq!(it.size_hint(), (0, Some(0)));
+ assert_eq!(it.next(), None, "The final call to next() should return None");
+ }
+
+ // next_back()
+ {
+ let mut it = v.iter();
+ for i in 0..len {
+ let remaining = len - i;
+ assert_eq!(it.size_hint(), (remaining, Some(remaining)));
+
+ let prev = it.next_back().unwrap();
+ assert_eq!(prev as *const _, v_ptrs[remaining - 1]);
+ }
+ assert_eq!(it.size_hint(), (0, Some(0)));
+ assert_eq!(it.next_back(), None, "The final call to next_back() should return None");
+ }
+ }
+
+ fn test_mut<T: Copy + Debug + PartialEq>(x: T) {
+ let v: &mut [T] = &mut [x, x, x];
+ let v_ptrs: [*mut T; 3] = match v {
+ [ref v1, ref v2, ref v3] => {
+ [v1 as *const _ as *mut _, v2 as *const _ as *mut _, v3 as *const _ as *mut _]
+ }
+ _ => unreachable!(),
+ };
+ let len = v.len();
+
+ // nth(i)
+ for i in 0..len {
+ assert_eq!(&mut v[i] as *mut _, v_ptrs[i]); // check the v_ptrs array, just to be sure
+ let nth = v.iter_mut().nth(i).unwrap();
+ assert_eq!(nth as *mut _, v_ptrs[i]);
+ }
+ assert_eq!(v.iter().nth(len), None, "nth(len) should return None");
+
+ // stepping through with nth(0)
+ {
+ let mut it = v.iter();
+ for i in 0..len {
+ let next = it.nth(0).unwrap();
+ assert_eq!(next as *const _, v_ptrs[i]);
+ }
+ assert_eq!(it.nth(0), None);
+ }
+
+ // next()
+ {
+ let mut it = v.iter_mut();
+ for i in 0..len {
+ let remaining = len - i;
+ assert_eq!(it.size_hint(), (remaining, Some(remaining)));
+
+ let next = it.next().unwrap();
+ assert_eq!(next as *mut _, v_ptrs[i]);
+ }
+ assert_eq!(it.size_hint(), (0, Some(0)));
+ assert_eq!(it.next(), None, "The final call to next() should return None");
+ }
+
+ // next_back()
+ {
+ let mut it = v.iter_mut();
+ for i in 0..len {
+ let remaining = len - i;
+ assert_eq!(it.size_hint(), (remaining, Some(remaining)));
+
+ let prev = it.next_back().unwrap();
+ assert_eq!(prev as *mut _, v_ptrs[remaining - 1]);
+ }
+ assert_eq!(it.size_hint(), (0, Some(0)));
+ assert_eq!(it.next_back(), None, "The final call to next_back() should return None");
+ }
+ }
+
+ // Make sure iterators and slice patterns yield consistent addresses for various types,
+ // including ZSTs.
+ test(0u32);
+ test(());
+ test([0u32; 0]); // ZST with alignment > 0
+ test_mut(0u32);
+ test_mut(());
+ test_mut([0u32; 0]); // ZST with alignment > 0
+}
+
+// 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 {
+ // This checks all six indexing methods, given an input range that
+ // should succeed. (it is NOT suitable for testing invalid inputs)
+ macro_rules! assert_range_eq {
+ ($arr:expr, $range:expr, $expected:expr) => {
+ let mut arr = $arr;
+ let mut expected = $expected;
+ {
+ let s: &[_] = &arr;
+ let expected: &[_] = &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 [_] = &mut arr;
+ let expected: &mut [_] = &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 range")]
+ fn assert_range_eq_can_fail_by_panic() {
+ assert_range_eq!([0, 1, 2], 0..5, [0, 1, 2]);
+ }
+
+ // (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!([0, 1, 2], 0..2, [0, 1, 2]);
+ }
+
+ // 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 {
+ ($(
+ // each test case needs a unique name to namespace the tests
+ in mod $case_name:ident {
+ data: $data:expr;
+
+ // optional:
+ //
+ // one or more similar inputs for which data[input] succeeds,
+ // and the corresponding output as an array. 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;
+ }
+ )*) => {$(
+ mod $case_name {
+ #[allow(unused_imports)]
+ use core::ops::Bound;
+
+ #[test]
+ fn pass() {
+ let mut v = $data;
+
+ $( assert_range_eq!($data, $good, $output); )*
+
+ {
+ let v: &[_] = &v;
+ assert_eq!(v.get($bad), None, "(in None assertion for get)");
+ }
+
+ {
+ let v: &mut [_] = &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 = $data;
+ let v: &[_] = &v;
+ let _v = &v[$bad];
+ }
+
+ #[test]
+ #[should_panic(expected = $expect_msg)]
+ fn index_mut_fail() {
+ let mut v = $data;
+ let v: &mut [_] = &mut v;
+ let _v = &mut v[$bad];
+ }
+ }
+ )*};
+ }
+
+ #[test]
+ fn simple() {
+ let v = [0, 1, 2, 3, 4, 5];
+
+ assert_range_eq!(v, .., [0, 1, 2, 3, 4, 5]);
+ assert_range_eq!(v, ..2, [0, 1]);
+ assert_range_eq!(v, ..=1, [0, 1]);
+ assert_range_eq!(v, 2.., [2, 3, 4, 5]);
+ assert_range_eq!(v, 1..4, [1, 2, 3]);
+ assert_range_eq!(v, 1..=3, [1, 2, 3]);
+ }
+
+ panic_cases! {
+ in mod rangefrom_len {
+ data: [0, 1, 2, 3, 4, 5];
+
+ good: data[6..] == [];
+ bad: data[7..];
+ message: "out of range";
+ }
+
+ in mod rangeto_len {
+ data: [0, 1, 2, 3, 4, 5];
+
+ good: data[..6] == [0, 1, 2, 3, 4, 5];
+ bad: data[..7];
+ message: "out of range";
+ }
+
+ in mod rangetoinclusive_len {
+ data: [0, 1, 2, 3, 4, 5];
+
+ good: data[..=5] == [0, 1, 2, 3, 4, 5];
+ bad: data[..=6];
+ message: "out of range";
+ }
+
+ in mod rangeinclusive_len {
+ data: [0, 1, 2, 3, 4, 5];
+
+ good: data[0..=5] == [0, 1, 2, 3, 4, 5];
+ bad: data[0..=6];
+ message: "out of range";
+ }
+
+ in mod range_len_len {
+ data: [0, 1, 2, 3, 4, 5];
+
+ good: data[6..6] == [];
+ bad: data[7..7];
+ message: "out of range";
+ }
+
+ in mod rangeinclusive_len_len {
+ data: [0, 1, 2, 3, 4, 5];
+
+ good: data[6..=5] == [];
+ bad: data[7..=6];
+ message: "out of range";
+ }
+
+ in mod boundpair_len {
+ data: [0, 1, 2, 3, 4, 5];
+
+ good: data[(Bound::Included(6), Bound::Unbounded)] == [];
+ good: data[(Bound::Unbounded, Bound::Included(5))] == [0, 1, 2, 3, 4, 5];
+ good: data[(Bound::Unbounded, Bound::Excluded(6))] == [0, 1, 2, 3, 4, 5];
+ good: data[(Bound::Included(0), Bound::Included(5))] == [0, 1, 2, 3, 4, 5];
+ good: data[(Bound::Included(0), Bound::Excluded(6))] == [0, 1, 2, 3, 4, 5];
+ good: data[(Bound::Included(2), Bound::Excluded(4))] == [2, 3];
+ good: data[(Bound::Excluded(1), Bound::Included(4))] == [2, 3, 4];
+ good: data[(Bound::Excluded(5), Bound::Excluded(6))] == [];
+ good: data[(Bound::Included(6), Bound::Excluded(6))] == [];
+ good: data[(Bound::Excluded(5), Bound::Included(5))] == [];
+ good: data[(Bound::Included(6), Bound::Included(5))] == [];
+ bad: data[(Bound::Unbounded, Bound::Included(6))];
+ message: "out of range";
+ }
+ }
+
+ panic_cases! {
+ in mod rangeinclusive_exhausted {
+ data: [0, 1, 2, 3, 4, 5];
+
+ good: data[0..=5] == [0, 1, 2, 3, 4, 5];
+ good: data[{
+ let mut iter = 0..=5;
+ iter.by_ref().count(); // exhaust it
+ iter
+ }] == [];
+
+ // 0..=6 is out of range 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 range";
+ }
+ }
+
+ panic_cases! {
+ in mod range_neg_width {
+ data: [0, 1, 2, 3, 4, 5];
+
+ good: data[4..4] == [];
+ bad: data[4..3];
+ message: "but ends at";
+ }
+
+ in mod rangeinclusive_neg_width {
+ data: [0, 1, 2, 3, 4, 5];
+
+ good: data[4..=3] == [];
+ bad: data[4..=2];
+ message: "but ends at";
+ }
+
+ in mod boundpair_neg_width {
+ data: [0, 1, 2, 3, 4, 5];
+
+ good: data[(Bound::Included(4), Bound::Excluded(4))] == [];
+ bad: data[(Bound::Included(4), Bound::Excluded(3))];
+ message: "but ends at";
+ }
+ }
+
+ panic_cases! {
+ in mod rangeinclusive_overflow {
+ data: [0, 1];
+
+ // 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_overflow {
+ data: [0, 1];
+
+ bad: data[..= usize::MAX];
+ message: "maximum usize";
+ }
+
+ in mod boundpair_overflow_end {
+ data: [0; 1];
+
+ bad: data[(Bound::Unbounded, Bound::Included(usize::MAX))];
+ message: "maximum usize";
+ }
+
+ in mod boundpair_overflow_start {
+ data: [0; 1];
+
+ bad: data[(Bound::Excluded(usize::MAX), Bound::Unbounded)];
+ message: "maximum usize";
+ }
+ } // panic_cases!
+}
+
+#[test]
+fn test_find_rfind() {
+ let v = [0, 1, 2, 3, 4, 5];
+ let mut iter = v.iter();
+ let mut i = v.len();
+ while let Some(&elt) = iter.rfind(|_| true) {
+ i -= 1;
+ assert_eq!(elt, v[i]);
+ }
+ assert_eq!(i, 0);
+ assert_eq!(v.iter().rfind(|&&x| x <= 3), Some(&3));
+}
+
+#[test]
+fn test_iter_folds() {
+ let a = [1, 2, 3, 4, 5]; // len>4 so the unroll is used
+ assert_eq!(a.iter().fold(0, |acc, &x| 2 * acc + x), 57);
+ assert_eq!(a.iter().rfold(0, |acc, &x| 2 * acc + x), 129);
+ let fold = |acc: i32, &x| acc.checked_mul(2)?.checked_add(x);
+ assert_eq!(a.iter().try_fold(0, &fold), Some(57));
+ assert_eq!(a.iter().try_rfold(0, &fold), Some(129));
+
+ // short-circuiting try_fold, through other methods
+ let a = [0, 1, 2, 3, 5, 5, 5, 7, 8, 9];
+ let mut iter = a.iter();
+ assert_eq!(iter.position(|&x| x == 3), Some(3));
+ assert_eq!(iter.rfind(|&&x| x == 5), Some(&5));
+ assert_eq!(iter.len(), 2);
+}
+
+#[test]
+fn test_rotate_left() {
+ const N: usize = 600;
+ let a: &mut [_] = &mut [0; N];
+ for i in 0..N {
+ a[i] = i;
+ }
+
+ a.rotate_left(42);
+ let k = N - 42;
+
+ for i in 0..N {
+ assert_eq!(a[(i + k) % N], i);
+ }
+}
+
+#[test]
+fn test_rotate_right() {
+ const N: usize = 600;
+ let a: &mut [_] = &mut [0; N];
+ for i in 0..N {
+ a[i] = i;
+ }
+
+ a.rotate_right(42);
+
+ for i in 0..N {
+ assert_eq!(a[(i + 42) % N], i);
+ }
+}
+
+#[test]
+#[cfg_attr(miri, ignore)] // Miri is too slow
+fn brute_force_rotate_test_0() {
+ // In case of edge cases involving multiple algorithms
+ let n = 300;
+ for len in 0..n {
+ for s in 0..len {
+ let mut v = Vec::with_capacity(len);
+ for i in 0..len {
+ v.push(i);
+ }
+ v[..].rotate_right(s);
+ for i in 0..v.len() {
+ assert_eq!(v[i], v.len().wrapping_add(i.wrapping_sub(s)) % v.len());
+ }
+ }
+ }
+}
+
+#[test]
+fn brute_force_rotate_test_1() {
+ // `ptr_rotate` covers so many kinds of pointer usage, that this is just a good test for
+ // pointers in general. This uses a `[usize; 4]` to hit all algorithms without overwhelming miri
+ let n = 30;
+ for len in 0..n {
+ for s in 0..len {
+ let mut v: Vec<[usize; 4]> = Vec::with_capacity(len);
+ for i in 0..len {
+ v.push([i, 0, 0, 0]);
+ }
+ v[..].rotate_right(s);
+ for i in 0..v.len() {
+ assert_eq!(v[i][0], v.len().wrapping_add(i.wrapping_sub(s)) % v.len());
+ }
+ }
+ }
+}
+
+#[test]
+#[cfg(not(target_arch = "wasm32"))]
+fn sort_unstable() {
+ use core::cmp::Ordering::{Equal, Greater, Less};
+ use core::slice::heapsort;
+ use rand::{rngs::StdRng, seq::SliceRandom, Rng, SeedableRng};
+
+ // Miri is too slow (but still need to `chain` to make the types match)
+ let lens = if cfg!(miri) { (2..20).chain(0..0) } else { (2..25).chain(500..510) };
+ let rounds = if cfg!(miri) { 1 } else { 100 };
+
+ let mut v = [0; 600];
+ let mut tmp = [0; 600];
+ let mut rng = StdRng::from_entropy();
+
+ for len in lens {
+ let v = &mut v[0..len];
+ let tmp = &mut tmp[0..len];
+
+ for &modulus in &[5, 10, 100, 1000] {
+ for _ in 0..rounds {
+ for i in 0..len {
+ v[i] = rng.gen::<i32>() % modulus;
+ }
+
+ // Sort in default order.
+ tmp.copy_from_slice(v);
+ tmp.sort_unstable();
+ assert!(tmp.windows(2).all(|w| w[0] <= w[1]));
+
+ // Sort in ascending order.
+ tmp.copy_from_slice(v);
+ tmp.sort_unstable_by(|a, b| a.cmp(b));
+ assert!(tmp.windows(2).all(|w| w[0] <= w[1]));
+
+ // Sort in descending order.
+ tmp.copy_from_slice(v);
+ tmp.sort_unstable_by(|a, b| b.cmp(a));
+ assert!(tmp.windows(2).all(|w| w[0] >= w[1]));
+
+ // Test heapsort using `<` operator.
+ tmp.copy_from_slice(v);
+ heapsort(tmp, |a, b| a < b);
+ assert!(tmp.windows(2).all(|w| w[0] <= w[1]));
+
+ // Test heapsort using `>` operator.
+ tmp.copy_from_slice(v);
+ heapsort(tmp, |a, b| a > b);
+ assert!(tmp.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.
+ for i in 0..v.len() {
+ v[i] = i as i32;
+ }
+ v.sort_unstable_by(|_, _| *[Less, Equal, Greater].choose(&mut rng).unwrap());
+ v.sort_unstable();
+ for i in 0..v.len() {
+ assert_eq!(v[i], i as i32);
+ }
+
+ // Should not panic.
+ [0i32; 0].sort_unstable();
+ [(); 10].sort_unstable();
+ [(); 100].sort_unstable();
+
+ let mut v = [0xDEADBEEFu64];
+ v.sort_unstable();
+ assert!(v == [0xDEADBEEF]);
+}
+
+#[test]
+#[cfg(not(target_arch = "wasm32"))]
+#[cfg_attr(miri, ignore)] // Miri is too slow
+fn select_nth_unstable() {
+ use core::cmp::Ordering::{Equal, Greater, Less};
+ use rand::rngs::StdRng;
+ use rand::seq::SliceRandom;
+ use rand::{Rng, SeedableRng};
+
+ let mut rng = StdRng::from_entropy();
+
+ for len in (2..21).chain(500..501) {
+ let mut orig = vec![0; len];
+
+ for &modulus in &[5, 10, 1000] {
+ for _ in 0..10 {
+ for i in 0..len {
+ orig[i] = rng.gen::<i32>() % modulus;
+ }
+
+ let v_sorted = {
+ let mut v = orig.clone();
+ v.sort();
+ v
+ };
+
+ // Sort in default order.
+ for pivot in 0..len {
+ let mut v = orig.clone();
+ v.select_nth_unstable(pivot);
+
+ assert_eq!(v_sorted[pivot], v[pivot]);
+ for i in 0..pivot {
+ for j in pivot..len {
+ assert!(v[i] <= v[j]);
+ }
+ }
+ }
+
+ // Sort in ascending order.
+ for pivot in 0..len {
+ let mut v = orig.clone();
+ let (left, pivot, right) = v.select_nth_unstable_by(pivot, |a, b| a.cmp(b));
+
+ assert_eq!(left.len() + right.len(), len - 1);
+
+ for l in left {
+ assert!(l <= pivot);
+ for r in right.iter_mut() {
+ assert!(l <= r);
+ assert!(pivot <= r);
+ }
+ }
+ }
+
+ // Sort in descending order.
+ let sort_descending_comparator = |a: &i32, b: &i32| b.cmp(a);
+ let v_sorted_descending = {
+ let mut v = orig.clone();
+ v.sort_by(sort_descending_comparator);
+ v
+ };
+
+ for pivot in 0..len {
+ let mut v = orig.clone();
+ v.select_nth_unstable_by(pivot, sort_descending_comparator);
+
+ assert_eq!(v_sorted_descending[pivot], v[pivot]);
+ for i in 0..pivot {
+ for j in pivot..len {
+ assert!(v[j] <= v[i]);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Sort at index 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;
+ }
+
+ for pivot in 0..v.len() {
+ v.select_nth_unstable_by(pivot, |_, _| *[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.
+ [(); 10].select_nth_unstable(0);
+ [(); 10].select_nth_unstable(5);
+ [(); 10].select_nth_unstable(9);
+ [(); 100].select_nth_unstable(0);
+ [(); 100].select_nth_unstable(50);
+ [(); 100].select_nth_unstable(99);
+
+ let mut v = [0xDEADBEEFu64];
+ v.select_nth_unstable(0);
+ assert!(v == [0xDEADBEEF]);
+}
+
+#[test]
+#[should_panic(expected = "index 0 greater than length of slice")]
+fn select_nth_unstable_zero_length() {
+ [0i32; 0].select_nth_unstable(0);
+}
+
+#[test]
+#[should_panic(expected = "index 20 greater than length of slice")]
+fn select_nth_unstable_past_length() {
+ [0i32; 10].select_nth_unstable(20);
+}
+
+pub mod memchr {
+ use core::slice::memchr::{memchr, memrchr};
+
+ // test fallback implementations on all platforms
+ #[test]
+ fn matches_one() {
+ assert_eq!(Some(0), memchr(b'a', b"a"));
+ }
+
+ #[test]
+ fn matches_begin() {
+ assert_eq!(Some(0), memchr(b'a', b"aaaa"));
+ }
+
+ #[test]
+ fn matches_end() {
+ assert_eq!(Some(4), memchr(b'z', b"aaaaz"));
+ }
+
+ #[test]
+ fn matches_nul() {
+ assert_eq!(Some(4), memchr(b'\x00', b"aaaa\x00"));
+ }
+
+ #[test]
+ fn matches_past_nul() {
+ assert_eq!(Some(5), memchr(b'z', b"aaaa\x00z"));
+ }
+
+ #[test]
+ fn no_match_empty() {
+ assert_eq!(None, memchr(b'a', b""));
+ }
+
+ #[test]
+ fn no_match() {
+ assert_eq!(None, memchr(b'a', b"xyz"));
+ }
+
+ #[test]
+ fn matches_one_reversed() {
+ assert_eq!(Some(0), memrchr(b'a', b"a"));
+ }
+
+ #[test]
+ fn matches_begin_reversed() {
+ assert_eq!(Some(3), memrchr(b'a', b"aaaa"));
+ }
+
+ #[test]
+ fn matches_end_reversed() {
+ assert_eq!(Some(0), memrchr(b'z', b"zaaaa"));
+ }
+
+ #[test]
+ fn matches_nul_reversed() {
+ assert_eq!(Some(4), memrchr(b'\x00', b"aaaa\x00"));
+ }
+
+ #[test]
+ fn matches_past_nul_reversed() {
+ assert_eq!(Some(0), memrchr(b'z', b"z\x00aaaa"));
+ }
+
+ #[test]
+ fn no_match_empty_reversed() {
+ assert_eq!(None, memrchr(b'a', b""));
+ }
+
+ #[test]
+ fn no_match_reversed() {
+ assert_eq!(None, memrchr(b'a', b"xyz"));
+ }
+
+ #[test]
+ fn each_alignment_reversed() {
+ let mut data = [1u8; 64];
+ let needle = 2;
+ let pos = 40;
+ data[pos] = needle;
+ for start in 0..16 {
+ assert_eq!(Some(pos - start), memrchr(needle, &data[start..]));
+ }
+ }
+}
+
+#[test]
+fn test_align_to_simple() {
+ let bytes = [1u8, 2, 3, 4, 5, 6, 7];
+ let (prefix, aligned, suffix) = unsafe { bytes.align_to::<u16>() };
+ assert_eq!(aligned.len(), 3);
+ assert!(prefix == [1] || suffix == [7]);
+ let expect1 = [1 << 8 | 2, 3 << 8 | 4, 5 << 8 | 6];
+ let expect2 = [1 | 2 << 8, 3 | 4 << 8, 5 | 6 << 8];
+ let expect3 = [2 << 8 | 3, 4 << 8 | 5, 6 << 8 | 7];
+ let expect4 = [2 | 3 << 8, 4 | 5 << 8, 6 | 7 << 8];
+ assert!(
+ aligned == expect1 || aligned == expect2 || aligned == expect3 || aligned == expect4,
+ "aligned={:?} expected={:?} || {:?} || {:?} || {:?}",
+ aligned,
+ expect1,
+ expect2,
+ expect3,
+ expect4
+ );
+}
+
+#[test]
+fn test_align_to_zst() {
+ let bytes = [1, 2, 3, 4, 5, 6, 7];
+ let (prefix, aligned, suffix) = unsafe { bytes.align_to::<()>() };
+ assert_eq!(aligned.len(), 0);
+ assert!(prefix == [1, 2, 3, 4, 5, 6, 7] || suffix == [1, 2, 3, 4, 5, 6, 7]);
+}
+
+#[test]
+fn test_align_to_non_trivial() {
+ #[repr(align(8))]
+ struct U64(u64, u64);
+ #[repr(align(8))]
+ struct U64U64U32(u64, u64, u32);
+ let data = [
+ U64(1, 2),
+ U64(3, 4),
+ U64(5, 6),
+ U64(7, 8),
+ U64(9, 10),
+ U64(11, 12),
+ U64(13, 14),
+ U64(15, 16),
+ ];
+ let (prefix, aligned, suffix) = unsafe { data.align_to::<U64U64U32>() };
+ assert_eq!(aligned.len(), 4);
+ assert_eq!(prefix.len() + suffix.len(), 2);
+}
+
+#[test]
+fn test_align_to_empty_mid() {
+ use core::mem;
+
+ // Make sure that we do not create empty unaligned slices for the mid part, even when the
+ // overall slice is too short to contain an aligned address.
+ let bytes = [1, 2, 3, 4, 5, 6, 7];
+ type Chunk = u32;
+ for offset in 0..4 {
+ let (_, mid, _) = unsafe { bytes[offset..offset + 1].align_to::<Chunk>() };
+ assert_eq!(mid.as_ptr() as usize % mem::align_of::<Chunk>(), 0);
+ }
+}
+
+#[test]
+fn test_align_to_mut_aliasing() {
+ let mut val = [1u8, 2, 3, 4, 5];
+ // `align_to_mut` used to create `mid` in a way that there was some intermediate
+ // incorrect aliasing, invalidating the resulting `mid` slice.
+ let (begin, mid, end) = unsafe { val.align_to_mut::<[u8; 2]>() };
+ assert!(begin.len() == 0);
+ assert!(end.len() == 1);
+ mid[0] = mid[1];
+ assert_eq!(val, [3, 4, 3, 4, 5])
+}
+
+#[test]
+fn test_slice_partition_dedup_by() {
+ let mut slice: [i32; 9] = [1, -1, 2, 3, 1, -5, 5, -2, 2];
+
+ let (dedup, duplicates) = slice.partition_dedup_by(|a, b| a.abs() == b.abs());
+
+ assert_eq!(dedup, [1, 2, 3, 1, -5, -2]);
+ assert_eq!(duplicates, [5, -1, 2]);
+}
+
+#[test]
+fn test_slice_partition_dedup_empty() {
+ let mut slice: [i32; 0] = [];
+
+ let (dedup, duplicates) = slice.partition_dedup();
+
+ assert_eq!(dedup, []);
+ assert_eq!(duplicates, []);
+}
+
+#[test]
+fn test_slice_partition_dedup_one() {
+ let mut slice = [12];
+
+ let (dedup, duplicates) = slice.partition_dedup();
+
+ assert_eq!(dedup, [12]);
+ assert_eq!(duplicates, []);
+}
+
+#[test]
+fn test_slice_partition_dedup_multiple_ident() {
+ let mut slice = [12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11];
+
+ let (dedup, duplicates) = slice.partition_dedup();
+
+ assert_eq!(dedup, [12, 11]);
+ assert_eq!(duplicates, [12, 12, 12, 12, 11, 11, 11, 11, 11]);
+}
+
+#[test]
+fn test_slice_partition_dedup_partialeq() {
+ #[derive(Debug)]
+ struct Foo(i32, i32);
+
+ impl PartialEq for Foo {
+ fn eq(&self, other: &Foo) -> bool {
+ self.0 == other.0
+ }
+ }
+
+ let mut slice = [Foo(0, 1), Foo(0, 5), Foo(1, 7), Foo(1, 9)];
+
+ let (dedup, duplicates) = slice.partition_dedup();
+
+ assert_eq!(dedup, [Foo(0, 1), Foo(1, 7)]);
+ assert_eq!(duplicates, [Foo(0, 5), Foo(1, 9)]);
+}
+
+#[test]
+fn test_copy_within() {
+ // Start to end, with a RangeTo.
+ let mut bytes = *b"Hello, World!";
+ bytes.copy_within(..3, 10);
+ assert_eq!(&bytes, b"Hello, WorHel");
+
+ // End to start, with a RangeFrom.
+ let mut bytes = *b"Hello, World!";
+ bytes.copy_within(10.., 0);
+ assert_eq!(&bytes, b"ld!lo, World!");
+
+ // Overlapping, with a RangeInclusive.
+ let mut bytes = *b"Hello, World!";
+ bytes.copy_within(0..=11, 1);
+ assert_eq!(&bytes, b"HHello, World");
+
+ // Whole slice, with a RangeFull.
+ let mut bytes = *b"Hello, World!";
+ bytes.copy_within(.., 0);
+ assert_eq!(&bytes, b"Hello, World!");
+
+ // Ensure that copying at the end of slice won't cause UB.
+ let mut bytes = *b"Hello, World!";
+ bytes.copy_within(13..13, 5);
+ assert_eq!(&bytes, b"Hello, World!");
+ bytes.copy_within(5..5, 13);
+ assert_eq!(&bytes, b"Hello, World!");
+}
+
+#[test]
+#[should_panic(expected = "range end index 14 out of range for slice of length 13")]
+fn test_copy_within_panics_src_too_long() {
+ let mut bytes = *b"Hello, World!";
+ // The length is only 13, so 14 is out of bounds.
+ bytes.copy_within(10..14, 0);
+}
+
+#[test]
+#[should_panic(expected = "dest is out of bounds")]
+fn test_copy_within_panics_dest_too_long() {
+ let mut bytes = *b"Hello, World!";
+ // The length is only 13, so a slice of length 4 starting at index 10 is out of bounds.
+ bytes.copy_within(0..4, 10);
+}
+
+#[test]
+#[should_panic(expected = "slice index starts at 2 but ends at 1")]
+fn test_copy_within_panics_src_inverted() {
+ let mut bytes = *b"Hello, World!";
+ // 2 is greater than 1, so this range is invalid.
+ bytes.copy_within(2..1, 0);
+}
+#[test]
+#[should_panic(expected = "attempted to index slice up to maximum usize")]
+fn test_copy_within_panics_src_out_of_bounds() {
+ let mut bytes = *b"Hello, World!";
+ // an inclusive range ending at usize::MAX would make src_end overflow
+ bytes.copy_within(usize::MAX..=usize::MAX, 0);
+}
+
+#[test]
+fn test_is_sorted() {
+ let empty: [i32; 0] = [];
+
+ assert!([1, 2, 2, 9].is_sorted());
+ assert!(![1, 3, 2].is_sorted());
+ assert!([0].is_sorted());
+ assert!(empty.is_sorted());
+ assert!(![0.0, 1.0, f32::NAN].is_sorted());
+ assert!([-2, -1, 0, 3].is_sorted());
+ assert!(![-2i32, -1, 0, 3].is_sorted_by_key(|n| n.abs()));
+ assert!(!["c", "bb", "aaa"].is_sorted());
+ assert!(["c", "bb", "aaa"].is_sorted_by_key(|s| s.len()));
+}
+
+#[test]
+fn test_slice_run_destructors() {
+ // Make sure that destructors get run on slice literals
+ struct Foo<'a> {
+ x: &'a Cell<isize>,
+ }
+
+ impl<'a> Drop for Foo<'a> {
+ fn drop(&mut self) {
+ self.x.set(self.x.get() + 1);
+ }
+ }
+
+ fn foo(x: &Cell<isize>) -> Foo<'_> {
+ Foo { x }
+ }
+
+ let x = &Cell::new(0);
+
+ {
+ let l = &[foo(x)];
+ assert_eq!(l[0].x.get(), 0);
+ }
+
+ assert_eq!(x.get(), 1);
+}
+
+#[test]
+fn test_const_from_ref() {
+ const VALUE: &i32 = &1;
+ const SLICE: &[i32] = core::slice::from_ref(VALUE);
+
+ assert!(core::ptr::eq(VALUE, &SLICE[0]))
+}
+
+#[test]
+fn test_slice_fill_with_uninit() {
+ // This should not UB. See #87891
+ let mut a = [MaybeUninit::<u8>::uninit(); 10];
+ a.fill(MaybeUninit::uninit());
+}
+
+#[test]
+fn test_swap() {
+ let mut x = ["a", "b", "c", "d"];
+ x.swap(1, 3);
+ assert_eq!(x, ["a", "d", "c", "b"]);
+ x.swap(0, 3);
+ assert_eq!(x, ["b", "d", "c", "a"]);
+}
+
+mod swap_panics {
+ #[test]
+ #[should_panic(expected = "index out of bounds: the len is 4 but the index is 4")]
+ fn index_a_equals_len() {
+ let mut x = ["a", "b", "c", "d"];
+ x.swap(4, 2);
+ }
+
+ #[test]
+ #[should_panic(expected = "index out of bounds: the len is 4 but the index is 4")]
+ fn index_b_equals_len() {
+ let mut x = ["a", "b", "c", "d"];
+ x.swap(2, 4);
+ }
+
+ #[test]
+ #[should_panic(expected = "index out of bounds: the len is 4 but the index is 5")]
+ fn index_a_greater_than_len() {
+ let mut x = ["a", "b", "c", "d"];
+ x.swap(5, 2);
+ }
+
+ #[test]
+ #[should_panic(expected = "index out of bounds: the len is 4 but the index is 5")]
+ fn index_b_greater_than_len() {
+ let mut x = ["a", "b", "c", "d"];
+ x.swap(2, 5);
+ }
+}
+
+#[test]
+fn slice_split_array_mut() {
+ let v = &mut [1, 2, 3, 4, 5, 6][..];
+
+ {
+ let (left, right) = v.split_array_mut::<0>();
+ assert_eq!(left, &mut []);
+ assert_eq!(right, [1, 2, 3, 4, 5, 6]);
+ }
+
+ {
+ let (left, right) = v.split_array_mut::<6>();
+ assert_eq!(left, &mut [1, 2, 3, 4, 5, 6]);
+ assert_eq!(right, []);
+ }
+}
+
+#[test]
+fn slice_rsplit_array_mut() {
+ let v = &mut [1, 2, 3, 4, 5, 6][..];
+
+ {
+ let (left, right) = v.rsplit_array_mut::<0>();
+ assert_eq!(left, [1, 2, 3, 4, 5, 6]);
+ assert_eq!(right, &mut []);
+ }
+
+ {
+ let (left, right) = v.rsplit_array_mut::<6>();
+ assert_eq!(left, []);
+ assert_eq!(right, &mut [1, 2, 3, 4, 5, 6]);
+ }
+}
+
+#[test]
+fn split_as_slice() {
+ let arr = [1, 2, 3, 4, 5, 6];
+ let mut split = arr.split(|v| v % 2 == 0);
+ assert_eq!(split.as_slice(), &[1, 2, 3, 4, 5, 6]);
+ assert!(split.next().is_some());
+ assert_eq!(split.as_slice(), &[3, 4, 5, 6]);
+ assert!(split.next().is_some());
+ assert!(split.next().is_some());
+ assert_eq!(split.as_slice(), &[]);
+}
+
+#[should_panic]
+#[test]
+fn slice_split_array_ref_out_of_bounds() {
+ let v = &[1, 2, 3, 4, 5, 6][..];
+
+ let _ = v.split_array_ref::<7>();
+}
+
+#[should_panic]
+#[test]
+fn slice_split_array_mut_out_of_bounds() {
+ let v = &mut [1, 2, 3, 4, 5, 6][..];
+
+ let _ = v.split_array_mut::<7>();
+}
+
+#[should_panic]
+#[test]
+fn slice_rsplit_array_ref_out_of_bounds() {
+ let v = &[1, 2, 3, 4, 5, 6][..];
+
+ let _ = v.rsplit_array_ref::<7>();
+}
+
+#[should_panic]
+#[test]
+fn slice_rsplit_array_mut_out_of_bounds() {
+ let v = &mut [1, 2, 3, 4, 5, 6][..];
+
+ let _ = v.rsplit_array_mut::<7>();
+}
+
+macro_rules! take_tests {
+ (slice: &[], $($tts:tt)*) => {
+ take_tests!(ty: &[()], slice: &[], $($tts)*);
+ };
+ (slice: &mut [], $($tts:tt)*) => {
+ take_tests!(ty: &mut [()], slice: &mut [], $($tts)*);
+ };
+ (slice: &$slice:expr, $($tts:tt)*) => {
+ take_tests!(ty: &[_], slice: &$slice, $($tts)*);
+ };
+ (slice: &mut $slice:expr, $($tts:tt)*) => {
+ take_tests!(ty: &mut [_], slice: &mut $slice, $($tts)*);
+ };
+ (ty: $ty:ty, slice: $slice:expr, method: $method:ident, $(($test_name:ident, ($($args:expr),*), $output:expr, $remaining:expr),)*) => {
+ $(
+ #[test]
+ fn $test_name() {
+ let mut slice: $ty = $slice;
+ assert_eq!($output, slice.$method($($args)*));
+ let remaining: $ty = $remaining;
+ assert_eq!(remaining, slice);
+ }
+ )*
+ };
+}
+
+take_tests! {
+ slice: &[0, 1, 2, 3], method: take,
+ (take_in_bounds_range_to, (..1), Some(&[0] as _), &[1, 2, 3]),
+ (take_in_bounds_range_to_inclusive, (..=0), Some(&[0] as _), &[1, 2, 3]),
+ (take_in_bounds_range_from, (2..), Some(&[2, 3] as _), &[0, 1]),
+ (take_oob_range_to, (..5), None, &[0, 1, 2, 3]),
+ (take_oob_range_to_inclusive, (..=4), None, &[0, 1, 2, 3]),
+ (take_oob_range_from, (5..), None, &[0, 1, 2, 3]),
+}
+
+take_tests! {
+ slice: &mut [0, 1, 2, 3], method: take_mut,
+ (take_mut_in_bounds_range_to, (..1), Some(&mut [0] as _), &mut [1, 2, 3]),
+ (take_mut_in_bounds_range_to_inclusive, (..=0), Some(&mut [0] as _), &mut [1, 2, 3]),
+ (take_mut_in_bounds_range_from, (2..), Some(&mut [2, 3] as _), &mut [0, 1]),
+ (take_mut_oob_range_to, (..5), None, &mut [0, 1, 2, 3]),
+ (take_mut_oob_range_to_inclusive, (..=4), None, &mut [0, 1, 2, 3]),
+ (take_mut_oob_range_from, (5..), None, &mut [0, 1, 2, 3]),
+}
+
+take_tests! {
+ slice: &[1, 2], method: take_first,
+ (take_first_nonempty, (), Some(&1), &[2]),
+}
+
+take_tests! {
+ slice: &mut [1, 2], method: take_first_mut,
+ (take_first_mut_nonempty, (), Some(&mut 1), &mut [2]),
+}
+
+take_tests! {
+ slice: &[1, 2], method: take_last,
+ (take_last_nonempty, (), Some(&2), &[1]),
+}
+
+take_tests! {
+ slice: &mut [1, 2], method: take_last_mut,
+ (take_last_mut_nonempty, (), Some(&mut 2), &mut [1]),
+}
+
+take_tests! {
+ slice: &[], method: take_first,
+ (take_first_empty, (), None, &[]),
+}
+
+take_tests! {
+ slice: &mut [], method: take_first_mut,
+ (take_first_mut_empty, (), None, &mut []),
+}
+
+take_tests! {
+ slice: &[], method: take_last,
+ (take_last_empty, (), None, &[]),
+}
+
+take_tests! {
+ slice: &mut [], method: take_last_mut,
+ (take_last_mut_empty, (), None, &mut []),
+}
+
+#[cfg(not(miri))] // unused in Miri
+const EMPTY_MAX: &'static [()] = &[(); usize::MAX];
+
+// can't be a constant due to const mutability rules
+#[cfg(not(miri))] // unused in Miri
+macro_rules! empty_max_mut {
+ () => {
+ &mut [(); usize::MAX] as _
+ };
+}
+
+#[cfg(not(miri))] // Comparing usize::MAX many elements takes forever in Miri (and in rustc without optimizations)
+take_tests! {
+ slice: &[(); usize::MAX], method: take,
+ (take_in_bounds_max_range_to, (..usize::MAX), Some(EMPTY_MAX), &[(); 0]),
+ (take_oob_max_range_to_inclusive, (..=usize::MAX), None, EMPTY_MAX),
+ (take_in_bounds_max_range_from, (usize::MAX..), Some(&[] as _), EMPTY_MAX),
+}
+
+#[cfg(not(miri))] // Comparing usize::MAX many elements takes forever in Miri (and in rustc without optimizations)
+take_tests! {
+ slice: &mut [(); usize::MAX], method: take_mut,
+ (take_mut_in_bounds_max_range_to, (..usize::MAX), Some(empty_max_mut!()), &mut [(); 0]),
+ (take_mut_oob_max_range_to_inclusive, (..=usize::MAX), None, empty_max_mut!()),
+ (take_mut_in_bounds_max_range_from, (usize::MAX..), Some(&mut [] as _), empty_max_mut!()),
+}
+
+#[test]
+fn test_slice_from_ptr_range() {
+ let arr = ["foo".to_owned(), "bar".to_owned()];
+ let range = arr.as_ptr_range();
+ unsafe {
+ assert_eq!(slice::from_ptr_range(range), &arr);
+ }
+
+ let mut arr = [1, 2, 3];
+ let range = arr.as_mut_ptr_range();
+ unsafe {
+ assert_eq!(slice::from_mut_ptr_range(range), &mut [1, 2, 3]);
+ }
+
+ let arr: [Vec<String>; 0] = [];
+ let range = arr.as_ptr_range();
+ unsafe {
+ assert_eq!(slice::from_ptr_range(range), &arr);
+ }
+}
+
+#[test]
+#[should_panic = "slice len overflow"]
+fn test_flatten_size_overflow() {
+ let x = &[[(); usize::MAX]; 2][..];
+ let _ = x.flatten();
+}
+
+#[test]
+#[should_panic = "slice len overflow"]
+fn test_flatten_mut_size_overflow() {
+ let x = &mut [[(); usize::MAX]; 2][..];
+ let _ = x.flatten_mut();
+}
diff --git a/library/core/tests/str.rs b/library/core/tests/str.rs
new file mode 100644
index 000000000..ed939ca71
--- /dev/null
+++ b/library/core/tests/str.rs
@@ -0,0 +1 @@
+// All `str` tests live in liballoc/tests
diff --git a/library/core/tests/str_lossy.rs b/library/core/tests/str_lossy.rs
new file mode 100644
index 000000000..d4b47a470
--- /dev/null
+++ b/library/core/tests/str_lossy.rs
@@ -0,0 +1,85 @@
+use core::str::lossy::*;
+
+#[test]
+fn chunks() {
+ let mut iter = Utf8Lossy::from_bytes(b"hello").chunks();
+ assert_eq!(Some(Utf8LossyChunk { valid: "hello", broken: b"" }), iter.next());
+ assert_eq!(None, iter.next());
+
+ let mut iter = Utf8Lossy::from_bytes("ศไทย中华Việt Nam".as_bytes()).chunks();
+ assert_eq!(Some(Utf8LossyChunk { valid: "ศไทย中华Việt Nam", broken: b"" }), iter.next());
+ assert_eq!(None, iter.next());
+
+ let mut iter = Utf8Lossy::from_bytes(b"Hello\xC2 There\xFF Goodbye").chunks();
+ assert_eq!(Some(Utf8LossyChunk { valid: "Hello", broken: b"\xC2" }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: " There", broken: b"\xFF" }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: " Goodbye", broken: b"" }), iter.next());
+ assert_eq!(None, iter.next());
+
+ let mut iter = Utf8Lossy::from_bytes(b"Hello\xC0\x80 There\xE6\x83 Goodbye").chunks();
+ assert_eq!(Some(Utf8LossyChunk { valid: "Hello", broken: b"\xC0" }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80" }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: " There", broken: b"\xE6\x83" }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: " Goodbye", broken: b"" }), iter.next());
+ assert_eq!(None, iter.next());
+
+ let mut iter = Utf8Lossy::from_bytes(b"\xF5foo\xF5\x80bar").chunks();
+ assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xF5" }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "foo", broken: b"\xF5" }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80" }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "bar", broken: b"" }), iter.next());
+ assert_eq!(None, iter.next());
+
+ let mut iter = Utf8Lossy::from_bytes(b"\xF1foo\xF1\x80bar\xF1\x80\x80baz").chunks();
+ assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xF1" }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "foo", broken: b"\xF1\x80" }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "bar", broken: b"\xF1\x80\x80" }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "baz", broken: b"" }), iter.next());
+ assert_eq!(None, iter.next());
+
+ let mut iter = Utf8Lossy::from_bytes(b"\xF4foo\xF4\x80bar\xF4\xBFbaz").chunks();
+ assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xF4" }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "foo", broken: b"\xF4\x80" }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "bar", broken: b"\xF4" }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xBF" }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "baz", broken: b"" }), iter.next());
+ assert_eq!(None, iter.next());
+
+ let mut iter = Utf8Lossy::from_bytes(b"\xF0\x80\x80\x80foo\xF0\x90\x80\x80bar").chunks();
+ assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xF0" }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80" }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80" }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80" }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "foo\u{10000}bar", broken: b"" }), iter.next());
+ assert_eq!(None, iter.next());
+
+ // surrogates
+ let mut iter = Utf8Lossy::from_bytes(b"\xED\xA0\x80foo\xED\xBF\xBFbar").chunks();
+ assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xED" }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xA0" }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80" }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "foo", broken: b"\xED" }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xBF" }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xBF" }), iter.next());
+ assert_eq!(Some(Utf8LossyChunk { valid: "bar", broken: b"" }), iter.next());
+ assert_eq!(None, iter.next());
+}
+
+#[test]
+fn display() {
+ assert_eq!(
+ "Hello\u{FFFD}\u{FFFD} There\u{FFFD} Goodbye",
+ &Utf8Lossy::from_bytes(b"Hello\xC0\x80 There\xE6\x83 Goodbye").to_string()
+ );
+}
+
+#[test]
+fn debug() {
+ assert_eq!(
+ "\"Hello\\xc0\\x80 There\\xe6\\x83 Goodbye\\u{10d4ea}\"",
+ &format!(
+ "{:?}",
+ Utf8Lossy::from_bytes(b"Hello\xC0\x80 There\xE6\x83 Goodbye\xf4\x8d\x93\xaa")
+ )
+ );
+}
diff --git a/library/core/tests/task.rs b/library/core/tests/task.rs
new file mode 100644
index 000000000..d71fef9e5
--- /dev/null
+++ b/library/core/tests/task.rs
@@ -0,0 +1,14 @@
+use core::task::Poll;
+
+#[test]
+fn poll_const() {
+ // test that the methods of `Poll` are usable in a const context
+
+ const POLL: Poll<usize> = Poll::Pending;
+
+ const IS_READY: bool = POLL.is_ready();
+ assert!(!IS_READY);
+
+ const IS_PENDING: bool = POLL.is_pending();
+ assert!(IS_PENDING);
+}
diff --git a/library/core/tests/time.rs b/library/core/tests/time.rs
new file mode 100644
index 000000000..fe2d2f241
--- /dev/null
+++ b/library/core/tests/time.rs
@@ -0,0 +1,447 @@
+use core::time::Duration;
+
+#[test]
+fn creation() {
+ assert_ne!(Duration::from_secs(1), Duration::from_secs(0));
+ assert_eq!(Duration::from_secs(1) + Duration::from_secs(2), Duration::from_secs(3));
+ assert_eq!(
+ Duration::from_millis(10) + Duration::from_secs(4),
+ Duration::new(4, 10 * 1_000_000)
+ );
+ assert_eq!(Duration::from_millis(4000), Duration::new(4, 0));
+}
+
+#[test]
+#[should_panic]
+fn new_overflow() {
+ let _ = Duration::new(u64::MAX, 1_000_000_000);
+}
+
+#[test]
+fn secs() {
+ assert_eq!(Duration::new(0, 0).as_secs(), 0);
+ assert_eq!(Duration::new(0, 500_000_005).as_secs(), 0);
+ assert_eq!(Duration::new(0, 1_050_000_001).as_secs(), 1);
+ assert_eq!(Duration::from_secs(1).as_secs(), 1);
+ assert_eq!(Duration::from_millis(999).as_secs(), 0);
+ assert_eq!(Duration::from_millis(1001).as_secs(), 1);
+ assert_eq!(Duration::from_micros(999_999).as_secs(), 0);
+ assert_eq!(Duration::from_micros(1_000_001).as_secs(), 1);
+ assert_eq!(Duration::from_nanos(999_999_999).as_secs(), 0);
+ assert_eq!(Duration::from_nanos(1_000_000_001).as_secs(), 1);
+}
+
+#[test]
+fn millis() {
+ assert_eq!(Duration::new(0, 0).subsec_millis(), 0);
+ assert_eq!(Duration::new(0, 500_000_005).subsec_millis(), 500);
+ assert_eq!(Duration::new(0, 1_050_000_001).subsec_millis(), 50);
+ assert_eq!(Duration::from_secs(1).subsec_millis(), 0);
+ assert_eq!(Duration::from_millis(999).subsec_millis(), 999);
+ assert_eq!(Duration::from_millis(1001).subsec_millis(), 1);
+ assert_eq!(Duration::from_micros(999_999).subsec_millis(), 999);
+ assert_eq!(Duration::from_micros(1_001_000).subsec_millis(), 1);
+ assert_eq!(Duration::from_nanos(999_999_999).subsec_millis(), 999);
+ assert_eq!(Duration::from_nanos(1_001_000_000).subsec_millis(), 1);
+}
+
+#[test]
+fn micros() {
+ assert_eq!(Duration::new(0, 0).subsec_micros(), 0);
+ assert_eq!(Duration::new(0, 500_000_005).subsec_micros(), 500_000);
+ assert_eq!(Duration::new(0, 1_050_000_001).subsec_micros(), 50_000);
+ assert_eq!(Duration::from_secs(1).subsec_micros(), 0);
+ assert_eq!(Duration::from_millis(999).subsec_micros(), 999_000);
+ assert_eq!(Duration::from_millis(1001).subsec_micros(), 1_000);
+ assert_eq!(Duration::from_micros(999_999).subsec_micros(), 999_999);
+ assert_eq!(Duration::from_micros(1_000_001).subsec_micros(), 1);
+ assert_eq!(Duration::from_nanos(999_999_999).subsec_micros(), 999_999);
+ assert_eq!(Duration::from_nanos(1_000_001_000).subsec_micros(), 1);
+}
+
+#[test]
+fn nanos() {
+ assert_eq!(Duration::new(0, 0).subsec_nanos(), 0);
+ assert_eq!(Duration::new(0, 5).subsec_nanos(), 5);
+ assert_eq!(Duration::new(0, 1_000_000_001).subsec_nanos(), 1);
+ assert_eq!(Duration::from_secs(1).subsec_nanos(), 0);
+ assert_eq!(Duration::from_millis(999).subsec_nanos(), 999_000_000);
+ assert_eq!(Duration::from_millis(1001).subsec_nanos(), 1_000_000);
+ assert_eq!(Duration::from_micros(999_999).subsec_nanos(), 999_999_000);
+ assert_eq!(Duration::from_micros(1_000_001).subsec_nanos(), 1000);
+ assert_eq!(Duration::from_nanos(999_999_999).subsec_nanos(), 999_999_999);
+ assert_eq!(Duration::from_nanos(1_000_000_001).subsec_nanos(), 1);
+}
+
+#[test]
+fn add() {
+ assert_eq!(Duration::new(0, 0) + Duration::new(0, 1), Duration::new(0, 1));
+ assert_eq!(Duration::new(0, 500_000_000) + Duration::new(0, 500_000_001), Duration::new(1, 1));
+}
+
+#[test]
+fn checked_add() {
+ assert_eq!(Duration::new(0, 0).checked_add(Duration::new(0, 1)), Some(Duration::new(0, 1)));
+ assert_eq!(
+ Duration::new(0, 500_000_000).checked_add(Duration::new(0, 500_000_001)),
+ Some(Duration::new(1, 1))
+ );
+ assert_eq!(Duration::new(1, 0).checked_add(Duration::new(u64::MAX, 0)), None);
+}
+
+#[test]
+fn saturating_add() {
+ assert_eq!(Duration::new(0, 0).saturating_add(Duration::new(0, 1)), Duration::new(0, 1));
+ assert_eq!(
+ Duration::new(0, 500_000_000).saturating_add(Duration::new(0, 500_000_001)),
+ Duration::new(1, 1)
+ );
+ assert_eq!(Duration::new(1, 0).saturating_add(Duration::new(u64::MAX, 0)), Duration::MAX);
+}
+
+#[test]
+fn sub() {
+ assert_eq!(Duration::new(0, 1) - Duration::new(0, 0), Duration::new(0, 1));
+ assert_eq!(Duration::new(0, 500_000_001) - Duration::new(0, 500_000_000), Duration::new(0, 1));
+ assert_eq!(Duration::new(1, 0) - Duration::new(0, 1), Duration::new(0, 999_999_999));
+}
+
+#[test]
+fn checked_sub() {
+ assert_eq!(Duration::NANOSECOND.checked_sub(Duration::ZERO), Some(Duration::NANOSECOND));
+ assert_eq!(
+ Duration::SECOND.checked_sub(Duration::NANOSECOND),
+ Some(Duration::new(0, 999_999_999))
+ );
+ assert_eq!(Duration::ZERO.checked_sub(Duration::NANOSECOND), None);
+ assert_eq!(Duration::ZERO.checked_sub(Duration::SECOND), None);
+}
+
+#[test]
+fn saturating_sub() {
+ assert_eq!(Duration::NANOSECOND.saturating_sub(Duration::ZERO), Duration::NANOSECOND);
+ assert_eq!(
+ Duration::SECOND.saturating_sub(Duration::NANOSECOND),
+ Duration::new(0, 999_999_999)
+ );
+ assert_eq!(Duration::ZERO.saturating_sub(Duration::NANOSECOND), Duration::ZERO);
+ assert_eq!(Duration::ZERO.saturating_sub(Duration::SECOND), Duration::ZERO);
+}
+
+#[test]
+#[should_panic]
+fn sub_bad1() {
+ let _ = Duration::new(0, 0) - Duration::new(0, 1);
+}
+
+#[test]
+#[should_panic]
+fn sub_bad2() {
+ let _ = Duration::new(0, 0) - Duration::new(1, 0);
+}
+
+#[test]
+fn mul() {
+ assert_eq!(Duration::new(0, 1) * 2, Duration::new(0, 2));
+ assert_eq!(Duration::new(1, 1) * 3, Duration::new(3, 3));
+ assert_eq!(Duration::new(0, 500_000_001) * 4, Duration::new(2, 4));
+ assert_eq!(Duration::new(0, 500_000_001) * 4000, Duration::new(2000, 4000));
+}
+
+#[test]
+fn checked_mul() {
+ assert_eq!(Duration::new(0, 1).checked_mul(2), Some(Duration::new(0, 2)));
+ assert_eq!(Duration::new(1, 1).checked_mul(3), Some(Duration::new(3, 3)));
+ assert_eq!(Duration::new(0, 500_000_001).checked_mul(4), Some(Duration::new(2, 4)));
+ assert_eq!(Duration::new(0, 500_000_001).checked_mul(4000), Some(Duration::new(2000, 4000)));
+ assert_eq!(Duration::new(u64::MAX - 1, 0).checked_mul(2), None);
+}
+
+#[test]
+fn saturating_mul() {
+ assert_eq!(Duration::new(0, 1).saturating_mul(2), Duration::new(0, 2));
+ assert_eq!(Duration::new(1, 1).saturating_mul(3), Duration::new(3, 3));
+ assert_eq!(Duration::new(0, 500_000_001).saturating_mul(4), Duration::new(2, 4));
+ assert_eq!(Duration::new(0, 500_000_001).saturating_mul(4000), Duration::new(2000, 4000));
+ assert_eq!(Duration::new(u64::MAX - 1, 0).saturating_mul(2), Duration::MAX);
+}
+
+#[test]
+fn div() {
+ assert_eq!(Duration::new(0, 1) / 2, Duration::new(0, 0));
+ assert_eq!(Duration::new(1, 1) / 3, Duration::new(0, 333_333_333));
+ assert_eq!(Duration::new(99, 999_999_000) / 100, Duration::new(0, 999_999_990));
+}
+
+#[test]
+fn checked_div() {
+ assert_eq!(Duration::new(2, 0).checked_div(2), Some(Duration::new(1, 0)));
+ assert_eq!(Duration::new(1, 0).checked_div(2), Some(Duration::new(0, 500_000_000)));
+ assert_eq!(Duration::new(2, 0).checked_div(0), None);
+}
+
+#[test]
+fn correct_sum() {
+ let durations = [
+ Duration::new(1, 999_999_999),
+ Duration::new(2, 999_999_999),
+ Duration::new(0, 999_999_999),
+ Duration::new(0, 999_999_999),
+ Duration::new(0, 999_999_999),
+ Duration::new(5, 0),
+ ];
+ let sum = durations.iter().sum::<Duration>();
+ assert_eq!(sum, Duration::new(1 + 2 + 5 + 4, 1_000_000_000 - 5));
+}
+
+#[test]
+fn debug_formatting_extreme_values() {
+ assert_eq!(
+ format!("{:?}", Duration::new(18_446_744_073_709_551_615, 123_456_789)),
+ "18446744073709551615.123456789s"
+ );
+}
+
+#[test]
+fn debug_formatting_secs() {
+ assert_eq!(format!("{:?}", Duration::new(7, 000_000_000)), "7s");
+ assert_eq!(format!("{:?}", Duration::new(7, 100_000_000)), "7.1s");
+ assert_eq!(format!("{:?}", Duration::new(7, 000_010_000)), "7.00001s");
+ assert_eq!(format!("{:?}", Duration::new(7, 000_000_001)), "7.000000001s");
+ assert_eq!(format!("{:?}", Duration::new(7, 123_456_789)), "7.123456789s");
+
+ assert_eq!(format!("{:?}", Duration::new(88, 000_000_000)), "88s");
+ assert_eq!(format!("{:?}", Duration::new(88, 100_000_000)), "88.1s");
+ assert_eq!(format!("{:?}", Duration::new(88, 000_010_000)), "88.00001s");
+ assert_eq!(format!("{:?}", Duration::new(88, 000_000_001)), "88.000000001s");
+ assert_eq!(format!("{:?}", Duration::new(88, 123_456_789)), "88.123456789s");
+
+ assert_eq!(format!("{:?}", Duration::new(999, 000_000_000)), "999s");
+ assert_eq!(format!("{:?}", Duration::new(999, 100_000_000)), "999.1s");
+ assert_eq!(format!("{:?}", Duration::new(999, 000_010_000)), "999.00001s");
+ assert_eq!(format!("{:?}", Duration::new(999, 000_000_001)), "999.000000001s");
+ assert_eq!(format!("{:?}", Duration::new(999, 123_456_789)), "999.123456789s");
+}
+
+#[test]
+fn debug_formatting_millis() {
+ assert_eq!(format!("{:?}", Duration::new(0, 7_000_000)), "7ms");
+ assert_eq!(format!("{:?}", Duration::new(0, 7_100_000)), "7.1ms");
+ assert_eq!(format!("{:?}", Duration::new(0, 7_000_001)), "7.000001ms");
+ assert_eq!(format!("{:?}", Duration::new(0, 7_123_456)), "7.123456ms");
+
+ assert_eq!(format!("{:?}", Duration::new(0, 88_000_000)), "88ms");
+ assert_eq!(format!("{:?}", Duration::new(0, 88_100_000)), "88.1ms");
+ assert_eq!(format!("{:?}", Duration::new(0, 88_000_001)), "88.000001ms");
+ assert_eq!(format!("{:?}", Duration::new(0, 88_123_456)), "88.123456ms");
+
+ assert_eq!(format!("{:?}", Duration::new(0, 999_000_000)), "999ms");
+ assert_eq!(format!("{:?}", Duration::new(0, 999_100_000)), "999.1ms");
+ assert_eq!(format!("{:?}", Duration::new(0, 999_000_001)), "999.000001ms");
+ assert_eq!(format!("{:?}", Duration::new(0, 999_123_456)), "999.123456ms");
+}
+
+#[test]
+fn debug_formatting_micros() {
+ assert_eq!(format!("{:?}", Duration::new(0, 7_000)), "7µs");
+ assert_eq!(format!("{:?}", Duration::new(0, 7_100)), "7.1µs");
+ assert_eq!(format!("{:?}", Duration::new(0, 7_001)), "7.001µs");
+ assert_eq!(format!("{:?}", Duration::new(0, 7_123)), "7.123µs");
+
+ assert_eq!(format!("{:?}", Duration::new(0, 88_000)), "88µs");
+ assert_eq!(format!("{:?}", Duration::new(0, 88_100)), "88.1µs");
+ assert_eq!(format!("{:?}", Duration::new(0, 88_001)), "88.001µs");
+ assert_eq!(format!("{:?}", Duration::new(0, 88_123)), "88.123µs");
+
+ assert_eq!(format!("{:?}", Duration::new(0, 999_000)), "999µs");
+ assert_eq!(format!("{:?}", Duration::new(0, 999_100)), "999.1µs");
+ assert_eq!(format!("{:?}", Duration::new(0, 999_001)), "999.001µs");
+ assert_eq!(format!("{:?}", Duration::new(0, 999_123)), "999.123µs");
+}
+
+#[test]
+fn debug_formatting_nanos() {
+ assert_eq!(format!("{:?}", Duration::new(0, 0)), "0ns");
+ assert_eq!(format!("{:?}", Duration::new(0, 1)), "1ns");
+ assert_eq!(format!("{:?}", Duration::new(0, 88)), "88ns");
+ assert_eq!(format!("{:?}", Duration::new(0, 999)), "999ns");
+}
+
+#[test]
+fn debug_formatting_precision_zero() {
+ assert_eq!(format!("{:.0?}", Duration::new(0, 0)), "0ns");
+ assert_eq!(format!("{:.0?}", Duration::new(0, 123)), "123ns");
+
+ assert_eq!(format!("{:.0?}", Duration::new(0, 1_001)), "1µs");
+ assert_eq!(format!("{:.0?}", Duration::new(0, 1_499)), "1µs");
+ assert_eq!(format!("{:.0?}", Duration::new(0, 1_500)), "2µs");
+ assert_eq!(format!("{:.0?}", Duration::new(0, 1_999)), "2µs");
+
+ assert_eq!(format!("{:.0?}", Duration::new(0, 1_000_001)), "1ms");
+ assert_eq!(format!("{:.0?}", Duration::new(0, 1_499_999)), "1ms");
+ assert_eq!(format!("{:.0?}", Duration::new(0, 1_500_000)), "2ms");
+ assert_eq!(format!("{:.0?}", Duration::new(0, 1_999_999)), "2ms");
+
+ assert_eq!(format!("{:.0?}", Duration::new(1, 000_000_001)), "1s");
+ assert_eq!(format!("{:.0?}", Duration::new(1, 499_999_999)), "1s");
+ assert_eq!(format!("{:.0?}", Duration::new(1, 500_000_000)), "2s");
+ assert_eq!(format!("{:.0?}", Duration::new(1, 999_999_999)), "2s");
+}
+
+#[test]
+fn debug_formatting_precision_two() {
+ assert_eq!(format!("{:.2?}", Duration::new(0, 0)), "0.00ns");
+ assert_eq!(format!("{:.2?}", Duration::new(0, 123)), "123.00ns");
+
+ assert_eq!(format!("{:.2?}", Duration::new(0, 1_000)), "1.00µs");
+ assert_eq!(format!("{:.2?}", Duration::new(0, 7_001)), "7.00µs");
+ assert_eq!(format!("{:.2?}", Duration::new(0, 7_100)), "7.10µs");
+ assert_eq!(format!("{:.2?}", Duration::new(0, 7_109)), "7.11µs");
+ assert_eq!(format!("{:.2?}", Duration::new(0, 7_199)), "7.20µs");
+ assert_eq!(format!("{:.2?}", Duration::new(0, 1_999)), "2.00µs");
+
+ assert_eq!(format!("{:.2?}", Duration::new(0, 1_000_000)), "1.00ms");
+ assert_eq!(format!("{:.2?}", Duration::new(0, 3_001_000)), "3.00ms");
+ assert_eq!(format!("{:.2?}", Duration::new(0, 3_100_000)), "3.10ms");
+ assert_eq!(format!("{:.2?}", Duration::new(0, 1_999_999)), "2.00ms");
+
+ assert_eq!(format!("{:.2?}", Duration::new(1, 000_000_000)), "1.00s");
+ assert_eq!(format!("{:.2?}", Duration::new(4, 001_000_000)), "4.00s");
+ assert_eq!(format!("{:.2?}", Duration::new(2, 100_000_000)), "2.10s");
+ assert_eq!(format!("{:.2?}", Duration::new(2, 104_990_000)), "2.10s");
+ assert_eq!(format!("{:.2?}", Duration::new(2, 105_000_000)), "2.11s");
+ assert_eq!(format!("{:.2?}", Duration::new(8, 999_999_999)), "9.00s");
+}
+
+#[test]
+fn debug_formatting_padding() {
+ assert_eq!("0ns ", format!("{:<9?}", Duration::new(0, 0)));
+ assert_eq!(" 0ns", format!("{:>9?}", Duration::new(0, 0)));
+ assert_eq!(" 0ns ", format!("{:^9?}", Duration::new(0, 0)));
+ assert_eq!("123ns ", format!("{:<9.0?}", Duration::new(0, 123)));
+ assert_eq!(" 123ns", format!("{:>9.0?}", Duration::new(0, 123)));
+ assert_eq!(" 123ns ", format!("{:^9.0?}", Duration::new(0, 123)));
+ assert_eq!("123.0ns ", format!("{:<9.1?}", Duration::new(0, 123)));
+ assert_eq!(" 123.0ns", format!("{:>9.1?}", Duration::new(0, 123)));
+ assert_eq!(" 123.0ns ", format!("{:^9.1?}", Duration::new(0, 123)));
+ assert_eq!("7.1µs ", format!("{:<9?}", Duration::new(0, 7_100)));
+ assert_eq!(" 7.1µs", format!("{:>9?}", Duration::new(0, 7_100)));
+ assert_eq!(" 7.1µs ", format!("{:^9?}", Duration::new(0, 7_100)));
+ assert_eq!("999.123456ms", format!("{:<9?}", Duration::new(0, 999_123_456)));
+ assert_eq!("999.123456ms", format!("{:>9?}", Duration::new(0, 999_123_456)));
+ assert_eq!("999.123456ms", format!("{:^9?}", Duration::new(0, 999_123_456)));
+ assert_eq!("5s ", format!("{:<9?}", Duration::new(5, 0)));
+ assert_eq!(" 5s", format!("{:>9?}", Duration::new(5, 0)));
+ assert_eq!(" 5s ", format!("{:^9?}", Duration::new(5, 0)));
+ assert_eq!("5.000000000000s", format!("{:<9.12?}", Duration::new(5, 0)));
+ assert_eq!("5.000000000000s", format!("{:>9.12?}", Duration::new(5, 0)));
+ assert_eq!("5.000000000000s", format!("{:^9.12?}", Duration::new(5, 0)));
+
+ // default alignment is left:
+ assert_eq!("5s ", format!("{:9?}", Duration::new(5, 0)));
+}
+
+#[test]
+fn debug_formatting_precision_high() {
+ assert_eq!(format!("{:.5?}", Duration::new(0, 23_678)), "23.67800µs");
+
+ assert_eq!(format!("{:.9?}", Duration::new(1, 000_000_000)), "1.000000000s");
+ assert_eq!(format!("{:.10?}", Duration::new(4, 001_000_000)), "4.0010000000s");
+ assert_eq!(format!("{:.20?}", Duration::new(4, 001_000_000)), "4.00100000000000000000s");
+}
+
+#[test]
+fn duration_const() {
+ // test that the methods of `Duration` are usable in a const context
+
+ const DURATION: Duration = Duration::new(0, 123_456_789);
+
+ const SUB_SEC_MILLIS: u32 = DURATION.subsec_millis();
+ assert_eq!(SUB_SEC_MILLIS, 123);
+
+ const SUB_SEC_MICROS: u32 = DURATION.subsec_micros();
+ assert_eq!(SUB_SEC_MICROS, 123_456);
+
+ const SUB_SEC_NANOS: u32 = DURATION.subsec_nanos();
+ assert_eq!(SUB_SEC_NANOS, 123_456_789);
+
+ const IS_ZERO: bool = Duration::ZERO.is_zero();
+ assert!(IS_ZERO);
+
+ const SECONDS: u64 = Duration::SECOND.as_secs();
+ assert_eq!(SECONDS, 1);
+
+ const FROM_SECONDS: Duration = Duration::from_secs(1);
+ assert_eq!(FROM_SECONDS, Duration::SECOND);
+
+ const SECONDS_F32: f32 = Duration::SECOND.as_secs_f32();
+ assert_eq!(SECONDS_F32, 1.0);
+
+ const FROM_SECONDS_F32: Duration = Duration::from_secs_f32(1.0);
+ assert_eq!(FROM_SECONDS_F32, Duration::SECOND);
+
+ const SECONDS_F64: f64 = Duration::SECOND.as_secs_f64();
+ assert_eq!(SECONDS_F64, 1.0);
+
+ const FROM_SECONDS_F64: Duration = Duration::from_secs_f64(1.0);
+ assert_eq!(FROM_SECONDS_F64, Duration::SECOND);
+
+ const MILLIS: u128 = Duration::SECOND.as_millis();
+ assert_eq!(MILLIS, 1_000);
+
+ const FROM_MILLIS: Duration = Duration::from_millis(1_000);
+ assert_eq!(FROM_MILLIS, Duration::SECOND);
+
+ const MICROS: u128 = Duration::SECOND.as_micros();
+ assert_eq!(MICROS, 1_000_000);
+
+ const FROM_MICROS: Duration = Duration::from_micros(1_000_000);
+ assert_eq!(FROM_MICROS, Duration::SECOND);
+
+ const NANOS: u128 = Duration::SECOND.as_nanos();
+ assert_eq!(NANOS, 1_000_000_000);
+
+ const FROM_NANOS: Duration = Duration::from_nanos(1_000_000_000);
+ assert_eq!(FROM_NANOS, Duration::SECOND);
+
+ const MAX: Duration = Duration::new(u64::MAX, 999_999_999);
+
+ const CHECKED_ADD: Option<Duration> = MAX.checked_add(Duration::SECOND);
+ assert_eq!(CHECKED_ADD, None);
+
+ const CHECKED_SUB: Option<Duration> = Duration::ZERO.checked_sub(Duration::SECOND);
+ assert_eq!(CHECKED_SUB, None);
+
+ const CHECKED_MUL: Option<Duration> = Duration::SECOND.checked_mul(1);
+ assert_eq!(CHECKED_MUL, Some(Duration::SECOND));
+
+ const MUL_F32: Duration = Duration::SECOND.mul_f32(1.0);
+ assert_eq!(MUL_F32, Duration::SECOND);
+
+ const MUL_F64: Duration = Duration::SECOND.mul_f64(1.0);
+ assert_eq!(MUL_F64, Duration::SECOND);
+
+ const CHECKED_DIV: Option<Duration> = Duration::SECOND.checked_div(1);
+ assert_eq!(CHECKED_DIV, Some(Duration::SECOND));
+
+ const DIV_F32: Duration = Duration::SECOND.div_f32(1.0);
+ assert_eq!(DIV_F32, Duration::SECOND);
+
+ const DIV_F64: Duration = Duration::SECOND.div_f64(1.0);
+ assert_eq!(DIV_F64, Duration::SECOND);
+
+ const DIV_DURATION_F32: f32 = Duration::SECOND.div_duration_f32(Duration::SECOND);
+ assert_eq!(DIV_DURATION_F32, 1.0);
+
+ const DIV_DURATION_F64: f64 = Duration::SECOND.div_duration_f64(Duration::SECOND);
+ assert_eq!(DIV_DURATION_F64, 1.0);
+
+ const SATURATING_ADD: Duration = MAX.saturating_add(Duration::SECOND);
+ assert_eq!(SATURATING_ADD, MAX);
+
+ const SATURATING_SUB: Duration = Duration::ZERO.saturating_sub(Duration::SECOND);
+ assert_eq!(SATURATING_SUB, Duration::ZERO);
+
+ const SATURATING_MUL: Duration = MAX.saturating_mul(2);
+ assert_eq!(SATURATING_MUL, MAX);
+}
diff --git a/library/core/tests/tuple.rs b/library/core/tests/tuple.rs
new file mode 100644
index 000000000..ea1e28142
--- /dev/null
+++ b/library/core/tests/tuple.rs
@@ -0,0 +1,61 @@
+use std::cmp::Ordering::{Equal, Greater, Less};
+
+#[test]
+fn test_clone() {
+ let a = (1, "2");
+ let b = a.clone();
+ assert_eq!(a, b);
+}
+
+#[test]
+fn test_partial_eq() {
+ let (small, big) = ((1, 2, 3), (3, 2, 1));
+ assert_eq!(small, small);
+ assert_eq!(big, big);
+ assert_ne!(small, big);
+ assert_ne!(big, small);
+}
+
+#[test]
+fn test_partial_ord() {
+ let (small, big) = ((1, 2, 3), (3, 2, 1));
+
+ assert!(small < big);
+ assert!(!(small < small));
+ assert!(!(big < small));
+ assert!(!(big < big));
+
+ assert!(small <= small);
+ assert!(big <= big);
+
+ assert!(big > small);
+ assert!(small >= small);
+ assert!(big >= small);
+ assert!(big >= big);
+
+ assert!(!((1.0f64, 2.0f64) < (f64::NAN, 3.0)));
+ assert!(!((1.0f64, 2.0f64) <= (f64::NAN, 3.0)));
+ assert!(!((1.0f64, 2.0f64) > (f64::NAN, 3.0)));
+ assert!(!((1.0f64, 2.0f64) >= (f64::NAN, 3.0)));
+ assert!(((1.0f64, 2.0f64) < (2.0, f64::NAN)));
+ assert!(!((2.0f64, 2.0f64) < (2.0, f64::NAN)));
+}
+
+#[test]
+fn test_ord() {
+ let (small, big) = ((1, 2, 3), (3, 2, 1));
+ assert_eq!(small.cmp(&small), Equal);
+ assert_eq!(big.cmp(&big), Equal);
+ assert_eq!(small.cmp(&big), Less);
+ assert_eq!(big.cmp(&small), Greater);
+}
+
+#[test]
+fn test_show() {
+ let s = format!("{:?}", (1,));
+ assert_eq!(s, "(1,)");
+ let s = format!("{:?}", (1, true));
+ assert_eq!(s, "(1, true)");
+ let s = format!("{:?}", (1, "hi", true));
+ assert_eq!(s, "(1, \"hi\", true)");
+}
diff --git a/library/core/tests/unicode.rs b/library/core/tests/unicode.rs
new file mode 100644
index 000000000..bbace0ef6
--- /dev/null
+++ b/library/core/tests/unicode.rs
@@ -0,0 +1,5 @@
+#[test]
+pub fn version() {
+ let (major, _minor, _update) = core::char::UNICODE_VERSION;
+ assert!(major >= 10);
+}
diff --git a/library/core/tests/waker.rs b/library/core/tests/waker.rs
new file mode 100644
index 000000000..38a3a0ada
--- /dev/null
+++ b/library/core/tests/waker.rs
@@ -0,0 +1,22 @@
+use std::ptr;
+use std::task::{RawWaker, RawWakerVTable, Waker};
+
+#[test]
+fn test_waker_getters() {
+ let raw_waker = RawWaker::new(ptr::invalid_mut(42usize), &WAKER_VTABLE);
+ assert_eq!(raw_waker.data() as usize, 42);
+ assert!(ptr::eq(raw_waker.vtable(), &WAKER_VTABLE));
+
+ let waker = unsafe { Waker::from_raw(raw_waker) };
+ let waker2 = waker.clone();
+ let raw_waker2 = waker2.as_raw();
+ assert_eq!(raw_waker2.data() as usize, 43);
+ assert!(ptr::eq(raw_waker2.vtable(), &WAKER_VTABLE));
+}
+
+static WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(
+ |data| RawWaker::new(ptr::invalid_mut(data as usize + 1), &WAKER_VTABLE),
+ |_| {},
+ |_| {},
+ |_| {},
+);