orx_parallel/
iter_into_par_iter.rs

1use crate::{Params, computational_variants::Par, runner::DefaultRunner};
2use orx_concurrent_iter::{IterIntoConcurrentIter, implementations::ConIterOfIter};
3
4/// Any regular iterator implements [`IterIntoParIter`] trait allowing them to be used
5/// as a parallel iterator; i.e., [`ParIter`], by calling [`iter_into_par`].
6///
7/// Pulling of elements from the iterator are synchronized and safely shared to threads.
8///
9/// Therefore, converting an iterator into a parallel iterator is most useful whenever
10/// the work to be done on each element is a larger task than just yielding elements by the
11/// underlying collection or generator.
12///
13/// Note that every [`IterIntoConcurrentIter`] type automatically implements [`IterIntoParIter`].
14///
15/// [`iter_into_par`]: crate::IterIntoParIter::iter_into_par
16/// [`ParIter`]: crate::ParIter
17/// [`IterIntoConcurrentIter`]: orx_concurrent_iter::IterIntoConcurrentIter
18///
19/// # Examples
20///
21/// In the following example, an arbitrary iterator is converted into a parallel iterator
22/// and shared with multiple threads as a shared reference.
23///
24/// ```
25/// use orx_parallel::*;
26///
27/// let data: Vec<_> = (0..100).map(|x| x.to_string()).collect();
28///
29/// // an arbitrary iterator
30/// let iter = data
31///     .into_iter()
32///     .filter(|x| !x.starts_with('3'))
33///     .map(|x| format!("{x}!"));
34///
35/// // convert arbitrary iterator into ParIter
36/// let par_iter = iter.iter_into_par();
37/// let num_characters = par_iter.map(|x| x.len()).sum();
38///
39/// assert_eq!(num_characters, 258);
40/// ```
41///
42/// Similarly, in the following example, computation over elements of a generic
43/// iterator are distributed into multiple threads.
44///
45/// ```
46/// use orx_parallel::*;
47///
48/// let data: Vec<_> = (0..123).collect();
49///
50/// // arbitrary iterator
51/// let iter = data.iter().filter(|x| *x % 2 == 0).map(|x| x.to_string());
52///
53/// // parallel computation
54/// let sum_evens = iter
55///     .iter_into_par()
56///     .map(|x| x.parse::<u64>().unwrap())
57///     .sum();
58///
59/// assert_eq!(sum_evens, 3782);
60/// ```
61pub trait IterIntoParIter: Iterator {
62    /// Any regular iterator implements [`IterIntoParIter`] trait allowing them to be used
63    /// as a parallel iterator; i.e., [`ParIter`], by calling [`iter_into_par`].
64    ///
65    /// Pulling of elements from the iterator are synchronized and safely shared to threads.
66    ///
67    /// Therefore, converting an iterator into a parallel iterator is most useful whenever
68    /// the work to be done on each element is a larger task than just yielding elements by the
69    /// underlying collection or generator.
70    ///
71    /// Note that every [`IterIntoConcurrentIter`] type automatically implements [`IterIntoParIter`].
72    ///
73    /// [`iter_into_par`]: crate::IterIntoParIter::iter_into_par
74    /// [`ParIter`]: crate::ParIter
75    /// [`IterIntoConcurrentIter`]: orx_concurrent_iter::IterIntoConcurrentIter
76    ///
77    /// # Examples
78    ///
79    /// In the following example, an arbitrary iterator is converted into a parallel iterator
80    /// and shared with multiple threads as a shared reference.
81    ///
82    /// ```
83    /// use orx_parallel::*;
84    ///
85    /// let data: Vec<_> = (0..100).map(|x| x.to_string()).collect();
86    ///
87    /// // an arbitrary iterator
88    /// let iter = data
89    ///     .into_iter()
90    ///     .filter(|x| !x.starts_with('3'))
91    ///     .map(|x| format!("{x}!"));
92    ///
93    /// // convert arbitrary iterator into ParIter
94    /// let par_iter = iter.iter_into_par();
95    /// let num_characters = par_iter.map(|x| x.len()).sum();
96    ///
97    /// assert_eq!(num_characters, 258);
98    /// ```
99    ///
100    /// Similarly, in the following example, computation over elements of a generic
101    /// iterator are distributed into multiple threads.
102    ///
103    /// ```
104    /// use orx_parallel::*;
105    ///
106    /// let data: Vec<_> = (0..123).collect();
107    ///
108    /// // arbitrary iterator
109    /// let iter = data.iter().filter(|x| *x % 2 == 0).map(|x| x.to_string());
110    ///
111    /// // parallel computation
112    /// let sum_evens = iter
113    ///     .iter_into_par()
114    ///     .map(|x| x.parse::<u64>().unwrap())
115    ///     .sum();
116    ///
117    /// assert_eq!(sum_evens, 3782);
118    /// ```
119    fn iter_into_par(self) -> Par<ConIterOfIter<Self>, DefaultRunner>
120    where
121        Self: Sized,
122        Self::Item: Send;
123}
124
125impl<I> IterIntoParIter for I
126where
127    I: Iterator,
128    I::Item: Send + Sync,
129{
130    fn iter_into_par(self) -> Par<ConIterOfIter<Self>, DefaultRunner> {
131        Par::new(
132            Default::default(),
133            Params::default(),
134            self.iter_into_con_iter(),
135        )
136    }
137}