| use core::array::{self, IntoIter}; |
| use core::convert::TryFrom; |
| |
| #[test] |
| fn array_from_ref() { |
| let value: String = "Hello World!".into(); |
| let arr: &[String; 1] = array::from_ref(&value); |
| assert_eq!(&[value.clone()], arr); |
| } |
| |
| #[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 array: Array = [0; $N]; |
| let slice: &[u8] = &array[..]; |
| |
| let result = <&Array>::try_from(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<_> = IntoIter::new(arr.clone()).collect(); |
| assert_eq!(&arr[..], &v[..]); |
| } |
| |
| #[test] |
| fn iterator_rev_collect() { |
| let arr = [0, 1, 2, 5, 9]; |
| let v: Vec<_> = IntoIter::new(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!(IntoIter::new(v.clone()).nth(i).unwrap(), v[i]); |
| } |
| assert_eq!(IntoIter::new(v.clone()).nth(v.len()), None); |
| |
| let mut iter = IntoIter::new(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!(IntoIter::new(v).last().unwrap(), 4); |
| assert_eq!(IntoIter::new([0]).last().unwrap(), 0); |
| |
| let mut it = IntoIter::new([0, 9, 2, 4]); |
| assert_eq!(it.next_back(), Some(4)); |
| assert_eq!(it.last(), Some(2)); |
| } |
| |
| #[test] |
| fn iterator_clone() { |
| let mut it = IntoIter::new([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 = IntoIter::new([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 = IntoIter::new([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 = IntoIter::new([] 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!(IntoIter::new(v.clone()).count(), 5); |
| |
| let mut iter2 = IntoIter::new(v); |
| iter2.next(); |
| iter2.next(); |
| assert_eq!(iter2.count(), 3); |
| } |
| |
| #[test] |
| fn iterator_flat_map() { |
| assert!((0..5).flat_map(|i| IntoIter::new([2 * i, 2 * i + 1])).eq(0..10)); |
| } |
| |
| #[test] |
| fn iterator_debug() { |
| let arr = [0, 1, 2, 5, 9]; |
| assert_eq!(format!("{:?}", IntoIter::new(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); |
| { |
| IntoIter::new(five(&i)); |
| } |
| assert_eq!(i.get(), 5); |
| |
| // Call `next()` once. |
| let i = Cell::new(0); |
| { |
| let mut iter = IntoIter::new(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 = IntoIter::new(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 = IntoIter::new(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 IntoIter::new(five(&i)).enumerate() { |
| assert_eq!(i.get(), index); |
| } |
| assert_eq!(i.get(), 5); |
| |
| let i = Cell::new(0); |
| for (index, _x) in IntoIter::new(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-unkown. |
| // |
| // 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() { |
| use core::sync::atomic::AtomicUsize; |
| use core::sync::atomic::Ordering; |
| 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)); |
| } |