Skip to main content

p3_maybe_rayon/
lib.rs

1//! Thin compatibility layer that re-exports either `rayon` or a sequential
2//! fallback under a unified prelude, gated by the `parallel` feature.
3
4#![no_std]
5
6#[cfg(not(feature = "parallel"))]
7mod serial;
8
9pub mod prelude {
10    #[cfg(not(feature = "parallel"))]
11    pub use core::iter::{
12        ExactSizeIterator as IndexedParallelIterator, Iterator as ParallelIterator,
13    };
14    use core::marker::{Send, Sync};
15
16    #[cfg(feature = "parallel")]
17    pub use rayon::prelude::*;
18    #[cfg(feature = "parallel")]
19    pub use rayon::{current_num_threads, join};
20
21    #[cfg(not(feature = "parallel"))]
22    pub use super::serial::*;
23
24    pub trait SharedExt: ParallelIterator {
25        /// Folds each split of the iterator with `fold_op` (seeded by `identity`), then
26        /// combines the per-split accumulators with `reduce_op`.
27        ///
28        /// `identity()` must be neutral for `reduce_op`, and `fold_op`/`reduce_op` must be
29        /// mutually associative so that regrouping splits doesn't change the result — under
30        /// the `parallel` feature the split count (and thus how many times `reduce_op` runs)
31        /// depends on the thread pool. **The serial fallback never calls `reduce_op`** (there
32        /// is only one split), so an inconsistent `reduce_op` yields results that diverge
33        /// between `cargo test` and `cargo test --features parallel`.
34        fn par_fold_reduce<Acc, Id, F, R>(self, identity: Id, fold_op: F, reduce_op: R) -> Acc
35        where
36            Acc: Send,
37            Id: Fn() -> Acc + Sync + Send,
38            F: Fn(Acc, Self::Item) -> Acc + Sync + Send,
39            R: Fn(Acc, Acc) -> Acc + Sync + Send;
40    }
41
42    impl<I: ParallelIterator> SharedExt for I {
43        #[inline]
44        fn par_fold_reduce<Acc, Id, F, R>(self, identity: Id, fold_op: F, reduce_op: R) -> Acc
45        where
46            Acc: Send,
47            Id: Fn() -> Acc + Sync + Send,
48            F: Fn(Acc, Self::Item) -> Acc + Sync + Send,
49            R: Fn(Acc, Acc) -> Acc + Sync + Send,
50        {
51            #[cfg(feature = "parallel")]
52            {
53                self.fold(&identity, fold_op).reduce(&identity, reduce_op)
54            }
55
56            #[cfg(not(feature = "parallel"))]
57            {
58                let _ = reduce_op;
59                self.fold(identity(), fold_op)
60            }
61        }
62    }
63}
64
65pub mod iter {
66    #[cfg(not(feature = "parallel"))]
67    pub use core::iter::{repeat, repeat_n};
68
69    #[cfg(feature = "parallel")]
70    pub use rayon::iter::{repeat, repeat_n};
71}