1use crate::error::CoreError;
13use serde::{Deserialize, Serialize};
14use std::{fmt::Display, ops::Range, str::FromStr};
15use uom::{
16 fmt::DisplayStyle,
17 si::{
18 f64::{Frequency as BaseFrequency, Length as BaseLength},
19 frequency as frequency_unit, length as length_unit,
20 },
21};
22
23#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd, Deserialize, Serialize)]
32pub struct Frequency(BaseFrequency);
33
34#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd, Deserialize, Serialize)]
35pub struct Wavelength(BaseLength);
36
37pub const SPEED_OF_LIGHT: f64 = 299792458.0; #[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
40pub struct FrequencyRange(Range<Frequency>);
41
42pub fn gigahertz(value: f64) -> Frequency {
47 Frequency(BaseFrequency::new::<frequency_unit::gigahertz>(value))
48}
49pub fn megahertz(value: f64) -> Frequency {
50 Frequency(BaseFrequency::new::<frequency_unit::megahertz>(value))
51}
52pub fn kilohertz(value: f64) -> Frequency {
53 Frequency(BaseFrequency::new::<frequency_unit::kilohertz>(value))
54}
55pub fn hertz(value: f64) -> Frequency {
56 Frequency(BaseFrequency::new::<frequency_unit::hertz>(value))
57}
58
59pub fn millimeters(value: f64) -> Wavelength {
60 Wavelength(BaseLength::new::<length_unit::millimeter>(value))
61}
62
63pub fn centimeters(value: f64) -> Wavelength {
64 Wavelength(BaseLength::new::<length_unit::centimeter>(value))
65}
66
67pub fn meters(value: f64) -> Wavelength {
68 Wavelength(BaseLength::new::<length_unit::meter>(value))
69}
70
71pub fn kilometers(value: f64) -> Wavelength {
72 Wavelength(BaseLength::new::<length_unit::kilometer>(value))
73}
74
75impl Display for Frequency {
88 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
89 if f.alternate() {
90 match self.value() {
91 0.0..1_000.0 => self
92 .0
93 .into_format_args(frequency_unit::hertz, DisplayStyle::Description)
94 .fmt(f),
95 1_000.0..1_000_000.0 => self
96 .0
97 .into_format_args(frequency_unit::kilohertz, DisplayStyle::Description)
98 .fmt(f),
99 1_000_000.0..1_000_000_000.0 => self
100 .0
101 .into_format_args(frequency_unit::megahertz, DisplayStyle::Description)
102 .fmt(f),
103 1_000_000_000.0..1_000_000_000_000.0 => self
104 .0
105 .into_format_args(frequency_unit::gigahertz, DisplayStyle::Description)
106 .fmt(f),
107 _ => self
108 .0
109 .into_format_args(frequency_unit::terahertz, DisplayStyle::Description)
110 .fmt(f),
111 }
112 } else {
113 self.0
114 .into_format_args(frequency_unit::megahertz, DisplayStyle::Abbreviation)
115 .fmt(f)
116 }
117 }
118}
119
120impl FromStr for Frequency {
121 type Err = CoreError;
122
123 fn from_str(s: &str) -> Result<Self, Self::Err> {
124 BaseFrequency::from_str(s)
125 .map(Self)
126 .map_err(|_| CoreError::InvalidValueFromStr(s.to_string(), "Frequency"))
127 }
128}
129
130impl From<BaseFrequency> for Frequency {
131 fn from(value: BaseFrequency) -> Self {
132 Self(value)
133 }
134}
135
136impl From<f64> for Frequency {
137 fn from(value: f64) -> Self {
138 megahertz(value)
139 }
140}
141
142impl From<Frequency> for BaseFrequency {
143 fn from(value: Frequency) -> Self {
144 value.0
145 }
146}
147
148impl From<Frequency> for f64 {
149 fn from(value: Frequency) -> Self {
150 value.0.value
151 }
152}
153
154impl AsRef<BaseFrequency> for Frequency {
155 fn as_ref(&self) -> &BaseFrequency {
156 &self.0
157 }
158}
159
160impl Frequency {
161 pub fn value(&self) -> f64 {
162 self.0.value
163 }
164
165 pub fn to_wavelength(&self) -> Wavelength {
166 meters(SPEED_OF_LIGHT / self.value())
167 }
168}
169
170impl Display for FrequencyRange {
175 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
176 self.0.start.fmt(f)?;
177 write!(f, " {} ", if f.alternate() { "to" } else { "-" },)?;
178 self.0.end.fmt(f)
179 }
180}
181
182impl From<Range<Frequency>> for FrequencyRange {
183 fn from(range: Range<Frequency>) -> Self {
184 Self(range)
185 }
186}
187
188impl From<Range<f64>> for FrequencyRange {
189 fn from(range: Range<f64>) -> Self {
190 Self::new(megahertz(range.start), megahertz(range.end))
191 }
192}
193
194impl From<(Frequency, Frequency)> for FrequencyRange {
195 fn from(range: (Frequency, Frequency)) -> Self {
196 Self::new(range.0, range.1)
197 }
198}
199
200impl From<(f64, f64)> for FrequencyRange {
201 fn from(range: (f64, f64)) -> Self {
202 Self::new(megahertz(range.0), megahertz(range.1))
203 }
204}
205
206impl From<FrequencyRange> for Range<Frequency> {
207 fn from(range: FrequencyRange) -> Self {
208 range.0
209 }
210}
211
212impl From<FrequencyRange> for Range<f64> {
213 fn from(range: FrequencyRange) -> Self {
214 Range {
215 start: range.0.start.value(),
216 end: range.0.end.value(),
217 }
218 }
219}
220
221impl FrequencyRange {
222 pub fn new(start: Frequency, end: Frequency) -> Self {
223 assert!(start <= end);
224 Self(Range { start, end })
225 }
226 pub fn new_mhz(start: f64, end: f64) -> Self {
227 Self::new(megahertz(start), megahertz(end))
228 }
229
230 pub const fn start(&self) -> Frequency {
231 self.0.start
232 }
233
234 pub const fn end(&self) -> Frequency {
235 self.0.end
236 }
237
238 pub fn mid_band(&self) -> Frequency {
239 hertz(self.0.start.value() + ((self.0.end.value() - self.0.start.value()) / 2.0))
240 }
241
242 pub fn contains(&self, frequency: Frequency) -> bool {
243 self.0.contains(&frequency)
244 }
245
246 pub fn contains_mhz(&self, frequency: f64) -> bool {
247 self.0.contains(&megahertz(frequency))
248 }
249
250 pub fn is_empty(&self) -> bool {
251 self.0.is_empty()
252 }
253
254 pub fn starts_before(&self, other: &Self) -> bool {
255 self.start() < other.start()
256 }
257
258 pub fn starts_with(&self, other: &Self) -> bool {
259 self.start() == other.start() && self.contains(other.end())
260 }
261
262 pub fn ends_before(&self, other: &Self) -> bool {
263 self.end() < other.end()
264 }
265
266 pub fn ends_with(&self, other: &Self) -> bool {
267 self.contains(other.start()) && self.end() == other.end()
268 }
269
270 pub fn is_subrange(&self, other: &Self) -> bool {
271 self.start() <= other.start() && self.end() >= other.end()
272 }
273
274 pub fn is_overlapping(&self, other: &Self) -> bool {
275 self.contains(other.start()) || self.contains(other.end())
276 }
277}
278
279impl Display for Wavelength {
284 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
285 if f.alternate() {
286 match self.value() {
287 0.001..0.01 => self
288 .0
289 .into_format_args(length_unit::millimeter, DisplayStyle::Description)
290 .fmt(f),
291 0.01..1.0 => self
292 .0
293 .into_format_args(length_unit::centimeter, DisplayStyle::Description)
294 .fmt(f),
295 1_000.0.. => self
296 .0
297 .into_format_args(length_unit::kilometer, DisplayStyle::Description)
298 .fmt(f),
299 _ => self
300 .0
301 .into_format_args(length_unit::meter, DisplayStyle::Description)
302 .fmt(f),
303 }
304 } else {
305 self.0
306 .into_format_args(length_unit::meter, DisplayStyle::Abbreviation)
307 .fmt(f)
308 }
309 }
310}
311
312impl FromStr for Wavelength {
313 type Err = CoreError;
314
315 fn from_str(s: &str) -> Result<Self, Self::Err> {
316 BaseLength::from_str(s)
317 .map(Self)
318 .map_err(|_| CoreError::InvalidValueFromStr(s.to_string(), "Wavelength"))
319 }
320}
321
322impl From<BaseLength> for Wavelength {
323 fn from(value: BaseLength) -> Self {
324 Self(value)
325 }
326}
327
328impl From<f64> for Wavelength {
329 fn from(value: f64) -> Self {
330 meters(value)
331 }
332}
333
334impl From<Wavelength> for BaseLength {
335 fn from(value: Wavelength) -> Self {
336 value.0
337 }
338}
339
340impl From<Wavelength> for f64 {
341 fn from(value: Wavelength) -> Self {
342 value.0.value
343 }
344}
345
346impl AsRef<BaseLength> for Wavelength {
347 fn as_ref(&self) -> &BaseLength {
348 &self.0
349 }
350}
351
352impl Wavelength {
353 pub fn value(&self) -> f64 {
354 self.0.value
355 }
356
357 pub fn to_frequency(&self) -> Frequency {
358 megahertz(SPEED_OF_LIGHT / self.value())
359 }
360}
361
362#[cfg(test)]
375mod tests {
376 use super::FrequencyRange;
377 use pretty_assertions::assert_eq;
378
379 #[test]
380 fn test_default_fmt_frequency() {
381 assert_eq!("0.000001 MHz", &super::hertz(1.0).to_string());
382 assert_eq!("0.001 MHz", &super::kilohertz(1.0).to_string());
383 assert_eq!("1 MHz", &super::megahertz(1.0).to_string());
384 assert_eq!("1000 MHz", &super::gigahertz(1.0).to_string());
385 }
386
387 #[test]
388 fn test_default_fmt_frequency_precision() {
389 assert_eq!("0.000001 MHz", &format!("{:.6}", super::hertz(1.0)));
390 assert_eq!("0.001000 MHz", &format!("{:.6}", super::kilohertz(1.0)));
391 assert_eq!("1.000000 MHz", &format!("{:.6}", super::megahertz(1.0)));
392 assert_eq!("1000.000000 MHz", &format!("{:.6}", super::gigahertz(1.0)));
393 }
394
395 #[test]
396 fn test_default_fmt_frequency_width_and_precision() {
397 assert_eq!(
398 " 0.000001 MHz",
399 &format!("{:>14.6}", super::hertz(1.0))
400 );
401 assert_eq!(
402 " 0.001000 MHz",
403 &format!("{:>14.6}", super::kilohertz(1.0))
404 );
405 assert_eq!(
406 " 1.000000 MHz",
407 &format!("{:>14.6}", super::megahertz(1.0))
408 );
409 assert_eq!(
410 " 1000.000000 MHz",
411 &format!("{:>14.6}", super::gigahertz(1.0))
412 );
413 }
414
415 #[test]
416 fn test_alternate_fmt_frequency() {
417 assert_eq!("1 hertz", &format!("{:#}", super::hertz(1.0)));
418 assert_eq!("1 kilohertz", &format!("{:#}", super::kilohertz(1.0)));
419 assert_eq!("1 megahertz", &format!("{:#}", super::megahertz(1.0)));
420 assert_eq!("1 gigahertz", &format!("{:#}", super::gigahertz(1.0)));
421 }
422
423 #[test]
424 fn test_default_fmt_range() {
425 assert_eq!(
426 "0.000001 MHz - 0.00001 MHz",
427 &FrequencyRange::new(super::hertz(1.0), super::hertz(10.0)).to_string()
428 );
429 assert_eq!(
430 "0.001 MHz - 0.01 MHz",
431 &FrequencyRange::new(super::kilohertz(1.0), super::kilohertz(10.0)).to_string()
432 );
433 assert_eq!(
434 "1 MHz - 10 MHz",
435 &FrequencyRange::new(super::megahertz(1.0), super::megahertz(10.0)).to_string()
436 );
437 assert_eq!(
438 "1000 MHz - 10000 MHz",
439 &FrequencyRange::new(super::gigahertz(1.0), super::gigahertz(10.0)).to_string()
440 );
441 }
442}