1use super::plumbing::*;
2use super::ParallelIterator;
3
4use std::iter::{self, Product};
5use std::marker::PhantomData;
6
7pub(super) fn product<PI, P>(pi: PI) -> P
8where
9 PI: ParallelIterator,
10 P: Send + Product<PI::Item> + Product,
11{
12 pi.drive_unindexed(ProductConsumer::new())
13}
14
15fn mul<T: Product>(left: T, right: T) -> T {
16 [left, right].into_iter().product()
17}
18
19struct ProductConsumer<P: Send> {
20 _marker: PhantomData<*const P>,
21}
22
23unsafe impl<P: Send> Send for ProductConsumer<P> {}
24
25impl<P: Send> ProductConsumer<P> {
26 fn new() -> ProductConsumer<P> {
27 ProductConsumer {
28 _marker: PhantomData,
29 }
30 }
31}
32
33impl<P, T> Consumer<T> for ProductConsumer<P>
34where
35 P: Send + Product<T> + Product,
36{
37 type Folder = ProductFolder<P>;
38 type Reducer = Self;
39 type Result = P;
40
41 fn split_at(self, _index: usize) -> (Self, Self, Self) {
42 (
43 ProductConsumer::new(),
44 ProductConsumer::new(),
45 ProductConsumer::new(),
46 )
47 }
48
49 fn into_folder(self) -> Self::Folder {
50 ProductFolder {
51 product: iter::empty::<T>().product(),
52 }
53 }
54
55 fn full(&self) -> bool {
56 false
57 }
58}
59
60impl<P, T> UnindexedConsumer<T> for ProductConsumer<P>
61where
62 P: Send + Product<T> + Product,
63{
64 fn split_off_left(&self) -> Self {
65 ProductConsumer::new()
66 }
67
68 fn to_reducer(&self) -> Self::Reducer {
69 ProductConsumer::new()
70 }
71}
72
73impl<P> Reducer<P> for ProductConsumer<P>
74where
75 P: Send + Product,
76{
77 fn reduce(self, left: P, right: P) -> P {
78 mul(left, right)
79 }
80}
81
82struct ProductFolder<P> {
83 product: P,
84}
85
86impl<P, T> Folder<T> for ProductFolder<P>
87where
88 P: Product<T> + Product,
89{
90 type Result = P;
91
92 fn consume(self, item: T) -> Self {
93 ProductFolder {
94 product: mul(self.product, iter::once(item).product()),
95 }
96 }
97
98 fn consume_iter<I>(self, iter: I) -> Self
99 where
100 I: IntoIterator<Item = T>,
101 {
102 ProductFolder {
103 product: mul(self.product, iter.into_iter().product()),
104 }
105 }
106
107 fn complete(self) -> P {
108 self.product
109 }
110
111 fn full(&self) -> bool {
112 false
113 }
114}
115