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::Celcius }, }, // 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 }, }, } } #[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::Celcius, }); assert_eq!(convert(NonMetricQuantity { amount: 32.0, unit: NonMetric::Fahrenheit, }), MetricQuantity { amount: 0.0, unit: Metric::Celcius, }); } #[test] fn area() { let tests = [ Test(NonMetric::SquareInch, 0.00064516), Test(NonMetric::SquareFoot, 0.09290304), ]; 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); } } }