| 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 | |