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