metrify/src/conversions.rs

161 lines
3.9 KiB
Rust

use crate::units::{Metric, MetricQuantity, NonMetric, NonMetricQuantity};
pub fn convert(from: NonMetricQuantity) -> MetricQuantity {
let conversion = get_conversion(from.unit);
let amount = (from.amount - conversion.offset) * conversion.to.amount / conversion.from;
let unit = conversion.to.unit;
MetricQuantity { amount, unit }
}
struct Conversion {
offset: f64,
from: f64,
to: MetricQuantity,
}
fn get_conversion(unit: NonMetric) -> Conversion {
let inch_from = 10_000.0;
let inch_to = 254.0;
let pound_from = 100_000.0;
let pound_to = 45359237.0;
match unit {
// Length
NonMetric::Inch => Conversion {
offset: 0.0,
from: inch_from,
to: MetricQuantity { amount: inch_to, unit: Metric::Metre },
},
NonMetric::Foot => Conversion {
offset: 0.0,
from: inch_from,
to: MetricQuantity { amount: 12.0 * inch_to, unit: Metric::Metre },
},
NonMetric::Yard => Conversion {
offset: 0.0,
from: inch_from,
to: MetricQuantity { amount: 3.0 * 12.0 * inch_to, unit: Metric::Metre },
},
NonMetric::Mile => Conversion {
offset: 0.0,
from: inch_from,
to: MetricQuantity { amount: 1760.0 * 3.0 * 12.0 * inch_to, unit: Metric::Metre },
},
// Weight
NonMetric::Ounce => Conversion {
offset: 0.0,
from: 16.0 * pound_from,
to: MetricQuantity { amount: pound_to, unit: Metric::Gram },
},
NonMetric::Pound => Conversion {
offset: 0.0,
from: pound_from,
to: MetricQuantity { amount: pound_to, unit: Metric::Gram },
},
NonMetric::Stone => Conversion {
offset: 0.0,
from: pound_from,
to: MetricQuantity { amount: 14.0 * pound_to, unit: Metric::Gram },
},
// Temperature
NonMetric::Fahrenheit => Conversion {
offset: 32.0,
from: 9.0,
to: MetricQuantity { amount: 5.0, unit: Metric::Celsius },
},
// Area
NonMetric::SquareInch => Conversion {
offset: 0.0,
from: inch_from * inch_from,
to: MetricQuantity { amount: inch_to * inch_to, unit: Metric::SquareMetre },
},
NonMetric::SquareFoot => Conversion {
offset: 0.0,
from: inch_from * inch_from,
to: MetricQuantity { amount: 12.0 * inch_to * 12.0 * inch_to, unit: Metric::SquareMetre },
},
NonMetric::Acre => Conversion {
offset: 0.0,
from: inch_from * inch_from,
to: MetricQuantity { amount: 43_560.0 * 12.0 * inch_to * 12.0 * inch_to, unit: Metric::SquareMetre },
},
NonMetric::SquareMile => Conversion {
offset: 0.0,
from: inch_from * inch_from,
to: MetricQuantity { amount: 1760.0 * 3.0 * 12.0 * inch_to * 1760.0 * 3.0 * 12.0 * inch_to, unit: Metric::SquareMetre },
},
}
}
#[cfg(test)]
mod test {
use super::*;
struct Test(NonMetric, f64);
#[test]
fn length() {
let tests = [
Test(NonMetric::Inch, 0.0254),
Test(NonMetric::Foot, 0.3048),
Test(NonMetric::Yard, 0.9144),
Test(NonMetric::Mile, 1609.344),
];
run_tests(&tests, Metric::Metre);
}
#[test]
fn weight() {
let tests = [
Test(NonMetric::Ounce, 28.349523125),
Test(NonMetric::Pound, 453.59237),
Test(NonMetric::Stone, 6350.29318),
];
run_tests(&tests, Metric::Gram);
}
#[test]
fn temperature() {
assert_eq!(convert(NonMetricQuantity {
amount: -40.0,
unit: NonMetric::Fahrenheit,
}), MetricQuantity {
amount: -40.0,
unit: Metric::Celsius,
});
assert_eq!(convert(NonMetricQuantity {
amount: 32.0,
unit: NonMetric::Fahrenheit,
}), MetricQuantity {
amount: 0.0,
unit: Metric::Celsius,
});
}
#[test]
fn area() {
let tests = [
Test(NonMetric::SquareInch, 0.00064516),
Test(NonMetric::SquareFoot, 0.09290304),
Test(NonMetric::Acre, 4046.8564224),
Test(NonMetric::SquareMile, 2589988.110336),
];
run_tests(&tests, Metric::SquareMetre);
}
fn run_tests(tests: &[Test], unit: Metric) {
for test in tests {
let from = NonMetricQuantity {
amount: 1.0,
unit: test.0,
};
let to = MetricQuantity {
amount: test.1,
unit: unit,
};
assert_eq!(convert(from), to);
}
}
}