162 lines
3.6 KiB
Rust
162 lines
3.6 KiB
Rust
use crate::units::{Metric, MetricQuantity};
|
|
|
|
pub fn format(quantity: MetricQuantity) -> String {
|
|
let SiUnit(multiplier, unit) = si_unit(quantity);
|
|
let amount = quantity.amount / multiplier;
|
|
|
|
format!("{amount} {unit}")
|
|
}
|
|
|
|
#[derive(Debug, PartialEq)]
|
|
struct SiUnit(f64, &'static str);
|
|
|
|
fn si_unit(quantity: MetricQuantity) -> SiUnit {
|
|
let absolute = quantity.amount.abs();
|
|
|
|
match quantity.unit {
|
|
Metric::Metre => {
|
|
if absolute >= 1000.0 {
|
|
return SiUnit(1000.0, "km");
|
|
} else if absolute >= 1.0 {
|
|
return SiUnit(1.0, "m");
|
|
} else if absolute >= 0.01 {
|
|
return SiUnit(0.01, "cm");
|
|
} else {
|
|
return SiUnit(0.001, "mm");
|
|
}
|
|
}
|
|
Metric::Gram => {
|
|
if absolute >= 1000.0 {
|
|
return SiUnit(1000.0, "kg");
|
|
} else {
|
|
return SiUnit(1.0, "g");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod test {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn quantities() {
|
|
assert_eq!("0.1 mm", &format(MetricQuantity {
|
|
amount: 0.000_1,
|
|
unit: Metric::Metre,
|
|
}));
|
|
assert_eq!("-1 m", &format(MetricQuantity {
|
|
amount: -1.0,
|
|
unit: Metric::Metre,
|
|
}));
|
|
assert_eq!("1.5 m", &format(MetricQuantity {
|
|
amount: 1.5,
|
|
unit: Metric::Metre,
|
|
}));
|
|
assert_eq!("1000 km", &format(MetricQuantity {
|
|
amount: 1_000_000.0,
|
|
unit: Metric::Metre,
|
|
}));
|
|
|
|
assert_eq!("-5 g", &format(MetricQuantity {
|
|
amount: -5.0,
|
|
unit: Metric::Gram,
|
|
}));
|
|
assert_eq!("3.2 kg", &format(MetricQuantity {
|
|
amount: 3_200.0,
|
|
unit: Metric::Gram,
|
|
}));
|
|
}
|
|
|
|
#[test]
|
|
fn units() {
|
|
assert_eq!(SiUnit(0.001, "mm"), si_unit(MetricQuantity {
|
|
amount: 0.0001,
|
|
unit: Metric::Metre,
|
|
}));
|
|
assert_eq!(SiUnit(0.001, "mm"), si_unit(MetricQuantity {
|
|
amount: 0.001,
|
|
unit: Metric::Metre,
|
|
}));
|
|
assert_eq!(SiUnit(0.01, "cm"), si_unit(MetricQuantity {
|
|
amount: 0.01,
|
|
unit: Metric::Metre,
|
|
}));
|
|
assert_eq!(SiUnit(0.01, "cm"), si_unit(MetricQuantity {
|
|
amount: 0.1,
|
|
unit: Metric::Metre,
|
|
}));
|
|
assert_eq!(SiUnit(1.0, "m"), si_unit(MetricQuantity {
|
|
amount: 1.0,
|
|
unit: Metric::Metre,
|
|
}));
|
|
assert_eq!(SiUnit(1.0, "m"), si_unit(MetricQuantity {
|
|
amount: 10.0,
|
|
unit: Metric::Metre,
|
|
}));
|
|
assert_eq!(SiUnit(1.0, "m"), si_unit(MetricQuantity {
|
|
amount: 100.0,
|
|
unit: Metric::Metre,
|
|
}));
|
|
assert_eq!(SiUnit(1000.0, "km"), si_unit(MetricQuantity {
|
|
amount: 1000.0,
|
|
unit: Metric::Metre,
|
|
}));
|
|
assert_eq!(SiUnit(1000.0, "km"), si_unit(MetricQuantity {
|
|
amount: 10_000.0,
|
|
unit: Metric::Metre,
|
|
}));
|
|
|
|
assert_eq!(SiUnit(0.001, "mm"), si_unit(MetricQuantity {
|
|
amount: -0.001,
|
|
unit: Metric::Metre,
|
|
}));
|
|
assert_eq!(SiUnit(0.01, "cm"), si_unit(MetricQuantity {
|
|
amount: -0.01,
|
|
unit: Metric::Metre,
|
|
}));
|
|
assert_eq!(SiUnit(1.0, "m"), si_unit(MetricQuantity {
|
|
amount: -1.0,
|
|
unit: Metric::Metre,
|
|
}));
|
|
assert_eq!(SiUnit(1000.0, "km"), si_unit(MetricQuantity {
|
|
amount: -1000.0,
|
|
unit: Metric::Metre,
|
|
}));
|
|
|
|
assert_eq!(SiUnit(1.0, "g"), si_unit(MetricQuantity {
|
|
amount: 0.1,
|
|
unit: Metric::Gram,
|
|
}));
|
|
assert_eq!(SiUnit(1.0, "g"), si_unit(MetricQuantity {
|
|
amount: 1.0,
|
|
unit: Metric::Gram,
|
|
}));
|
|
assert_eq!(SiUnit(1.0, "g"), si_unit(MetricQuantity {
|
|
amount: 10.0,
|
|
unit: Metric::Gram,
|
|
}));
|
|
assert_eq!(SiUnit(1.0, "g"), si_unit(MetricQuantity {
|
|
amount: 100.0,
|
|
unit: Metric::Gram,
|
|
}));
|
|
assert_eq!(SiUnit(1000.0, "kg"), si_unit(MetricQuantity {
|
|
amount: 1000.0,
|
|
unit: Metric::Gram,
|
|
}));
|
|
assert_eq!(SiUnit(1000.0, "kg"), si_unit(MetricQuantity {
|
|
amount: 10_1000.0,
|
|
unit: Metric::Gram,
|
|
}));
|
|
|
|
assert_eq!(SiUnit(1.0, "g"), si_unit(MetricQuantity {
|
|
amount: -1.0,
|
|
unit: Metric::Gram,
|
|
}));
|
|
assert_eq!(SiUnit(1000.0, "kg"), si_unit(MetricQuantity {
|
|
amount: -1000.0,
|
|
unit: Metric::Gram,
|
|
}));
|
|
}
|
|
}
|