Skip to main content

orx_parallel/infallible/
par.rs

1use crate::infallible::fun::{FnCloned, FnCopied};
2use crate::infallible::xap::FlattenOf;
3use crate::infallible::{FilMapOf, FilOf, FlatMapOf, InsOf, MapOf, MappedOf, ParIter};
4use crate::infallible::{Xap, xap_variants::Id};
5use crate::infallible_use::{ParUseIter, xap_variants::IdUse};
6use crate::option::ParOptionIter;
7use crate::result::ParResultIter;
8use crate::sizes::{One, Size};
9use crate::use_var::{UseSlice, UseVec};
10use crate::{ChunkSize, IterationOrder, NumThreads, ParExtend};
11use crate::{ParOption, ParResult, ParUse, Sum};
12use crate::{infallible::par_core::ParCore, runner::ParRunner};
13use alloc::vec::Vec;
14use core::cmp::Ordering;
15use orx_concurrent_iter::ExactSizeConcurrentIter;
16
17/// Infallible parallel iterator.
18///
19/// `Par` is the central trait for describing parallel computations as iterator
20/// pipelines. It mirrors common sequential iterator operations (`map`,
21/// `filter`, `flat_map`, `collect`, `reduce`, ...) while allowing runtime
22/// configuration of execution details such as number of threads, chunk size,
23/// iteration order, and runner/pool selection.
24///
25/// Related traits:
26/// - [`ParUse`](crate::ParUse) for worker-local mutable state,
27/// - [`ParOption`](crate::ParOption) for `Option`-based fallibility,
28/// - [`ParResult`](crate::ParResult) for `Result`-based fallibility.
29///
30/// # Examples
31///
32/// ```
33/// use orx_parallel::*;
34///
35/// let sum_of_even_squares: usize = (1..11)
36///     .into_par()
37///     .map(|x| x * x)
38///     .filter(|x| x % 2 == 0)
39///     .sum();
40///
41/// assert_eq!(sum_of_even_squares, 220);
42/// ```
43pub trait Par: Sized + ParCore {
44    // configuration
45
46    /// Replaces the current parallel runner with `runner`.
47    ///
48    /// This allows per-computation control over execution strategy.
49    ///
50    /// Please see [`Runner`] for parallel runners implemented in this crate.
51    ///
52    /// [`Runner`]: crate::Runner
53    ///
54    /// # Examples
55    ///
56    /// ```
57    /// use orx_parallel::*;
58    ///
59    /// let baseline: usize = (0..1000).into_par().sum();
60    ///
61    /// let par = (0..1000).par();
62    ///
63    /// let par = par.runner(Runner::fixed());
64    ///     
65    /// let configured: usize = par.sum();
66    /// assert_eq!(baseline, configured);
67    /// ```
68    fn runner<Q: ParRunner>(
69        self,
70        runner: Q,
71    ) -> impl Par<Item = Self::Item, Xap = Self::Xap, Input = Self::Input>;
72
73    /// Wraps the current parallel runner with a diagnostics-enabled runner.
74    ///
75    /// The returned iterator behaves the same, but additionally reports runtime
76    /// diagnostics at the end of the computation.
77    ///
78    /// # Examples
79    ///
80    /// ```
81    /// # #[cfg(feature = "std")]
82    /// # fn main() {
83    /// use orx_parallel::*;
84    ///
85    /// let par = (1..10_001).par().num_threads(4);
86    ///
87    /// #[cfg(feature = "std")]
88    /// let par = par.runner_with_diagnostics();
89    ///
90    /// let sum = par.sum();
91    /// assert_eq!(sum, 50005000);
92    /// # }
93    /// ```
94    ///
95    /// This will print a summary report which currently looks like the following:
96    ///
97    /// ```console
98    /// │ # Parallel Executor Diagnostics
99    /// │
100    /// │   Available threads : 4
101    /// │   Used threads      : 4
102    /// │   Wall time         : 1.15 ms
103    /// │
104    /// │ ## Summary Table
105    /// │   thread  num_chunks   num_tasks  min_chunk  avg_chunk  max_chunk    util%
106    /// │   ------  ----------  ----------  ---------  ---------  ---------  -------
107    /// │        0          35       27335        781        781        781   100.0%
108    /// │        1          32       24992        781        781        781    91.5%
109    /// │        2          30       23430        781        781        781    85.9%
110    /// │        3          28       21868        781        781        781    77.8%
111    /// │
112    /// │ ## Workload Balance
113    /// │   max/min task ratio  : 1.25x  (1.00 = perfect balance)
114    /// │   coeff. of variation : 8.3%  (lower is better)
115    /// │
116    /// │ ## Thread Active Timeline  (each block ≈ 0.02 ms)
117    /// │   [ 0] ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇
118    /// │   [ 1]     ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇
119    /// │   [ 2]         ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇
120    /// │   [ 3]             ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇
121    /// │
122    /// │ ## Thread Task Distribution  (bar length ∝ tasks processed)
123    /// │   [ 0] ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇  (27335)
124    /// │   [ 1] ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇  (24992)
125    /// │   [ 2] ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇  (23430)
126    /// │   [ 3] ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇  (21868)
127    /// ```
128    #[cfg(feature = "std")]
129    fn runner_with_diagnostics(
130        self,
131    ) -> impl Par<Item = Self::Item, Xap = Self::Xap, Input = Self::Input>;
132
133    /// Sets the maximum number of worker threads for this computation.
134    ///
135    /// This method configures the **computation layer** of the thread count decision.
136    /// The actual number of threads used is determined by combining:
137    ///
138    /// 1. **Pool constraint** (from `pool()` method or default pool)
139    ///    - Already includes `ORX_NUM_THREADS` environment variable constraint
140    /// 2. **Computation constraint** (this method)
141    ///    - Your per-computation thread preference
142    /// 3. **Input size constraint**
143    ///    - Cannot spawn more threads than input elements
144    ///
145    /// The actual thread count is the **minimum** of all these constraints.
146    ///
147    /// # Parameter Interpretation
148    ///
149    /// Integer values map as follows:
150    /// - `0` => `NumThreads::Auto` (use all available threads, spawn only as needed)
151    /// - `n > 0` => `NumThreads::Max(n)` (cap at `n` threads)
152    ///
153    /// # Thread Count Decision Logic
154    ///
155    /// ```text
156    /// available = pool.max_num_threads()      // Pool maximum (includes env variable)
157    ///
158    /// requested = match num_threads {
159    ///     0 | Auto => input_size.max(1),      // Limited by input size
160    ///     Max(n) => min(input_size, n),       // Limited by input size and this param
161    /// };
162    ///
163    /// actual_threads = min(requested, available)
164    /// ```
165    ///
166    /// # Examples
167    ///
168    /// ```ignore
169    /// use orx_parallel::*;
170    ///
171    /// // Sequential execution
172    /// let sum: usize = (1..11).into_par().num_threads(1).sum();
173    /// assert_eq!(sum, 55);
174    ///
175    /// // Cap at 4 threads
176    /// let sum: usize = (1..1001).into_par().num_threads(4).sum();
177    ///
178    /// // Auto: uses available threads (respects ORX_NUM_THREADS)
179    /// let sum: usize = (1..11).into_par().num_threads(0).sum();
180    /// ```
181    ///
182    /// # See Also
183    ///
184    /// - [`NumThreads`](crate::NumThreads) - Type for thread configuration
185    /// - [`thread_usage.md`](https://github.com/orxfun/orx-parallel/blob/main/docs/thread_usage.md) - Complete threading guide
186    fn num_threads(self, num_threads: impl Into<NumThreads>) -> Self;
187
188    /// Sets chunk size used when pulling items from the concurrent input.
189    ///
190    /// Integer values map as follows:
191    /// - `0` => automatic (default)
192    /// - `n > 0` => exact chunk size `n`
193    ///
194    /// # Examples
195    ///
196    /// ```
197    /// use orx_parallel::*;
198    ///
199    /// let values: Vec<_> = (0..32)
200    ///     .into_par()
201    ///     .chunk_size(8)
202    ///     .map(|x| x + 1)
203    ///     .collect();
204    ///
205    /// assert_eq!(values.len(), 32);
206    /// assert_eq!(values[0], 1);
207    /// assert_eq!(values[31], 32);
208    /// ```
209    ///
210    /// # Rules of Thumb
211    ///
212    /// * Automatic chunk size (default) is efficient in general.
213    ///   Parallel runner aims to find best chunk sizes to balance between minimizing parallelization overhead
214    ///   and maximizing resource utilization.
215    /// * While tuning a specific computation, we aim to find the smallest chunk size that is large enough
216    ///   to mitigate the impact of parallelization overhead.
217    /// * If the individual tasks are large enough, parallelization overhead becomes insignificant making
218    ///   `chunk_size = 1` the optimal choice.
219    fn chunk_size(self, chunk_size: impl Into<ChunkSize>) -> Self;
220
221    /// Sets iteration order semantics for operations sensitive to ordering.
222    ///
223    /// `Ordered` (default) preserves positional meaning (for example, `first` returns the
224    /// earliest matching element in input order). `Arbitrary` allows any matching
225    /// element that is reached first in parallel execution.
226    ///
227    /// # Examples
228    ///
229    /// ```
230    /// use orx_parallel::*;
231    ///
232    /// let ordered = (1..10_000)
233    ///     .into_par()
234    ///     .iteration_order(IterationOrder::Ordered)
235    ///     .find(|x| x % 3421 == 0);
236    /// assert_eq!(ordered, Some(3421));
237    ///
238    /// let any = (1..10_000)
239    ///     .into_par()
240    ///     .iteration_order(IterationOrder::Arbitrary)
241    ///     .find(|x| x % 3421 == 0)
242    ///     .unwrap();
243    /// assert!([3421, 6842].contains(&any));
244    /// ```
245    fn iteration_order(self, collect: IterationOrder) -> Self;
246
247    // kind transformations
248
249    /// Converts `Par<Item = Option<T>>` into `ParOption<Item = T>`.
250    ///
251    /// The resulting fallible iterator **short-circuits** to `None` if any element is `None`.
252    ///
253    /// Similar to pattern using the `?` operator, fallible iterators allow us to work with
254    /// the **success path**.
255    ///
256    /// # Examples
257    ///
258    /// ```
259    /// use orx_parallel::*;
260    ///
261    /// let ok: Option<Vec<_>> = ["1", "2", "3"]
262    ///     .into_par()
263    ///     .map(|s| s.parse::<i32>().ok())
264    ///     .into_optional()
265    ///     .map(|x| x * 2)
266    ///     .filter(|x| *x > 3)
267    ///     .collect();
268    /// assert_eq!(ok, Some(vec![4, 6]));
269    ///
270    /// let fail: Option<Vec<_>> = ["1", "x", "3"]
271    ///     .into_par()
272    ///     .map(|s| s.parse::<i32>().ok())
273    ///     .into_optional()
274    ///     .map(|x| x * 2)
275    ///     .filter(|x| *x > 3)
276    ///     .collect();
277    /// assert_eq!(fail, None);
278    /// ```
279    ///
280    /// Notice that `x` is of type `i32`, rather than `Option<i32>`, which allows for concise
281    /// expressions.
282    ///
283    /// Without fallible iterators, the above result could be obtained by the following version,
284    /// which is not only more verbose, but also lacks the short-circuiting mechanism.
285    ///
286    /// ```
287    /// use orx_parallel::*;
288    ///
289    /// let ok: Option<Vec<_>> = ["1", "2", "3"]
290    ///     .into_par()
291    ///     .map(|s| s.parse::<i32>().ok())
292    ///     .map(|x| x.map(|x| x * 2))
293    ///     .filter(|x| x.as_ref().map(|x| *x > 3).unwrap_or(true))
294    ///     .collect::<Vec<_>>()
295    ///     .into_iter()
296    ///     .collect();
297    /// assert_eq!(ok, Some(vec![4, 6]));
298    /// ```
299    fn into_optional<T>(
300        self,
301    ) -> impl ParOption<
302        Elem = T,
303        Xap1 = Self::Xap,
304        M = T,
305        Xap2 = Id<T>,
306        Input = Self::Input,
307        Size = <<Self::Xap as Xap>::Size as Size>::IntoPair,
308    >
309    where
310        Self::Xap: Xap<O = Option<T>>,
311    {
312        let (iter, xap, exe, params) = self.destruct();
313
314        ParOptionIter::new(iter, xap, Id::new(), exe, params)
315    }
316
317    /// Converts `Par<Item = Result<T, E>>` into `ParResult<Item = T, Error = E>`.
318    ///
319    /// The resulting fallible iterator **short-circuits** and returns the first
320    /// observed error.
321    ///
322    /// Similar to pattern using the `?` operator, fallible iterators allow us to
323    /// work with the **success path**.
324    ///
325    /// # Examples
326    ///
327    /// ```
328    /// use orx_parallel::*;
329    ///
330    /// let ok: Result<Vec<_>, _> = ["1", "2", "3"]
331    ///     .into_par()
332    ///     .map(|s| s.parse::<i32>())
333    ///     .into_fallible()
334    ///     .map(|x| x * 2)
335    ///     .filter(|x| *x > 3)
336    ///     .collect();
337    /// assert_eq!(ok, Ok(vec![4, 6]));
338    ///
339    /// let fail: Result<Vec<_>, _> = ["1", "x", "3"]
340    ///     .into_par()
341    ///     .map(|s| s.parse::<i32>())
342    ///     .into_fallible()
343    ///     .map(|x| x * 2)
344    ///     .filter(|x| *x > 3)
345    ///     .collect();
346    /// assert!(fail.is_err());
347    /// ```
348    ///
349    /// Notice that `x` is of type `i32`, rather than `Result<i32, _>`, which
350    /// allows for concise expressions.
351    ///
352    /// Without fallible iterators, the above result could be obtained by the
353    /// following version, which is not only more verbose, but also lacks the
354    /// short-circuiting mechanism.
355    ///
356    /// ```
357    /// use orx_parallel::*;
358    ///
359    /// let ok: Result<Vec<_>, _> = ["1", "2", "3"]
360    ///     .into_par()
361    ///     .map(|s| s.parse::<i32>())
362    ///     .map(|x| x.map(|x| x * 2))
363    ///     .filter(|x| x.as_ref().map(|x| *x > 3).unwrap_or(true))
364    ///     .collect::<Vec<_>>()
365    ///     .into_iter()
366    ///     .collect();
367    /// assert_eq!(ok, Ok(vec![4, 6]));
368    /// ```
369    fn into_fallible<T, E>(
370        self,
371    ) -> impl ParResult<
372        Elem = T,
373        Error = E,
374        Xap1 = Self::Xap,
375        M = T,
376        Xap2 = Id<T>,
377        Input = Self::Input,
378        Size = <<Self::Xap as Xap>::Size as Size>::IntoPair,
379    >
380    where
381        Self::Xap: Xap<O = Result<T, E>>,
382    {
383        let (iter, xap, exe, params) = self.destruct();
384        ParResultIter::new(iter, xap, Id::new(), exe, params)
385    }
386
387    /// Creates one mutable `Use` value per participating worker.
388    ///
389    /// The initializer `f` is called with the worker's thread index, and the
390    /// returned value is then passed as `&mut Use` to downstream [`ParUse`]
391    /// operations such as `map`, `filter`, `flat_map`, `reduce`, and `for_each`.
392    ///
393    /// This is useful for thread-local scratch buffers, counters, or other
394    /// mutable state that should not be shared across workers.
395    ///
396    /// # Examples
397    ///
398    /// Reusing one buffer per worker avoids allocating a fresh String
399    /// for every parsed item.
400    ///
401    /// ```
402    /// use orx_parallel::*;
403    ///
404    /// let values: Vec<_> = (1..4)
405    ///     .into_par()
406    ///     .num_threads(1)
407    ///     .use_new(|_| String::new())
408    ///     .map(|buffer, x| {
409    ///         buffer.clear();
410    ///         buffer.push_str(&x.to_string());
411    ///         buffer.parse::<usize>().unwrap() * 10
412    ///     })
413    ///     .collect();
414    ///
415    /// assert_eq!(values, vec![10, 20, 30]);
416    /// ```
417    ///
418    /// Some pipelines need fast worker-local randomness, for example for
419    /// sampling, randomized search, or simulation.
420    /// Seeding one RNG per worker with thread_idx creates independent
421    /// thread-local random streams without shared mutable state.
422    ///
423    /// ```
424    /// use orx_parallel::*;
425    /// use rand::{Rng, RngExt, SeedableRng};
426    /// use rand_chacha::ChaCha8Rng;
427    ///
428    /// let values: Vec<_> = (0..8)
429    ///     .into_par()
430    ///     .num_threads(2)
431    ///     .use_new(|thread_idx| ChaCha8Rng::seed_from_u64(thread_idx as u64 + 1))
432    ///     .map(|rng, _| rng.random_range(0..100usize))
433    ///     .collect();
434    ///
435    /// assert_eq!(values.len(), 8);
436    /// assert!(values.into_iter().all(|x| x < 100));
437    /// ```
438    fn use_new<U, F>(
439        self,
440        f: F,
441    ) -> impl ParUse<Item = Self::Item, Use = U, Xap = IdUse<Self::Xap, U>, Input = Self::Input>
442    where
443        U: Send,
444        F: Fn(usize) -> U + Sync,
445    {
446        let (iter, xap, exe, params) = self.destruct();
447        let xap = IdUse::new(xap);
448        let using = UseVec::new(f);
449        ParUseIter::new(using, iter, xap, exe, params)
450    }
451
452    /// Uses an externally owned [`UseVec`] as worker-local mutable state.
453    ///
454    /// Unlike [`Par::use_new`], the state container is provided by the caller,
455    /// which allows reading back per-worker values after the computation.
456    ///
457    /// This is practical when we need thread-local accumulation with a final
458    /// merge step, such as per-thread partial sums or local metrics.
459    ///
460    /// Note that the resulting `UseVec` length equals the number of worker
461    /// threads that actually participated in the computation. Exactly one
462    /// element is created per participating thread.
463    ///
464    /// # Examples
465    ///
466    /// ```
467    /// use orx_parallel::*;
468    ///
469    /// let n = 10_000usize;
470    /// let mut use_vec = UseVec::new(|_| 0usize);
471    ///
472    /// (0..n)
473    ///     .into_par()
474    ///     .map(|x| 2 * x)
475    ///     .use_vec(&mut use_vec)
476    ///     .for_each(|thread_sum, x| *thread_sum += x);
477    ///
478    /// let partial_sums = use_vec.into_vec();
479    /// let total: usize = partial_sums.into_iter().sum();
480    ///
481    /// assert_eq!(total, (n - 1) * n);
482    /// ```
483    ///
484    /// The following example demonstrates an expensive per-thread state:
485    /// a pre-allocated scratch buffer.
486    ///
487    /// ```
488    /// use core::fmt::Write;
489    /// use core::sync::atomic::{AtomicUsize, Ordering};
490    /// use orx_parallel::*;
491    ///
492    /// let created = AtomicUsize::new(0);
493    /// let mut use_vec = UseVec::new(|_| {
494    ///     created.fetch_add(1, Ordering::Relaxed);
495    ///     String::with_capacity(4096)
496    /// });
497    ///
498    /// let out: Vec<_> = (0..64)
499    ///     .into_par()
500    ///     .num_threads(4)
501    ///     .use_vec(&mut use_vec)
502    ///     .map(|buffer, x| {
503    ///         buffer.clear();
504    ///         write!(buffer, "{x}").unwrap();
505    ///         buffer.parse::<usize>().unwrap()
506    ///     })
507    ///     .collect();
508    ///
509    /// assert_eq!(out, (0..64).collect::<Vec<_>>());
510    ///
511    /// let buffers = use_vec.into_vec();
512    /// assert_eq!(created.load(Ordering::Relaxed), buffers.len());
513    /// assert!(buffers.len() <= 4);
514    /// ```
515    fn use_vec<U, F>(
516        self,
517        use_vec: &mut UseVec<U, F>,
518    ) -> impl ParUse<Item = Self::Item, Use = U, Xap = IdUse<Self::Xap, U>, Input = Self::Input>
519    where
520        U: Send,
521        F: Fn(usize) -> U + Sync,
522    {
523        let (iter, xap, exe, params) = self.destruct();
524        let xap = IdUse::new(xap);
525        ParUseIter::new(use_vec, iter, xap, exe, params)
526    }
527
528    /// Uses a caller-provided mutable slice as worker-local mutable state.
529    ///
530    /// This is similar to [`Par::use_vec`], but the state storage is a
531    /// borrowed slice instead of an owned `UseVec`. Therefore, no per-thread
532    /// state objects are created by this method; existing slice elements are
533    /// reused as thread-local state.
534    ///
535    /// The number of worker threads that can participate in the computation is
536    /// limited by `slice.len()`.
537    ///
538    /// # Examples
539    ///
540    /// ```
541    /// use orx_parallel::*;
542    ///
543    /// let n = 10_000usize;
544    /// let mut thread_sums = vec![0usize; 4];
545    ///
546    /// (0..n)
547    ///     .into_par()
548    ///     .map(|x| 2 * x)
549    ///     .use_slice(&mut thread_sums)    // participating workers are limited to 4
550    ///     .for_each(|thread_sum, x| *thread_sum += x);
551    ///
552    /// let total: usize = thread_sums.into_iter().sum();
553    /// assert_eq!(total, (n - 1) * n);
554    /// ```
555    ///
556    /// # Panics
557    ///
558    /// Panics if `slice` is empty.
559    fn use_slice<'a, U>(
560        self,
561        slice: &'a mut [U],
562    ) -> impl ParUse<Item = Self::Item, Use = U, Xap = IdUse<Self::Xap, U>, Input = Self::Input>
563    where
564        U: Send + 'a,
565    {
566        assert!(
567            !slice.is_empty(),
568            "Number of parallel threads is limited to slice.len(); and hence, slice cannot be empty."
569        );
570        let (iter, xap, exe, params) = self.destruct();
571        let xap = IdUse::new(xap);
572        let using = UseSlice::new(slice);
573        ParUseIter::new(using, iter, xap, exe, params)
574    }
575
576    /// Copies elements of a reference iterator.
577    ///
578    /// Equivalent to `.map(|&x| x)`.
579    ///
580    /// # Examples
581    ///
582    /// ```
583    /// use orx_parallel::*;
584    ///
585    /// let data = vec![1, 2, 3];
586    /// let copied: Vec<_> = data.par().copied().collect();
587    ///
588    /// assert_eq!(copied, vec![1, 2, 3]);
589    /// ```
590    fn copied<'a, O>(
591        self,
592    ) -> impl Par<Item = O, Xap = MappedOf<Self::Xap, FnCopied<'a, O>>, Input = Self::Input>
593    where
594        Self: Par<Item = &'a O>,
595        O: Copy + 'a,
596    {
597        let (iter, xap, exe, params) = self.destruct();
598        ParIter::new(iter, xap.mapped(FnCopied::new()), exe, params)
599    }
600
601    /// Clones elements of a reference iterator.
602    ///
603    /// Equivalent to `.map(|x| x.clone())`.
604    ///
605    /// # Examples
606    ///
607    /// ```
608    /// use orx_parallel::*;
609    ///
610    /// let data = vec!["a".to_string(), "b".to_string()];
611    /// let cloned: Vec<_> = data.par().cloned().collect();
612    ///
613    /// assert_eq!(cloned, vec!["a".to_string(), "b".to_string()]);
614    /// ```
615    fn cloned<'a, O>(
616        self,
617    ) -> impl Par<Item = O, Xap = MappedOf<Self::Xap, FnCloned<'a, O>>, Input = Self::Input>
618    where
619        Self: Par<Item = &'a O>,
620        O: Clone + 'a,
621    {
622        let (iter, xap, exe, params) = self.destruct();
623        ParIter::new(iter, xap.mapped(FnCloned::new()), exe, params)
624    }
625
626    // transformations
627
628    /// Maps each element with closure `h`.
629    ///
630    /// # Examples
631    ///
632    /// ```
633    /// use orx_parallel::*;
634    ///
635    /// let doubled: Vec<_> = (1..4).into_par().map(|x| 2 * x).collect();
636    /// assert_eq!(doubled, vec![2, 4, 6]);
637    /// ```
638    fn map<Q, H>(
639        self,
640        h: H,
641    ) -> impl Par<Item = Q, Xap = MapOf<Self::Xap, Q, H>, Input = Self::Input>
642    where
643        H: Fn(Self::Item) -> Q + Copy + Send;
644
645    /// Runs `h` on each element and forwards the item unchanged.
646    ///
647    /// Useful for logging or debugging pipelines.
648    ///
649    /// # Examples
650    ///
651    /// ```
652    /// use orx_parallel::*;
653    ///
654    /// let out: Vec<_> = (1..5)
655    ///     .into_par()
656    ///     .inspect(|x| {
657    ///         println!("observed {x}");
658    ///     })
659    ///     .collect();
660    ///
661    /// assert_eq!(out, vec![1, 2, 3, 4]);
662    /// ```
663    fn inspect<H>(
664        self,
665        h: H,
666    ) -> impl Par<Item = Self::Item, Xap = InsOf<Self::Xap, H>, Input = Self::Input>
667    where
668        H: Fn(&Self::Item) + Copy + Send;
669
670    /// Keeps only elements satisfying predicate `h`.
671    ///
672    /// # Examples
673    ///
674    /// ```
675    /// use orx_parallel::*;
676    ///
677    /// let odds: Vec<_> = (1..7).into_par().filter(|x| x % 2 == 1).collect();
678    /// assert_eq!(odds, vec![1, 3, 5]);
679    /// ```
680    fn filter<H>(
681        self,
682        h: H,
683    ) -> impl Par<Item = Self::Item, Xap = FilOf<Self::Xap, H>, Input = Self::Input>
684    where
685        H: Fn(&Self::Item) -> bool + Copy + Send;
686
687    /// Maps and filters in a single pass.
688    ///
689    /// Returns mapped values for elements where `h` returns `Some(_)`.
690    ///
691    /// # Examples
692    ///
693    /// ```
694    /// use orx_parallel::*;
695    ///
696    /// let numbers: Vec<_> = ["1", "x", "5"]
697    ///     .into_par()
698    ///     .filter_map(|s| s.parse::<usize>().ok())
699    ///     .collect();
700    ///
701    /// assert_eq!(numbers, vec![1, 5]);
702    /// ```
703    fn filter_map<Q, H>(
704        self,
705        h: H,
706    ) -> impl Par<Item = Q, Xap = FilMapOf<Self::Xap, Q, H>, Input = Self::Input>
707    where
708        H: Fn(Self::Item) -> Option<Q> + Copy + Send;
709
710    /// Maps each element to an iterator and flattens one level.
711    ///
712    /// # Examples
713    ///
714    /// ```
715    /// use orx_parallel::*;
716    ///
717    /// let out: Vec<_> = (1..4).into_par().flat_map(|x| [x, x + 10]).collect();
718    /// assert_eq!(out, vec![1, 11, 2, 12, 3, 13]);
719    /// ```
720    fn flat_map<V, H>(
721        self,
722        h: H,
723    ) -> impl Par<Item = V::Item, Xap = FlatMapOf<Self::Xap, V, H>, Input = Self::Input>
724    where
725        V: IntoIterator,
726        H: Fn(Self::Item) -> V + Copy + Send;
727
728    /// Flattens one level of nested iterables.
729    ///
730    /// # Examples
731    ///
732    /// ```
733    /// use orx_parallel::*;
734    ///
735    /// let nested = vec![vec![1, 2], vec![3, 4]];
736    /// let flat: Vec<_> = nested.into_par().flatten().collect();
737    ///
738    /// assert_eq!(flat, vec![1, 2, 3, 4]);
739    /// ```
740    fn flatten(
741        self,
742    ) -> impl Par<
743        Item = <Self::Item as IntoIterator>::Item,
744        Xap = FlattenOf<Self::Xap>,
745        Input = Self::Input,
746    >
747    where
748        Self::Item: IntoIterator;
749
750    // get
751
752    /// Returns a lower and optional upper bound on the number of output items.
753    ///
754    /// The bounds follow the usual [`Iterator::size_hint`] convention. For an
755    /// exact-size input and a one-to-one transformation, both bounds are exact.
756    /// Transformations such as `filter` may reduce the lower bound while keeping
757    /// the input length as the upper bound.
758    ///
759    /// # Examples
760    ///
761    /// ```
762    /// use orx_parallel::*;
763    ///
764    /// let mapped = (0..4).into_par().map(|x| x * 2);
765    /// assert_eq!(mapped.size_hint(), (4, Some(4)));
766    ///
767    /// let filtered = (0..4).into_par().filter(|x| x % 2 == 0);
768    /// assert_eq!(filtered.size_hint(), (0, Some(4)));
769    /// ```
770    fn size_hint(&self) -> (usize, Option<usize>);
771
772    /// Returns the exact number of output items.
773    ///
774    /// # Examples
775    ///
776    /// ```
777    /// use orx_parallel::*;
778    ///
779    /// assert_eq!((0..10).into_par().len(), 10);
780    /// assert_eq!((0..10).into_par().map(|x| x + 2).len(), 10);
781    /// ```
782    fn len(&self) -> usize
783    where
784        Self::Input: ExactSizeConcurrentIter,
785        Self::Xap: Xap<Size = One>,
786    {
787        self.size_hint().0
788    }
789
790    /// Returns `true` when the parallel iterator has no output items.
791    ///
792    /// # Examples
793    ///
794    /// ```
795    /// use orx_parallel::*;
796    ///
797    /// assert!((0..0).into_par().is_empty());
798    /// assert!(!(0..1).into_par().is_empty());
799    /// ```
800    fn is_empty(&self) -> bool
801    where
802        Self::Input: ExactSizeConcurrentIter,
803        Self::Xap: Xap<Size = One>,
804    {
805        self.len() == 0
806    }
807
808    // compute
809
810    /// Returns the first item according to iteration order, or `None` if empty.
811    ///
812    /// With `IterationOrder::Ordered` (default), this is the earliest matching item by
813    /// input position. With `IterationOrder::Arbitrary`, this may be any
814    /// matching item reached first in parallel execution.
815    ///
816    /// This operation is short-circuiting: once a first candidate is determined,
817    /// remaining work is cancelled.
818    ///
819    /// # Examples
820    ///
821    /// ```
822    /// use orx_parallel::*;
823    ///
824    /// assert_eq!(Vec::<usize>::new().into_par().first(), None);
825    /// assert_eq!((1..4).into_par().first(), Some(1));
826    /// ```
827    fn first(self) -> Option<Self::Item>
828    where
829        Self::Item: Send;
830
831    /// Reduces items into one value using associative reducer `f`.
832    ///
833    /// Returns `None` for an empty iterator.
834    ///
835    /// # Examples
836    ///
837    /// ```
838    /// use orx_parallel::*;
839    ///
840    /// let reduced = (1..6).into_par().reduce(|a, b| a + b);
841    /// assert_eq!(reduced, Some(15));
842    /// ```
843    fn reduce<F>(self, f: F) -> Option<Self::Item>
844    where
845        F: Fn(Self::Item, Self::Item) -> Self::Item + Send + Copy,
846        Self::Item: Send;
847
848    /// Collects all items into `dst`.
849    ///
850    /// # Examples
851    ///
852    /// ```
853    /// use orx_parallel::*;
854    ///
855    /// let mut dst = vec![10];
856    /// (0..3).into_par().collect_into(&mut dst);
857    /// assert_eq!(dst, vec![10, 0, 1, 2]);
858    /// ```
859    fn collect_into<P>(self, dst: &mut P)
860    where
861        P: ParExtend<Self::Item>,
862        Self::Item: Send;
863
864    /// Collects all items into a new collection.
865    ///
866    /// # Examples
867    ///
868    /// ```
869    /// use orx_parallel::*;
870    ///
871    /// let out: Vec<_> = (1..4).into_par().map(|x| x * 2).collect();
872    /// assert_eq!(out, vec![2, 4, 6]);
873    /// ```
874    fn collect<P>(self) -> P
875    where
876        P: ParExtend<Self::Item> + Default,
877        Self::Item: Send,
878    {
879        let mut dst = P::default();
880        self.collect_into(&mut dst);
881        dst
882    }
883
884    // compute - derived
885
886    /// Returns `true` if all items satisfy predicate `f`.
887    ///
888    /// Empty iterators return `true`.
889    ///
890    /// This operation is short-circuiting: evaluation stops as soon as one item
891    /// fails the predicate.
892    ///
893    /// # Examples
894    ///
895    /// ```
896    /// use orx_parallel::*;
897    ///
898    /// assert!((1..5).into_par().all(|x| x > &0));
899    /// assert!(!(1..5).into_par().all(|x| x % 2 == 0));
900    /// ```
901    fn all<F>(self, f: F) -> bool
902    where
903        F: Fn(&Self::Item) -> bool + Sync,
904    {
905        self.map(|x| f(&x)).find(|x| !*x).is_none()
906    }
907
908    /// Returns `true` if any item satisfies predicate `f`.
909    ///
910    /// Empty iterators return `false`.
911    ///
912    /// This operation is short-circuiting: evaluation stops as soon as one item
913    /// satisfies the predicate.
914    ///
915    /// # Examples
916    ///
917    /// ```
918    /// use orx_parallel::*;
919    ///
920    /// assert!((1..5).into_par().any(|x| x % 2 == 0));
921    /// assert!(!(1..5).into_par().any(|x| x > &10));
922    /// ```
923    fn any<F>(self, f: F) -> bool
924    where
925        F: Fn(&Self::Item) -> bool + Sync,
926    {
927        self.map(|x| f(&x)).find(|x| *x).is_some()
928    }
929
930    /// Counts elements.
931    ///
932    /// # Examples
933    ///
934    /// ```
935    /// use orx_parallel::*;
936    ///
937    /// let n = (1..11).into_par().filter(|x| x % 3 == 0).count();
938    /// assert_eq!(n, 3);
939    /// ```
940    fn count(self) -> usize {
941        self.map(|_| 1).reduce(|a, b| a + b).unwrap_or(0)
942    }
943
944    /// Finds first ([`Ordered`], default) or any ([`Arbitrary`]) item satisfying predicate `f`.
945    ///
946    /// This is equivalent to `self.filter(f).first()`.
947    ///
948    /// This operation is short-circuiting: once a matching item is found,
949    /// remaining work is cancelled.
950    ///
951    /// [`Ordered`]: crate::IterationOrder::Ordered
952    /// [`Arbitrary`]: crate::IterationOrder::Arbitrary
953    ///
954    /// # Examples
955    ///
956    /// ```
957    /// use orx_parallel::*;
958    ///
959    /// let found = (1..101).into_par().find(|x| x % 17 == 0);
960    /// assert_eq!(found, Some(17));
961    /// ```
962    fn find<F>(self, f: F) -> Option<Self::Item>
963    where
964        Self::Item: Send,
965        F: Fn(&Self::Item) -> bool + Sync,
966    {
967        self.filter(&f).first()
968    }
969
970    /// Folds elements into per-thread accumulators and returns them.
971    ///
972    /// The output contains one accumulator for each participating worker.
973    ///
974    /// # Examples
975    ///
976    /// ```
977    /// use orx_parallel::*;
978    ///
979    /// let num_threads = 2;
980    ///
981    /// let partials: Vec<usize> = (1..6)
982    ///     .into_par()
983    ///     .num_threads(num_threads)
984    ///     .fold(|| 0usize, |acc, x| *acc += x);
985    ///
986    /// assert!(partials.len() <= num_threads);
987    ///
988    /// assert_eq!(partials.iter().sum::<usize>(), 15);
989    /// ```
990    fn fold<B, I, F>(self, init: I, f: F) -> Vec<B>
991    where
992        B: Send,
993        I: Fn() -> B + Sync,
994        F: Fn(&mut B, Self::Item) + Copy + Send,
995    {
996        let mut use_vec = UseVec::new(|_| init());
997        let par_use = self.use_vec(&mut use_vec);
998        par_use.for_each(move |u: &mut B, x| f(u, x));
999        use_vec.into_vec()
1000    }
1001
1002    /// Executes `f` for each item.
1003    ///
1004    /// # Examples
1005    ///
1006    /// ```
1007    /// use core::sync::atomic::{AtomicUsize, Ordering};
1008    /// use orx_parallel::*;
1009    ///
1010    /// let total = AtomicUsize::new(0);
1011    ///
1012    /// (1..5)
1013    ///     .into_par()
1014    ///     .for_each(|x| {
1015    ///         total.fetch_add(x, Ordering::Relaxed);
1016    ///     });
1017    ///
1018    /// assert_eq!(total.load(Ordering::Relaxed), 10);
1019    /// ```
1020    fn for_each<F>(self, f: F)
1021    where
1022        F: Fn(Self::Item) + Send + Copy,
1023    {
1024        let _ = self.map(f).reduce(|_, _| {});
1025    }
1026
1027    /// Returns maximum element, or `None` if empty.
1028    ///
1029    /// # Examples
1030    ///
1031    /// ```
1032    /// use orx_parallel::*;
1033    ///
1034    /// assert_eq!((1..5).into_par().max(), Some(4));
1035    /// assert_eq!(Vec::<usize>::new().into_par().max(), None);
1036    /// ```
1037    fn max(self) -> Option<Self::Item>
1038    where
1039        Self::Item: Ord + Send,
1040    {
1041        self.reduce(Ord::max)
1042    }
1043
1044    /// Returns element considered maximum by comparator `f`.
1045    ///
1046    /// # Examples
1047    ///
1048    /// ```
1049    /// use orx_parallel::*;
1050    ///
1051    /// let x = vec![-3_i32, 0, 1, 5, -10]
1052    ///     .into_par()
1053    ///     .max_by(|a, b| a.cmp(b));
1054    /// assert_eq!(x, Some(5));
1055    /// ```
1056    fn max_by<F>(self, f: F) -> Option<Self::Item>
1057    where
1058        Self::Item: Send,
1059        F: Fn(&Self::Item, &Self::Item) -> Ordering + Sync,
1060    {
1061        let reduce = |x, y| match f(&x, &y) {
1062            Ordering::Greater | Ordering::Equal => x,
1063            Ordering::Less => y,
1064        };
1065        self.reduce(reduce)
1066    }
1067
1068    /// Returns element with maximum key value.
1069    ///
1070    /// # Examples
1071    ///
1072    /// ```
1073    /// use orx_parallel::*;
1074    ///
1075    /// let x = vec![-3_i32, 0, 1, 5, -10]
1076    ///     .into_par()
1077    ///     .max_by_key(|x| x.abs());
1078    /// assert_eq!(x, Some(-10));
1079    /// ```
1080    fn max_by_key<B, F>(self, f: F) -> Option<Self::Item>
1081    where
1082        Self::Item: Send,
1083        B: Ord,
1084        F: Fn(&Self::Item) -> B + Sync,
1085    {
1086        let reduce = |x, y| match f(&x).cmp(&f(&y)) {
1087            Ordering::Greater | Ordering::Equal => x,
1088            Ordering::Less => y,
1089        };
1090        self.reduce(reduce)
1091    }
1092
1093    /// Returns minimum element, or `None` if empty.
1094    ///
1095    /// # Examples
1096    ///
1097    /// ```
1098    /// use orx_parallel::*;
1099    ///
1100    /// assert_eq!((1..5).into_par().min(), Some(1));
1101    /// assert_eq!(Vec::<usize>::new().into_par().min(), None);
1102    /// ```
1103    fn min(self) -> Option<Self::Item>
1104    where
1105        Self::Item: Ord + Send,
1106    {
1107        self.reduce(Ord::min)
1108    }
1109
1110    /// Returns element considered minimum by comparator `f`.
1111    ///
1112    /// # Examples
1113    ///
1114    /// ```
1115    /// use orx_parallel::*;
1116    ///
1117    /// let x = vec![-3_i32, 0, 1, 5, -10]
1118    ///     .into_par()
1119    ///     .min_by(|a, b| a.cmp(b));
1120    /// assert_eq!(x, Some(-10));
1121    /// ```
1122    fn min_by<F>(self, f: F) -> Option<Self::Item>
1123    where
1124        Self::Item: Send,
1125        F: Fn(&Self::Item, &Self::Item) -> Ordering + Sync,
1126    {
1127        let reduce = |x, y| match f(&x, &y) {
1128            Ordering::Less | Ordering::Equal => x,
1129            Ordering::Greater => y,
1130        };
1131        self.reduce(reduce)
1132    }
1133
1134    /// Returns element with minimum key value.
1135    ///
1136    /// # Examples
1137    ///
1138    /// ```
1139    /// use orx_parallel::*;
1140    ///
1141    /// let x = vec![-3_i32, 0, 1, 5, -10]
1142    ///     .into_par()
1143    ///     .min_by_key(|x| x.abs());
1144    /// assert_eq!(x, Some(0));
1145    /// ```
1146    fn min_by_key<B, F>(self, f: F) -> Option<Self::Item>
1147    where
1148        Self::Item: Send,
1149        B: Ord,
1150        F: Fn(&Self::Item) -> B + Sync,
1151    {
1152        let reduce = |x, y| match f(&x).cmp(&f(&y)) {
1153            Ordering::Less | Ordering::Equal => x,
1154            Ordering::Greater => y,
1155        };
1156        self.reduce(reduce)
1157    }
1158
1159    /// Sums elements using [`Sum`] implementation of the item type.
1160    ///
1161    /// Empty iterators return additive identity (`zero`).
1162    ///
1163    /// # Examples
1164    ///
1165    /// ```
1166    /// use orx_parallel::*;
1167    ///
1168    /// let sum: usize = (1..5).into_par().sum();
1169    /// assert_eq!(sum, 10);
1170    /// ```
1171    fn sum<S>(self) -> S
1172    where
1173        Self::Item: Sum<S>,
1174        S: Send,
1175    {
1176        self.map(Self::Item::owned)
1177            .reduce(Self::Item::add)
1178            .unwrap_or(Self::Item::zero())
1179    }
1180}