metrify/src/conversions.rs

285 lines
8.0 KiB
Rust
Raw Normal View History

2023-05-13 14:50:18 +00:00
use crate::units::{Metric, MetricQuantity, NonMetric, NonMetricQuantity};
pub fn convert(from: NonMetricQuantity) -> MetricQuantity {
let conversion = get_conversion(from.unit);
2023-05-28 17:32:31 +00:00
let amount = (from.amount - conversion.offset) * conversion.to.amount / conversion.from;
let unit = conversion.to.unit;
MetricQuantity { amount, unit }
}
2023-05-13 14:50:18 +00:00
struct Conversion {
2023-05-28 17:32:31 +00:00
offset: f64,
2023-05-13 14:50:18 +00:00
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;
2023-05-30 17:01:35 +00:00
let imperial_gallon_from = 100_000.0;
let imperial_gallon_to = 454609.0;
2023-05-31 14:35:19 +00:00
let us_gallon_from = inch_from * inch_from * inch_from;
let us_gallon_to = 231.0 * inch_to * inch_to * inch_to * 1000.0;
2023-05-13 14:50:18 +00:00
match unit {
// Length
NonMetric::Inch => Conversion {
2023-05-28 17:32:31 +00:00
offset: 0.0,
from: inch_from,
to: MetricQuantity { amount: inch_to, unit: Metric::Metre },
2023-05-13 14:50:18 +00:00
},
2023-05-13 23:18:27 +00:00
NonMetric::Foot => Conversion {
2023-05-28 17:32:31 +00:00
offset: 0.0,
2023-05-13 23:18:27 +00:00
from: inch_from,
to: MetricQuantity { amount: 12.0 * inch_to, unit: Metric::Metre },
},
2023-05-13 14:50:18 +00:00
NonMetric::Yard => Conversion {
2023-05-28 17:32:31 +00:00
offset: 0.0,
from: inch_from,
to: MetricQuantity { amount: 3.0 * 12.0 * inch_to, unit: Metric::Metre },
2023-05-13 14:50:18 +00:00
},
NonMetric::Mile => Conversion {
2023-05-28 17:32:31 +00:00
offset: 0.0,
from: inch_from,
to: MetricQuantity { amount: 1760.0 * 3.0 * 12.0 * inch_to, unit: Metric::Metre },
2023-05-13 14:50:18 +00:00
},
2023-06-01 00:00:10 +00:00
// Mass
2023-05-13 14:50:18 +00:00
NonMetric::Ounce => Conversion {
2023-05-28 17:32:31 +00:00
offset: 0.0,
from: 16.0 * pound_from,
to: MetricQuantity { amount: pound_to, unit: Metric::Gram },
2023-05-13 14:50:18 +00:00
},
NonMetric::Pound => Conversion {
2023-05-28 17:32:31 +00:00
offset: 0.0,
from: pound_from,
to: MetricQuantity { amount: pound_to, unit: Metric::Gram },
2023-05-13 14:50:18 +00:00
},
NonMetric::Stone => Conversion {
2023-05-28 17:32:31 +00:00
offset: 0.0,
from: pound_from,
to: MetricQuantity { amount: 14.0 * pound_to, unit: Metric::Gram },
2023-05-13 14:50:18 +00:00
},
2023-05-31 23:38:49 +00:00
NonMetric::ShortTon => Conversion {
offset: 0.0,
from: pound_from,
to: MetricQuantity { amount: 2000.0 * pound_to, unit: Metric::Gram },
},
2023-05-31 23:48:34 +00:00
NonMetric::LongTon => Conversion {
offset: 0.0,
from: pound_from,
to: MetricQuantity { amount: 2240.0 * pound_to, unit: Metric::Gram },
},
2023-05-28 17:32:31 +00:00
// Temperature
NonMetric::Fahrenheit => Conversion {
offset: 32.0,
from: 9.0,
2023-05-29 18:37:56 +00:00
to: MetricQuantity { amount: 5.0, unit: Metric::Celsius },
2023-05-28 17:32:31 +00:00
},
2023-05-28 23:55:43 +00:00
// Area
NonMetric::SquareInch => Conversion {
offset: 0.0,
from: inch_from * inch_from,
to: MetricQuantity { amount: inch_to * inch_to, unit: Metric::SquareMetre },
},
2023-05-29 00:01:56 +00:00
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 },
},
2023-06-01 16:24:11 +00:00
NonMetric::SquareYard => Conversion {
offset: 0.0,
from: inch_from * inch_from,
to: MetricQuantity { amount: 3.0 * 12.0 * inch_to * 3.0 * 12.0 * inch_to, unit: Metric::SquareMetre },
},
2023-05-29 00:18:30 +00:00
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 },
},
2023-05-29 00:27:55 +00:00
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 },
},
2023-05-29 19:29:10 +00:00
// Volume
NonMetric::CubicInch => Conversion {
offset: 0.0,
from: inch_from * inch_from * inch_from,
to: MetricQuantity { amount: inch_to * inch_to * inch_to, unit: Metric::CubicMetre },
},
2023-05-29 19:40:03 +00:00
NonMetric::CubicFoot => Conversion {
offset: 0.0,
from: inch_from * inch_from * inch_from,
to: MetricQuantity { amount: 12.0 * inch_to * 12.0 * inch_to * 12.0 * inch_to, unit: Metric::CubicMetre },
},
2023-06-01 16:31:55 +00:00
NonMetric::CubicYard => Conversion {
offset: 0.0,
from: inch_from * inch_from * inch_from,
to: MetricQuantity { amount: 3.0 * 12.0 * inch_to * 3.0 * 12.0 * inch_to * 3.0 * 12.0 * inch_to, unit: Metric::CubicMetre },
},
2023-05-30 17:01:35 +00:00
// Fluid volume
NonMetric::ImperialFluidOunce => Conversion {
2023-05-30 17:01:35 +00:00
offset: 0.0,
from: 20.0 * 2.0 * 4.0 * imperial_gallon_from,
2023-05-30 17:01:35 +00:00
to: MetricQuantity { amount: imperial_gallon_to, unit: Metric::Litre },
},
NonMetric::ImperialPint => Conversion {
2023-05-30 17:08:42 +00:00
offset: 0.0,
from: 2.0 * 4.0 * imperial_gallon_from,
2023-05-30 17:08:42 +00:00
to: MetricQuantity { amount: imperial_gallon_to, unit: Metric::Litre },
},
NonMetric::ImperialQuart => Conversion {
2023-05-30 17:16:17 +00:00
offset: 0.0,
from: 4.0 * imperial_gallon_from,
2023-05-30 17:16:17 +00:00
to: MetricQuantity { amount: imperial_gallon_to, unit: Metric::Litre },
},
NonMetric::ImperialGallon => Conversion {
2023-05-30 17:34:38 +00:00
offset: 0.0,
from: imperial_gallon_from,
2023-05-30 17:34:38 +00:00
to: MetricQuantity { amount: imperial_gallon_to, unit: Metric::Litre },
},
2023-05-31 19:38:50 +00:00
NonMetric::USTeaspoon => Conversion {
offset: 0.0,
from: 6.0 * 16.0 * 2.0 * 4.0 * us_gallon_from,
to: MetricQuantity { amount: us_gallon_to, unit: Metric::Litre },
},
2023-05-31 19:29:58 +00:00
NonMetric::USTablespoon => Conversion {
offset: 0.0,
from: 2.0 * 16.0 * 2.0 * 4.0 * us_gallon_from,
to: MetricQuantity { amount: us_gallon_to, unit: Metric::Litre },
},
2023-05-31 19:19:55 +00:00
NonMetric::USFluidOunce => Conversion {
offset: 0.0,
from: 16.0 * 2.0 * 4.0 * us_gallon_from,
to: MetricQuantity { amount: us_gallon_to, unit: Metric::Litre },
},
2023-05-31 19:10:49 +00:00
NonMetric::USCup => Conversion {
offset: 0.0,
from: 2.0 * 2.0 * 4.0 * us_gallon_from,
to: MetricQuantity { amount: us_gallon_to, unit: Metric::Litre },
},
2023-05-31 14:49:24 +00:00
NonMetric::USLiquidPint => Conversion {
offset: 0.0,
from: 2.0 * 4.0 * us_gallon_from,
to: MetricQuantity { amount: us_gallon_to, unit: Metric::Litre },
},
2023-05-31 14:42:18 +00:00
NonMetric::USLiquidQuart => Conversion {
offset: 0.0,
from: 4.0 * us_gallon_from,
to: MetricQuantity { amount: us_gallon_to, unit: Metric::Litre },
},
2023-05-31 14:35:19 +00:00
NonMetric::USGallon => Conversion {
offset: 0.0,
from: us_gallon_from,
to: MetricQuantity { amount: us_gallon_to, unit: Metric::Litre },
},
2023-05-13 14:50:18 +00:00
}
}
#[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]
2023-06-01 00:00:10 +00:00
fn mass() {
2023-05-13 14:50:18 +00:00
let tests = [
Test(NonMetric::Ounce, 28.349523125),
Test(NonMetric::Pound, 453.59237),
Test(NonMetric::Stone, 6350.29318),
2023-05-31 23:38:49 +00:00
Test(NonMetric::ShortTon, 907184.74),
2023-05-31 23:48:34 +00:00
Test(NonMetric::LongTon, 1016046.9088),
2023-05-13 14:50:18 +00:00
];
run_tests(&tests, Metric::Gram);
}
2023-05-28 17:32:31 +00:00
#[test]
fn temperature() {
assert_eq!(convert(NonMetricQuantity {
amount: -40.0,
unit: NonMetric::Fahrenheit,
}), MetricQuantity {
amount: -40.0,
2023-05-29 18:37:56 +00:00
unit: Metric::Celsius,
2023-05-28 17:32:31 +00:00
});
assert_eq!(convert(NonMetricQuantity {
amount: 32.0,
unit: NonMetric::Fahrenheit,
}), MetricQuantity {
amount: 0.0,
2023-05-29 18:37:56 +00:00
unit: Metric::Celsius,
2023-05-28 17:32:31 +00:00
});
}
2023-05-28 23:55:43 +00:00
#[test]
fn area() {
let tests = [
Test(NonMetric::SquareInch, 0.00064516),
2023-05-29 00:01:56 +00:00
Test(NonMetric::SquareFoot, 0.09290304),
2023-06-01 16:24:11 +00:00
Test(NonMetric::SquareYard, 0.83612736),
2023-05-29 00:18:30 +00:00
Test(NonMetric::Acre, 4046.8564224),
2023-05-29 00:27:55 +00:00
Test(NonMetric::SquareMile, 2589988.110336),
2023-05-28 23:55:43 +00:00
];
run_tests(&tests, Metric::SquareMetre);
}
2023-05-29 19:29:10 +00:00
#[test]
fn volume() {
let tests = [
Test(NonMetric::CubicInch, 1.6387064e-5),
2023-05-29 19:40:03 +00:00
Test(NonMetric::CubicFoot, 0.028316846592),
2023-06-01 16:31:55 +00:00
Test(NonMetric::CubicYard, 0.764554857984),
2023-05-29 19:29:10 +00:00
];
run_tests(&tests, Metric::CubicMetre);
}
2023-05-30 17:01:35 +00:00
#[test]
fn fluid_volume() {
let tests = [
2023-05-30 17:34:38 +00:00
Test(NonMetric::ImperialFluidOunce, 0.0284130625),
Test(NonMetric::ImperialPint, 0.56826125),
Test(NonMetric::ImperialQuart, 1.1365225),
Test(NonMetric::ImperialGallon, 4.54609),
2023-05-31 19:38:50 +00:00
Test(NonMetric::USTeaspoon, 0.00492892159375),
2023-05-31 19:29:58 +00:00
Test(NonMetric::USTablespoon, 0.01478676478125),
2023-05-31 19:19:55 +00:00
Test(NonMetric::USFluidOunce, 0.0295735295625),
2023-05-31 19:10:49 +00:00
Test(NonMetric::USCup, 0.2365882365),
2023-05-31 14:49:24 +00:00
Test(NonMetric::USLiquidPint, 0.473176473),
2023-05-31 14:42:18 +00:00
Test(NonMetric::USLiquidQuart, 0.946352946),
2023-05-31 14:35:19 +00:00
Test(NonMetric::USGallon, 3.785411784),
2023-05-30 17:01:35 +00:00
];
run_tests(&tests, Metric::Litre);
}
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);
}
}
2023-05-13 14:50:18 +00:00
}