eng_units/units/
mass_unit.rs

1// eng-units - engineering unit conversion and calculation library
2// Copyright (C) 2023 Frank Pereny
3
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with this program.  If not, see <https://www.gnu.org/licenses/>.
16
17use crate::units::AmountOfSubstanceUnit;
18use crate::units::ElectricCurrentUnit;
19use crate::units::IsEngUnitType;
20use crate::units::LengthUnit;
21use crate::units::LuminousIntensityUnit;
22use crate::units::TemperatureDeltaUnit;
23use crate::units::TimeUnit;
24
25/// Create new unit of mass
26#[macro_export]
27macro_rules! mass {
28    ($value:literal, $unit:expr) => {{
29        let mut unit = EngUnit::new();
30        unit.value = $value;
31        unit.mass_count = 1;
32        if $unit == MassUnit::None {
33            unit.mass_count = 0;
34        }
35        unit.mass_unit = $unit;
36        unit
37    }};
38}
39
40#[macro_export]
41macro_rules! mass_kg {
42    ($value:expr) => {{
43        let mut unit = EngUnit::new();
44        unit.value = $value;
45        unit.mass_count = 1;
46        unit.mass_unit = MassUnit::Kilogram;
47        unit
48    }};
49}
50
51#[macro_export]
52macro_rules! mass_lb {
53    ($value:expr) => {{
54        let mut unit = EngUnit::new();
55        unit.value = $value;
56        unit.mass_count = 1;
57        unit.mass_unit = MassUnit::Pound;
58        unit
59    }};
60}
61
62#[derive(Copy, Clone, Debug, PartialEq)]
63pub enum MassUnit {
64    Kilogram,
65    Pound,
66    None,
67}
68
69impl<
70        T: IsEngUnitType
71            + Into<AmountOfSubstanceUnit>
72            + Into<ElectricCurrentUnit>
73            + Into<LengthUnit>
74            + Into<LuminousIntensityUnit>
75            + Into<MassUnit>
76            + Into<TemperatureDeltaUnit>
77            + Into<TimeUnit>,
78    > From<&T> for MassUnit
79{
80    fn from(value: &T) -> Self {
81        if T::is_amount_unit() {
82            value.into()
83        } else {
84            Self::None
85        }
86    }
87}
88impl IsEngUnitType for MassUnit {
89    fn is_mass_unit() -> bool {
90        true
91    }
92}
93impl From<AmountOfSubstanceUnit> for MassUnit {
94    fn from(_: AmountOfSubstanceUnit) -> Self {
95        MassUnit::None
96    }
97}
98impl From<ElectricCurrentUnit> for MassUnit {
99    fn from(_: ElectricCurrentUnit) -> Self {
100        MassUnit::None
101    }
102}
103impl From<LengthUnit> for MassUnit {
104    fn from(_: LengthUnit) -> Self {
105        MassUnit::None
106    }
107}
108impl From<LuminousIntensityUnit> for MassUnit {
109    fn from(_: LuminousIntensityUnit) -> Self {
110        MassUnit::None
111    }
112}
113impl From<TemperatureDeltaUnit> for MassUnit {
114    fn from(_: TemperatureDeltaUnit) -> Self {
115        MassUnit::None
116    }
117}
118impl From<TimeUnit> for MassUnit {
119    fn from(_: TimeUnit) -> Self {
120        MassUnit::None
121    }
122}
123
124pub const KILOGRAM_TO_POUND: f64 = 2.204_622_62;
125
126impl MassUnit {
127    pub fn to_string(&self) -> &'static str {
128        match self {
129            MassUnit::Kilogram => "kg",
130            MassUnit::Pound => "lb",
131            MassUnit::None => "",
132        }
133    }
134
135    pub fn conversion_factor(from: &MassUnit, to: &MassUnit) -> f64 {
136        match from {
137            MassUnit::Kilogram => match to {
138                MassUnit::Kilogram => 1.0,
139                MassUnit::Pound => KILOGRAM_TO_POUND,
140                MassUnit::None => 1.0,
141            },
142            MassUnit::Pound => match to {
143                MassUnit::Pound => 1.0,
144                MassUnit::Kilogram => 1.0 / KILOGRAM_TO_POUND,
145                MassUnit::None => 1.0,
146            },
147            MassUnit::None => 1.0,
148        }
149    }
150}
151
152#[cfg(test)]
153mod tests {
154    use crate::units::amount_of_substance_unit::AmountOfSubstanceUnit;
155    use crate::units::electric_current_unit::ElectricCurrentUnit;
156    use crate::units::length_unit::LengthUnit;
157    use crate::units::luminous_intensity_unit::LuminousIntensityUnit;
158    use crate::units::mass_unit::MassUnit;
159    use crate::units::temperature_unit::TemperatureDeltaUnit;
160    use crate::units::time_unit::TimeUnit;
161    use crate::units::EngUnit;
162
163    #[test]
164    fn test_new() {
165        let unit = mass!(123.45, MassUnit::Kilogram);
166        assert_eq!(123.45, unit.value);
167        assert_eq!("123.45 kg", unit.to_string());
168        assert_eq!(TimeUnit::None, unit.time_unit);
169        assert_eq!(AmountOfSubstanceUnit::None, unit.amount_of_substance_unit);
170        assert_eq!(ElectricCurrentUnit::None, unit.electric_current_unit);
171        assert_eq!(LengthUnit::None, unit.length_unit);
172        assert_eq!(LuminousIntensityUnit::None, unit.luminous_intensity_unit);
173        assert_eq!(MassUnit::Kilogram, unit.mass_unit);
174        assert_eq!(TemperatureDeltaUnit::None, unit.temperature_unit);
175        assert_eq!(TimeUnit::None, unit.time_unit);
176        assert_eq!(0, unit.temperature_count);
177        assert_eq!(0, unit.time_count);
178        assert_eq!(0, unit.length_count);
179        assert_eq!(1, unit.mass_count);
180        assert_eq!(0, unit.luminous_intensity_count);
181        assert_eq!(0, unit.amount_of_substance_count);
182        assert_eq!(0, unit.electric_current_count);
183    }
184
185    #[test]
186    fn test_value() {
187        let m1 = mass!(123.45, MassUnit::Kilogram);
188        assert_eq!(123.45, m1.value);
189    }
190
191    #[test]
192    fn test_kg_to_str() {
193        let m1 = mass!(1.0, MassUnit::Kilogram);
194        assert_eq!("1.00 kg", m1.to_string());
195    }
196
197    #[test]
198    fn test_lb_to_str() {
199        let m1 = mass!(1.0, MassUnit::Pound);
200        assert_eq!("1.00 lb", m1.to_string());
201    }
202
203    #[test]
204    fn test_none_to_str() {
205        let m1 = mass!(1.0, MassUnit::None);
206        assert_eq!("1.00", m1.to_string());
207    }
208
209    #[test]
210    fn test_latex() {
211        let m1 = mass!(1.0, MassUnit::Kilogram);
212        assert_eq!("$1\\ kg$", m1.to_latex())
213    }
214
215    #[test]
216    fn test_unit_to_str_kg() {
217        let m1 = mass!(1.0, MassUnit::Kilogram);
218        assert_eq!("kg", m1.unit_to_string());
219    }
220
221    #[test]
222    fn test_unit_to_str_lb() {
223        let m1 = mass!(1.0, MassUnit::Pound);
224        assert_eq!("lb", m1.unit_to_string());
225    }
226
227    #[test]
228    fn test_unit_to_str_none() {
229        let m1 = mass!(1.0, MassUnit::None);
230        assert_eq!("", m1.unit_to_string());
231        assert_eq!("", MassUnit::to_string(&MassUnit::None));
232    }
233
234    #[test]
235    fn test_conversion_kg_lb() {
236        let m1 = mass!(1.0, MassUnit::Kilogram);
237        let m2 = m1.convert(MassUnit::Pound);
238        assert_eq!(1.0, m1.value);
239        assert_eq!(2.204_622_62, m2.value);
240        assert_eq!(MassUnit::Kilogram, m1.mass_unit);
241        assert_eq!(MassUnit::Pound, m2.mass_unit);
242        assert_eq!("1.00 kg", m1.to_string());
243        assert_eq!("2.20 lb", m2.to_string());
244    }
245
246    #[test]
247    fn test_conversion_lb_kg() {
248        let m1 = mass!(1.0, MassUnit::Pound);
249        let m2 = m1.convert(MassUnit::Kilogram);
250        assert_eq!(1.0, m1.value);
251        let expected = 0.45359237;
252        assert!(f64::abs(expected - m2.value) < 0.00001);
253        assert_eq!(MassUnit::Pound, m1.mass_unit);
254        assert_eq!(MassUnit::Kilogram, m2.mass_unit);
255        assert_eq!("1.00 lb", m1.to_string());
256        assert_eq!("0.45 kg", m2.to_string());
257    }
258}