Implement most of application logic
This commit is contained in:
parent
7d82e46fd7
commit
da620a04aa
3 changed files with 88 additions and 8 deletions
85
src/lib.rs
85
src/lib.rs
|
@ -2,5 +2,86 @@ mod conversions;
|
|||
mod parse;
|
||||
mod units;
|
||||
|
||||
pub use conversions::convert;
|
||||
pub use parse::{parse, ParseError};
|
||||
use conversions::convert;
|
||||
use parse::{parse, ParseError};
|
||||
use units::{MetricQuantity, NonMetric};
|
||||
|
||||
pub fn run(input: &str) -> Result<String, String> {
|
||||
let non_metric = match parse(input) {
|
||||
Ok(non_metric) => non_metric,
|
||||
Err(ParseError::NotValidNumber(string)) => {
|
||||
return Err(format!("Not a valid number: {string}"));
|
||||
}
|
||||
Err(ParseError::UnexpectedUnit(unit)) => {
|
||||
return Err(format!("Unexpected unit: {unit}"));
|
||||
}
|
||||
Err(ParseError::UnknownUnit(unit)) => {
|
||||
return Err(format!("Unknown unit: {unit}"));
|
||||
}
|
||||
Err(ParseError::ExpectedUnit) => {
|
||||
return Err("Expected a unit".to_string());
|
||||
}
|
||||
};
|
||||
|
||||
if non_metric.len() == 0 {
|
||||
return Err("Expected quantity or quantities to convert".to_string());
|
||||
}
|
||||
|
||||
let metric: Vec<MetricQuantity> = non_metric.clone().into_iter().map(convert).collect();
|
||||
|
||||
// Make sure the results of the conversions can be summed together
|
||||
// This is the case if the units after conversion are the same
|
||||
let mut metric_unit = None;
|
||||
for index in 0..metric.len() {
|
||||
match metric_unit {
|
||||
Some(metric_unit) => {
|
||||
if metric[index].unit != metric_unit {
|
||||
let first_unit_name = unit_to_name(non_metric[0].unit);
|
||||
let unit_name = unit_to_name(non_metric[index].unit);
|
||||
return Err(format!("Incompatible units: {first_unit_name}, {unit_name}"));
|
||||
}
|
||||
}
|
||||
None => {
|
||||
metric_unit = Some(metric[index].unit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let amount = metric.into_iter().map(|quantity| { quantity.amount }).sum();
|
||||
|
||||
let quantity = MetricQuantity {
|
||||
amount: amount,
|
||||
unit: metric_unit.expect("we must have at least one quantity by this point"),
|
||||
};
|
||||
|
||||
Ok(format!("{quantity:?}"))
|
||||
}
|
||||
|
||||
fn unit_to_name(unit: NonMetric) -> &'static str {
|
||||
match unit {
|
||||
// Length
|
||||
NonMetric::Inch => "inches",
|
||||
NonMetric::Foot => "feet",
|
||||
NonMetric::Yard => "yards",
|
||||
NonMetric::Mile => "miles",
|
||||
// Weight
|
||||
NonMetric::Ounce => "ounces",
|
||||
NonMetric::Pound => "pounds",
|
||||
NonMetric::Stone => "stones",
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn errors() {
|
||||
assert_eq!(run("1.0."), Err("Not a valid number: 1.0.".to_string()));
|
||||
assert_eq!(run("ft"), Err("Unexpected unit: ft".to_string()));
|
||||
assert_eq!(run("1 tf"), Err("Unknown unit: tf".to_string()));
|
||||
assert_eq!(run("1"), Err("Expected a unit".to_string()));
|
||||
assert_eq!(run(""), Err("Expected quantity or quantities to convert".to_string()));
|
||||
assert_eq!(run("6 ft 1 lbs"), Err("Incompatible units: feet, pounds".to_string()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
use metrify::parse;
|
||||
use metrify::run;
|
||||
|
||||
fn main() {
|
||||
let parsed = parse("12 stones 1 pound");
|
||||
match parsed {
|
||||
Ok(parsed) => println!("{parsed:?}"),
|
||||
Err(err) => eprintln!("{err:?}"),
|
||||
match run("5′7″") {
|
||||
Ok(str) => println!("{str}"),
|
||||
Err(err) => eprintln!("{err}"),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ pub struct MetricQuantity {
|
|||
pub unit: Metric,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct NonMetricQuantity {
|
||||
pub amount: f64,
|
||||
pub unit: NonMetric,
|
||||
|
|
Loading…
Reference in a new issue