Skip to main content

mag/time/
timepriv.rs

1// timepriv.rs
2//
3// Copyright (C) 2019-2021  Minnesota Department of Transportation
4// Copyright (C) 2019-2022  Douglas P Lau
5//
6//! Private module for time structs
7//!
8extern crate alloc;
9
10use crate::{Length, Speed, length, time::Unit};
11use core::fmt;
12use core::marker::PhantomData;
13use core::ops::{Add, Div, Mul, Sub};
14
15/// _Period_, _duration_ or _interval_ of time.
16///
17/// Period is a base quantity with a specific [unit].
18///
19/// ## Operations
20///
21/// * f64 `*` [unit] `=>` Period
22/// * i32 `*` [unit] `=>` Period
23/// * Period `+` Period `=>` Period
24/// * Period `-` Period `=>` Period
25/// * Period `*` f64 `=>` Period
26/// * f64 `*` Period `=>` Period
27/// * f64 `/` Period `=>` [Frequency]
28///
29/// Units must be the same for operations with two Period operands.  The [to]
30/// method can be used for conversion.
31///
32/// ```rust
33/// use mag::time::{min, s};
34///
35/// let a = 15 * min;
36/// let b = 90.0 * s;
37///
38/// assert_eq!(a.to_string(), "15 min");
39/// assert_eq!((a + b.to()).to_string(), "16.5 min");
40/// ```
41/// [Frequency]: struct.Frequency.html
42/// [unit]: time/index.html
43/// [to]: struct.Period.html#method.to
44///
45#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
46pub struct Period<U>
47where
48    U: Unit,
49{
50    /// Period quantity
51    pub quantity: f64,
52
53    /// Measurement unit
54    unit: PhantomData<U>,
55}
56
57/// Temporal _frequency_, or _rate_ over time.
58///
59/// Frequency is a derived quantity with a specific [unit].
60///
61/// ## Operations
62///
63/// * f64 `/` [unit] `=>` Frequency
64/// * i32 `/` [unit] `=>` Frequency
65/// * Frequency `+` Frequency `=>` Frequency
66/// * Frequency `-` Frequency `=>` Frequency
67/// * Frequency `*` f64 `=>` Frequency
68/// * f64 `*` Frequency `=>` Frequency
69/// * f64 `/` [Period] `=>` Frequency
70/// * f64 `/` Frequency `=>` [Period]
71///
72/// Units must be the same for operations with two Frequency operands.  The
73/// [to] method can be used for conversion.
74///
75/// ```rust
76/// use mag::time::{ns, s};
77///
78/// let a = 25.0 / s;
79/// let b = 500.0 / ns;
80///
81/// assert_eq!(a.to_string(), "25 ㎐");
82/// assert_eq!(b.to_string(), "500 ㎓");
83/// ```
84/// [Period]: struct.Period.html
85/// [unit]: time/index.html
86/// [to]: struct.Frequency.html#method.to
87///
88#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
89pub struct Frequency<U>
90where
91    U: Unit,
92{
93    /// Frequency quantity
94    pub quantity: f64,
95
96    /// Measurement unit
97    unit: PhantomData<U>,
98}
99
100impl_base_ops!(Period, Unit);
101impl_base_ops!(Frequency, Unit);
102
103impl<U> fmt::Display for Period<U>
104where
105    U: Unit,
106{
107    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
108        self.quantity.fmt(f)?;
109        write!(f, " {}", U::LABEL)
110    }
111}
112
113impl<U> fmt::Display for Frequency<U>
114where
115    U: Unit,
116{
117    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
118        self.quantity.fmt(f)?;
119        write!(f, " {}", U::INVERSE)
120    }
121}
122
123impl<U> Period<U>
124where
125    U: Unit,
126{
127    /// Create a new period quantity
128    pub fn new(quantity: f64) -> Self {
129        Period::<U> {
130            quantity,
131            unit: PhantomData,
132        }
133    }
134
135    /// Convert to specified units
136    pub fn to<T: Unit>(self) -> Period<T> {
137        let quantity = self.quantity * U::factor::<T>();
138        Period::new(quantity)
139    }
140}
141
142// f64 / Period => Frequency
143impl<U> Div<Period<U>> for f64
144where
145    U: Unit,
146{
147    type Output = Frequency<U>;
148    fn div(self, other: Period<U>) -> Self::Output {
149        Self::Output::new(self / other.quantity)
150    }
151}
152
153// Length / Period => Speed
154impl<L, T> Div<Period<T>> for Length<L>
155where
156    L: length::Unit,
157    T: Unit,
158{
159    type Output = Speed<L, T>;
160    fn div(self, per: Period<T>) -> Self::Output {
161        Speed::new(self.quantity / per.quantity)
162    }
163}
164
165impl<U> Frequency<U>
166where
167    U: Unit,
168{
169    /// Create a new frequency quantity
170    pub fn new(quantity: f64) -> Self {
171        Frequency::<U> {
172            quantity,
173            unit: PhantomData,
174        }
175    }
176
177    /// Convert to specified units
178    pub fn to<T: Unit>(self) -> Frequency<T> {
179        let quantity = self.quantity / U::factor::<T>();
180        Frequency::new(quantity)
181    }
182}
183
184// f64 / Frequency => Period
185impl<U> Div<Frequency<U>> for f64
186where
187    U: Unit,
188{
189    type Output = Period<U>;
190    fn div(self, other: Frequency<U>) -> Self::Output {
191        Self::Output::new(self / other.quantity)
192    }
193}
194
195// Frequency * Length => Speed
196impl<L, T> Mul<Length<L>> for Frequency<T>
197where
198    L: length::Unit,
199    T: Unit,
200{
201    type Output = Speed<L, T>;
202    fn mul(self, len: Length<L>) -> Self::Output {
203        Speed::new(self.quantity * len.quantity)
204    }
205}
206
207// Length * Frequency => Speed
208impl<L, T> Mul<Frequency<T>> for Length<L>
209where
210    L: length::Unit,
211    T: Unit,
212{
213    type Output = Speed<L, T>;
214    fn mul(self, freq: Frequency<T>) -> Self::Output {
215        Speed::new(self.quantity * freq.quantity)
216    }
217}