spectrum_analyzer/
limit.rs1use crate::NonNegF32;
27use core::error::Error;
28use core::fmt::{Display, Formatter};
29
30#[derive(Debug, Copy, Clone)]
39pub enum FrequencyLimit {
40 All,
43 Min(NonNegF32),
46 Max(NonNegF32),
49 Range(NonNegF32, NonNegF32),
54}
55
56impl FrequencyLimit {
57 #[inline]
62 #[must_use]
63 pub fn min(min: impl Into<NonNegF32>) -> Self {
64 Self::Min(min.into())
65 }
66
67 #[inline]
72 #[must_use]
73 pub fn max(max: impl Into<NonNegF32>) -> Self {
74 Self::Max(max.into())
75 }
76
77 #[inline]
82 #[must_use]
83 pub fn range(min: impl Into<NonNegF32>, max: impl Into<NonNegF32>) -> Self {
84 let min = min.into();
85 let max = max.into();
86 assert!(min <= max, "min should not be bigger than max");
87 Self::Range(min, max)
88 }
89
90 #[inline]
92 #[must_use]
93 pub const fn maybe_min(&self) -> Option<NonNegF32> {
94 match self {
95 Self::Min(min) => Some(*min),
96 Self::Range(min, _) => Some(*min),
97 _ => None,
98 }
99 }
100
101 #[inline]
103 #[must_use]
104 pub const fn maybe_max(&self) -> Option<NonNegF32> {
105 match self {
106 Self::Max(max) => Some(*max),
107 Self::Range(_, max) => Some(*max),
108 _ => None,
109 }
110 }
111
112 pub fn verify(&self, max_detectable_frequency: f32) -> Result<(), FrequencyLimitError> {
115 match self {
116 Self::All => Ok(()),
117 Self::Min(x) | Self::Max(x) => {
118 if *x > max_detectable_frequency {
119 Err(FrequencyLimitError::ValueAboveNyquist(*x))
120 } else {
121 Ok(())
122 }
123 }
124 Self::Range(min, max) => {
125 Self::Min(*min).verify(max_detectable_frequency)?;
126 Self::Max(*max).verify(max_detectable_frequency)?;
127 if min > max {
128 Err(FrequencyLimitError::InvalidRange(*min, *max))
129 } else {
130 Ok(())
131 }
132 }
133 }
134 }
135}
136
137#[derive(Debug)]
139pub enum FrequencyLimitError {
140 ValueAboveNyquist(NonNegF32),
143 InvalidRange(NonNegF32, NonNegF32),
147}
148
149impl Display for FrequencyLimitError {
150 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
151 match self {
152 Self::ValueAboveNyquist(x) => write!(f, "Value above Nyquist: {x}"),
153 Self::InvalidRange(min, max) => write!(f, "Invalid range: {min} <= x <= {max}"),
154 }
155 }
156}
157
158impl Error for FrequencyLimitError {}
159
160#[cfg(test)]
161mod tests {
162 use crate::limit::FrequencyLimitError;
163 use crate::{FrequencyLimit, NonNegF32};
164
165 #[test]
166 #[should_panic(expected = "value should be finite and not negative")]
167 fn test_construction_rejects_not_a_number() {
168 let _ = FrequencyLimit::min(f32::NAN);
169 }
170
171 #[test]
172 #[should_panic(expected = "value should be finite and not negative")]
173 fn test_construction_rejects_negative() {
174 let _ = FrequencyLimit::max(-1.0);
175 }
176
177 #[test]
178 fn test_min_above_nyquist() {
179 let _ = FrequencyLimit::min(1.0).verify(0.0).unwrap_err();
180 }
181
182 #[test]
183 fn test_max_above_nyquist() {
184 let _ = FrequencyLimit::max(1.0).verify(0.0).unwrap_err();
185 }
186
187 #[test]
188 fn test_range_above_nyquist() {
189 let _ = FrequencyLimit::range(0.0, 1.0).verify(0.0).unwrap_err();
190 }
191
192 #[test]
193 #[should_panic(expected = "min should not be bigger than max")]
194 fn test_range_rejects_wrong_order() {
195 let _ = FrequencyLimit::range(1.0, 0.0);
196 }
197
198 #[test]
199 fn test_range_allows_equal_bounds() {
200 let limit = FrequencyLimit::range(50.0, 50.0);
201
202 assert_eq!(50.0, limit.maybe_min().unwrap());
203 assert_eq!(50.0, limit.maybe_max().unwrap());
204 }
205
206 #[test]
209 fn test_verify_catches_a_wrong_range() {
210 let limit = FrequencyLimit::Range(NonNegF32::from(1.0), NonNegF32::from(0.0));
211
212 assert!(matches!(
213 limit.verify(1.0),
214 Err(FrequencyLimitError::InvalidRange(_, _))
215 ));
216 }
217
218 #[test]
219 fn test_constructors_fill_the_right_bound() {
220 let min = FrequencyLimit::min(50.0);
221 assert_eq!(50.0, min.maybe_min().unwrap());
222 assert_eq!(None, min.maybe_max());
223
224 let max = FrequencyLimit::max(70.0);
225 assert_eq!(None, max.maybe_min());
226 assert_eq!(70.0, max.maybe_max().unwrap());
227
228 let range = FrequencyLimit::range(50.0, 70.0);
229 assert_eq!(50.0, range.maybe_min().unwrap());
230 assert_eq!(70.0, range.maybe_max().unwrap());
231
232 assert_eq!(None, FrequencyLimit::All.maybe_min());
233 assert_eq!(None, FrequencyLimit::All.maybe_max());
234 }
235
236 #[test]
237 fn test_ok() {
238 FrequencyLimit::min(50.0).verify(100.0).unwrap();
239 FrequencyLimit::max(50.0).verify(100.0).unwrap();
240 FrequencyLimit::range(50.0, 50.0).verify(100.0).unwrap();
242 FrequencyLimit::range(50.0, 70.0).verify(100.0).unwrap();
243 }
244}