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 { new(base: I, identity: ID, fold_op: F) -> Self16 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> { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result41 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 42 f.debug_struct("TryFold").field("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 drive_unindexed<C>(self, consumer: C) -> C::Result where C: UnindexedConsumer<Self::Item>,55 fn drive_unindexed<C>(self, consumer: C) -> C::Result 56 where 57 C: UnindexedConsumer<Self::Item>, 58 { 59 let consumer1 = TryFoldConsumer { 60 base: consumer, 61 identity: &self.identity, 62 fold_op: &self.fold_op, 63 marker: PhantomData, 64 }; 65 self.base.drive_unindexed(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 split_at(self, index: usize) -> (Self, Self, Self::Reducer)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 into_folder(self) -> Self::Folder99 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 full(&self) -> bool107 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 { split_off_left(&self) -> Self119 fn split_off_left(&self) -> Self { 120 TryFoldConsumer { 121 base: self.base.split_off_left(), 122 ..*self 123 } 124 } 125 to_reducer(&self) -> Self::Reducer126 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 consume(mut self, item: T) -> Self145 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 complete(self) -> C::Result153 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 full(&self) -> bool161 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 { new(base: I, item: U::Output, fold_op: F) -> Self178 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 { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result204 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 205 f.debug_struct("TryFoldWith") 206 .field("base", &self.base) 207 .field("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 drive_unindexed<C>(self, consumer: C) -> C::Result where C: UnindexedConsumer<Self::Item>,221 fn drive_unindexed<C>(self, consumer: C) -> C::Result 222 where 223 C: UnindexedConsumer<Self::Item>, 224 { 225 let consumer1 = TryFoldWithConsumer { 226 base: consumer, 227 item: self.item, 228 fold_op: &self.fold_op, 229 }; 230 self.base.drive_unindexed(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 split_at(self, index: usize) -> (Self, Self, Self::Reducer)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 into_folder(self) -> Self::Folder267 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 full(&self) -> bool275 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 { split_off_left(&self) -> Self287 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 to_reducer(&self) -> Self::Reducer295 fn to_reducer(&self) -> Self::Reducer { 296 self.base.to_reducer() 297 } 298 } 299