1 | //! Traits for the minimun and maximum [`OptionOperations`]. |
2 | |
3 | // Required for doc |
4 | #[allow (unused)] |
5 | use crate::OptionOperations; |
6 | |
7 | use crate::OptionOrd; |
8 | |
9 | /// Trait for values and `Option`s that can be compared |
10 | /// to get the minimum or maximum. |
11 | /// |
12 | /// Implementing this type leads to the following auto-implementations: |
13 | /// |
14 | /// - `OptionMinMax<Option<InnerRhs>> for T`. |
15 | /// - `OptionMinMax<Rhs> for Option<T>`. |
16 | /// - `OptionMinMax<Option<InnerRhs>> for Option<T>`. |
17 | /// - ... and some variants with references. |
18 | /// |
19 | /// This trait is auto-implemented for [`OptionOperations`] types |
20 | /// implementing `OptionOrd<Rhs>`. |
21 | pub trait OptionMinMax<Other, Inner = Other> { |
22 | /// Compares and returns the minimum of two values. |
23 | /// |
24 | /// Returns `None` if they can't be compared, e.g. if |
25 | /// at most one argument is `None`. |
26 | #[must_use ] |
27 | fn opt_min(self, other: Other) -> Option<Inner>; |
28 | |
29 | /// Compares and returns the maximum of two values. |
30 | /// |
31 | /// Returns `None` if they can't be compared, e.g. if |
32 | /// at most one argument is `None`. |
33 | #[must_use ] |
34 | fn opt_max(self, other: Other) -> Option<Inner>; |
35 | } |
36 | |
37 | impl<T> OptionMinMax<T> for T |
38 | where |
39 | T: for<'a> OptionOrd<&'a T, T>, |
40 | { |
41 | fn opt_min(self, other: T) -> Option<T> { |
42 | self.opt_lt(&other) |
43 | .map(|is_lt: bool| if is_lt { self } else { other }) |
44 | } |
45 | |
46 | fn opt_max(self, other: T) -> Option<T> { |
47 | self.opt_gt(&other) |
48 | .map(|is_gt: bool| if is_gt { self } else { other }) |
49 | } |
50 | } |
51 | |
52 | impl<T> OptionMinMax<Option<T>, T> for T |
53 | where |
54 | T: for<'a> OptionOrd<&'a T, T>, |
55 | { |
56 | fn opt_min(self, other: Option<T>) -> Option<T> { |
57 | other.and_then(|inner_other: T| { |
58 | self.opt_lt(&inner_other) |
59 | .map(|is_lt: bool| if is_lt { self } else { inner_other }) |
60 | }) |
61 | } |
62 | |
63 | fn opt_max(self, other: Option<T>) -> Option<T> { |
64 | other.and_then(|inner_other: T| { |
65 | self.opt_gt(&inner_other) |
66 | .map(|is_gt: bool| if is_gt { self } else { inner_other }) |
67 | }) |
68 | } |
69 | } |
70 | |
71 | impl<T> OptionMinMax<T> for Option<T> |
72 | where |
73 | T: for<'a> OptionOrd<&'a T, T>, |
74 | { |
75 | fn opt_min(self, other: T) -> Option<T> { |
76 | self.and_then(|inner_self: T| { |
77 | inner_selfOption |
78 | .opt_lt(&other) |
79 | .map(|is_lt: bool| if is_lt { inner_self } else { other }) |
80 | }) |
81 | } |
82 | |
83 | fn opt_max(self, other: T) -> Option<T> { |
84 | self.and_then(|inner_self: T| { |
85 | inner_selfOption |
86 | .opt_gt(&other) |
87 | .map(|is_gt: bool| if is_gt { inner_self } else { other }) |
88 | }) |
89 | } |
90 | } |
91 | |
92 | impl<T> OptionMinMax<Option<T>, T> for Option<T> |
93 | where |
94 | T: for<'a> OptionOrd<&'a T, T>, |
95 | { |
96 | fn opt_min(self, other: Option<T>) -> Option<T> { |
97 | self.zip(other).and_then(|(inner_self: T, inner_other: T)| { |
98 | inner_selfOption |
99 | .opt_lt(&inner_other) |
100 | .map(|is_lt: bool| if is_lt { inner_self } else { inner_other }) |
101 | }) |
102 | } |
103 | |
104 | fn opt_max(self, other: Option<T>) -> Option<T> { |
105 | self.zip(other).and_then(|(inner_self: T, inner_other: T)| { |
106 | inner_selfOption |
107 | .opt_gt(&inner_other) |
108 | .map(|is_gt: bool| if is_gt { inner_self } else { inner_other }) |
109 | }) |
110 | } |
111 | } |
112 | |
113 | #[cfg (test)] |
114 | mod test { |
115 | use super::OptionMinMax; |
116 | use crate::OptionOperations; |
117 | |
118 | #[derive (Copy, Clone, Debug, PartialEq, PartialOrd)] |
119 | struct MyInt(u64); |
120 | |
121 | impl OptionOperations for MyInt {} |
122 | |
123 | const MY_1: MyInt = MyInt(1); |
124 | const MY_2: MyInt = MyInt(2); |
125 | const SOME_1: Option<MyInt> = Some(MY_1); |
126 | const SOME_2: Option<MyInt> = Some(MY_2); |
127 | const NONE: Option<MyInt> = None; |
128 | |
129 | #[test ] |
130 | fn min() { |
131 | assert_eq!(SOME_1.opt_min(SOME_2), SOME_1); |
132 | assert_eq!(SOME_2.opt_min(SOME_1), SOME_1); |
133 | assert_eq!(SOME_1.opt_min(NONE), None); |
134 | |
135 | assert_eq!(SOME_1.opt_min(MY_2), SOME_1); |
136 | assert_eq!(SOME_2.opt_min(MY_1), SOME_1); |
137 | |
138 | assert_eq!(MY_1.opt_min(MY_2), SOME_1); |
139 | assert_eq!(MY_2.opt_min(MY_1), SOME_1); |
140 | |
141 | assert_eq!(MY_1.opt_min(SOME_2), SOME_1); |
142 | assert_eq!(MY_2.opt_min(SOME_1), SOME_1); |
143 | |
144 | assert_eq!(MY_1.opt_min(NONE), None); |
145 | assert_eq!(NONE.opt_min(MY_1), None); |
146 | |
147 | assert_eq!(SOME_1.opt_min(NONE).or(SOME_1), SOME_1); |
148 | } |
149 | |
150 | #[test ] |
151 | fn max() { |
152 | assert_eq!(SOME_1.opt_max(SOME_2), SOME_2); |
153 | assert_eq!(SOME_2.opt_max(SOME_1), SOME_2); |
154 | assert_eq!(SOME_1.opt_max(NONE), None); |
155 | |
156 | assert_eq!(SOME_1.opt_max(MY_2), SOME_2); |
157 | assert_eq!(SOME_2.opt_max(MY_1), SOME_2); |
158 | |
159 | assert_eq!(MY_1.opt_max(MY_2), SOME_2); |
160 | assert_eq!(MY_2.opt_max(MY_1), SOME_2); |
161 | |
162 | assert_eq!(MY_1.opt_max(SOME_2), SOME_2); |
163 | assert_eq!(MY_2.opt_max(SOME_1), SOME_2); |
164 | |
165 | assert_eq!(MY_1.opt_max(NONE), None); |
166 | assert_eq!(NONE.opt_max(MY_1), None); |
167 | |
168 | assert_eq!(SOME_1.opt_max(NONE).or(SOME_1), SOME_1); |
169 | } |
170 | } |
171 | |