rayon_cond/
lib.rs

1//! Experimental iterator wrapper that is conditionally parallel or serial, using
2//! Rayon's `ParallelIterator` or the standard `Iterator` respectively.
3//!
4//! ## Usage
5//!
6//! First add this crate to your `Cargo.toml`:
7//!
8//! ```toml
9//! [dependencies]
10//! rayon-cond = "0.3"
11//! ```
12//!
13//! Then in your code, it may be used something like this:
14//!
15//! ```rust
16//! use rayon_cond::CondIterator;
17//!
18//! let args: Vec<_> = std::env::args().collect();
19//!
20//! // Run in parallel if there are an even number of args
21//! let par = args.len() % 2 == 0;
22//!
23//! CondIterator::new(args, par).enumerate().for_each(|(i, arg)| {
24//!     println!("arg {}: {:?}", i, arg);
25//! });
26//! ```
27
28use either::Either;
29use itertools::Itertools;
30use rayon::prelude::*;
31use std::cmp::Ordering;
32
33use itertools::structs as it;
34use rayon::iter as ri;
35use std::iter as si;
36
37use crate::CondIterator::*;
38
39/// An iterator that could be parallel or serial, with a common API either way.
40///
41/// The available methods mostly follow [`ParallelIterator`] and [`IndexedParallelIterator`], as
42/// `rayon` has the stricter requirements, and they are parallelized with [`rayon::iter`] types.
43/// Serial implementations use appropriate types from [`std::iter`] and [`itertools::structs`].
44///
45/// [`ParallelIterator`]: https://docs.rs/rayon/1/rayon/iter/trait.ParallelIterator.html
46/// [`IndexedParallelIterator`]: https://docs.rs/rayon/1/rayon/iter/trait.IndexedParallelIterator.html
47/// [`rayon::iter`]: https://docs.rs/rayon/1/rayon/iter/index.html#structs
48/// [`std::iter`]: https://doc.rust-lang.org/std/iter/index.html#structs
49/// [`itertools::structs`]: https://docs.rs/itertools/0.8/itertools/structs/index.html#structs
50pub enum CondIterator<P, S>
51where
52    P: ParallelIterator,
53    S: Iterator<Item = P::Item>,
54{
55    Parallel(P),
56    Serial(S),
57}
58
59impl<P, S> CondIterator<P, S>
60where
61    P: ParallelIterator,
62    S: Iterator<Item = P::Item>,
63{
64    pub fn new<I>(iterable: I, parallel: bool) -> Self
65    where
66        I: IntoParallelIterator<Iter = P, Item = P::Item>
67            + IntoIterator<IntoIter = S, Item = S::Item>,
68    {
69        if parallel {
70            Self::from_parallel(iterable)
71        } else {
72            Self::from_serial(iterable)
73        }
74    }
75
76    pub fn from_parallel<I>(iterable: I) -> Self
77    where
78        I: IntoParallelIterator<Iter = P, Item = P::Item>,
79    {
80        Parallel(iterable.into_par_iter())
81    }
82
83    pub fn from_serial<I>(iterable: I) -> Self
84    where
85        I: IntoIterator<IntoIter = S, Item = S::Item>,
86    {
87        Serial(iterable.into_iter())
88    }
89
90    pub fn is_parallel(&self) -> bool {
91        matches!(self, Parallel(_))
92    }
93
94    pub fn is_serial(&self) -> bool {
95        matches!(self, Serial(_))
96    }
97}
98
99impl<P, S> CondIterator<P, S>
100where
101    P: ParallelIterator,
102    S: Iterator<Item = P::Item> + Send,
103{
104    pub fn into_parallel(self) -> Either<P, ri::IterBridge<S>> {
105        match self {
106            Parallel(iter) => Either::Left(iter),
107            Serial(iter) => Either::Right(iter.par_bridge()),
108        }
109    }
110}
111
112macro_rules! either {
113    ($self:ident, $pattern:pat => $result:expr) => {
114        match $self {
115            Parallel($pattern) => $result,
116            Serial($pattern) => $result,
117        }
118    };
119}
120
121macro_rules! wrap_either {
122    ($self:ident, $pattern:pat => $result:expr) => {
123        match $self {
124            Parallel($pattern) => Parallel($result),
125            Serial($pattern) => Serial($result),
126        }
127    };
128}
129
130impl<P, S> CondIterator<P, S>
131where
132    P: ParallelIterator,
133    S: Iterator<Item = P::Item>,
134{
135    pub fn for_each<OP>(self, op: OP)
136    where
137        OP: Fn(P::Item) + Sync + Send,
138    {
139        either!(self, iter => iter.for_each(op))
140    }
141
142    pub fn for_each_with<OP, T>(self, mut init: T, op: OP)
143    where
144        OP: Fn(&mut T, P::Item) + Sync + Send,
145        T: Send + Clone,
146    {
147        match self {
148            Parallel(iter) => iter.for_each_with(init, op),
149            Serial(iter) => iter.for_each(move |item| op(&mut init, item)),
150        }
151    }
152
153    pub fn for_each_init<OP, INIT, T>(self, init: INIT, op: OP)
154    where
155        OP: Fn(&mut T, P::Item) + Sync + Send,
156        INIT: Fn() -> T + Sync + Send,
157    {
158        match self {
159            Parallel(iter) => iter.for_each_init(init, op),
160            Serial(iter) => {
161                let mut init = init();
162                iter.for_each(move |item| op(&mut init, item))
163            }
164        }
165    }
166
167    pub fn count(self) -> usize {
168        either!(self, iter => iter.count())
169    }
170
171    pub fn map<F, R>(self, map_op: F) -> CondIterator<ri::Map<P, F>, si::Map<S, F>>
172    where
173        F: Fn(P::Item) -> R + Sync + Send,
174        R: Send,
175    {
176        wrap_either!(self, iter => iter.map(map_op))
177    }
178
179    // If we want to avoid `impl FnMut`, we'll need to implement a custom
180    // serialized `MapWith` type to return.
181    pub fn map_with<F, T, R>(
182        self,
183        mut init: T,
184        map_op: F,
185    ) -> CondIterator<ri::MapWith<P, T, F>, si::Map<S, impl FnMut(P::Item) -> R>>
186    where
187        F: Fn(&mut T, P::Item) -> R + Sync + Send,
188        T: Send + Clone,
189        R: Send,
190    {
191        match self {
192            Parallel(iter) => Parallel(iter.map_with(init, map_op)),
193            Serial(iter) => Serial(iter.map(move |item| map_op(&mut init, item))),
194        }
195    }
196
197    // If we want to avoid `impl FnMut`, we'll need to implement a custom
198    // serialized `MapInit` type to return.
199    pub fn map_init<F, INIT, T, R>(
200        self,
201        init: INIT,
202        map_op: F,
203    ) -> CondIterator<ri::MapInit<P, INIT, F>, si::Map<S, impl FnMut(P::Item) -> R>>
204    where
205        F: Fn(&mut T, P::Item) -> R + Sync + Send,
206        INIT: Fn() -> T + Sync + Send,
207        R: Send,
208    {
209        match self {
210            Parallel(iter) => Parallel(iter.map_init(init, map_op)),
211            Serial(iter) => {
212                let mut init = init();
213                Serial(iter.map(move |item| map_op(&mut init, item)))
214            }
215        }
216    }
217
218    pub fn cloned<'a, T>(self) -> CondIterator<ri::Cloned<P>, si::Cloned<S>>
219    where
220        T: 'a + Clone + Sync + Send,
221        P: ParallelIterator<Item = &'a T>,
222        S: Iterator<Item = &'a T>,
223    {
224        wrap_either!(self, iter => iter.cloned())
225    }
226
227    pub fn copied<'a, T>(self) -> CondIterator<ri::Copied<P>, si::Copied<S>>
228    where
229        T: 'a + Copy + Sync + Send,
230        P: ParallelIterator<Item = &'a T>,
231        S: Iterator<Item = &'a T>,
232    {
233        wrap_either!(self, iter => iter.copied())
234    }
235
236    pub fn inspect<OP>(self, inspect_op: OP) -> CondIterator<ri::Inspect<P, OP>, si::Inspect<S, OP>>
237    where
238        OP: Fn(&P::Item) + Sync + Send,
239    {
240        wrap_either!(self, iter => iter.inspect(inspect_op))
241    }
242
243    pub fn update<OP>(self, update_op: OP) -> CondIterator<ri::Update<P, OP>, it::Update<S, OP>>
244    where
245        OP: Fn(&mut P::Item) + Sync + Send,
246    {
247        wrap_either!(self, iter => iter.update(update_op))
248    }
249
250    pub fn filter<Pred>(
251        self,
252        filter_op: Pred,
253    ) -> CondIterator<ri::Filter<P, Pred>, si::Filter<S, Pred>>
254    where
255        Pred: Fn(&P::Item) -> bool + Sync + Send,
256    {
257        wrap_either!(self, iter => iter.filter(filter_op))
258    }
259
260    pub fn filter_map<Pred, R>(
261        self,
262        filter_op: Pred,
263    ) -> CondIterator<ri::FilterMap<P, Pred>, si::FilterMap<S, Pred>>
264    where
265        Pred: Fn(P::Item) -> Option<R> + Sync + Send,
266        R: Send,
267    {
268        wrap_either!(self, iter => iter.filter_map(filter_op))
269    }
270
271    pub fn flat_map<F, I>(self, map_op: F) -> CondIterator<ri::FlatMap<P, F>, si::FlatMap<S, I, F>>
272    where
273        F: Fn(P::Item) -> I + Sync + Send,
274        I: IntoParallelIterator + IntoIterator<Item = <I as IntoParallelIterator>::Item>,
275    {
276        wrap_either!(self, iter => iter.flat_map(map_op))
277    }
278
279    pub fn flat_map_iter<F, I>(
280        self,
281        map_op: F,
282    ) -> CondIterator<ri::FlatMapIter<P, F>, si::FlatMap<S, I, F>>
283    where
284        F: Fn(P::Item) -> I + Sync + Send,
285        I: IntoIterator,
286        I::Item: Send,
287    {
288        match self {
289            Parallel(iter) => Parallel(iter.flat_map_iter(map_op)),
290            Serial(iter) => Serial(iter.flat_map(map_op)),
291        }
292    }
293
294    pub fn flatten(self) -> CondIterator<ri::Flatten<P>, si::Flatten<S>>
295    where
296        P::Item: IntoParallelIterator,
297        S::Item: IntoIterator<Item = <P::Item as IntoParallelIterator>::Item>,
298    {
299        wrap_either!(self, iter => iter.flatten())
300    }
301
302    pub fn flatten_iter(self) -> CondIterator<ri::FlattenIter<P>, si::Flatten<S>>
303    where
304        P::Item: IntoIterator,
305        <P::Item as IntoIterator>::Item: Send,
306    {
307        match self {
308            Parallel(iter) => Parallel(iter.flatten_iter()),
309            Serial(iter) => Serial(iter.flatten()),
310        }
311    }
312
313    pub fn reduce<OP, ID>(self, identity: ID, op: OP) -> P::Item
314    where
315        OP: Fn(P::Item, P::Item) -> P::Item + Sync + Send,
316        ID: Fn() -> P::Item + Sync + Send,
317    {
318        match self {
319            Parallel(iter) => iter.reduce(identity, op),
320            Serial(iter) => iter.fold(identity(), op),
321        }
322    }
323
324    pub fn reduce_with<OP>(self, op: OP) -> Option<P::Item>
325    where
326        OP: Fn(P::Item, P::Item) -> P::Item + Sync + Send,
327    {
328        match self {
329            Parallel(iter) => iter.reduce_with(op),
330            Serial(iter) => iter.reduce(op),
331        }
332    }
333
334    // NB: Rayon's `fold` produces another iterator, so we have to fake that serially.
335    pub fn fold<T, ID, F>(
336        self,
337        identity: ID,
338        fold_op: F,
339    ) -> CondIterator<ri::Fold<P, ID, F>, si::Once<T>>
340    where
341        F: Fn(T, P::Item) -> T + Sync + Send,
342        ID: Fn() -> T + Sync + Send,
343        T: Send,
344    {
345        match self {
346            Parallel(iter) => Parallel(iter.fold(identity, fold_op)),
347            Serial(iter) => Serial(si::once(iter.fold(identity(), fold_op))),
348        }
349    }
350
351    pub fn fold_with<F, T>(
352        self,
353        init: T,
354        fold_op: F,
355    ) -> CondIterator<ri::FoldWith<P, T, F>, si::Once<T>>
356    where
357        F: Fn(T, P::Item) -> T + Sync + Send,
358        T: Send + Clone,
359    {
360        match self {
361            Parallel(iter) => Parallel(iter.fold_with(init, fold_op)),
362            Serial(iter) => Serial(si::once(iter.fold(init, fold_op))),
363        }
364    }
365
366    pub fn sum<Sum>(self) -> Sum
367    where
368        Sum: Send + si::Sum<P::Item> + si::Sum<Sum>,
369    {
370        either!(self, iter => iter.sum())
371    }
372
373    pub fn product<Product>(self) -> Product
374    where
375        Product: Send + si::Product<P::Item> + si::Product<Product>,
376    {
377        either!(self, iter => iter.product())
378    }
379
380    pub fn min(self) -> Option<P::Item>
381    where
382        P::Item: Ord,
383    {
384        either!(self, iter => iter.min())
385    }
386
387    pub fn min_by<F>(self, f: F) -> Option<P::Item>
388    where
389        F: Sync + Send + Fn(&P::Item, &P::Item) -> Ordering,
390    {
391        either!(self, iter => iter.min_by(f))
392    }
393
394    pub fn min_by_key<K, F>(self, f: F) -> Option<P::Item>
395    where
396        K: Ord + Send,
397        F: Sync + Send + Fn(&P::Item) -> K,
398    {
399        either!(self, iter => iter.min_by_key(f))
400    }
401
402    pub fn max(self) -> Option<P::Item>
403    where
404        P::Item: Ord,
405    {
406        either!(self, iter => iter.max())
407    }
408
409    pub fn max_by<F>(self, f: F) -> Option<P::Item>
410    where
411        F: Sync + Send + Fn(&P::Item, &P::Item) -> Ordering,
412    {
413        either!(self, iter => iter.max_by(f))
414    }
415
416    pub fn max_by_key<K, F>(self, f: F) -> Option<P::Item>
417    where
418        K: Ord + Send,
419        F: Sync + Send + Fn(&P::Item) -> K,
420    {
421        either!(self, iter => iter.max_by_key(f))
422    }
423
424    pub fn chain<C>(
425        self,
426        chain: C,
427    ) -> CondIterator<ri::Chain<P, C::Iter>, si::Chain<S, C::IntoIter>>
428    where
429        C: IntoParallelIterator<Item = P::Item> + IntoIterator<Item = P::Item>,
430    {
431        wrap_either!(self, iter => iter.chain(chain))
432    }
433
434    pub fn find_any<Pred>(self, predicate: Pred) -> Option<P::Item>
435    where
436        Pred: Fn(&P::Item) -> bool + Sync + Send,
437    {
438        match self {
439            Parallel(iter) => iter.find_any(predicate),
440            Serial(mut iter) => iter.find(predicate),
441        }
442    }
443
444    pub fn find_first<Pred>(self, predicate: Pred) -> Option<P::Item>
445    where
446        Pred: Fn(&P::Item) -> bool + Sync + Send,
447    {
448        match self {
449            Parallel(iter) => iter.find_first(predicate),
450            Serial(mut iter) => iter.find(predicate),
451        }
452    }
453
454    pub fn any<Pred>(self, predicate: Pred) -> bool
455    where
456        Pred: Fn(P::Item) -> bool + Sync + Send,
457    {
458        match self {
459            Parallel(iter) => iter.any(predicate),
460            Serial(mut iter) => iter.any(predicate),
461        }
462    }
463
464    pub fn all<Pred>(self, predicate: Pred) -> bool
465    where
466        Pred: Fn(P::Item) -> bool + Sync + Send,
467    {
468        match self {
469            Parallel(iter) => iter.all(predicate),
470            Serial(mut iter) => iter.all(predicate),
471        }
472    }
473
474    pub fn while_some<T>(self) -> CondIterator<ri::WhileSome<P>, it::WhileSome<S>>
475    where
476        P: ParallelIterator<Item = Option<T>>,
477        S: Iterator<Item = Option<T>>,
478        T: Send,
479    {
480        wrap_either!(self, iter => iter.while_some())
481    }
482
483    pub fn collect<C>(self) -> C
484    where
485        C: FromCondIterator<P::Item>,
486    {
487        either!(self, iter => iter.collect())
488    }
489
490    pub fn unzip<A, B, FromA, FromB>(self) -> (FromA, FromB)
491    where
492        P: ParallelIterator<Item = (A, B)>,
493        S: Iterator<Item = (A, B)>,
494        FromA: Default + Send + CondExtend<A>,
495        FromB: Default + Send + CondExtend<B>,
496        A: Send,
497        B: Send,
498    {
499        either!(self, iter => iter.unzip())
500    }
501
502    // NB: `Iterator::partition` only allows a single output type, but
503    // we can be more flexible using `partition_map`!
504    pub fn partition<A, B, Pred>(self, predicate: Pred) -> (A, B)
505    where
506        A: Default + Send + CondExtend<P::Item>,
507        B: Default + Send + CondExtend<P::Item>,
508        Pred: Fn(&P::Item) -> bool + Sync + Send,
509    {
510        match self {
511            Parallel(iter) => iter.partition(predicate),
512            Serial(iter) => iter.partition_map(|item| {
513                if predicate(&item) {
514                    Either::Left(item)
515                } else {
516                    Either::Right(item)
517                }
518            }),
519        }
520    }
521
522    pub fn partition_map<A, B, Pred, L, R>(self, predicate: Pred) -> (A, B)
523    where
524        A: Default + Send + CondExtend<L>,
525        B: Default + Send + CondExtend<R>,
526        Pred: Fn(P::Item) -> Either<L, R> + Sync + Send,
527        L: Send,
528        R: Send,
529    {
530        either!(self, iter => iter.partition_map(predicate))
531    }
532
533    pub fn intersperse(
534        self,
535        element: P::Item,
536    ) -> CondIterator<ri::Intersperse<P>, it::Intersperse<S>>
537    where
538        P::Item: Clone,
539    {
540        match self {
541            Parallel(iter) => Parallel(iter.intersperse(element)),
542            Serial(iter) => Serial(Itertools::intersperse(iter, element)),
543        }
544    }
545
546    pub fn opt_len(&self) -> Option<usize> {
547        match self {
548            Parallel(ref iter) => iter.opt_len(),
549            Serial(ref iter) => match iter.size_hint() {
550                (lo, Some(hi)) if lo == hi => Some(lo),
551                _ => None,
552            },
553        }
554    }
555}
556
557impl<P, S> CondIterator<P, S>
558where
559    P: ParallelIterator,
560    S: DoubleEndedIterator<Item = P::Item>,
561{
562    pub fn find_last<Pred>(self, predicate: Pred) -> Option<P::Item>
563    where
564        Pred: Fn(&P::Item) -> bool + Sync + Send,
565    {
566        match self {
567            Parallel(iter) => iter.find_last(predicate),
568            Serial(mut iter) => iter.rfind(predicate),
569        }
570    }
571}
572
573impl<P, S> CondIterator<P, S>
574where
575    P: IndexedParallelIterator,
576    S: Iterator<Item = P::Item>,
577{
578    pub fn collect_into_vec(self, target: &mut Vec<P::Item>) {
579        match self {
580            Parallel(iter) => iter.collect_into_vec(target),
581            Serial(iter) => {
582                target.clear();
583                let (lower, _) = iter.size_hint();
584                target.reserve(lower);
585                target.extend(iter);
586            }
587        }
588    }
589
590    pub fn unzip_into_vecs<A, B>(self, left: &mut Vec<A>, right: &mut Vec<B>)
591    where
592        P: IndexedParallelIterator<Item = (A, B)>,
593        S: Iterator<Item = (A, B)>,
594        A: Send,
595        B: Send,
596    {
597        match self {
598            Parallel(iter) => iter.unzip_into_vecs(left, right),
599            Serial(iter) => {
600                left.clear();
601                right.clear();
602                let (lower, _) = iter.size_hint();
603                left.reserve(lower);
604                right.reserve(lower);
605                iter.for_each(|(a, b)| {
606                    left.push(a);
607                    right.push(b);
608                })
609            }
610        }
611    }
612
613    pub fn zip<Z>(self, other: Z) -> CondIterator<ri::Zip<P, Z::Iter>, si::Zip<S, Z::IntoIter>>
614    where
615        Z: IntoParallelIterator + IntoIterator<Item = <Z as IntoParallelIterator>::Item>,
616        Z::Iter: IndexedParallelIterator,
617    {
618        wrap_either!(self, iter => iter.zip(other))
619    }
620
621    pub fn zip_eq<Z>(
622        self,
623        other: Z,
624    ) -> CondIterator<ri::ZipEq<P, Z::Iter>, it::ZipEq<S, Z::IntoIter>>
625    where
626        Z: IntoParallelIterator + IntoIterator<Item = <Z as IntoParallelIterator>::Item>,
627        Z::Iter: IndexedParallelIterator,
628    {
629        wrap_either!(self, iter => iter.zip_eq(other))
630    }
631
632    pub fn interleave<I>(
633        self,
634        other: I,
635    ) -> CondIterator<ri::Interleave<P, I::Iter>, it::Interleave<S, I::IntoIter>>
636    where
637        I: IntoParallelIterator<Item = P::Item> + IntoIterator<Item = S::Item>,
638        I::Iter: IndexedParallelIterator<Item = P::Item>,
639    {
640        wrap_either!(self, iter => iter.interleave(other))
641    }
642
643    pub fn interleave_shortest<I>(
644        self,
645        other: I,
646    ) -> CondIterator<ri::InterleaveShortest<P, I::Iter>, it::InterleaveShortest<S, I::IntoIter>>
647    where
648        I: IntoParallelIterator<Item = P::Item> + IntoIterator<Item = S::Item>,
649        I::Iter: IndexedParallelIterator<Item = P::Item>,
650    {
651        wrap_either!(self, iter => iter.interleave_shortest(other))
652    }
653
654    pub fn cmp<I>(self, other: I) -> Ordering
655    where
656        I: IntoParallelIterator<Item = P::Item> + IntoIterator<Item = S::Item>,
657        I::Iter: IndexedParallelIterator,
658        P::Item: Ord,
659    {
660        either!(self, iter => iter.cmp(other))
661    }
662
663    pub fn partial_cmp<I>(self, other: I) -> Option<Ordering>
664    where
665        I: IntoParallelIterator + IntoIterator<Item = <I as IntoParallelIterator>::Item>,
666        I::Iter: IndexedParallelIterator,
667        P::Item: PartialOrd<<I as IntoParallelIterator>::Item>,
668    {
669        either!(self, iter => iter.partial_cmp(other))
670    }
671
672    pub fn eq<I>(self, other: I) -> bool
673    where
674        I: IntoParallelIterator + IntoIterator<Item = <I as IntoParallelIterator>::Item>,
675        I::Iter: IndexedParallelIterator,
676        P::Item: PartialEq<<I as IntoParallelIterator>::Item>,
677    {
678        either!(self, iter => iter.eq(other))
679    }
680
681    pub fn ne<I>(self, other: I) -> bool
682    where
683        I: IntoParallelIterator + IntoIterator<Item = <I as IntoParallelIterator>::Item>,
684        I::Iter: IndexedParallelIterator,
685        P::Item: PartialEq<<I as IntoParallelIterator>::Item>,
686    {
687        either!(self, iter => iter.ne(other))
688    }
689
690    pub fn lt<I>(self, other: I) -> bool
691    where
692        I: IntoParallelIterator + IntoIterator<Item = <I as IntoParallelIterator>::Item>,
693        I::Iter: IndexedParallelIterator,
694        P::Item: PartialOrd<<I as IntoParallelIterator>::Item>,
695    {
696        either!(self, iter => iter.lt(other))
697    }
698
699    pub fn le<I>(self, other: I) -> bool
700    where
701        I: IntoParallelIterator + IntoIterator<Item = <I as IntoParallelIterator>::Item>,
702        I::Iter: IndexedParallelIterator,
703        P::Item: PartialOrd<<I as IntoParallelIterator>::Item>,
704    {
705        either!(self, iter => iter.le(other))
706    }
707
708    pub fn gt<I>(self, other: I) -> bool
709    where
710        I: IntoParallelIterator + IntoIterator<Item = <I as IntoParallelIterator>::Item>,
711        I::Iter: IndexedParallelIterator,
712        P::Item: PartialOrd<<I as IntoParallelIterator>::Item>,
713    {
714        either!(self, iter => iter.gt(other))
715    }
716
717    pub fn ge<I>(self, other: I) -> bool
718    where
719        I: IntoParallelIterator + IntoIterator<Item = <I as IntoParallelIterator>::Item>,
720        I::Iter: IndexedParallelIterator,
721        P::Item: PartialOrd<<I as IntoParallelIterator>::Item>,
722    {
723        either!(self, iter => iter.ge(other))
724    }
725
726    pub fn enumerate(self) -> CondIterator<ri::Enumerate<P>, si::Enumerate<S>> {
727        wrap_either!(self, iter => iter.enumerate())
728    }
729
730    pub fn skip(self, n: usize) -> CondIterator<ri::Skip<P>, si::Skip<S>> {
731        wrap_either!(self, iter => iter.skip(n))
732    }
733
734    pub fn take(self, n: usize) -> CondIterator<ri::Take<P>, si::Take<S>> {
735        wrap_either!(self, iter => iter.take(n))
736    }
737
738    pub fn position_any<Pred>(self, predicate: Pred) -> Option<usize>
739    where
740        Pred: Fn(P::Item) -> bool + Sync + Send,
741    {
742        match self {
743            Parallel(iter) => iter.position_any(predicate),
744            Serial(mut iter) => iter.position(predicate),
745        }
746    }
747
748    pub fn position_first<Pred>(self, predicate: Pred) -> Option<usize>
749    where
750        Pred: Fn(P::Item) -> bool + Sync + Send,
751    {
752        match self {
753            Parallel(iter) => iter.position_first(predicate),
754            Serial(mut iter) => iter.position(predicate),
755        }
756    }
757
758    pub fn positions<Pred>(
759        self,
760        predicate: Pred,
761    ) -> CondIterator<ri::Positions<P, Pred>, it::Positions<S, Pred>>
762    where
763        Pred: Fn(P::Item) -> bool + Sync + Send,
764    {
765        wrap_either!(self, iter => iter.positions(predicate))
766    }
767
768    pub fn step_by(self, step: usize) -> CondIterator<ri::StepBy<P>, si::StepBy<S>> {
769        wrap_either!(self, iter => iter.step_by(step))
770    }
771}
772
773impl<P, S> CondIterator<P, S>
774where
775    P: IndexedParallelIterator,
776    S: DoubleEndedIterator<Item = P::Item>,
777{
778    pub fn rev(self) -> CondIterator<ri::Rev<P>, si::Rev<S>> {
779        wrap_either!(self, iter => iter.rev())
780    }
781}
782
783impl<P, S> CondIterator<P, S>
784where
785    P: IndexedParallelIterator,
786    S: ExactSizeIterator<Item = P::Item>,
787{
788    #[allow(clippy::len_without_is_empty)]
789    pub fn len(&self) -> usize {
790        either!(self, ref iter => iter.len())
791    }
792}
793
794impl<P, S> CondIterator<P, S>
795where
796    P: IndexedParallelIterator,
797    S: ExactSizeIterator + DoubleEndedIterator<Item = P::Item>,
798{
799    pub fn position_last<Pred>(self, predicate: Pred) -> Option<usize>
800    where
801        Pred: Fn(P::Item) -> bool + Sync + Send,
802    {
803        match self {
804            Parallel(iter) => iter.position_last(predicate),
805            Serial(mut iter) => iter.rposition(predicate),
806        }
807    }
808}
809
810pub trait FromCondIterator<T>: FromParallelIterator<T> + si::FromIterator<T>
811where
812    T: Send,
813{
814    fn from_cond_iter<P, S>(cond_iter: CondIterator<P, S>) -> Self
815    where
816        P: ParallelIterator<Item = T>,
817        S: Iterator<Item = T>,
818    {
819        match cond_iter {
820            Parallel(iter) => Self::from_par_iter(iter),
821            Serial(iter) => Self::from_iter(iter),
822        }
823    }
824}
825
826impl<C, T> FromCondIterator<T> for C
827where
828    C: FromParallelIterator<T> + si::FromIterator<T>,
829    T: Send,
830{
831}
832
833pub trait CondExtend<T>: ParallelExtend<T> + Extend<T>
834where
835    T: Send,
836{
837    fn cond_extend<P, S>(&mut self, cond_iter: CondIterator<P, S>)
838    where
839        P: ParallelIterator<Item = T>,
840        S: Iterator<Item = T>,
841    {
842        match cond_iter {
843            Parallel(iter) => self.par_extend(iter),
844            Serial(iter) => self.extend(iter),
845        }
846    }
847}
848
849impl<C, T> CondExtend<T> for C
850where
851    C: ParallelExtend<T> + Extend<T>,
852    T: Send,
853{
854}