1//! Traits for the minimun and maximum [`OptionOperations`].
2
3// Required for doc
4#[allow(unused)]
5use crate::OptionOperations;
6
7use 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>`.
21pub 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
37impl<T> OptionMinMax<T> for T
38where
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
52impl<T> OptionMinMax<Option<T>, T> for T
53where
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
71impl<T> OptionMinMax<T> for Option<T>
72where
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
92impl<T> OptionMinMax<Option<T>, T> for Option<T>
93where
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)]
114mod 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