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}