bio_forge/utils/
parallel.rs

1//! Abstraction layer for parallel iteration.
2//!
3//! This module provides conditional compilation for parallel processing.
4//! When the `parallel` feature is enabled, it exports Rayon's parallelism primitives.
5//! When disabled, it provides serial fallbacks that mimic the parallel API,
6//! allowing internal code to be written once.
7
8#[cfg(feature = "parallel")]
9pub use rayon::prelude::{
10    IndexedParallelIterator, IntoParallelIterator, IntoParallelRefIterator,
11    IntoParallelRefMutIterator, ParallelBridge, ParallelIterator, ParallelSliceMut,
12};
13
14#[cfg(not(feature = "parallel"))]
15pub use self::fallback::*;
16
17#[cfg(not(feature = "parallel"))]
18mod fallback {
19    pub use std::iter::Iterator as ParallelIterator;
20    pub use std::iter::Iterator as IndexedParallelIterator;
21
22    /// Shim trait to allow `into_par_iter()` on types that implement `IntoIterator`.
23    pub trait IntoParallelIterator {
24        type Item;
25        type Iter: Iterator<Item = Self::Item>;
26        fn into_par_iter(self) -> Self::Iter;
27    }
28
29    impl<I: IntoIterator> IntoParallelIterator for I {
30        type Item = I::Item;
31        type Iter = I::IntoIter;
32        fn into_par_iter(self) -> Self::Iter {
33            self.into_iter()
34        }
35    }
36
37    /// Shim trait to allow `par_iter()` on types that implement `IntoIterator` for `&T`.
38    pub trait IntoParallelRefIterator<'data> {
39        type Item;
40        type Iter: Iterator<Item = Self::Item>;
41        fn par_iter(&'data self) -> Self::Iter;
42    }
43
44    impl<'data, I: 'data + ?Sized> IntoParallelRefIterator<'data> for I
45    where
46        &'data I: IntoIterator,
47    {
48        type Item = <&'data I as IntoIterator>::Item;
49        type Iter = <&'data I as IntoIterator>::IntoIter;
50        fn par_iter(&'data self) -> Self::Iter {
51            self.into_iter()
52        }
53    }
54
55    /// Shim trait to allow `par_iter_mut()` on types that implement `IntoIterator` for `&mut T`.
56    pub trait IntoParallelRefMutIterator<'data> {
57        type Item;
58        type Iter: Iterator<Item = Self::Item>;
59        fn par_iter_mut(&'data mut self) -> Self::Iter;
60    }
61
62    impl<'data, I: 'data + ?Sized> IntoParallelRefMutIterator<'data> for I
63    where
64        &'data mut I: IntoIterator,
65    {
66        type Item = <&'data mut I as IntoIterator>::Item;
67        type Iter = <&'data mut I as IntoIterator>::IntoIter;
68        fn par_iter_mut(&'data mut self) -> Self::Iter {
69            self.into_iter()
70        }
71    }
72
73    /// Shim trait to allow `par_bridge()` on Iterators.
74    pub trait ParallelBridge: Iterator {
75        fn par_bridge(self) -> Self;
76    }
77
78    impl<T: Iterator> ParallelBridge for T {
79        fn par_bridge(self) -> Self {
80            self
81        }
82    }
83
84    /// Shim trait to allow parallel sorting on slices.
85    pub trait ParallelSliceMut<T> {
86        /// Sorts the slice using the default ordering, potentially in parallel.
87        fn par_sort_unstable(&mut self)
88        where
89            T: Ord;
90
91        /// Sorts the slice using a key extraction function, potentially in parallel.
92        fn par_sort_unstable_by_key<K, F>(&mut self, f: F)
93        where
94            K: Ord,
95            F: Fn(&T) -> K;
96    }
97
98    impl<T> ParallelSliceMut<T> for [T] {
99        fn par_sort_unstable(&mut self)
100        where
101            T: Ord,
102        {
103            self.sort_unstable();
104        }
105
106        fn par_sort_unstable_by_key<K, F>(&mut self, f: F)
107        where
108            K: Ord,
109            F: Fn(&T) -> K,
110        {
111            self.sort_unstable_by_key(f)
112        }
113    }
114
115    /// Extension trait to add Rayon-like methods to standard Iterators.
116    pub trait ParallelIteratorExt: Iterator {
117        fn flat_map_iter<U, F>(self, f: F) -> std::iter::FlatMap<Self, U, F>
118        where
119            Self: Sized,
120            U: IntoIterator,
121            F: FnMut(Self::Item) -> U,
122        {
123            self.flat_map(f)
124        }
125
126        fn try_reduce<T, E, ID, OP>(mut self, identity: ID, mut op: OP) -> Result<T, E>
127        where
128            Self: Sized + Iterator<Item = Result<T, E>>,
129            ID: Fn() -> T,
130            OP: FnMut(T, T) -> Result<T, E>,
131        {
132            let mut acc = identity();
133            for item in self {
134                match item {
135                    Ok(v) => acc = op(acc, v)?,
136                    Err(e) => return Err(e),
137                }
138            }
139            Ok(acc)
140        }
141    }
142
143    impl<I: Iterator> ParallelIteratorExt for I {}
144}