metrify/src/format.rs

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,
}));
}
}