1 | use super::plumbing::*; |
2 | use super::ParallelIterator; |
3 | use super::Try; |
4 | |
5 | use std::fmt::{self, Debug}; |
6 | use std::marker::PhantomData; |
7 | use std::ops::ControlFlow::{self, Break, Continue}; |
8 | |
9 | impl<U, I, ID, F> TryFold<I, U, ID, F> |
10 | where |
11 | I: ParallelIterator, |
12 | F: Fn(U::Output, I::Item) -> U + Sync + Send, |
13 | ID: Fn() -> U::Output + Sync + Send, |
14 | U: Try + Send, |
15 | { |
16 | pub(super) fn new(base: I, identity: ID, fold_op: F) -> Self { |
17 | TryFold { |
18 | base, |
19 | identity, |
20 | fold_op, |
21 | marker: PhantomData, |
22 | } |
23 | } |
24 | } |
25 | |
26 | /// `TryFold` is an iterator that applies a function over an iterator producing a single value. |
27 | /// This struct is created by the [`try_fold()`] method on [`ParallelIterator`] |
28 | /// |
29 | /// [`try_fold()`]: trait.ParallelIterator.html#method.try_fold |
30 | /// [`ParallelIterator`]: trait.ParallelIterator.html |
31 | #[must_use = "iterator adaptors are lazy and do nothing unless consumed" ] |
32 | #[derive (Clone)] |
33 | pub struct TryFold<I, U, ID, F> { |
34 | base: I, |
35 | identity: ID, |
36 | fold_op: F, |
37 | marker: PhantomData<U>, |
38 | } |
39 | |
40 | impl<U, I: ParallelIterator + Debug, ID, F> Debug for TryFold<I, U, ID, F> { |
41 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
42 | f.debug_struct("TryFold" ).field(name:"base" , &self.base).finish() |
43 | } |
44 | } |
45 | |
46 | impl<U, I, ID, F> ParallelIterator for TryFold<I, U, ID, F> |
47 | where |
48 | I: ParallelIterator, |
49 | F: Fn(U::Output, I::Item) -> U + Sync + Send, |
50 | ID: Fn() -> U::Output + Sync + Send, |
51 | U: Try + Send, |
52 | { |
53 | type Item = U; |
54 | |
55 | fn drive_unindexed<C>(self, consumer: C) -> C::Result |
56 | where |
57 | C: UnindexedConsumer<Self::Item>, |
58 | { |
59 | let consumer1: TryFoldConsumer<'_, U, C, …, …> = TryFoldConsumer { |
60 | base: consumer, |
61 | identity: &self.identity, |
62 | fold_op: &self.fold_op, |
63 | marker: PhantomData, |
64 | }; |
65 | self.base.drive_unindexed(consumer:consumer1) |
66 | } |
67 | } |
68 | |
69 | struct TryFoldConsumer<'c, U, C, ID, F> { |
70 | base: C, |
71 | identity: &'c ID, |
72 | fold_op: &'c F, |
73 | marker: PhantomData<U>, |
74 | } |
75 | |
76 | impl<'r, U, T, C, ID, F> Consumer<T> for TryFoldConsumer<'r, U, C, ID, F> |
77 | where |
78 | C: Consumer<U>, |
79 | F: Fn(U::Output, T) -> U + Sync, |
80 | ID: Fn() -> U::Output + Sync, |
81 | U: Try + Send, |
82 | { |
83 | type Folder = TryFoldFolder<'r, C::Folder, U, F>; |
84 | type Reducer = C::Reducer; |
85 | type Result = C::Result; |
86 | |
87 | fn split_at(self, index: usize) -> (Self, Self, Self::Reducer) { |
88 | let (left, right, reducer) = self.base.split_at(index); |
89 | ( |
90 | TryFoldConsumer { base: left, ..self }, |
91 | TryFoldConsumer { |
92 | base: right, |
93 | ..self |
94 | }, |
95 | reducer, |
96 | ) |
97 | } |
98 | |
99 | fn into_folder(self) -> Self::Folder { |
100 | TryFoldFolder { |
101 | base: self.base.into_folder(), |
102 | control: Continue((self.identity)()), |
103 | fold_op: self.fold_op, |
104 | } |
105 | } |
106 | |
107 | fn full(&self) -> bool { |
108 | self.base.full() |
109 | } |
110 | } |
111 | |
112 | impl<'r, U, T, C, ID, F> UnindexedConsumer<T> for TryFoldConsumer<'r, U, C, ID, F> |
113 | where |
114 | C: UnindexedConsumer<U>, |
115 | F: Fn(U::Output, T) -> U + Sync, |
116 | ID: Fn() -> U::Output + Sync, |
117 | U: Try + Send, |
118 | { |
119 | fn split_off_left(&self) -> Self { |
120 | TryFoldConsumer { |
121 | base: self.base.split_off_left(), |
122 | ..*self |
123 | } |
124 | } |
125 | |
126 | fn to_reducer(&self) -> Self::Reducer { |
127 | self.base.to_reducer() |
128 | } |
129 | } |
130 | |
131 | struct TryFoldFolder<'r, C, U: Try, F> { |
132 | base: C, |
133 | fold_op: &'r F, |
134 | control: ControlFlow<U::Residual, U::Output>, |
135 | } |
136 | |
137 | impl<'r, C, U, F, T> Folder<T> for TryFoldFolder<'r, C, U, F> |
138 | where |
139 | C: Folder<U>, |
140 | F: Fn(U::Output, T) -> U + Sync, |
141 | U: Try, |
142 | { |
143 | type Result = C::Result; |
144 | |
145 | fn consume(mut self, item: T) -> Self { |
146 | let fold_op = self.fold_op; |
147 | if let Continue(acc) = self.control { |
148 | self.control = fold_op(acc, item).branch(); |
149 | } |
150 | self |
151 | } |
152 | |
153 | fn complete(self) -> C::Result { |
154 | let item = match self.control { |
155 | Continue(c) => U::from_output(c), |
156 | Break(r) => U::from_residual(r), |
157 | }; |
158 | self.base.consume(item).complete() |
159 | } |
160 | |
161 | fn full(&self) -> bool { |
162 | match self.control { |
163 | Break(_) => true, |
164 | _ => self.base.full(), |
165 | } |
166 | } |
167 | } |
168 | |
169 | // /////////////////////////////////////////////////////////////////////////// |
170 | |
171 | impl<U, I, F> TryFoldWith<I, U, F> |
172 | where |
173 | I: ParallelIterator, |
174 | F: Fn(U::Output, I::Item) -> U + Sync, |
175 | U: Try + Send, |
176 | U::Output: Clone + Send, |
177 | { |
178 | pub(super) fn new(base: I, item: U::Output, fold_op: F) -> Self { |
179 | TryFoldWith { |
180 | base, |
181 | item, |
182 | fold_op, |
183 | } |
184 | } |
185 | } |
186 | |
187 | /// `TryFoldWith` is an iterator that applies a function over an iterator producing a single value. |
188 | /// This struct is created by the [`try_fold_with()`] method on [`ParallelIterator`] |
189 | /// |
190 | /// [`try_fold_with()`]: trait.ParallelIterator.html#method.try_fold_with |
191 | /// [`ParallelIterator`]: trait.ParallelIterator.html |
192 | #[must_use = "iterator adaptors are lazy and do nothing unless consumed" ] |
193 | #[derive (Clone)] |
194 | pub struct TryFoldWith<I, U: Try, F> { |
195 | base: I, |
196 | item: U::Output, |
197 | fold_op: F, |
198 | } |
199 | |
200 | impl<I: ParallelIterator + Debug, U: Try, F> Debug for TryFoldWith<I, U, F> |
201 | where |
202 | U::Output: Debug, |
203 | { |
204 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
205 | f&mut DebugStruct<'_, '_>.debug_struct("TryFoldWith" ) |
206 | .field("base" , &self.base) |
207 | .field(name:"item" , &self.item) |
208 | .finish() |
209 | } |
210 | } |
211 | |
212 | impl<U, I, F> ParallelIterator for TryFoldWith<I, U, F> |
213 | where |
214 | I: ParallelIterator, |
215 | F: Fn(U::Output, I::Item) -> U + Sync + Send, |
216 | U: Try + Send, |
217 | U::Output: Clone + Send, |
218 | { |
219 | type Item = U; |
220 | |
221 | fn drive_unindexed<C>(self, consumer: C) -> C::Result |
222 | where |
223 | C: UnindexedConsumer<Self::Item>, |
224 | { |
225 | let consumer1: TryFoldWithConsumer<'_, C, …, …> = TryFoldWithConsumer { |
226 | base: consumer, |
227 | item: self.item, |
228 | fold_op: &self.fold_op, |
229 | }; |
230 | self.base.drive_unindexed(consumer:consumer1) |
231 | } |
232 | } |
233 | |
234 | struct TryFoldWithConsumer<'c, C, U: Try, F> { |
235 | base: C, |
236 | item: U::Output, |
237 | fold_op: &'c F, |
238 | } |
239 | |
240 | impl<'r, U, T, C, F> Consumer<T> for TryFoldWithConsumer<'r, C, U, F> |
241 | where |
242 | C: Consumer<U>, |
243 | F: Fn(U::Output, T) -> U + Sync, |
244 | U: Try + Send, |
245 | U::Output: Clone + Send, |
246 | { |
247 | type Folder = TryFoldFolder<'r, C::Folder, U, F>; |
248 | type Reducer = C::Reducer; |
249 | type Result = C::Result; |
250 | |
251 | fn split_at(self, index: usize) -> (Self, Self, Self::Reducer) { |
252 | let (left, right, reducer) = self.base.split_at(index); |
253 | ( |
254 | TryFoldWithConsumer { |
255 | base: left, |
256 | item: self.item.clone(), |
257 | ..self |
258 | }, |
259 | TryFoldWithConsumer { |
260 | base: right, |
261 | ..self |
262 | }, |
263 | reducer, |
264 | ) |
265 | } |
266 | |
267 | fn into_folder(self) -> Self::Folder { |
268 | TryFoldFolder { |
269 | base: self.base.into_folder(), |
270 | control: Continue(self.item), |
271 | fold_op: self.fold_op, |
272 | } |
273 | } |
274 | |
275 | fn full(&self) -> bool { |
276 | self.base.full() |
277 | } |
278 | } |
279 | |
280 | impl<'r, U, T, C, F> UnindexedConsumer<T> for TryFoldWithConsumer<'r, C, U, F> |
281 | where |
282 | C: UnindexedConsumer<U>, |
283 | F: Fn(U::Output, T) -> U + Sync, |
284 | U: Try + Send, |
285 | U::Output: Clone + Send, |
286 | { |
287 | fn split_off_left(&self) -> Self { |
288 | TryFoldWithConsumer { |
289 | base: self.base.split_off_left(), |
290 | item: self.item.clone(), |
291 | ..*self |
292 | } |
293 | } |
294 | |
295 | fn to_reducer(&self) -> Self::Reducer { |
296 | self.base.to_reducer() |
297 | } |
298 | } |
299 | |