misc_utils/
minmax.rs

1use num_traits::Bounded;
2use std::{
3    fmt::{Display, Formatter, Result as FmtResult},
4    str::FromStr,
5};
6
7/// Helper type to ensure to calculate a minimal value
8#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
9pub struct Min<T> {
10    value: Option<T>,
11}
12
13impl<T> Min<T>
14where
15    T: Copy + Ord,
16{
17    /// Create a new instance
18    pub fn new() -> Self {
19        Self::default()
20    }
21
22    /// Create a new instance with an initial value to compare to
23    pub fn with_initial(initial: T) -> Self {
24        Self {
25            value: Some(initial),
26        }
27    }
28
29    /// Return the minimal value found so far
30    ///
31    /// Returns `None` if neither an initial value exists nor `update` was called.
32    /// Returns `Some(T)` if at least one value exists.
33    pub fn get_min(&self) -> Option<T> {
34        self.value
35    }
36
37    /// Return the minimal value found so far
38    ///
39    /// This method falls back to the maximal value for type `T`, if no other value exists.
40    pub fn get_min_extreme(&self) -> T
41    where
42        T: Bounded,
43    {
44        self.get_min().unwrap_or_else(T::max_value)
45    }
46
47    /// Update the value by replacing it with a lower value
48    ///
49    /// If `value` is less than `self`, then self is replaced with `value`.
50    /// This method can be called with type `T` or type `Min<T>`.
51    pub fn update<V: Into<Self>>(&mut self, value: V) {
52        match (self.value, value.into().value) {
53            (None, None) => self.value = None,
54            (Some(v), None) | (None, Some(v)) => self.value = Some(v),
55            (Some(v1), Some(v2)) => self.value = Some(v1.min(v2)),
56        }
57    }
58}
59
60impl<T> Default for Min<T> {
61    fn default() -> Self {
62        Self { value: None }
63    }
64}
65
66impl<T> From<T> for Min<T>
67where
68    T: Copy + Ord,
69{
70    fn from(value: T) -> Self {
71        Self::with_initial(value)
72    }
73}
74
75impl<T> FromIterator<T> for Min<T>
76where
77    T: Ord,
78{
79    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
80        let m = iter.into_iter().min();
81        if m.is_some() {
82            Self { value: m }
83        } else {
84            Self::default()
85        }
86    }
87}
88
89impl<T> Display for Min<T>
90where
91    T: Display,
92{
93    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
94        if let Some(v) = &self.value {
95            write!(f, "{}", v)
96        } else {
97            write!(f, "<uninitialized>")
98        }
99    }
100}
101
102impl<T> FromStr for Min<T>
103where
104    T: Copy + FromStr + Ord,
105{
106    type Err = T::Err;
107
108    fn from_str(s: &str) -> Result<Self, Self::Err> {
109        Ok(Self::with_initial(T::from_str(s)?))
110    }
111}
112
113/// Helper type to ensure to calculate a maximal value
114#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
115pub struct Max<T> {
116    value: Option<T>,
117}
118
119impl<T> Max<T>
120where
121    T: Copy + Ord,
122{
123    /// Create a new instance
124    pub fn new() -> Self {
125        Self::default()
126    }
127
128    /// Create a new instance with an initial value to compare to
129    pub fn with_initial(initial: T) -> Self {
130        Self {
131            value: Some(initial),
132        }
133    }
134
135    /// Return the maximal value found so far
136    ///
137    /// Returns `None` if neither an initial value exists nor `update` was called.
138    /// Returns `Some(T)` if at least one value exists.
139    pub fn get_max(&self) -> Option<T> {
140        self.value
141    }
142
143    /// Return the maximal value found so far
144    ///
145    /// This method falls back to the minimal value for type `T`, if no other value exists.
146    pub fn get_max_extreme(&self) -> T
147    where
148        T: Bounded,
149    {
150        self.get_max().unwrap_or_else(T::min_value)
151    }
152
153    /// Update the value by replacing it with a higher value
154    ///
155    /// If `value` is greater than `self`, then self is replaced with `value`.
156    /// This method can be called with type `T` or type `Max<T>`.
157    pub fn update<V: Into<Self>>(&mut self, value: V) {
158        match (self.value, value.into().value) {
159            (None, None) => self.value = None,
160            (Some(v), None) | (None, Some(v)) => self.value = Some(v),
161            (Some(v1), Some(v2)) => self.value = Some(v1.max(v2)),
162        }
163    }
164}
165
166impl<T> Default for Max<T> {
167    fn default() -> Self {
168        Self { value: None }
169    }
170}
171
172impl<T> From<T> for Max<T>
173where
174    T: Copy + Ord,
175{
176    fn from(value: T) -> Self {
177        Self::with_initial(value)
178    }
179}
180
181impl<T> FromIterator<T> for Max<T>
182where
183    T: Ord,
184{
185    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
186        let m = iter.into_iter().max();
187        if m.is_some() {
188            Self { value: m }
189        } else {
190            Self::default()
191        }
192    }
193}
194
195impl<T> Display for Max<T>
196where
197    T: Display,
198{
199    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
200        if let Some(v) = &self.value {
201            write!(f, "{}", v)
202        } else {
203            write!(f, "<uninitialized>")
204        }
205    }
206}
207
208impl<T> FromStr for Max<T>
209where
210    T: Copy + FromStr + Ord,
211{
212    type Err = T::Err;
213
214    fn from_str(s: &str) -> Result<Self, Self::Err> {
215        Ok(Self::with_initial(T::from_str(s)?))
216    }
217}