Skip to main content

orx_parallel/infallible_use/
par.rs

1#![allow(clippy::type_complexity)]
2
3use crate::infallible::xap_variants::Id;
4use crate::infallible_use::fun::{UFnCloned, UFnCopied};
5use crate::infallible_use::par_core::ParUseCore;
6use crate::infallible_use::xap::FlattenOf;
7use crate::infallible_use::xap_variants::{IdUse, UDummyPair};
8use crate::infallible_use::{
9    FilMapOf, FilOf, FlatMapOf, InsOf, MapOf, MappedOf, ParUseIter, XapUse,
10};
11use crate::option_use::ParUseOptionIter;
12use crate::result_use::ParUseResultIter;
13use crate::runner::ParRunner;
14use crate::sizes::One;
15use crate::sizes::Size;
16use crate::use_var::{PairPtr, UseFold};
17use crate::{ChunkSize, IterationOrder, NumThreads, ParExtend, ParUseOption, ParUseResult, Sum};
18use alloc::vec::Vec;
19use core::cmp::Ordering;
20use orx_concurrent_iter::{ConcurrentIter, ExactSizeConcurrentIter};
21
22/// Parallel iterator pipelines with worker-local mutable state.
23///
24/// `ParUse` extends the usual parallel iterator pipeline with an associated
25/// [`Use`](crate::Use) value that is passed into transformation and reduction
26/// steps as mutable worker-local state. This is useful when each worker needs
27/// its own reusable scratch space, accumulator, or other per-thread context.
28///
29/// You can enter this mode from [`Par`](crate::Par) via
30/// [`use_new`](crate::Par::use_new),
31/// [`use_vec`](crate::Par::use_vec), or
32/// [`use_slice`](crate::Par::use_slice).
33///
34/// Related traits:
35/// - [`Par`](crate::Par) for pipelines without worker-local state,
36/// - [`ParUseOption`](crate::ParUseOption) via [`into_optional`](crate::ParUse::into_optional),
37/// - [`ParUseResult`](crate::ParUseResult) via [`into_fallible`](crate::ParUse::into_fallible).
38///
39/// # Examples
40///
41/// ```
42/// use orx_parallel::*;
43///
44/// let n = 10_000usize;
45/// let mut partial_sums = UseVec::new(|_| 0usize);
46///
47/// (0..n)
48///     .into_par()
49///     .use_vec(&mut partial_sums)
50///     .for_each(|thread_sum, x| *thread_sum += x);
51///
52/// let total: usize = partial_sums.into_vec().into_iter().sum();
53/// assert_eq!(total, (n - 1) * n / 2);
54/// ```
55///
56/// Using an RNG as mutable worker-local state:
57///
58/// ```
59/// use orx_parallel::*;
60/// use rand::prelude::*;
61/// use rand_chacha::ChaCha8Rng;
62///
63/// let values: Vec<_> = (0..128usize)
64///     .into_par()
65///     .use_new(|thread_idx| ChaCha8Rng::seed_from_u64(42 + thread_idx as u64))
66///     .map(|rng, x| x + rng.random_range(0..10))
67///     .collect();
68///
69/// assert_eq!(values.len(), 128);
70/// assert!(
71///     values
72///         .iter()
73///         .enumerate()
74///         .all(|(i, v)| *v >= i && *v < i + 10)
75/// );
76/// ```
77pub trait ParUse: Sized + ParUseCore {
78    // configuration
79
80    /// Replaces the current parallel runner with `runner`.
81    ///
82    /// This allows per-computation control over execution strategy.
83    ///
84    /// Please see [`Runner`](crate::Runner) for available runners.
85    ///
86    /// # Examples
87    ///
88    /// ```
89    /// use orx_parallel::*;
90    ///
91    /// let par = (1..101).par().use_new(|_| ());
92    ///
93    /// let par = par.runner(Runner::fixed());
94    ///
95    /// let sum = par.sum();
96    /// assert_eq!(sum, 5050);
97    /// ```
98    fn runner<Q: ParRunner>(
99        self,
100        runner: Q,
101    ) -> impl ParUse<Item = Self::Item, Use = Self::Use, Xap = Self::Xap, Input = Self::Input>;
102
103    #[cfg(feature = "std")]
104    /// Wraps the current runner with diagnostics-enabled execution.
105    ///
106    /// The resulting pipeline behaves the same, while also printing runtime
107    /// diagnostics at the end.
108    ///
109    /// # Examples
110    ///
111    /// ```
112    /// use orx_parallel::*;
113    ///
114    /// let par = (1..1001).par().use_new(|_| ());
115    ///
116    /// #[cfg(feature = "std")]
117    /// let par = par.runner_with_diagnostics();
118    ///
119    /// let sum = par.sum();
120    /// assert_eq!(sum, 500500);
121    /// ```
122    fn runner_with_diagnostics(
123        self,
124    ) -> impl ParUse<Item = Self::Item, Use = Self::Use, Xap = Self::Xap, Input = Self::Input>;
125
126    /// Sets the maximum number of worker threads for this computation.
127    ///
128    /// Integer values map as follows:
129    /// - `0` => automatic (default)
130    /// - `n > 0` => at most `n` threads
131    ///
132    /// # Examples
133    ///
134    /// ```
135    /// use orx_parallel::*;
136    ///
137    /// let sum: usize = (1..11)
138    ///     .into_par()
139    ///     .use_new(|_| ())
140    ///     .num_threads(1)
141    ///     .sum();
142    ///
143    /// assert_eq!(sum, 55);
144    /// ```
145    fn num_threads(self, num_threads: impl Into<NumThreads>) -> Self;
146
147    /// Sets chunk size used when pulling items from the concurrent input.
148    ///
149    /// Integer values map as follows:
150    /// - `0` => automatic (default)
151    /// - `n > 0` => exact chunk size `n`
152    ///
153    /// # Examples
154    ///
155    /// ```
156    /// use orx_parallel::*;
157    ///
158    /// let values: Vec<_> = (0..16)
159    ///     .into_par()
160    ///     .use_new(|_| ())
161    ///     .chunk_size(4)
162    ///     .map(|_, x| x + 1)
163    ///     .collect();
164    ///
165    /// assert_eq!(values.len(), 16);
166    /// assert_eq!(values[0], 1);
167    /// ```
168    fn chunk_size(self, chunk_size: impl Into<ChunkSize>) -> Self;
169
170    /// Sets iteration order semantics for order-sensitive operations.
171    ///
172    /// With `Ordered` (default), methods like `first` and `find` follow input
173    /// position. With `Arbitrary`, any matching item found first in parallel
174    /// execution may be returned.
175    ///
176    /// # Examples
177    ///
178    /// ```
179    /// use orx_parallel::*;
180    ///
181    /// let ordered = (1..10_000)
182    ///     .into_par()
183    ///     .use_new(|_| ())
184    ///     .iteration_order(IterationOrder::Ordered)
185    ///     .find(|_, x| x % 3421 == 0);
186    /// assert_eq!(ordered, Some(3421));
187    ///
188    /// let any = (1..10_000)
189    ///     .into_par()
190    ///     .use_new(|_| ())
191    ///     .iteration_order(IterationOrder::Arbitrary)
192    ///     .find(|_, x| x % 3421 == 0)
193    ///     .unwrap();
194    /// assert!([3421, 6842].contains(&any));
195    /// ```
196    fn iteration_order(self, collect: IterationOrder) -> Self;
197
198    // kind transformations
199
200    /// Converts `ParUse<Item = Option<T>>` into [`ParUseOption`](crate::ParUseOption).
201    ///
202    /// The result short-circuits to `None` if any element is `None`.
203    ///
204    /// # Examples
205    ///
206    /// ```
207    /// use orx_parallel::*;
208    ///
209    /// let ok: Option<Vec<_>> = ["1", "2", "3"]
210    ///     .into_par()
211    ///     .use_new(|_| ())
212    ///     .map(|_, s| s.parse::<i32>().ok())
213    ///     .into_optional()
214    ///     .map(|_, x| x * 2)
215    ///     .collect();
216    /// assert_eq!(ok, Some(vec![2, 4, 6]));
217    ///
218    /// let fail: Option<Vec<_>> = ["1", "x", "3"]
219    ///     .into_par()
220    ///     .use_new(|_| ())
221    ///     .map(|_, s| s.parse::<i32>().ok())
222    ///     .into_optional()
223    ///     .map(|_, x| x * 2)
224    ///     .collect();
225    /// assert_eq!(fail, None);
226    /// ```
227    fn into_optional<T>(
228        self,
229    ) -> impl ParUseOption<
230        Elem = T,
231        Use = Self::Use,
232        Xap1 = Self::Xap,
233        M = T,
234        Xap2 = IdUse<Id<T>, Self::Use>,
235        Input = Self::Input,
236        Size = <<Self::Xap as XapUse>::Size as Size>::IntoPair,
237    >
238    where
239        Self::Xap: XapUse<U = Self::Use, I = <Self::Input as ConcurrentIter>::Item, O = Option<T>>,
240    {
241        let (u, iter, xap, exe, params) = self.destruct();
242        ParUseOptionIter::new(u, iter, xap, IdUse::new(Id::new()), exe, params)
243    }
244
245    /// Converts `ParUse<Item = Result<T, E>>` into [`ParUseResult`](crate::ParUseResult).
246    ///
247    /// The result short-circuits and returns the first observed error.
248    ///
249    /// # Examples
250    ///
251    /// ```
252    /// use orx_parallel::*;
253    ///
254    /// let ok: Result<Vec<_>, _> = ["1", "2", "3"]
255    ///     .into_par()
256    ///     .use_new(|_| ())
257    ///     .map(|_, s| s.parse::<i32>())
258    ///     .into_fallible()
259    ///     .map(|_, x| x * 2)
260    ///     .collect();
261    /// assert_eq!(ok, Ok(vec![2, 4, 6]));
262    ///
263    /// let fail: Result<Vec<_>, _> = ["1", "x", "3"]
264    ///     .into_par()
265    ///     .use_new(|_| ())
266    ///     .map(|_, s| s.parse::<i32>())
267    ///     .into_fallible()
268    ///     .map(|_, x| x * 2)
269    ///     .collect();
270    /// assert!(fail.is_err());
271    /// ```
272    fn into_fallible<T, E>(
273        self,
274    ) -> impl ParUseResult<
275        Elem = T,
276        Error = E,
277        Use = Self::Use,
278        Xap1 = Self::Xap,
279        M = T,
280        Xap2 = IdUse<Id<T>, Self::Use>,
281        Input = Self::Input,
282        Size = <<Self::Xap as XapUse>::Size as Size>::IntoPair,
283    >
284    where
285        Self::Xap:
286            XapUse<U = Self::Use, I = <Self::Input as ConcurrentIter>::Item, O = Result<T, E>>,
287    {
288        let (u, iter, xap, exe, params) = self.destruct();
289        ParUseResultIter::new(u, iter, xap, IdUse::new(Id::new()), exe, params)
290    }
291
292    /// Copies elements of a reference iterator.
293    ///
294    /// Equivalent to `.map(|_, &x| x)`.
295    ///
296    /// # Examples
297    ///
298    /// ```
299    /// use orx_parallel::*;
300    ///
301    /// let data = vec![1, 2, 3];
302    /// let copied: Vec<_> = data.par().use_new(|_| ()).copied().collect();
303    ///
304    /// assert_eq!(copied, vec![1, 2, 3]);
305    /// ```
306    fn copied<'a, O>(
307        self,
308    ) -> impl ParUse<
309        Item = O,
310        Use = Self::Use,
311        Xap = MappedOf<Self::Xap, UFnCopied<'a, Self::Use, O>>,
312        Input = Self::Input,
313    >
314    where
315        Self: ParUse<Item = &'a O>,
316        O: Copy + 'a,
317        Self::Use: 'a,
318    {
319        let (u, iter, xap, exe, params) = self.destruct();
320        ParUseIter::new(u, iter, xap.mapped(UFnCopied::new()), exe, params)
321    }
322
323    /// Clones elements of a reference iterator.
324    ///
325    /// Equivalent to `.map(|_, x| x.clone())`.
326    ///
327    /// # Examples
328    ///
329    /// ```
330    /// use orx_parallel::*;
331    ///
332    /// let data = vec!["a".to_string(), "b".to_string()];
333    /// let cloned: Vec<_> = data.par().use_new(|_| ()).cloned().collect();
334    ///
335    /// assert_eq!(cloned, vec!["a".to_string(), "b".to_string()]);
336    /// ```
337    fn cloned<'a, O>(
338        self,
339    ) -> impl ParUse<
340        Item = O,
341        Use = Self::Use,
342        Xap = MappedOf<Self::Xap, UFnCloned<'a, Self::Use, O>>,
343        Input = Self::Input,
344    >
345    where
346        Self: ParUse<Item = &'a O>,
347        O: Clone + 'a,
348        Self::Use: 'a,
349    {
350        let (u, iter, xap, exe, params) = self.destruct();
351        ParUseIter::new(u, iter, xap.mapped(UFnCloned::new()), exe, params)
352    }
353
354    // transformations
355
356    /// Maps each element with closure `h`.
357    ///
358    /// # Examples
359    ///
360    /// ```
361    /// use orx_parallel::*;
362    ///
363    /// let doubled: Vec<_> = (1..4)
364    ///     .into_par()
365    ///     .use_new(|_| ())
366    ///     .map(|_, x| 2 * x)
367    ///     .collect();
368    ///
369    /// assert_eq!(doubled, vec![2, 4, 6]);
370    /// ```
371    fn map<Q, H>(
372        self,
373        h: H,
374    ) -> impl ParUse<Item = Q, Use = Self::Use, Xap = MapOf<Self::Xap, Q, H>, Input = Self::Input>
375    where
376        H: Fn(&mut Self::Use, Self::Item) -> Q + Copy + Send;
377
378    /// Runs `h` on each element and forwards the item unchanged.
379    ///
380    /// Useful for logging, metrics, and tracing with worker-local state.
381    ///
382    /// # Examples
383    ///
384    /// ```
385    /// use orx_parallel::*;
386    ///
387    /// let mut calls = UseVec::new(|_| 0usize);
388    ///
389    /// let out: Vec<_> = (1..5)
390    ///     .into_par()
391    ///     .use_vec(&mut calls)
392    ///     .inspect(|count, _| *count += 1)
393    ///     .collect();
394    ///
395    /// assert_eq!(out, vec![1, 2, 3, 4]);
396    /// assert_eq!(calls.into_vec().into_iter().sum::<usize>(), 4);
397    /// ```
398    fn inspect<H>(
399        self,
400        h: H,
401    ) -> impl ParUse<Item = Self::Item, Use = Self::Use, Xap = InsOf<Self::Xap, H>, Input = Self::Input>
402    where
403        H: Fn(&mut Self::Use, &Self::Item) + Copy + Send;
404
405    /// Keeps only elements satisfying predicate `h`.
406    ///
407    /// # Examples
408    ///
409    /// ```
410    /// use orx_parallel::*;
411    ///
412    /// let odds: Vec<_> = (1..7)
413    ///     .into_par()
414    ///     .use_new(|_| ())
415    ///     .filter(|_, x| x % 2 == 1)
416    ///     .collect();
417    ///
418    /// assert_eq!(odds, vec![1, 3, 5]);
419    /// ```
420    fn filter<H>(
421        self,
422        h: H,
423    ) -> impl ParUse<Item = Self::Item, Use = Self::Use, Xap = FilOf<Self::Xap, H>, Input = Self::Input>
424    where
425        H: Fn(&mut Self::Use, &Self::Item) -> bool + Copy + Send;
426
427    /// Maps and filters in a single pass.
428    ///
429    /// Returns mapped values for elements where `h` returns `Some(_)`.
430    ///
431    /// # Examples
432    ///
433    /// ```
434    /// use orx_parallel::*;
435    ///
436    /// let nums: Vec<_> = ["1", "x", "5"]
437    ///     .into_par()
438    ///     .use_new(|_| ())
439    ///     .filter_map(|_, s| s.parse::<usize>().ok())
440    ///     .collect();
441    ///
442    /// assert_eq!(nums, vec![1, 5]);
443    /// ```
444    fn filter_map<Q, H>(
445        self,
446        h: H,
447    ) -> impl ParUse<Item = Q, Use = Self::Use, Xap = FilMapOf<Self::Xap, Q, H>, Input = Self::Input>
448    where
449        H: Fn(&mut Self::Use, Self::Item) -> Option<Q> + Copy + Send;
450
451    /// Maps each element to an iterator and flattens one level.
452    ///
453    /// # Examples
454    ///
455    /// ```
456    /// use orx_parallel::*;
457    ///
458    /// let out: Vec<_> = (1..4)
459    ///     .into_par()
460    ///     .use_new(|_| ())
461    ///     .flat_map(|_, x| [x, x + 10])
462    ///     .collect();
463    ///
464    /// assert_eq!(out, vec![1, 11, 2, 12, 3, 13]);
465    /// ```
466    fn flat_map<V, H>(
467        self,
468        h: H,
469    ) -> impl ParUse<
470        Item = V::Item,
471        Use = Self::Use,
472        Xap = FlatMapOf<Self::Xap, V, H>,
473        Input = Self::Input,
474    >
475    where
476        V: IntoIterator,
477        H: Fn(&mut Self::Use, Self::Item) -> V + Copy + Send;
478
479    /// Flattens one level of nested iterables.
480    ///
481    /// # Examples
482    ///
483    /// ```
484    /// use orx_parallel::*;
485    ///
486    /// let nested = vec![vec![1, 2], vec![3, 4]];
487    /// let flat: Vec<_> = nested.into_par().use_new(|_| ()).flatten().collect();
488    ///
489    /// assert_eq!(flat, vec![1, 2, 3, 4]);
490    /// ```
491    fn flatten(
492        self,
493    ) -> impl ParUse<
494        Item = <Self::Item as IntoIterator>::Item,
495        Use = Self::Use,
496        Xap = FlattenOf<Self::Xap>,
497        Input = Self::Input,
498    >
499    where
500        Self::Item: IntoIterator;
501
502    // get
503
504    /// Returns a lower and optional upper bound on the number of output items.
505    ///
506    /// The bounds follow the usual [`Iterator::size_hint`] convention. For an
507    /// exact-size input and a one-to-one transformation, both bounds are exact.
508    /// Transformations such as `filter` may reduce the lower bound while keeping
509    /// the input length as the upper bound.
510    ///
511    /// # Examples
512    ///
513    /// ```
514    /// use orx_parallel::*;
515    ///
516    /// let mapped = (0..4)
517    ///     .into_par()
518    ///     .use_new(|_| ())
519    ///     .map(|_, x| x * 2);
520    /// assert_eq!(mapped.size_hint(), (4, Some(4)));
521    ///
522    /// let filtered = (0..4)
523    ///     .into_par()
524    ///     .use_new(|_| ())
525    ///     .filter(|_, x| x % 2 == 0);
526    /// assert_eq!(filtered.size_hint(), (0, Some(4)));
527    /// ```
528    fn size_hint(&self) -> (usize, Option<usize>);
529
530    /// Returns the exact number of output items.
531    fn len(&self) -> usize
532    where
533        Self::Input: ExactSizeConcurrentIter,
534        Self::Xap: XapUse<Size = One>,
535    {
536        self.size_hint().0
537    }
538
539    /// Returns `true` when the parallel iterator has no output items.
540    fn is_empty(&self) -> bool
541    where
542        Self::Input: ExactSizeConcurrentIter,
543        Self::Xap: XapUse<Size = One>,
544    {
545        self.len() == 0
546    }
547
548    // compute
549
550    /// Returns the first item according to iteration order, or `None` if empty.
551    ///
552    /// With [`IterationOrder::Ordered`] (default), this is the earliest matching
553    /// item by input position. With [`IterationOrder::Arbitrary`], this may be
554    /// any matching item reached first in parallel execution.
555    ///
556    /// # Examples
557    ///
558    /// ```
559    /// use orx_parallel::*;
560    ///
561    /// assert_eq!(Vec::<usize>::new().into_par().use_new(|_| ()).first(), None);
562    /// assert_eq!((1..4).into_par().use_new(|_| ()).first(), Some(1));
563    /// ```
564    fn first(self) -> Option<Self::Item>
565    where
566        Self::Item: Send;
567
568    /// Reduces items into one value using reducer `f`.
569    ///
570    /// Returns `None` for an empty iterator.
571    ///
572    /// # Examples
573    ///
574    /// ```
575    /// use orx_parallel::*;
576    ///
577    /// let reduced = (1..6)
578    ///     .into_par()
579    ///     .use_new(|_| ())
580    ///     .reduce(|_, a, b| a + b);
581    ///
582    /// assert_eq!(reduced, Some(15));
583    /// ```
584    fn reduce<F>(self, f: F) -> Option<Self::Item>
585    where
586        F: Fn(&mut Self::Use, Self::Item, Self::Item) -> Self::Item + Send + Copy,
587        Self::Item: Send;
588
589    /// Collects all items into `dst`.
590    ///
591    /// # Examples
592    ///
593    /// ```
594    /// use orx_parallel::*;
595    ///
596    /// let mut dst = vec![10];
597    /// (0..3).into_par().use_new(|_| ()).collect_into(&mut dst);
598    /// assert_eq!(dst, vec![10, 0, 1, 2]);
599    /// ```
600    fn collect_into<P>(self, dst: &mut P)
601    where
602        P: ParExtend<Self::Item>,
603        Self::Item: Send;
604
605    /// Collects all items into a new collection.
606    ///
607    /// # Examples
608    ///
609    /// ```
610    /// use orx_parallel::*;
611    ///
612    /// let out: Vec<_> = (1..4)
613    ///     .into_par()
614    ///     .use_new(|_| ())
615    ///     .map(|_, x| x * 2)
616    ///     .collect();
617    ///
618    /// assert_eq!(out, vec![2, 4, 6]);
619    /// ```
620    fn collect<P>(self) -> P
621    where
622        P: ParExtend<Self::Item> + Default,
623        Self::Item: Send,
624    {
625        let mut dst = P::default();
626        self.collect_into(&mut dst);
627        dst
628    }
629
630    // compute - derived
631
632    /// Returns `true` if all items satisfy predicate `f`.
633    ///
634    /// Empty iterators return `true`.
635    ///
636    /// # Examples
637    ///
638    /// ```
639    /// use orx_parallel::*;
640    ///
641    /// assert!((1..5).into_par().use_new(|_| ()).all(|_, x| x > &0));
642    /// assert!(!(1..5).into_par().use_new(|_| ()).all(|_, x| x % 2 == 0));
643    /// ```
644    fn all<F>(self, f: F) -> bool
645    where
646        F: Fn(&mut Self::Use, &Self::Item) -> bool + Sync,
647    {
648        self.map(|u, x| f(u, &x)).find(|_, x| !*x).is_none()
649    }
650
651    /// Returns `true` if any item satisfies predicate `f`.
652    ///
653    /// Empty iterators return `false`.
654    ///
655    /// # Examples
656    ///
657    /// ```
658    /// use orx_parallel::*;
659    ///
660    /// assert!((1..5).into_par().use_new(|_| ()).any(|_, x| x % 2 == 0));
661    /// assert!(!(1..5).into_par().use_new(|_| ()).any(|_, x| x > &10));
662    /// ```
663    fn any<F>(self, f: F) -> bool
664    where
665        F: Fn(&mut Self::Use, &Self::Item) -> bool + Sync,
666    {
667        self.map(|u, x| f(u, &x)).find(|_, x| *x).is_some()
668    }
669
670    /// Counts elements.
671    ///
672    /// # Examples
673    ///
674    /// ```
675    /// use orx_parallel::*;
676    ///
677    /// let n = (1..11)
678    ///     .into_par()
679    ///     .use_new(|_| ())
680    ///     .filter(|_, x| x % 3 == 0)
681    ///     .count();
682    ///
683    /// assert_eq!(n, 3);
684    /// ```
685    fn count(self) -> usize {
686        self.map(|_, _| 1).reduce(|_, a, b| a + b).unwrap_or(0)
687    }
688
689    /// Finds first (ordered) or any (arbitrary) item satisfying predicate `f`.
690    ///
691    /// Equivalent to `self.filter(f).first()`.
692    ///
693    /// # Examples
694    ///
695    /// ```
696    /// use orx_parallel::*;
697    ///
698    /// let found = (1..101)
699    ///     .into_par()
700    ///     .use_new(|_| ())
701    ///     .find(|_, x| x % 17 == 0);
702    ///
703    /// assert_eq!(found, Some(17));
704    /// ```
705    fn find<F>(self, f: F) -> Option<Self::Item>
706    where
707        Self::Item: Send,
708        F: Fn(&mut Self::Use, &Self::Item) -> bool + Sync,
709    {
710        self.filter(&f).first()
711    }
712
713    /// Folds elements into per-thread accumulators and returns them.
714    ///
715    /// The output contains one accumulator for each participating worker.
716    ///
717    /// # Examples
718    ///
719    /// ```
720    /// use orx_parallel::*;
721    ///
722    /// let num_threads = 4;
723    /// let partials: Vec<usize> = (1..6)
724    ///     .into_par()
725    ///     .use_new(|_| ())
726    ///     .num_threads(num_threads)
727    ///     .fold(|| 0usize, |_, acc, x| *acc += x);
728    ///
729    /// assert!(partials.len() <= num_threads);
730    /// assert_eq!(partials.iter().sum::<usize>(), 15);
731    /// ```
732    fn fold<B, I, F>(self, init: I, f: F) -> Vec<B>
733    where
734        B: Send,
735        I: Fn() -> B + Sync,
736        F: Fn(&mut Self::Use, &mut B, Self::Item) + Copy + Send,
737    {
738        let (u, iter, xap, exe, params) = self.destruct();
739        let mut use_fold = UseFold::new(u, |_| init());
740        let xap = UDummyPair::<Self::Xap, B>::new(xap);
741        let par = ParUseIter::new(&mut use_fold, iter, xap, exe, params);
742
743        par.for_each(move |a: &mut PairPtr<Self::Use, B>, x| {
744            let (u, v) = a.u_v_mut();
745            f(u, v, x);
746        });
747
748        use_fold.into_vec()
749    }
750
751    /// Executes `f` for each item.
752    ///
753    /// # Examples
754    ///
755    /// ```
756    /// use orx_parallel::*;
757    ///
758    /// let mut sums = UseVec::new(|_| 0usize);
759    ///
760    /// (1..5)
761    ///     .into_par()
762    ///     .use_vec(&mut sums)
763    ///     .for_each(|local, x| *local += x);
764    ///
765    /// assert_eq!(sums.into_vec().into_iter().sum::<usize>(), 10);
766    /// ```
767    fn for_each<F>(self, f: F)
768    where
769        F: Fn(&mut Self::Use, Self::Item) + Send + Copy,
770    {
771        let _ = self.map(f).reduce(|_, _, _| {});
772    }
773
774    /// Returns maximum element, or `None` if empty.
775    ///
776    /// # Examples
777    ///
778    /// ```
779    /// use orx_parallel::*;
780    ///
781    /// assert_eq!((1..5).into_par().use_new(|_| ()).max(), Some(4));
782    /// assert_eq!(Vec::<usize>::new().into_par().use_new(|_| ()).max(), None);
783    /// ```
784    fn max(self) -> Option<Self::Item>
785    where
786        Self::Item: Ord + Send,
787    {
788        self.reduce(|_, a, b| Ord::max(a, b))
789    }
790
791    /// Returns element considered maximum by comparator `f`.
792    ///
793    /// # Examples
794    ///
795    /// ```
796    /// use core::cmp::Ordering;
797    /// use orx_parallel::*;
798    ///
799    /// let x = vec![-3_i32, 0, 1, 5, -10]
800    ///     .into_par()
801    ///     .use_new(|_| ())
802    ///     .max_by(|_, a, b| a.cmp(b));
803    /// assert_eq!(x, Some(5));
804    /// ```
805    fn max_by<F>(self, f: F) -> Option<Self::Item>
806    where
807        Self::Item: Send,
808        F: Fn(&mut Self::Use, &Self::Item, &Self::Item) -> Ordering + Sync,
809    {
810        let reduce = |u: &mut Self::Use, x, y| match f(u, &x, &y) {
811            Ordering::Greater | Ordering::Equal => x,
812            Ordering::Less => y,
813        };
814        self.reduce(reduce)
815    }
816
817    /// Returns element with maximum key value.
818    ///
819    /// # Examples
820    ///
821    /// ```
822    /// use orx_parallel::*;
823    ///
824    /// let x = vec![-3_i32, 0, 1, 5, -10]
825    ///     .into_par()
826    ///     .use_new(|_| ())
827    ///     .max_by_key(|_, x| x.abs());
828    /// assert_eq!(x, Some(-10));
829    /// ```
830    fn max_by_key<B, F>(self, f: F) -> Option<Self::Item>
831    where
832        Self::Item: Send,
833        B: Ord,
834        F: Fn(&mut Self::Use, &Self::Item) -> B + Sync,
835    {
836        let reduce = |u: &mut Self::Use, x, y| match f(u, &x).cmp(&f(u, &y)) {
837            Ordering::Greater | Ordering::Equal => x,
838            Ordering::Less => y,
839        };
840        self.reduce(reduce)
841    }
842
843    /// Returns minimum element, or `None` if empty.
844    ///
845    /// # Examples
846    ///
847    /// ```
848    /// use orx_parallel::*;
849    ///
850    /// assert_eq!((1..5).into_par().use_new(|_| ()).min(), Some(1));
851    /// assert_eq!(Vec::<usize>::new().into_par().use_new(|_| ()).min(), None);
852    /// ```
853    fn min(self) -> Option<Self::Item>
854    where
855        Self::Item: Ord + Send,
856    {
857        self.reduce(|_, a, b| Ord::min(a, b))
858    }
859
860    /// Returns element considered minimum by comparator `f`.
861    ///
862    /// # Examples
863    ///
864    /// ```
865    /// use orx_parallel::*;
866    ///
867    /// let x = vec![-3_i32, 0, 1, 5, -10]
868    ///     .into_par()
869    ///     .use_new(|_| ())
870    ///     .min_by(|_, a, b| a.cmp(b));
871    /// assert_eq!(x, Some(-10));
872    /// ```
873    fn min_by<F>(self, f: F) -> Option<Self::Item>
874    where
875        Self::Item: Send,
876        F: Fn(&mut Self::Use, &Self::Item, &Self::Item) -> Ordering + Sync,
877    {
878        let reduce = |u: &mut Self::Use, x, y| match f(u, &x, &y) {
879            Ordering::Less | Ordering::Equal => x,
880            Ordering::Greater => y,
881        };
882        self.reduce(reduce)
883    }
884
885    /// Returns element with minimum key value.
886    ///
887    /// # Examples
888    ///
889    /// ```
890    /// use orx_parallel::*;
891    ///
892    /// let x = vec![-3_i32, 0, 1, 5, -10]
893    ///     .into_par()
894    ///     .use_new(|_| ())
895    ///     .min_by_key(|_, x| x.abs());
896    /// assert_eq!(x, Some(0));
897    /// ```
898    fn min_by_key<B, F>(self, f: F) -> Option<Self::Item>
899    where
900        Self::Item: Send,
901        B: Ord,
902        F: Fn(&mut Self::Use, &Self::Item) -> B + Sync,
903    {
904        let reduce = |u: &mut Self::Use, x, y| match f(u, &x).cmp(&f(u, &y)) {
905            Ordering::Less | Ordering::Equal => x,
906            Ordering::Greater => y,
907        };
908        self.reduce(reduce)
909    }
910
911    /// Sums elements using [`Sum`] implementation of the item type.
912    ///
913    /// Empty iterators return additive identity (`zero`).
914    ///
915    /// # Examples
916    ///
917    /// ```
918    /// use orx_parallel::*;
919    ///
920    /// let sum: usize = (1..5).into_par().use_new(|_| ()).sum();
921    /// assert_eq!(sum, 10);
922    /// ```
923    fn sum<S>(self) -> S
924    where
925        Self::Item: Sum<S>,
926        S: Send,
927    {
928        self.map(|_, x| Self::Item::owned(x))
929            .reduce(|_, a, b| Self::Item::add(a, b))
930            .unwrap_or(Self::Item::zero())
931    }
932}