try_partialord/
min_max.rs1use crate::{InvalidOrderError, OrderResult};
2use core::cmp::Ordering;
3
4pub trait TryMinMax<T> {
21 #[inline]
23 fn try_min(self) -> OrderResult<Option<T>>
24 where
25 T: PartialOrd<T>,
26 Self: Sized,
27 {
28 self.try_select_by(|a, b| a.partial_cmp(b), Ordering::Greater)
29 }
30 #[inline]
32 fn try_min_by<F>(self, compare: F) -> OrderResult<Option<T>>
33 where
34 F: FnMut(&T, &T) -> Option<Ordering>,
35 Self: Sized,
36 {
37 self.try_select_by(compare, Ordering::Greater)
38 }
39 #[inline]
41 fn try_min_by_key<K, F>(self, f: F) -> OrderResult<Option<T>>
42 where
43 F: FnMut(&T) -> Option<K>,
44 K: PartialOrd<K>,
45 Self: Sized,
46 {
47 let mut fk = f;
48 self.try_select_by(|a, b| fk(a).partial_cmp(&fk(b)), Ordering::Greater)
49 }
50 #[inline]
52 fn try_max(self) -> OrderResult<Option<T>>
53 where
54 T: PartialOrd<T>,
55 Self: Sized,
56 {
57 self.try_select_by(|a, b| a.partial_cmp(b), Ordering::Less)
58 }
59 #[inline]
61 fn try_max_by<F>(self, compare: F) -> OrderResult<Option<T>>
62 where
63 F: FnMut(&T, &T) -> Option<Ordering>,
64 Self: Sized,
65 {
66 self.try_select_by(compare, Ordering::Less)
67 }
68 #[inline]
70 fn try_max_by_key<K, F>(self, f: F) -> OrderResult<Option<T>>
71 where
72 F: FnMut(&T) -> Option<K>,
73 K: PartialOrd<K>,
74 Self: Sized,
75 {
76 let mut fk = f;
77 self.try_select_by(|a, b| fk(a).partial_cmp(&fk(b)), Ordering::Less)
78 }
79 fn try_select_by<F>(self, compare: F, target: Ordering) -> OrderResult<Option<T>>
83 where
84 F: FnMut(&T, &T) -> Option<Ordering>;
85}
86
87impl<T, Iter> TryMinMax<T> for Iter
88where
89 Iter: IntoIterator<Item = T>,
90{
91 #[inline]
92 fn try_select_by<F>(self, compare: F, target: Ordering) -> OrderResult<Option<T>>
93 where
94 F: FnMut(&T, &T) -> Option<Ordering>,
95 {
96 try_select_by(self.into_iter(), compare, target)
97 }
98}
99
100fn try_select_by<T, F>(
101 mut iter: impl Iterator<Item = T>,
102 compare: F,
103 target: Ordering,
104) -> OrderResult<Option<T>>
105where
106 F: FnMut(&T, &T) -> Option<Ordering>,
107{
108 let mut compare = compare;
109 if let Some(first) = iter.next() {
110 match iter.try_fold(first, |a, b| {
111 Some(if compare(&a, &b)? == target { b } else { a })
112 }) {
113 None => Err(InvalidOrderError),
114 x => Ok(x), }
116 } else {
117 Ok(None)
118 }
119}
120
121#[cfg(test)]
122#[cfg(feature = "std")]
123mod tests {
124 use crate::*;
125 use rand::distributions::Standard;
126 use rand::prelude::*;
127 use std::vec::Vec;
128
129 #[test]
130 fn try_min_ok() {
131 let rng = thread_rng();
132 let v: Vec<f32> = Standard.sample_iter(rng).take(100).collect();
133 let min = v.iter().try_min().unwrap();
134 assert_eq!(min, v.iter().min_by(|a, b| a.partial_cmp(b).unwrap()));
135 let min = v.iter().try_min().unwrap();
136 assert_eq!(
137 min.as_deref(),
138 v.iter().min_by(|a, b| a.partial_cmp(b).unwrap())
139 );
140
141 let iter = &mut v.iter();
142 let min = iter.try_min().unwrap();
143 assert_eq!(min, v.iter().min_by(|a, b| a.partial_cmp(b).unwrap()));
144 }
145
146 #[test]
147 fn try_min_error() {
148 let rng = thread_rng();
149 let mut v: Vec<f32> = Standard.sample_iter(rng).take(100).collect();
150 v.push(f32::NAN);
151 let min = v.iter().try_min();
152 assert!(min.is_err());
153 }
154}