quantities/
rate.rs

1// ---------------------------------------------------------------------------
2// Copyright:   (c) 2022 ff. Michael Amrhein (michael@adrhinum.de)
3// License:     This program is part of a larger application. For license
4//              details please read the file LICENSE.TXT provided together
5//              with the application.
6// ---------------------------------------------------------------------------
7// $Source:     src/rate.rs $
8// $Revision:   2022-07-07T15:40:07+02:00 $
9
10use core::{
11    fmt,
12    ops::{Div, Mul},
13};
14
15use crate::{AmountT, Quantity, Unit, AMNT_ONE};
16
17/// The ratio between two related quantity values.
18#[derive(Copy, Clone, Debug)]
19pub struct Rate<TQ: Quantity, PQ: Quantity> {
20    term_amount: AmountT,
21    term_unit: TQ::UnitType,
22    per_unit_multiple: AmountT,
23    per_unit: PQ::UnitType,
24}
25
26impl<TQ: Quantity, PQ: Quantity> Rate<TQ, PQ> {
27    /// Returns a new instance of `Rate` with attributes equal to given params.
28    #[inline(always)]
29    pub const fn new(
30        term_amount: AmountT,
31        term_unit: TQ::UnitType,
32        per_unit_multiple: AmountT,
33        per_unit: PQ::UnitType,
34    ) -> Self {
35        Self {
36            term_amount,
37            term_unit,
38            per_unit_multiple,
39            per_unit,
40        }
41    }
42
43    /// Returns a new instance of `Rate` with attributes extracted from the
44    /// given quantity values.
45    #[inline(always)]
46    pub fn from_qty_vals(term: TQ, per: PQ) -> Self {
47        Self {
48            term_amount: term.amount(),
49            term_unit: term.unit(),
50            per_unit_multiple: per.amount(),
51            per_unit: per.unit(),
52        }
53    }
54
55    /// Returns the term amount of `self`.
56    #[inline(always)]
57    pub const fn term_amount(&self) -> AmountT {
58        self.term_amount
59    }
60
61    /// Returns the term unit of `self`.
62    #[inline(always)]
63    pub const fn term_unit(&self) -> TQ::UnitType {
64        self.term_unit
65    }
66
67    /// Returns the per unit multiple of `self`.
68    #[inline(always)]
69    pub const fn per_unit_multiple(&self) -> AmountT {
70        self.per_unit_multiple
71    }
72
73    /// Returns the per unit of `self`.
74    #[inline(always)]
75    pub const fn per_unit(&self) -> PQ::UnitType {
76        self.per_unit
77    }
78
79    /// Returns the multiplicative inverse of `self`
80    pub const fn reciprocal(&self) -> Rate<PQ, TQ> {
81        Rate::<PQ, TQ>::new(
82            self.per_unit_multiple(),
83            self.per_unit(),
84            self.term_amount(),
85            self.term_unit(),
86        )
87    }
88}
89
90impl<TQ: Quantity, PQ: Quantity> fmt::Display for Rate<TQ, PQ> {
91    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
92        if self.term_unit().symbol() == "" {
93            write!(f, "{} / ", self.term_amount())?;
94        } else {
95            write!(
96                f,
97                "{} {} / ",
98                self.term_amount(),
99                self.term_unit().symbol()
100            )?;
101        };
102        if self.per_unit().symbol() == "" {
103            write!(f, "{}", self.per_unit_multiple())
104        } else if self.per_unit_multiple() == AMNT_ONE {
105            write!(f, "{}", self.per_unit().symbol())
106        } else {
107            write!(
108                f,
109                "{} {}",
110                self.per_unit_multiple(),
111                self.per_unit().symbol()
112            )
113        }
114    }
115}
116
117impl<TQ: Quantity, PQ: Quantity> Mul<PQ> for Rate<TQ, PQ>
118where
119    PQ: Div<PQ, Output = AmountT>,
120{
121    type Output = TQ;
122
123    fn mul(self, rhs: PQ) -> Self::Output {
124        let amnt: AmountT =
125            (rhs / self.per_unit().as_qty()) / self.per_unit_multiple();
126        Self::Output::new(amnt * self.term_amount(), self.term_unit())
127    }
128}