| use rayon::iter::plumbing::*; |
| use rayon::prelude::*; |
| |
| /// Stress-test indexes for `Producer::split_at`. |
| fn check<F, I>(expected: &[I::Item], mut f: F) |
| where |
| F: FnMut() -> I, |
| I: IntoParallelIterator, |
| I::Iter: IndexedParallelIterator, |
| I::Item: PartialEq + std::fmt::Debug, |
| { |
| map_triples(expected.len() + 1, |i, j, k| { |
| Split::forward(f(), i, j, k, expected); |
| Split::reverse(f(), i, j, k, expected); |
| }); |
| } |
| |
| fn map_triples<F>(end: usize, mut f: F) |
| where |
| F: FnMut(usize, usize, usize), |
| { |
| for i in 0..end { |
| for j in i..end { |
| for k in j..end { |
| f(i, j, k); |
| } |
| } |
| } |
| } |
| |
| #[derive(Debug)] |
| struct Split { |
| i: usize, |
| j: usize, |
| k: usize, |
| reverse: bool, |
| } |
| |
| impl Split { |
| fn forward<I>(iter: I, i: usize, j: usize, k: usize, expected: &[I::Item]) |
| where |
| I: IntoParallelIterator, |
| I::Iter: IndexedParallelIterator, |
| I::Item: PartialEq + std::fmt::Debug, |
| { |
| let result = iter.into_par_iter().with_producer(Split { |
| i, |
| j, |
| k, |
| reverse: false, |
| }); |
| assert_eq!(result, expected); |
| } |
| |
| fn reverse<I>(iter: I, i: usize, j: usize, k: usize, expected: &[I::Item]) |
| where |
| I: IntoParallelIterator, |
| I::Iter: IndexedParallelIterator, |
| I::Item: PartialEq + std::fmt::Debug, |
| { |
| let result = iter.into_par_iter().with_producer(Split { |
| i, |
| j, |
| k, |
| reverse: true, |
| }); |
| assert!(result.iter().eq(expected.iter().rev())); |
| } |
| } |
| |
| impl<T> ProducerCallback<T> for Split { |
| type Output = Vec<T>; |
| |
| fn callback<P>(self, producer: P) -> Self::Output |
| where |
| P: Producer<Item = T>, |
| { |
| println!("{:?}", self); |
| |
| // Splitting the outer indexes first gets us an arbitrary mid section, |
| // which we then split further to get full test coverage. |
| let (left, d) = producer.split_at(self.k); |
| let (a, mid) = left.split_at(self.i); |
| let (b, c) = mid.split_at(self.j - self.i); |
| |
| let a = a.into_iter(); |
| let b = b.into_iter(); |
| let c = c.into_iter(); |
| let d = d.into_iter(); |
| |
| check_len(&a, self.i); |
| check_len(&b, self.j - self.i); |
| check_len(&c, self.k - self.j); |
| |
| let chain = a.chain(b).chain(c).chain(d); |
| if self.reverse { |
| chain.rev().collect() |
| } else { |
| chain.collect() |
| } |
| } |
| } |
| |
| fn check_len<I: ExactSizeIterator>(iter: &I, len: usize) { |
| assert_eq!(iter.size_hint(), (len, Some(len))); |
| assert_eq!(iter.len(), len); |
| } |
| |
| // **** Base Producers **** |
| |
| #[test] |
| fn array() { |
| let a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; |
| check(&a, || a); |
| } |
| |
| #[test] |
| fn empty() { |
| check(&[], rayon::iter::empty::<i32>); |
| } |
| |
| #[test] |
| fn once() { |
| check(&[42], || rayon::iter::once(42)); |
| } |
| |
| #[test] |
| fn option() { |
| check(&[42], || Some(42)); |
| } |
| |
| #[test] |
| fn range() { |
| let v: Vec<_> = (0..10).collect(); |
| check(&v, || 0..10); |
| } |
| |
| #[test] |
| fn range_inclusive() { |
| let v: Vec<_> = (0u16..=10).collect(); |
| check(&v, || 0u16..=10); |
| } |
| |
| #[test] |
| fn repeatn() { |
| let v: Vec<_> = std::iter::repeat(1).take(5).collect(); |
| check(&v, || rayon::iter::repeatn(1, 5)); |
| } |
| |
| #[test] |
| fn slice_iter() { |
| let s: Vec<_> = (0..10).collect(); |
| let v: Vec<_> = s.iter().collect(); |
| check(&v, || &s); |
| } |
| |
| #[test] |
| fn slice_iter_mut() { |
| let mut s: Vec<_> = (0..10).collect(); |
| let mut v: Vec<_> = s.clone(); |
| let expected: Vec<_> = v.iter_mut().collect(); |
| |
| map_triples(expected.len() + 1, |i, j, k| { |
| Split::forward(s.par_iter_mut(), i, j, k, &expected); |
| Split::reverse(s.par_iter_mut(), i, j, k, &expected); |
| }); |
| } |
| |
| #[test] |
| fn slice_chunks() { |
| let s: Vec<_> = (0..10).collect(); |
| for len in 1..s.len() + 2 { |
| let v: Vec<_> = s.chunks(len).collect(); |
| check(&v, || s.par_chunks(len)); |
| } |
| } |
| |
| #[test] |
| fn slice_chunks_exact() { |
| let s: Vec<_> = (0..10).collect(); |
| for len in 1..s.len() + 2 { |
| let v: Vec<_> = s.chunks_exact(len).collect(); |
| check(&v, || s.par_chunks_exact(len)); |
| } |
| } |
| |
| #[test] |
| fn slice_chunks_mut() { |
| let mut s: Vec<_> = (0..10).collect(); |
| let mut v: Vec<_> = s.clone(); |
| for len in 1..s.len() + 2 { |
| let expected: Vec<_> = v.chunks_mut(len).collect(); |
| map_triples(expected.len() + 1, |i, j, k| { |
| Split::forward(s.par_chunks_mut(len), i, j, k, &expected); |
| Split::reverse(s.par_chunks_mut(len), i, j, k, &expected); |
| }); |
| } |
| } |
| |
| #[test] |
| fn slice_chunks_exact_mut() { |
| let mut s: Vec<_> = (0..10).collect(); |
| let mut v: Vec<_> = s.clone(); |
| for len in 1..s.len() + 2 { |
| let expected: Vec<_> = v.chunks_exact_mut(len).collect(); |
| map_triples(expected.len() + 1, |i, j, k| { |
| Split::forward(s.par_chunks_exact_mut(len), i, j, k, &expected); |
| Split::reverse(s.par_chunks_exact_mut(len), i, j, k, &expected); |
| }); |
| } |
| } |
| |
| #[test] |
| fn slice_rchunks() { |
| let s: Vec<_> = (0..10).collect(); |
| for len in 1..s.len() + 2 { |
| let v: Vec<_> = s.rchunks(len).collect(); |
| check(&v, || s.par_rchunks(len)); |
| } |
| } |
| |
| #[test] |
| fn slice_rchunks_exact() { |
| let s: Vec<_> = (0..10).collect(); |
| for len in 1..s.len() + 2 { |
| let v: Vec<_> = s.rchunks_exact(len).collect(); |
| check(&v, || s.par_rchunks_exact(len)); |
| } |
| } |
| |
| #[test] |
| fn slice_rchunks_mut() { |
| let mut s: Vec<_> = (0..10).collect(); |
| let mut v: Vec<_> = s.clone(); |
| for len in 1..s.len() + 2 { |
| let expected: Vec<_> = v.rchunks_mut(len).collect(); |
| map_triples(expected.len() + 1, |i, j, k| { |
| Split::forward(s.par_rchunks_mut(len), i, j, k, &expected); |
| Split::reverse(s.par_rchunks_mut(len), i, j, k, &expected); |
| }); |
| } |
| } |
| |
| #[test] |
| fn slice_rchunks_exact_mut() { |
| let mut s: Vec<_> = (0..10).collect(); |
| let mut v: Vec<_> = s.clone(); |
| for len in 1..s.len() + 2 { |
| let expected: Vec<_> = v.rchunks_exact_mut(len).collect(); |
| map_triples(expected.len() + 1, |i, j, k| { |
| Split::forward(s.par_rchunks_exact_mut(len), i, j, k, &expected); |
| Split::reverse(s.par_rchunks_exact_mut(len), i, j, k, &expected); |
| }); |
| } |
| } |
| |
| #[test] |
| fn slice_windows() { |
| let s: Vec<_> = (0..10).collect(); |
| let v: Vec<_> = s.windows(2).collect(); |
| check(&v, || s.par_windows(2)); |
| } |
| |
| #[test] |
| fn vec() { |
| let v: Vec<_> = (0..10).collect(); |
| check(&v, || v.clone()); |
| } |
| |
| // **** Adaptors **** |
| |
| #[test] |
| fn chain() { |
| let v: Vec<_> = (0..10).collect(); |
| check(&v, || (0..5).into_par_iter().chain(5..10)); |
| } |
| |
| #[test] |
| fn cloned() { |
| let v: Vec<_> = (0..10).collect(); |
| check(&v, || v.par_iter().cloned()); |
| } |
| |
| #[test] |
| fn copied() { |
| let v: Vec<_> = (0..10).collect(); |
| check(&v, || v.par_iter().copied()); |
| } |
| |
| #[test] |
| fn enumerate() { |
| let v: Vec<_> = (0..10).enumerate().collect(); |
| check(&v, || (0..10).into_par_iter().enumerate()); |
| } |
| |
| #[test] |
| fn step_by() { |
| let v: Vec<_> = (0..10).step_by(2).collect(); |
| check(&v, || (0..10).into_par_iter().step_by(2)) |
| } |
| |
| #[test] |
| fn step_by_unaligned() { |
| let v: Vec<_> = (0..10).step_by(3).collect(); |
| check(&v, || (0..10).into_par_iter().step_by(3)) |
| } |
| |
| #[test] |
| fn inspect() { |
| let v: Vec<_> = (0..10).collect(); |
| check(&v, || (0..10).into_par_iter().inspect(|_| ())); |
| } |
| |
| #[test] |
| fn update() { |
| let v: Vec<_> = (0..10).collect(); |
| check(&v, || (0..10).into_par_iter().update(|_| ())); |
| } |
| |
| #[test] |
| fn interleave() { |
| let v = [0, 10, 1, 11, 2, 12, 3, 4]; |
| check(&v, || (0..5).into_par_iter().interleave(10..13)); |
| check(&v[..6], || (0..3).into_par_iter().interleave(10..13)); |
| |
| let v = [0, 10, 1, 11, 2, 12, 13, 14]; |
| check(&v, || (0..3).into_par_iter().interleave(10..15)); |
| } |
| |
| #[test] |
| fn intersperse() { |
| let v = [0, -1, 1, -1, 2, -1, 3, -1, 4]; |
| check(&v, || (0..5).into_par_iter().intersperse(-1)); |
| } |
| |
| #[test] |
| fn chunks() { |
| let s: Vec<_> = (0..10).collect(); |
| let v: Vec<_> = s.chunks(2).map(|c| c.to_vec()).collect(); |
| check(&v, || s.par_iter().cloned().chunks(2)); |
| } |
| |
| #[test] |
| fn map() { |
| let v: Vec<_> = (0..10).collect(); |
| check(&v, || v.par_iter().map(Clone::clone)); |
| } |
| |
| #[test] |
| fn map_with() { |
| let v: Vec<_> = (0..10).collect(); |
| check(&v, || v.par_iter().map_with(vec![0], |_, &x| x)); |
| } |
| |
| #[test] |
| fn map_init() { |
| let v: Vec<_> = (0..10).collect(); |
| check(&v, || v.par_iter().map_init(|| vec![0], |_, &x| x)); |
| } |
| |
| #[test] |
| fn panic_fuse() { |
| let v: Vec<_> = (0..10).collect(); |
| check(&v, || (0..10).into_par_iter().panic_fuse()); |
| } |
| |
| #[test] |
| fn rev() { |
| let v: Vec<_> = (0..10).rev().collect(); |
| check(&v, || (0..10).into_par_iter().rev()); |
| } |
| |
| #[test] |
| fn with_max_len() { |
| let v: Vec<_> = (0..10).collect(); |
| check(&v, || (0..10).into_par_iter().with_max_len(1)); |
| } |
| |
| #[test] |
| fn with_min_len() { |
| let v: Vec<_> = (0..10).collect(); |
| check(&v, || (0..10).into_par_iter().with_min_len(1)); |
| } |
| |
| #[test] |
| fn zip() { |
| let v: Vec<_> = (0..10).zip(10..20).collect(); |
| check(&v, || (0..10).into_par_iter().zip(10..20)); |
| check(&v[..5], || (0..5).into_par_iter().zip(10..20)); |
| check(&v[..5], || (0..10).into_par_iter().zip(10..15)); |
| } |