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}