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}