asparit/core/
from_iter.rs

1use super::{Executor, IntoParallelIterator};
2
3/// `FromParallelIterator` implements the creation of a collection
4/// from a [`ParallelIterator`]. By implementing
5/// `FromParallelIterator` for a given type, you define how it will be
6/// created from an iterator.
7///
8/// `FromParallelIterator` is used through [`ParallelIterator`]'s [`collect()`] method.
9///
10/// [`ParallelIterator`]: trait.ParallelIterator.html
11/// [`collect()`]: trait.ParallelIterator.html#method.collect
12///
13/// # Examples
14///
15/// Implementing `FromParallelIterator` for your type:
16///
17/// ```
18/// use asparit::*;
19/// use std::mem;
20///
21/// struct BlackHole {
22///     mass: usize,
23/// }
24///
25/// impl<'a, I> FromParallelIterator<'a, I> for BlackHole
26/// where
27///     I: Send + 'a,
28/// {
29///     type ExecutorItem2 = usize;
30///     type ExecutorItem3 = ();
31///
32///     fn from_par_iter<E, X>(executor: E, iterator: X) -> E::Result
33///     where
34///         E: Executor<'a, Self, Self::ExecutorItem2, Self::ExecutorItem3>,
35///         X: IntoParallelIterator<'a, Item = I>,
36///     {
37///         let iterator = iterator.into_par_iter();
38///         let executor = executor.into_inner();
39///
40///         let ret = iterator.count().exec_with(executor);
41///
42///         E::map(ret, |count| BlackHole {
43///             mass: count * std::mem::size_of::<I>(),
44///         })
45///     }
46/// }
47///
48/// let bh: BlackHole = (0i32..1000).into_par_iter().collect().exec();
49/// assert_eq!(bh.mass, 4000);
50/// ```
51pub trait FromParallelIterator<'a, I>: Send + Sized
52where
53    I: Send + 'a,
54{
55    type ExecutorItem2: Send + 'a;
56    type ExecutorItem3: Send + 'a;
57
58    /// Creates an instance of the collection from the parallel iterator `iterator`.
59    ///
60    /// If your collection is not naturally parallel, the easiest (and
61    /// fastest) way to do this is often to collect `iterator` into a
62    /// [`LinkedList`] or other intermediate data structure and then
63    /// sequentially extend your collection. However, a more 'native'
64    /// technique is to use the [`iterator.fold`] or
65    /// [`iterator.fold_with`] methods to create the collection.
66    /// Alternatively, if your collection is 'natively' parallel, you
67    /// can use `iterator.for_each` to process each element in turn.
68    ///
69    /// [`LinkedList`]: https://doc.rust-lang.org/std/collections/struct.LinkedList.html
70    /// [`iterator.fold`]: trait.ParallelIterator.html#method.fold
71    /// [`iterator.fold_with`]: trait.ParallelIterator.html#method.fold_with
72    /// [`iterator.for_each`]: trait.ParallelIterator.html#method.for_each
73    fn from_par_iter<E, X>(executor: E, iterator: X) -> E::Result
74    where
75        E: Executor<'a, Self, Self::ExecutorItem2, Self::ExecutorItem3>,
76        X: IntoParallelIterator<'a, Item = I>;
77}
78
79impl<'a> FromParallelIterator<'a, ()> for () {
80    type ExecutorItem2 = ();
81    type ExecutorItem3 = ();
82
83    fn from_par_iter<E, X>(executor: E, iterator: X) -> E::Result
84    where
85        E: Executor<'a, Self>,
86        X: IntoParallelIterator<'a, Item = ()>,
87    {
88        use crate::{iter::noop::NoOpConsumer, ParallelIterator};
89
90        iterator.into_par_iter().drive(executor, NoOpConsumer)
91    }
92}