1use super::{
12 Accumulator, ExactSizeAccumulator, ParallelAdaptor, ParallelAdaptorDescriptor, ParallelIterator,
13};
14use crossbeam_utils::CachePadded;
15use scopeguard::ScopeGuard;
16use std::cmp::Ordering;
17use std::iter::{Product, Sum};
18use std::marker::PhantomData;
19use std::ops::ControlFlow;
20#[cfg(feature = "nightly")]
21use std::ops::{FromResidual, Residual, Try};
22use std::sync::atomic::AtomicBool;
23
24pub struct Fuse(CachePadded<AtomicBool>);
30
31#[derive(PartialEq, Eq)]
33enum FuseState {
34 Unset,
35 Set,
36}
37
38impl Fuse {
39 pub fn new() -> Self {
41 Fuse(CachePadded::new(AtomicBool::new(false)))
42 }
43
44 fn load(&self) -> FuseState {
46 use std::sync::atomic::Ordering;
47
48 match self.0.load(Ordering::Relaxed) {
49 false => FuseState::Unset,
50 true => FuseState::Set,
51 }
52 }
53
54 fn set(&self) {
56 use std::sync::atomic::Ordering;
57
58 self.0.store(true, Ordering::Relaxed)
59 }
60}
61
62pub struct IterReducer<Reduce> {
65 pub(super) reduce: Reduce,
66}
67
68impl<Output, Reduce> ExactSizeAccumulator<Output, Option<Output>> for IterReducer<Reduce>
69where
70 Reduce: Fn(Output, Output) -> Output,
71{
72 #[inline(always)]
73 fn accumulate_exact(&self, iter: impl ExactSizeIterator<Item = Output>) -> Option<Output> {
74 iter.reduce(&self.reduce)
75 }
76}
77
78pub struct IterFolder<Init, Fold> {
79 pub(super) init: Init,
80 pub(super) fold: Fold,
81}
82
83impl<Item, Output, Init, Fold> ExactSizeAccumulator<Item, Output> for IterFolder<Init, Fold>
84where
85 Init: Fn(usize) -> Output,
86 Fold: Fn(Output, Item) -> Output,
87{
88 #[inline(always)]
89 fn accumulate_exact(&self, iter: impl ExactSizeIterator<Item = Item>) -> Output {
90 let init = (self.init)(iter.len());
91 iter.fold(init, &self.fold)
92 }
93}
94
95pub struct TryIterFolder<Init, TryFold> {
96 pub(super) init: Init,
97 pub(super) try_fold: TryFold,
98}
99
100#[cfg(not(feature = "nightly"))]
101impl<Item, Output, E, Init, TryFold> ExactSizeAccumulator<Item, Result<Output, E>>
102 for TryIterFolder<Init, TryFold>
103where
104 Init: Fn(usize) -> Output,
105 TryFold: Fn(Output, Item) -> Result<Output, E>,
106{
107 #[inline(always)]
108 fn accumulate_exact(&self, mut iter: impl ExactSizeIterator<Item = Item>) -> Result<Output, E> {
109 let init = (self.init)(iter.len());
110 iter.try_fold(init, &self.try_fold)
111 }
112}
113
114#[cfg(feature = "nightly")]
115impl<Item, Output, R, Init, TryFold> ExactSizeAccumulator<Item, R> for TryIterFolder<Init, TryFold>
116where
117 Init: Fn(usize) -> Output,
118 TryFold: Fn(Output, Item) -> R,
119 R: Try<Output = Output>,
120{
121 #[inline(always)]
122 fn accumulate_exact(&self, mut iter: impl ExactSizeIterator<Item = Item>) -> R {
123 let init = (self.init)(iter.len());
124 iter.try_fold(init, &self.try_fold)
125 }
126}
127
128pub struct IterAccumulator<Init, ProcessItem, Finalize> {
131 pub(super) init: Init,
132 pub(super) process_item: ProcessItem,
133 pub(super) finalize: Finalize,
134}
135
136impl<Item, Accum, Output, Init, ProcessItem, Finalize> Accumulator<Item, Output>
137 for IterAccumulator<Init, ProcessItem, Finalize>
138where
139 Init: Fn() -> Accum,
140 ProcessItem: Fn(Accum, Item) -> Accum,
141 Finalize: Fn(Accum) -> Output,
142{
143 #[inline(always)]
144 fn accumulate(&self, iter: impl Iterator<Item = Item>) -> Output {
145 let mut accumulator = (self.init)();
146 for item in iter {
147 accumulator = (self.process_item)(accumulator, item);
148 }
149 (self.finalize)(accumulator)
150 }
151}
152
153pub struct ShortCircuitingAccumulator<Init, ProcessItem, Finalize> {
154 pub(super) fuse: Fuse,
155 pub(super) init: Init,
156 pub(super) process_item: ProcessItem,
157 pub(super) finalize: Finalize,
158}
159
160#[cfg(not(feature = "nightly"))]
161impl<Item, Accum, Break, Output, Init, ProcessItem, Finalize> Accumulator<Item, Output>
162 for ShortCircuitingAccumulator<Init, ProcessItem, Finalize>
163where
164 Init: Fn() -> Accum,
165 ProcessItem: Fn(Accum, Item) -> ControlFlow<Break, Accum>,
166 Finalize: Fn(ControlFlow<Break, Accum>) -> Output,
167{
168 #[inline(always)]
169 fn accumulate(&self, mut iter: impl Iterator<Item = Item>) -> Output {
170 let mut accumulator = (self.init)();
171 let result = 'outer: {
172 while let FuseState::Unset = self.fuse.load() {
173 let Some(item) = iter.next() else {
174 break;
175 };
176
177 match (self.process_item)(accumulator, item) {
178 ControlFlow::Continue(acc) => {
179 accumulator = acc;
180 continue;
181 }
182 control_flow @ ControlFlow::Break(_) => {
183 self.fuse.set();
184 break 'outer control_flow;
185 }
186 }
187 }
188 ControlFlow::Continue(accumulator)
189 };
190 (self.finalize)(result)
191 }
192}
193
194#[cfg(feature = "nightly")]
195impl<Item, Accum, R, Output, Init, ProcessItem, Finalize> Accumulator<Item, Output>
196 for ShortCircuitingAccumulator<Init, ProcessItem, Finalize>
197where
198 Init: Fn() -> Accum,
199 ProcessItem: Fn(Accum, Item) -> R,
200 Finalize: Fn(R) -> Output,
201 R: Try<Output = Accum>,
202{
203 #[inline(always)]
204 fn accumulate(&self, mut iter: impl Iterator<Item = Item>) -> Output {
205 let mut accumulator = (self.init)();
206 let result = 'outer: {
207 while let FuseState::Unset = self.fuse.load() {
208 let Some(item) = iter.next() else {
209 break;
210 };
211
212 match (self.process_item)(accumulator, item).branch() {
213 ControlFlow::Continue(acc) => {
214 accumulator = acc;
215 continue;
216 }
217 ControlFlow::Break(residual) => {
218 self.fuse.set();
219 break 'outer R::from_residual(residual);
220 }
221 }
222 }
223 R::from_output(accumulator)
224 };
225 (self.finalize)(result)
226 }
227}
228
229pub struct AdaptorAccumulator<Inner, TransformItem> {
230 pub(super) inner: Inner,
231 pub(super) transform_item: TransformItem,
232}
233
234impl<InnerItem, Item, Output, Inner, TransformItem> Accumulator<InnerItem, Output>
235 for AdaptorAccumulator<Inner, TransformItem>
236where
237 Inner: Accumulator<Item, Output>,
238 TransformItem: Fn(InnerItem) -> Option<Item>,
239{
240 #[inline(always)]
241 fn accumulate(&self, iter: impl Iterator<Item = InnerItem>) -> Output {
242 self.inner.accumulate(iter.filter_map(&self.transform_item))
243 }
244}
245
246pub struct IterCollector<T> {
249 pub(super) _phantom: PhantomData<fn() -> T>,
250}
251
252impl<Item, T> Accumulator<Item, T> for IterCollector<T>
253where
254 T: FromIterator<Item>,
255{
256 #[inline(always)]
257 fn accumulate(&self, iter: impl Iterator<Item = Item>) -> T {
258 T::from_iter(iter)
259 }
260}
261
262pub struct TryIterCollector<T> {
263 pub(super) fuse: Fuse,
264 pub(super) _phantom: PhantomData<fn() -> T>,
265}
266
267#[cfg(not(feature = "nightly"))]
268impl<Item, C, E> Accumulator<Result<Item, E>, Result<C, E>> for TryIterCollector<C>
269where
270 C: FromIterator<Item>,
271{
272 #[inline(always)]
273 fn accumulate(&self, iter: impl Iterator<Item = Result<Item, E>>) -> Result<C, E> {
274 let mut error = None;
275 let c = C::from_iter(iter.map_while(|item| match item {
276 Err(e) => {
277 self.fuse.set();
278 error = Some(e);
279 None
280 }
281 Ok(x) => match self.fuse.load() {
282 FuseState::Set => None,
283 FuseState::Unset => Some(x),
284 },
285 }));
286 match error {
287 None => Ok(c),
288 Some(e) => Err(e),
289 }
290 }
291}
292
293#[cfg(feature = "nightly")]
294impl<Item, C> Accumulator<Item, <Item::Residual as Residual<C>>::TryType> for TryIterCollector<C>
295where
296 Item: Try,
297 Item::Residual: Residual<C>,
298 C: FromIterator<Item::Output>,
299{
300 #[inline(always)]
301 fn accumulate(
302 &self,
303 iter: impl Iterator<Item = Item>,
304 ) -> <Item::Residual as Residual<C>>::TryType {
305 let mut residual = None;
306 let c = C::from_iter(iter.map_while(|item| match item.branch() {
307 ControlFlow::Break(e) => {
308 self.fuse.set();
309 residual = Some(e);
310 None
311 }
312 ControlFlow::Continue(x) => match self.fuse.load() {
313 FuseState::Set => None,
314 FuseState::Unset => Some(x),
315 },
316 }));
317 match residual {
318 None => Try::from_output(c),
319 Some(e) => FromResidual::from_residual(e),
320 }
321 }
322}
323
324pub struct SumAccumulator;
328
329impl<Item, Output> Accumulator<Item, Output> for SumAccumulator
330where
331 Output: Sum<Item>,
332{
333 #[inline(always)]
334 fn accumulate(&self, iter: impl Iterator<Item = Item>) -> Output {
335 iter.sum()
336 }
337}
338
339impl<Item, Output> ExactSizeAccumulator<Item, Output> for SumAccumulator
340where
341 Output: Sum<Item>,
342{
343 #[inline(always)]
344 fn accumulate_exact(&self, iter: impl ExactSizeIterator<Item = Item>) -> Output {
345 iter.sum()
346 }
347}
348
349pub struct ProductAccumulator;
350
351impl<Item, Output> Accumulator<Item, Output> for ProductAccumulator
352where
353 Output: Product<Item>,
354{
355 #[inline(always)]
356 fn accumulate(&self, iter: impl Iterator<Item = Item>) -> Output {
357 iter.product()
358 }
359}
360
361impl<Item, Output> ExactSizeAccumulator<Item, Output> for ProductAccumulator
362where
363 Output: Product<Item>,
364{
365 #[inline(always)]
366 fn accumulate_exact(&self, iter: impl ExactSizeIterator<Item = Item>) -> Output {
367 iter.product()
368 }
369}
370
371#[derive(Clone, Copy, Debug, PartialEq, Eq)]
374pub enum MinMaxResult<T> {
375 NoElements,
377 OneElement(T),
379 MinMax {
381 min: T,
383 max: T,
385 },
386}
387
388impl<T> MinMaxResult<T> {
389 pub(super) fn map<U, F>(self, f: F) -> MinMaxResult<U>
390 where
391 F: Fn(T) -> U,
392 {
393 match self {
394 MinMaxResult::NoElements => MinMaxResult::NoElements,
395 MinMaxResult::OneElement(x) => MinMaxResult::OneElement(f(x)),
396 MinMaxResult::MinMax { min, max } => MinMaxResult::MinMax {
397 min: f(min),
398 max: f(max),
399 },
400 }
401 }
402
403 pub fn min(&self) -> Option<&T> {
412 match self {
413 MinMaxResult::NoElements => None,
414 MinMaxResult::OneElement(x) => Some(x),
415 MinMaxResult::MinMax { min, max: _ } => Some(min),
416 }
417 }
418
419 pub fn into_min(self) -> Option<T> {
431 match self {
432 MinMaxResult::NoElements => None,
433 MinMaxResult::OneElement(x) => Some(x),
434 MinMaxResult::MinMax { min, max: _ } => Some(min),
435 }
436 }
437
438 pub fn max(&self) -> Option<&T> {
447 match self {
448 MinMaxResult::NoElements => None,
449 MinMaxResult::OneElement(x) => Some(x),
450 MinMaxResult::MinMax { min: _, max } => Some(max),
451 }
452 }
453
454 pub fn into_max(self) -> Option<T> {
466 match self {
467 MinMaxResult::NoElements => None,
468 MinMaxResult::OneElement(x) => Some(x),
469 MinMaxResult::MinMax { min: _, max } => Some(max),
470 }
471 }
472
473 pub fn as_option(&self) -> Option<(&T, &T)>
486 where
487 T: Clone,
488 {
489 match self {
490 MinMaxResult::NoElements => None,
491 MinMaxResult::OneElement(x) => Some((x, x)),
492 MinMaxResult::MinMax { min, max } => Some((min, max)),
493 }
494 }
495
496 pub fn into_option(self) -> Option<(T, T)>
508 where
509 T: Clone,
510 {
511 match self {
512 MinMaxResult::NoElements => None,
513 MinMaxResult::OneElement(x) => Some((x.clone(), x)),
514 MinMaxResult::MinMax { min, max } => Some((min, max)),
515 }
516 }
517}
518
519pub struct MinMaxAccumulator<F> {
520 pub(super) f: F,
521}
522
523impl<Item, F> Accumulator<Item, MinMaxResult<Item>> for &MinMaxAccumulator<F>
524where
525 F: Fn(&Item, &Item) -> Ordering,
526{
527 #[inline(always)]
528 fn accumulate(&self, mut iter: impl Iterator<Item = Item>) -> MinMaxResult<Item> {
529 let (mut min, mut max) = match iter.next() {
530 None => return MinMaxResult::NoElements,
531 Some(x) => match iter.next() {
532 None => return MinMaxResult::OneElement(x),
533 Some(y) => match (self.f)(&x, &y) {
534 Ordering::Less | Ordering::Equal => (x, y),
535 Ordering::Greater => (y, x),
536 },
537 },
538 };
539
540 loop {
541 let a = match iter.next() {
542 Some(a) => a,
543 None => break,
544 };
545 let b = match iter.next() {
546 Some(b) => b,
547 None => {
548 if let Ordering::Less = (self.f)(&a, &min) {
549 min = a;
550 } else if let Ordering::Greater | Ordering::Equal = (self.f)(&a, &max) {
551 max = a;
552 }
553 break;
554 }
555 };
556
557 match (self.f)(&a, &b) {
558 Ordering::Less | Ordering::Equal => {
559 if let Ordering::Less = (self.f)(&a, &min) {
560 min = a;
561 }
562 if let Ordering::Greater | Ordering::Equal = (self.f)(&b, &max) {
563 max = b;
564 }
565 }
566 Ordering::Greater => {
567 if let Ordering::Less = (self.f)(&b, &min) {
568 min = b;
569 }
570 if let Ordering::Greater | Ordering::Equal = (self.f)(&a, &max) {
571 max = a;
572 }
573 }
574 }
575 }
576
577 MinMaxResult::MinMax { min, max }
578 }
579}
580
581impl<Item, F> ExactSizeAccumulator<MinMaxResult<Item>, MinMaxResult<Item>> for &MinMaxAccumulator<F>
582where
583 F: Fn(&Item, &Item) -> Ordering,
584{
585 #[inline(always)]
586 fn accumulate_exact(
587 &self,
588 iter: impl ExactSizeIterator<Item = MinMaxResult<Item>>,
589 ) -> MinMaxResult<Item> {
590 iter.fold(MinMaxResult::NoElements, |x, y| match (x, y) {
591 (MinMaxResult::NoElements, z) | (z, MinMaxResult::NoElements) => z,
592 (MinMaxResult::OneElement(a), MinMaxResult::OneElement(b)) => match (self.f)(&a, &b) {
593 Ordering::Less | Ordering::Equal => MinMaxResult::MinMax { min: a, max: b },
594 Ordering::Greater => MinMaxResult::MinMax { min: b, max: a },
595 },
596 (MinMaxResult::OneElement(z), MinMaxResult::MinMax { min, max }) => {
597 if let Ordering::Less | Ordering::Equal = (self.f)(&z, &min) {
598 MinMaxResult::MinMax { min: z, max }
599 } else if let Ordering::Greater = (self.f)(&z, &max) {
600 MinMaxResult::MinMax { min, max: z }
601 } else {
602 MinMaxResult::MinMax { min, max }
603 }
604 }
605 (MinMaxResult::MinMax { min, max }, MinMaxResult::OneElement(z)) => {
606 if let Ordering::Less = (self.f)(&z, &min) {
607 MinMaxResult::MinMax { min: z, max }
608 } else if let Ordering::Greater | Ordering::Equal = (self.f)(&z, &max) {
609 MinMaxResult::MinMax { min, max: z }
610 } else {
611 MinMaxResult::MinMax { min, max }
612 }
613 }
614 (
615 MinMaxResult::MinMax {
616 min: min1,
617 max: max1,
618 },
619 MinMaxResult::MinMax {
620 min: min2,
621 max: max2,
622 },
623 ) => {
624 let min = match (self.f)(&min1, &min2) {
625 Ordering::Less | Ordering::Equal => min1,
626 Ordering::Greater => min2,
627 };
628 let max = match (self.f)(&max1, &max2) {
629 Ordering::Greater => max1,
630 Ordering::Less | Ordering::Equal => max2,
631 };
632 MinMaxResult::MinMax { min, max }
633 }
634 })
635 }
636}
637
638#[must_use = "iterator adaptors are lazy"]
648pub struct Map<Inner: ParallelIterator, F> {
649 pub(super) inner: Inner,
650 pub(super) f: F,
651}
652
653impl<Inner: ParallelIterator, T, F> ParallelAdaptor for Map<Inner, F>
654where
655 F: Fn(Inner::Item) -> T + Sync,
656{
657 type Item = T;
658 type Inner = Inner;
659
660 fn descriptor(
661 self,
662 ) -> ParallelAdaptorDescriptor<
663 Self::Item,
664 Self::Inner,
665 impl Fn(<Self::Inner as ParallelIterator>::Item) -> Option<Self::Item> + Sync,
666 > {
667 ParallelAdaptorDescriptor {
668 inner: self.inner,
669 transform_item: move |item| Some((self.f)(item)),
670 }
671 }
672}
673
674#[must_use = "iterator adaptors are lazy"]
685pub struct PanicFuse<Inner: ParallelIterator> {
686 pub(super) inner: Inner,
687}
688
689impl<Inner: ParallelIterator> ParallelIterator for PanicFuse<Inner> {
690 type Item = Inner::Item;
691
692 fn upper_bounded_pipeline<Output: Send, Accum>(
693 self,
694 init: impl Fn() -> Accum + Sync,
695 process_item: impl Fn(Accum, usize, Self::Item) -> ControlFlow<Accum, Accum> + Sync,
696 finalize: impl Fn(Accum) -> Output + Sync,
697 reduce: impl Fn(Output, Output) -> Output,
698 ) -> Output {
699 let fuse = Fuse::new();
700 self.inner.upper_bounded_pipeline(
701 || (init(), scopeguard::guard(&fuse, |fuse| fuse.set())),
702 |(acc, guard), index, item| match guard.load() {
703 FuseState::Unset => match process_item(acc, index, item) {
704 ControlFlow::Continue(acc) => ControlFlow::Continue((acc, guard)),
705 ControlFlow::Break(acc) => ControlFlow::Break((acc, guard)),
706 },
707 FuseState::Set => ControlFlow::Break((acc, guard)),
708 },
709 |(acc, guard)| {
710 ScopeGuard::into_inner(guard);
711 finalize(acc)
712 },
713 reduce,
714 )
715 }
716
717 fn iter_pipeline<Output, Accum: Send>(
718 self,
719 accum: impl Accumulator<Self::Item, Accum> + Sync,
720 reduce: impl ExactSizeAccumulator<Accum, Output>,
721 ) -> Output {
722 let accumulator = PanicFuseAccumulator {
723 inner: accum,
724 fuse: Fuse::new(),
725 };
726 self.inner.iter_pipeline(accumulator, reduce)
727 }
728}
729
730struct PanicFuseAccumulator<Inner> {
731 inner: Inner,
732 fuse: Fuse,
733}
734
735impl<Item, Output, Inner> Accumulator<Item, Output> for PanicFuseAccumulator<Inner>
736where
737 Inner: Accumulator<Item, Output>,
738{
739 #[inline(always)]
740 fn accumulate(&self, iter: impl Iterator<Item = Item>) -> Output {
741 let guard = scopeguard::guard(&self.fuse, |fuse| fuse.set());
742 let output = self
743 .inner
744 .accumulate(iter.take_while(|_| self.fuse.load() == FuseState::Unset));
745 ScopeGuard::into_inner(guard);
746 output
747 }
748}
749
750#[cfg(test)]
751mod test {
752 use super::*;
753
754 #[test]
755 fn minmaxresult_min() {
756 assert_eq!(MinMaxResult::<i32>::NoElements.min(), None);
757 assert_eq!(MinMaxResult::OneElement(42).min(), Some(&42));
758 assert_eq!(MinMaxResult::MinMax { min: 42, max: 123 }.min(), Some(&42));
759 }
760
761 #[test]
762 fn minmaxresult_into_min() {
763 assert_eq!(MinMaxResult::<i32>::NoElements.into_min(), None);
764 assert_eq!(MinMaxResult::OneElement(42).into_min(), Some(42));
765 assert_eq!(
766 MinMaxResult::MinMax { min: 42, max: 123 }.into_min(),
767 Some(42)
768 );
769 }
770
771 #[test]
772 fn minmaxresult_max() {
773 assert_eq!(MinMaxResult::<i32>::NoElements.max(), None);
774 assert_eq!(MinMaxResult::OneElement(42).max(), Some(&42));
775 assert_eq!(MinMaxResult::MinMax { min: 42, max: 123 }.max(), Some(&123));
776 }
777
778 #[test]
779 fn minmaxresult_into_max() {
780 assert_eq!(MinMaxResult::<i32>::NoElements.into_max(), None);
781 assert_eq!(MinMaxResult::OneElement(42).into_max(), Some(42));
782 assert_eq!(
783 MinMaxResult::MinMax { min: 42, max: 123 }.into_max(),
784 Some(123)
785 );
786 }
787
788 #[test]
789 fn minmaxresult_as_option() {
790 assert_eq!(MinMaxResult::<i32>::NoElements.as_option(), None);
791 assert_eq!(MinMaxResult::OneElement(42).as_option(), Some((&42, &42)));
792 assert_eq!(
793 MinMaxResult::MinMax { min: 42, max: 123 }.as_option(),
794 Some((&42, &123))
795 );
796 }
797
798 #[test]
799 fn minmaxresult_into_option() {
800 assert_eq!(MinMaxResult::<i32>::NoElements.into_option(), None);
801 assert_eq!(MinMaxResult::OneElement(42).into_option(), Some((42, 42)));
802 assert_eq!(
803 MinMaxResult::MinMax { min: 42, max: 123 }.into_option(),
804 Some((42, 123))
805 );
806 }
807
808 #[test]
809 fn minmax_accumulator_edge_cases() {
810 let accumulator = &MinMaxAccumulator {
811 f: |x: &(i32, i32), y: &(i32, i32)| x.0.cmp(&y.0),
812 };
813
814 assert_eq!(
816 accumulator.accumulate_exact(
817 [
818 MinMaxResult::OneElement((0, 0)),
819 MinMaxResult::OneElement((0, 1))
820 ]
821 .into_iter()
822 ),
823 MinMaxResult::MinMax {
824 min: (0, 0),
825 max: (0, 1),
826 }
827 );
828 assert_eq!(
829 accumulator.accumulate_exact(
830 [
831 MinMaxResult::OneElement((1, 0)),
832 MinMaxResult::OneElement((0, 1))
833 ]
834 .into_iter()
835 ),
836 MinMaxResult::MinMax {
837 min: (0, 1),
838 max: (1, 0),
839 }
840 );
841
842 assert_eq!(
844 accumulator.accumulate_exact(
845 [
846 MinMaxResult::OneElement((0, 0)),
847 MinMaxResult::MinMax {
848 min: (0, 1),
849 max: (0, 2),
850 }
851 ]
852 .into_iter()
853 ),
854 MinMaxResult::MinMax {
855 min: (0, 0),
856 max: (0, 2),
857 }
858 );
859 assert_eq!(
860 accumulator.accumulate_exact(
861 [
862 MinMaxResult::OneElement((1, 0)),
863 MinMaxResult::MinMax {
864 min: (0, 1),
865 max: (2, 2),
866 }
867 ]
868 .into_iter()
869 ),
870 MinMaxResult::MinMax {
871 min: (0, 1),
872 max: (2, 2),
873 }
874 );
875 assert_eq!(
876 accumulator.accumulate_exact(
877 [
878 MinMaxResult::OneElement((0, 0)),
879 MinMaxResult::MinMax {
880 min: (1, 1),
881 max: (2, 2),
882 }
883 ]
884 .into_iter()
885 ),
886 MinMaxResult::MinMax {
887 min: (0, 0),
888 max: (2, 2),
889 }
890 );
891 assert_eq!(
892 accumulator.accumulate_exact(
893 [
894 MinMaxResult::OneElement((2, 0)),
895 MinMaxResult::MinMax {
896 min: (0, 1),
897 max: (1, 2),
898 }
899 ]
900 .into_iter()
901 ),
902 MinMaxResult::MinMax {
903 min: (0, 1),
904 max: (2, 0),
905 }
906 );
907
908 assert_eq!(
910 accumulator.accumulate_exact(
911 [
912 MinMaxResult::MinMax {
913 min: (0, 0),
914 max: (0, 1),
915 },
916 MinMaxResult::OneElement((0, 2)),
917 ]
918 .into_iter()
919 ),
920 MinMaxResult::MinMax {
921 min: (0, 0),
922 max: (0, 2),
923 }
924 );
925 assert_eq!(
926 accumulator.accumulate_exact(
927 [
928 MinMaxResult::MinMax {
929 min: (0, 0),
930 max: (2, 1),
931 },
932 MinMaxResult::OneElement((1, 2)),
933 ]
934 .into_iter()
935 ),
936 MinMaxResult::MinMax {
937 min: (0, 0),
938 max: (2, 1),
939 }
940 );
941 assert_eq!(
942 accumulator.accumulate_exact(
943 [
944 MinMaxResult::MinMax {
945 min: (1, 0),
946 max: (2, 1),
947 },
948 MinMaxResult::OneElement((0, 2)),
949 ]
950 .into_iter()
951 ),
952 MinMaxResult::MinMax {
953 min: (0, 2),
954 max: (2, 1),
955 }
956 );
957 assert_eq!(
958 accumulator.accumulate_exact(
959 [
960 MinMaxResult::MinMax {
961 min: (0, 0),
962 max: (1, 1),
963 },
964 MinMaxResult::OneElement((2, 2)),
965 ]
966 .into_iter()
967 ),
968 MinMaxResult::MinMax {
969 min: (0, 0),
970 max: (2, 2),
971 }
972 );
973 }
974}