diff --git a/Cargo.lock b/Cargo.lock index 6a952ae..04cccad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + [[package]] name = "az" version = "1.2.1" @@ -27,6 +33,7 @@ dependencies = [ "cfg-if", "rug", "termion", + "toml", ] [[package]] @@ -39,12 +46,34 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown", +] + [[package]] name = "libc" version = "0.2.140" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + [[package]] name = "numtoa" version = "0.1.0" @@ -80,6 +109,21 @@ dependencies = [ "libc", ] +[[package]] +name = "serde" +version = "1.0.164" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" + +[[package]] +name = "serde_spanned" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93107647184f6027e3b7dcb2e11034cf95ffa1e3a682c67951963ac69c1c007d" +dependencies = [ + "serde", +] + [[package]] name = "termion" version = "2.0.1" @@ -92,6 +136,40 @@ dependencies = [ "redox_termios", ] +[[package]] +name = "toml" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6135d499e69981f9ff0ef2167955a5333c35e36f6937d382974566b3d5b94ec" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a76a9312f5ba4c2dec6b9161fdf25d87ad8a09256ccea5a556fef03c706a10f" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380d56e8670370eee6566b0bfd4265f65b3f432e8c6d85623f728d4fa31f739" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + [[package]] name = "windows-sys" version = "0.42.0" @@ -148,3 +226,12 @@ name = "windows_x86_64_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "winnow" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61de7bac303dc551fe038e2b3cef0f571087a47571ea6e79a87692ac99b99699" +dependencies = [ + "memchr", +] diff --git a/Cargo.toml b/Cargo.toml index a93371f..7f58f81 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,7 @@ name = "daisy" version = "0.2.4" edition = "2021" +build = "buildscript/main.rs" [profile.release] opt-level = 3 @@ -18,4 +19,7 @@ cfg-if = "1.0.0" [target.'cfg(target_family = "unix")'.dependencies] termion = "2.0.1" -rug = "1.19.2" \ No newline at end of file +rug = "1.19.2" + +[build-dependencies] +toml = "0.7.4" \ No newline at end of file diff --git a/buildscript/main.rs b/buildscript/main.rs new file mode 100644 index 0000000..c5550e0 --- /dev/null +++ b/buildscript/main.rs @@ -0,0 +1,257 @@ +use std::env; +use std::io::Write; +use std::fs::OpenOptions; +use std::fs::File; +use std::path::Path; +use toml::Table; +use toml::Value; + + + + +/// Create WholeUnit enum with +/// basic impls. Should only be run once. +fn write_wholeunit_main(mut file: &File, units: &Vec) { + writeln!(file, + concat!( + "#[derive(Hash)]\n", + "#[derive(Debug)]\n", + "#[derive(Copy, Clone)]\n", + "#[derive(Eq, PartialEq)]\n", + "pub enum WholeUnit {{" + ) + ).unwrap(); + + for u in units { + writeln!(file, + "\t{},", + u["enum_name"].as_str().unwrap() + ).unwrap(); + } + + writeln!(file, "}}\n").unwrap(); + + writeln!(file, + concat!( + "impl ToString for WholeUnit {{\n", + "\tfn to_string(&self) -> String {{\n", + "\t\tString::from(match self {{" + ) + ).unwrap(); + + for u in units { + writeln!(file, + "\t\t\tWholeUnit::{e} => \"{s}\",", + s = u["print"].as_str().unwrap(), + e = u["enum_name"].as_str().unwrap() + ).unwrap(); + } + + writeln!(file, "\t\t}})\n\t}}\n}}").unwrap(); +} + + +/// Create WholeUnit::base_factor(). +/// Should only be run once. +fn write_wholeunit_base_factor(mut file: &File, units: &Vec) { + writeln!(file, + concat!( + "impl WholeUnit {{\n", + "\tfn base_factor(&self) -> Option {{\n", + "\t\tmatch self {{" + ) + ).unwrap(); + + for u in units { + + + if { // Base units should return None + u.as_table().unwrap().contains_key("base") && + u["base"].as_bool().unwrap() + } { + writeln!(file, + "\t\t\tWholeUnit::{} => None,", + u["enum_name"].as_str().unwrap() + ).unwrap(); + continue + } + + + writeln!(file, + "\t\t\tWholeUnit::{} => Some(Quantity{{", + u["enum_name"].as_str().unwrap() + ).unwrap(); + + match u["base_value_type"].as_str().unwrap() { + "exact" => { + writeln!(file, + "\t\t\t\tscalar: Scalar::new_rational_from_string(\"{}\").unwrap(),", + u["base_value"].as_str().unwrap(), + ).unwrap(); + }, + + "fract" => { + writeln!(file, + "\t\t\t\tscalar: Scalar::new_rational_from_frac({}, {}).unwrap(),", + u["base_value"].as_array().unwrap()[0].as_integer().unwrap(), + u["base_value"].as_array().unwrap()[1].as_integer().unwrap(), + ).unwrap(); + }, + + "approx" => { + writeln!(file, + "\t\t\t\tscalar: Scalar::new_float_from_string(\"{}\").unwrap(),", + u["base_value"].as_str().unwrap(), + ).unwrap(); + }, + + _ => panic!() + }; + + writeln!(file, + concat!( + "\t\t\t\tunit: Unit::from_array(&[\n", + "\t\t\t\t\t(FreeUnit{{whole: WholeUnit::{}, prefix: Prefix::None}}, Scalar::new_rational(-1f64).unwrap()),", + ), + u["enum_name"].as_str().unwrap() + ).unwrap(); + + for b in u["base_units"].as_array().unwrap() { + writeln!(file, + "\t\t\t\t\t(FreeUnit{{whole: WholeUnit::{u}, prefix: Prefix::None}}, Scalar::new_rational({p}f64).unwrap()),", + u = b.as_table().unwrap()["u"].as_str().unwrap(), + p = b.as_table().unwrap()["p"].as_integer().unwrap(), + ).unwrap(); + } + + writeln!(file, + concat!( + "\t\t\t\t])\n", + "\t\t\t}})," + ), + ).unwrap(); + } + + writeln!(file, "\t\t}}\n\t}}\n}}").unwrap(); +} + + +/// Write all SI prefixes. +/// Used inside freeunit_from_string(). +fn prefix_si(mut file: &File, enum_name: &str, s: &str) { + writeln!(file, + concat!( + "\t\t", "\"{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::None}}),\n", + "\t\t", "\"Q{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Quetta}}),\n", + "\t\t", "\"R{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Ronna}}),\n", + "\t\t", "\"Y{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Yotta}}),\n", + "\t\t", "\"Z{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Zetta}}),\n", + "\t\t", "\"E{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Exa}}),\n", + "\t\t", "\"P{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Peta}}),\n", + "\t\t", "\"T{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Tera}}),\n", + "\t\t", "\"G{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Giga}}),\n", + "\t\t", "\"M{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Mega}}),\n", + "\t\t", "\"k{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Kilo}}),\n", + "\t\t", "\"h{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Hecto}}),\n", + "\t\t", "\"da{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Deka}}),\n", + "\t\t", "\"d{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Deci}}),\n", + "\t\t", "\"c{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Centi}}),\n", + "\t\t", "\"m{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Milli}}),\n", + "\t\t", "\"u{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Micro}}),\n", + "\t\t", "\"n{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Nano}}),\n", + "\t\t", "\"p{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Pico}}),\n", + "\t\t", "\"f{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Femto}}),\n", + "\t\t", "\"a{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Atto}}),\n", + "\t\t", "\"z{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Zepto}}),\n", + "\t\t", "\"y{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Yocto}}),\n", + "\t\t", "\"r{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Ronto}}),\n", + "\t\t", "\"q{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Quecto}}),", + ), + e = enum_name, + s = s + ).unwrap(); +} + + +/// Create freeunit_from_string(). +/// Should only be run once. +fn write_freeunit_from_string(mut file: &File, units: &Vec) { + writeln!(file, + concat!( + "#[inline(always)]\n", + "fn freeunit_from_string(s: &str) -> Option {{\n", + "\tmatch s {{" + ), + ).unwrap(); + + for u in units { + if u.as_table().unwrap().contains_key("parse") { + for s in u["parse"].as_array().unwrap() { + writeln!(file, + "\t\t\"{}\" => Some(FreeUnit{{whole: WholeUnit::{}, prefix: Prefix::None}}),", + s.as_str().unwrap(), + u["enum_name"].as_str().unwrap() + ).unwrap(); + } + } + + + if u.as_table().unwrap().contains_key("parse_with_prefix") { + if u.as_table().unwrap()["parse_with_prefix"].is_array() { + for p in u["parse_with_prefix"].as_array().unwrap() { + prefix_si( + &file, + u["enum_name"].as_str().unwrap(), + p.as_str().unwrap() + ); + } + } else { + prefix_si( + &file, + u["enum_name"].as_str().unwrap(), + u["parse_with_prefix"].as_str().unwrap() + ); + } + } + + writeln!(file, "").unwrap(); + } + + writeln!(file, "\t\t_ => None\n\t}}\n}}").unwrap(); +} + + + + + + + +fn main() -> Result<(), ()>{ + + let out_dir = env::var_os("OUT_DIR").unwrap(); + let dest_path = Path::new(&out_dir).join("units.rs"); + println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rerun-if-changed=units.toml"); + + let units = include_str!("units.toml").parse::().unwrap(); + let toml::Value::Array(units) = &units["unit"] else {panic!()}; + + let mut file = OpenOptions::new() + .write(true) + .create(true) + .truncate(true) + .open(dest_path) + .unwrap(); + + + + write_wholeunit_main(&file, units); + writeln!(file, "\n\n").unwrap(); + + write_wholeunit_base_factor(&file, units); + writeln!(file, "\n\n").unwrap(); + + write_freeunit_from_string(&file, units); + + return Ok(()); +} \ No newline at end of file diff --git a/buildscript/units.toml b/buildscript/units.toml new file mode 100644 index 0000000..9e59c8d --- /dev/null +++ b/buildscript/units.toml @@ -0,0 +1,530 @@ +[[unit]] +enum_name = "Second" +print = "s" + +parse_with_prefix = "s" +parse = ["sec", "second", "seconds"] +base = true + + + +[[unit]] +enum_name = "Gram" +print = "g" + +parse_with_prefix = "g" +parse = ["gram", "grams", "gramme", "grammes"] +base = true + + + +[[unit]] +enum_name = "Meter" +print = "m" + +parse_with_prefix = "m" +parse = ["meter", "meters"] +base = true + + + +[[unit]] +enum_name = "Ampere" +print = "A" + +parse_with_prefix = "A" +parse = ["ampere", "amperes"] +base = true + + + +[[unit]] +enum_name = "Kelvin" +print = "K" + +parse_with_prefix = "K" +parse = ["kelvin"] +base = true + + + +[[unit]] +enum_name = "Mole" +print = "mol" + +parse_with_prefix = "mol" +parse = ["mole"] +base = true + + + +[[unit]] +enum_name = "Candela" +print = "cd" + +parse_with_prefix = "cd" +parse = ["candela"] +base = true + + + +# Time Units + + + +[[unit]] +enum_name = "Minute" +print = "min" +parse = ["min", "minute", "minutes"] + +# fract, exact, or approx +base_value_type = "exact" +base_value = "60" +base_units = [ { u = "Second", p = 1} ] + + + +[[unit]] +enum_name = "Hour" +print = "h" +parse = ["h", "hour", "hours"] + +base_value_type = "exact" +base_value = "3600" +base_units = [ { u = "Second", p = 1} ] + + + +[[unit]] +enum_name = "Day" +print = "d" +parse = ["d", "day", "days"] + +base_value_type = "exact" +base_value = "86400" +base_units = [ { u = "Second", p = 1} ] + + + +[[unit]] +enum_name = "Week" +print = "w" +parse = ["w", "week", "weeks"] + +base_value_type = "exact" +base_value = "604800" +base_units = [ { u = "Second", p = 1} ] + + + +[[unit]] +enum_name = "Month" +print = "month" +parse = ["month", "months"] + +base_value_type = "exact" +base_value = "2629746" +base_units = [ { u = "Second", p = 1} ] + + + +[[unit]] +enum_name = "Fortnight" +print = "fortnight" +parse = ["fortnight", "fortnights"] + +base_value_type = "exact" +base_value = "1209600" +base_units = [ { u = "Second", p = 1} ] + + + +[[unit]] +enum_name = "GregorianYear" +print = "year" +parse = ["year", "years"] + +base_value_type = "exact" +base_value = "31557000" +base_units = [ { u = "Second", p = 1} ] + + + +[[unit]] +enum_name = "JulianYear" +print = "julianYear" +parse = ["julianYear", "julianYears"] + +base_value_type = "exact" +base_value = "31557600" +base_units = [ { u = "Second", p = 1} ] + + + + +# Length Units + + +[[unit]] +enum_name = "Angstrom" +print = "Å" +parse = ["Å", "angstrom"] + +base_value_type = "exact" +base_value = "1e-10" +base_units = [ { u = "Meter", p = 1} ] + + + +[[unit]] +enum_name = "Thou" +print = "thou" +parse = ["thou"] + +base_value_type = "exact" +base_value = "0.0000254" +base_units = [ { u = "Meter", p = 1} ] + + + +[[unit]] +enum_name = "Point" +print = "pt" +parse = ["pt", "point"] + +base_value_type = "exact" +base_value = "0.0003514598" +base_units = [ { u = "Meter", p = 1} ] + + + +[[unit]] +enum_name = "Inch" +print = "in" +parse = ["in", "inch", "inches"] + +base_value_type = "exact" +base_value = "0.0254" +base_units = [ { u = "Meter", p = 1} ] + + + +[[unit]] +enum_name = "Foot" +print = "ft" +parse = ["ft", "foot", "feet"] + +base_value_type = "exact" +base_value = "0.3048" +base_units = [ { u = "Meter", p = 1} ] + + + +[[unit]] +enum_name = "Yard" +print = "yd" +parse = ["yd", "yard", "yards"] + +base_value_type = "exact" +base_value = "0.9144" +base_units = [ { u = "Meter", p = 1} ] + + + +[[unit]] +enum_name = "Furlong" +print = "furlong" +parse = ["furlong", "furlongs"] + +base_value_type = "exact" +base_value = "201.17" +base_units = [ { u = "Meter", p = 1} ] + + + +[[unit]] +enum_name = "Mile" +print = "mi" +parse = ["mi", "mile", "miles"] + +base_value_type = "exact" +base_value = "1609.344" +base_units = [ { u = "Meter", p = 1} ] + + + +[[unit]] +enum_name = "AstronomicalUnit" +print = "au" +parse = ["au", "AU", "astronomicalUnit", "astronomicalUnits"] + +base_value_type = "exact" +base_value = "149597870700" +base_units = [ { u = "Meter", p = 1} ] + + + +[[unit]] +enum_name = "Lightyear" +print = "ly" +parse = ["ly", "lightyear", "lightyears"] + +base_value_type = "exact" +base_value = "9460730472580800" +base_units = [ { u = "Meter", p = 1} ] + + + +[[unit]] +enum_name = "Parsec" +print = "pc" +parse = ["pc", "parsec", "parsecs"] + +base_value_type = "exact" +base_value = "3.085677581e16" +base_units = [ { u = "Meter", p = 1} ] + + + +# Area units + + +[[unit]] +enum_name = "Barn" +print = "b" +parse = ["b", "barn"] + +base_value_type = "exact" +base_value = "1e-28" +base_units = [ { u = "Meter", p = 2} ] + + + +[[unit]] +enum_name = "Hectare" +print = "ha" +parse = ["hectare", "hectares"] + +base_value_type = "exact" +base_value = "10000" +base_units = [ { u = "Meter", p = 2} ] + + + +[[unit]] +enum_name = "Acre" +print = "acre" +parse = ["acres"] + +base_value_type = "exact" +base_value = "4046.8564224" +base_units = [ { u = "Meter", p = 2} ] + + + +# Volume units + + +[[unit]] +enum_name = "Liter" +print = "l" +parse_with_prefix = ["l", "L"] +parse = ["liter", "liters", "litre", "litres"] + +base_value_type = "exact" +base_value = "0.001" +base_units = [ { u = "Meter", p = 3} ] + + + +[[unit]] +enum_name = "USGallon" +print = "gal" +parse = ["gal", "usgal", "gallon", "gallons"] + +base_value_type = "exact" +base_value = "0.003785411784" +base_units = [ { u = "Meter", p = 3} ] + + + +[[unit]] +enum_name = "Quart" +print = "qt" +parse = ["quart", "quarts"] + +base_value_type = "exact" +base_value = "0.000946352946" +base_units = [ { u = "Meter", p = 3} ] + + + +[[unit]] +enum_name = "ImperialGallon" +print = "impgal" +parse = ["imperialGallon", "imperialGallons"] + +base_value_type = "exact" +base_value = "0.00454609" +base_units = [ { u = "Meter", p = 3} ] + + + +[[unit]] +enum_name = "Hogshead" +print = "hogshead" +parse = ["hogshead", "hogsheads"] + +base_value_type = "exact" +base_value = "0.2385" # 63 gallons +base_units = [ { u = "Meter", p = 3} ] + + + +[[unit]] +enum_name = "Cup" +print = "cup" +parse = ["cup"] + +base_value_type = "exact" +base_value = "0.0002365882365" +base_units = [ { u = "Meter", p = 3} ] + + + +[[unit]] +enum_name = "Floz" +print = "floz" +parse = ["floz"] + +base_value_type = "exact" +base_value = "0.0000295735295625" +base_units = [ { u = "Meter", p = 3} ] + + + +[[unit]] +enum_name = "Pint" +print = "pint" +parse = ["pint", "pints"] + +base_value_type = "exact" +base_value = "0.00056826125" +base_units = [ { u = "Meter", p = 3} ] + + + +[[unit]] +enum_name = "Tablespoon" +print = "tbsp" +parse = ["tbsp", "Tbsp", "tablespoon", "Tablespoon"] + +base_value_type = "exact" +base_value = "0.00001478676478125" +base_units = [ { u = "Meter", p = 3} ] + + + +[[unit]] +enum_name = "Teaspoon" +print = "tsp" +parse = ["tsp", "Tsp", "teaspoon", "teaspoons"] + +base_value_type = "exact" +base_value = "0.000005" +base_units = [ { u = "Meter", p = 3} ] + + + +# Pressure units + + +[[unit]] +enum_name = "Pascal" +print = "Pa" +parse_with_prefix = "Pa" +parse = ["pascal"] + +base_value_type = "exact" +base_value = "1000" +base_units = [ { u = "Gram", p = 1}, { u = "Meter", p = -1}, { u = "Second", p = -2} ] + + +[[unit]] +enum_name = "Atmosphere" +print = "atm" +parse = ["atm", "atmosphere", "atmospheres"] + +base_value_type = "exact" +base_value = "101325000" +base_units = [ { u = "Gram", p = 1}, { u = "Meter", p = -1}, { u = "Second", p = -2} ] + + +[[unit]] +enum_name = "Bar" +print = "bar" +parse_with_prefix = "bar" + +base_value_type = "exact" +base_value = "100000000" +base_units = [ { u = "Gram", p = 1}, { u = "Meter", p = -1}, { u = "Second", p = -2} ] + + +[[unit]] +enum_name = "Barye" +print = "Ba" +parse = ["Ba", "Barye"] + +base_value_type = "exact" +base_value = "100" +base_units = [ { u = "Gram", p = 1}, { u = "Meter", p = -1}, { u = "Second", p = -2} ] + + +[[unit]] +enum_name = "Psi" +print = "psi" +parse = ["psi"] + +base_value_type = "exact" +base_value = "6894757.2931783" +base_units = [ { u = "Gram", p = 1}, { u = "Meter", p = -1}, { u = "Second", p = -2} ] + + +[[unit]] +enum_name = "MillimeterMercury" +print = "mmHg" +parse = ["mmhg", "mmHg"] + +base_value_type = "exact" +base_value = "133322.387415" +base_units = [ { u = "Gram", p = 1}, { u = "Meter", p = -1}, { u = "Second", p = -2} ] + + +[[unit]] +enum_name = "Torr" +print = "torr" +parse = ["torr", "Torr"] + +base_value_type = "fract" +base_value = [101325000, 760] +base_units = [ { u = "Gram", p = 1}, { u = "Meter", p = -1}, { u = "Second", p = -2} ] + + +[[unit]] +enum_name = "MeterSeaWater" +print = "MSW" +parse = ["MSW", "msw"] + +base_value_type = "exact" +base_value = "10000000" +base_units = [ { u = "Gram", p = 1}, { u = "Meter", p = -1}, { u = "Second", p = -2} ] + + +[[unit]] +enum_name = "FootSeaWater" +print = "FSW" +parse = ["FSW", "fsw"] + +base_value_type = "exact" +base_value = "3064330" +base_units = [ { u = "Gram", p = 1}, { u = "Meter", p = -1}, { u = "Second", p = -2} ] \ No newline at end of file diff --git a/src/quantity/unit/freeunit.rs b/src/quantity/unit/freeunit.rs index 0a478f5..5c371cd 100644 --- a/src/quantity/unit/freeunit.rs +++ b/src/quantity/unit/freeunit.rs @@ -4,8 +4,6 @@ use crate::quantity::Scalar; use crate::quantity::Quantity; use super::WholeUnit; use super::Prefix; -use super::Unit; -use super::unit_db; #[derive(Debug)] @@ -18,88 +16,16 @@ pub struct FreeUnit { } -macro_rules! unpack_string { - ( - $u:expr, $s:expr, - $( $_:expr ),* - ) => { $s }; -} - impl ToString for FreeUnit { fn to_string(&self) -> String { - let s = unit_db!(self.whole, unpack_string); + let s = self.whole.to_string(); let p = self.prefix.to_string(); format!("{p}{s}") } } - - -macro_rules! unpack_base_factor { - ( - $unit:expr, - $display_string:expr, - base - ) => { None }; - - ( - $unit:expr, - $display_string:expr, - float, - $value:expr, - $( ($u:expr, $p:expr) ),* - ) => { - Some(Quantity { - scalar: Scalar::new_float_from_string($value).unwrap(), - unit: Unit::from_array(&[ - $( - (FreeUnit::from_whole($u), Scalar::new_rational($p).unwrap()), - )* - (FreeUnit::from_whole($unit), Scalar::new_rational(-1f64).unwrap()) - ]) - }) - }; - - ( - $unit:expr, - $display_string:expr, - rational, - $value:expr, - $( ($u:expr, $p:expr) ),* - ) => { - Some(Quantity { - scalar: Scalar::new_rational_from_string($value).unwrap(), - unit: Unit::from_array(&[ - $( - (FreeUnit::from_whole($u), Scalar::new_rational($p).unwrap()), - )* - (FreeUnit::from_whole($unit), Scalar::new_rational(-1f64).unwrap()) - ]) - }) - }; - - ( - $unit:expr, - $display_string:expr, - rational_frac, - ($t:expr, $b:expr), - $( ($u:expr, $p:expr) ),* - ) => { - Some(Quantity { - scalar: Scalar::new_rational_from_frac($t, $b).unwrap(), - unit: Unit::from_array(&[ - $( - (FreeUnit::from_whole($u), Scalar::new_rational($p).unwrap()), - )* - (FreeUnit::from_whole($unit), Scalar::new_rational(-1f64).unwrap()) - ]) - }) - }; -} - - impl FreeUnit { pub fn from_whole(whole: WholeUnit) -> FreeUnit { return FreeUnit { whole, prefix: Prefix::None } @@ -113,7 +39,7 @@ impl FreeUnit { /// gives a quantity in base units. pub fn to_base_factor(&self) -> Quantity { - let q = unit_db!(self.whole, unpack_base_factor); + let q = self.whole.base_factor(); let mut q = q.unwrap_or(Quantity::new_rational_from_string("1").unwrap()); let mut p = self.prefix.to_ratio(); @@ -126,7 +52,7 @@ impl FreeUnit { // Get this unit in terms of base units pub fn get_base(&self) -> Quantity { - let q = unit_db!(self.whole, unpack_base_factor); + let q = self.whole.base_factor(); let mut q = q.unwrap_or(Quantity::new_rational_from_string("1").unwrap()); // Don't divide by self diff --git a/src/quantity/unit/mod.rs b/src/quantity/unit/mod.rs index d685f3e..383b977 100644 --- a/src/quantity/unit/mod.rs +++ b/src/quantity/unit/mod.rs @@ -8,611 +8,7 @@ pub use prefix::Prefix; pub use unit::Unit; pub use freeunit::FreeUnit; +use crate::quantity::Quantity; +use crate::quantity::Scalar; -#[derive(Hash)] -#[derive(Debug)] -#[derive(Copy, Clone)] -#[derive(Eq, PartialEq)] -pub enum WholeUnit { - // Base Units - Second, - Meter, - Gram, // Technically kilogram, but that messes with our prefix system. - Ampere, - Kelvin, - Mole, - Candela, - - // Length units - Angstrom, - Thou, - Point, // pt, typesetting unit - Inch, - Foot, - Yard, - Furlong, - Mile, - AstronomicalUnit, - Lightyear, - Parsec, - - // Area - Barn, - Hectare, - Acre, - - - - // Time units - Minute, - Hour, - Day, - Week, - Month, - Fortnight, - GregorianYear, - JulianYear, - - // Volume - Liter, - USGallon, - Quart, - ImperialGallon, - Hogshead, - Cup, - Floz, - Pint, - Tablespoon, - Teaspoon, - - // Pressure - Pascal, - Atmosphere, - Bar, - Barye, - Psi, - MillimeterMercury, - Torr, - MeterSeaWater, - FootSeaWater -} - - -// SI prefix list: -// ("Q","R","Y","Z","E","P","T","G","M","k","h","da","d","c","m","u","n","p","f","a","z","y","r","q") - -// X macro, used in Unit.from_string() -// -// Format is as follows: -// (Unit, string from, (prefixes_to_generate)) -// Prefixes must be valid prefixes as defined in -// Prefix::str_to_prefix. -// -// Prefix array can be ommited to prevent prefix generation. -pub (self) use prefix::str_to_prefix; -macro_rules! fromstring_db { - ($X:ident) => { - $X!( - // Base units - (WholeUnit::Meter, "meter"), - (WholeUnit::Meter, "meters"), - (WholeUnit::Ampere, "ampere"), - (WholeUnit::Ampere, "amperes"), - (WholeUnit::Gram, "gram"), - (WholeUnit::Gram, "grams"), - (WholeUnit::Gram, "gramme"), - (WholeUnit::Gram, "grammes"), - (WholeUnit::Kelvin, "kelvin"), - (WholeUnit::Mole, "mole"), - (WholeUnit::Candela, "candela"), - - (WholeUnit::Meter, "m", - ("Q","R","Y","Z","E","P","T","G","M","k","h","da","d","c","m","u","n","p","f","a","z","y","r","q") - ), - - (WholeUnit::Second, "s", - ("Q","R","Y","Z","E","P","T","G","M","k","h","da","d","c","m","u","n","p","f","a","z","y","r","q") - ), - - (WholeUnit::Gram, "g", - ("Q","R","Y","Z","E","P","T","G","M","k","h","da","d","c","m","u","n","p","f","a","z","y","r","q") - ), - - (WholeUnit::Ampere, "A", - ("Q","R","Y","Z","E","P","T","G","M","k","h","da","d","c","m","u","n","p","f","a","z","y","r","q") - ), - - (WholeUnit::Kelvin, "K", - ("Q","R","Y","Z","E","P","T","G","M","k","h","da","d","c","m","u","n","p","f","a","z","y","r","q") - ), - - (WholeUnit::Mole, "mol", - ("Q","R","Y","Z","E","P","T","G","M","k","h","da","d","c","m","u","n","p","f","a","z","y","r","q") - ), - - (WholeUnit::Candela, "cd", - ("Q","R","Y","Z","E","P","T","G","M","k","h","da","d","c","m","u","n","p","f","a","z","y","r","q") - ), - - // Length - (WholeUnit::Angstrom, "angstrom"), - (WholeUnit::Angstrom, "Å"), - (WholeUnit::Thou, "thou"), - (WholeUnit::Point, "pt"), - (WholeUnit::Point, "point"), - (WholeUnit::Inch, "in"), - (WholeUnit::Inch, "inch"), - (WholeUnit::Foot, "ft"), - (WholeUnit::Foot, "foot"), - (WholeUnit::Foot, "feet"), - (WholeUnit::Yard, "yard"), - (WholeUnit::Yard, "yd"), - (WholeUnit::Yard, "yards"), - (WholeUnit::Mile, "mi"), - (WholeUnit::Mile, "mile"), - (WholeUnit::Mile, "miles"), - (WholeUnit::AstronomicalUnit, "au"), - (WholeUnit::AstronomicalUnit, "AU"), - (WholeUnit::AstronomicalUnit, "astronomicalUnit"), - (WholeUnit::AstronomicalUnit, "astronomicalUnits"), - (WholeUnit::Lightyear, "ly"), - (WholeUnit::Lightyear, "lightyear"), - (WholeUnit::Lightyear, "lightyears"), - (WholeUnit::Parsec, "pc"), - (WholeUnit::Parsec, "parsec"), - (WholeUnit::Parsec, "parsecs"), - - // Time - (WholeUnit::Second, "sec"), - (WholeUnit::Second, "second"), - (WholeUnit::Second, "seconds"), - (WholeUnit::Minute, "min"), - (WholeUnit::Minute, "minute"), - (WholeUnit::Minute, "minutes"), - (WholeUnit::Hour, "h"), - (WholeUnit::Hour, "hour"), - (WholeUnit::Hour, "hours"), - (WholeUnit::Day, "d"), - (WholeUnit::Day, "day"), - (WholeUnit::Day, "days"), - (WholeUnit::Week, "w"), - (WholeUnit::Week, "week"), - (WholeUnit::Week, "weeks"), - (WholeUnit::Month, "month"), - (WholeUnit::Month, "months"), - (WholeUnit::Fortnight, "fortnight"), - (WholeUnit::Fortnight, "fortnights"), - (WholeUnit::GregorianYear, "year"), - (WholeUnit::GregorianYear, "years"), - (WholeUnit::JulianYear, "julianYear"), - (WholeUnit::JulianYear, "julianYears"), - - // Misc - (WholeUnit::Barn, "b"), - (WholeUnit::Barn, "barn"), - (WholeUnit::Hectare, "ha"), - (WholeUnit::Hectare, "hectare"), - (WholeUnit::Hectare, "hectares"), - (WholeUnit::Acre, "acre"), - (WholeUnit::Acre, "acres"), - - - // Volume - (WholeUnit::Liter, "liter"), - (WholeUnit::Liter, "liters"), - (WholeUnit::Liter, "litre"), - (WholeUnit::Liter, "litres"), - (WholeUnit::USGallon, "usgal"), - (WholeUnit::USGallon, "gal"), - (WholeUnit::USGallon, "gallon"), - (WholeUnit::USGallon, "gallons"), - (WholeUnit::Quart, "quart"), - (WholeUnit::Quart, "quarts"), - (WholeUnit::Quart, "qt"), - (WholeUnit::ImperialGallon, "impgal"), - (WholeUnit::ImperialGallon, "imperialGallon"), - (WholeUnit::ImperialGallon, "imperialGallons"), - (WholeUnit::Cup, "cup"), - (WholeUnit::Floz, "floz"), - (WholeUnit::Pint, "pint"), - (WholeUnit::Pint, "pints"), - (WholeUnit::Tablespoon, "tablespoon"), - (WholeUnit::Tablespoon, "tablespoons"), - (WholeUnit::Tablespoon, "tbsp"), - (WholeUnit::Tablespoon, "Tbsp"), - (WholeUnit::Teaspoon, "teaspoon"), - (WholeUnit::Teaspoon, "teaspoons"), - (WholeUnit::Teaspoon, "tsp"), - (WholeUnit::Teaspoon, "Tsp"), - - - - (WholeUnit::Hogshead, "hogshead"), - (WholeUnit::Hogshead, "hogsheads"), - - - (WholeUnit::Liter, "l", - ("Q","R","Y","Z","E","P","T","G","M","k","h","da","d","c","m","u","n","p","f","a","z","y","r","q") - ), - - (WholeUnit::Liter, "L", - ("Q","R","Y","Z","E","P","T","G","M","k","h","da","d","c","m","u","n","p","f","a","z","y","r","q") - ), - - - - // Pressure - (WholeUnit::Atmosphere, "atm"), - (WholeUnit::Atmosphere, "atmosphere"), - (WholeUnit::Atmosphere, "atmospheres"), - (WholeUnit::Pascal, "pascal"), - (WholeUnit::Barye, "Ba"), - (WholeUnit::Psi, "psi"), - (WholeUnit::MillimeterMercury, "mmhg"), - (WholeUnit::MillimeterMercury, "mmHg"), - (WholeUnit::Torr, "torr"), - (WholeUnit::Torr, "Torr"), - (WholeUnit::MeterSeaWater, "msw"), - (WholeUnit::FootSeaWater, "fsw"), - (WholeUnit::MeterSeaWater, "MSW"), - (WholeUnit::FootSeaWater, "FSW"), - - (WholeUnit::Pascal, "Pa", - ("Q","R","Y","Z","E","P","T","G","M","k","h","da","d","c","m","u","n","p","f","a","z","y","r","q") - ), - - (WholeUnit::Bar, "bar", - ("Q","R","Y","Z","E","P","T","G","M","k","h","da","d","c","m","u","n","p","f","a","z","y","r","q") - ) - ) - } -} -pub (self) use fromstring_db; - - -// X macro, used in the following functions: -// - FreeUnit.to_base_factor() -// - FreeUnit.to_string() -// -// Read below comments for explanation. -macro_rules! unit_db { - ($a:expr, $X:ident) => { - match $a { - - - // Base - - WholeUnit::Second => $X!( - - WholeUnit::Second, // Repeat the name of this base unit - "s", // String to display for this unit - - // "base", "float", or "rational." - // if base, this is a base unit and has no conversion factor. - // if float or rational, this is not a base unit. See below. - base - ), - WholeUnit::Meter => $X!( - WholeUnit::Meter, "m", - base - ), - WholeUnit::Gram => $X!( - WholeUnit::Gram, "g", - base - ), - WholeUnit::Ampere => $X!( - WholeUnit::Ampere, "A", - base - ), - WholeUnit::Kelvin => $X!( - WholeUnit::Kelvin, "K", - base - ), - WholeUnit::Mole => $X!( - WholeUnit::Mole, "mol", - base - ), - WholeUnit::Candela => $X!( - WholeUnit::Candela, "cd", - base - ), - - - - - // Time - - WholeUnit::Minute => $X!( - WholeUnit::Minute, "min", - - // "rational" and "float" determine what kind of Quantity - // this unit's conversion factor will be. Use "rational" - // if it is exact, and "float" if it is an approximation. - rational, - - - // The next two lines are interpreted as follows: - // One Minute = 60 Seconds. - - // The value - "60", - // The unit. Can be repeated for compound units. - // MUST BE BASE UNITS. - (WholeUnit::Second, 1f64) - ), - - WholeUnit::Hour => $X!( - WholeUnit::Hour, "h", - rational, "3600", - (WholeUnit::Second, 1f64) - ), - - WholeUnit::Day => $X!( - WholeUnit::Day, "day", - rational, "86400", - (WholeUnit::Second, 1f64) - ), - - WholeUnit::Week => $X!( - WholeUnit::Week, "week", - rational, "604800", - (WholeUnit::Second, 1f64) - ), - - WholeUnit::Month => $X!( - WholeUnit::Month, "month", - rational, "2629746", - (WholeUnit::Second, 1f64) - ), - - WholeUnit::Fortnight => $X!( - WholeUnit::Fortnight, "fortnight", - rational, "1209600", - (WholeUnit::Second, 1f64) - ), - - WholeUnit::GregorianYear => $X!( - WholeUnit::GregorianYear, "year", - rational, "31557000", - (WholeUnit::Second, 1f64) - ), - - WholeUnit::JulianYear => $X!( - WholeUnit::JulianYear, "julianYear", - rational, "31557600", - (WholeUnit::Second, 1f64) - ), - - - - // Length - - WholeUnit::Angstrom => $X!( - WholeUnit::Angstrom, "Å", - rational, "1e-10", - (WholeUnit::Meter, 1f64) - ), - - WholeUnit::Thou => $X!( - WholeUnit::Thou, "thou", - rational, "0.0000254", - (WholeUnit::Meter, 1f64) - ), - - WholeUnit::Point => $X!( - WholeUnit::Point, "pt", - rational, "0.0003514598", - (WholeUnit::Meter, 1f64) - ), - - WholeUnit::Inch => $X!( - WholeUnit::Inch, "in", - rational, "0.0254", - (WholeUnit::Meter, 1f64) - ), - - WholeUnit::Foot => $X!( - WholeUnit::Foot, "ft", - rational, "0.3048", - (WholeUnit::Meter, 1f64) - ), - - WholeUnit::Yard => $X!( - WholeUnit::Yard, "yd", - rational, "0.9144", - (WholeUnit::Meter, 1f64) - ), - - WholeUnit::Furlong => $X!( - WholeUnit::Furlong, "furlong", - rational, "201.17", - (WholeUnit::Meter, 1f64) - ), - - WholeUnit::Mile => $X!( - WholeUnit::Mile, "mi", - rational, "1609.344", - (WholeUnit::Meter, 1f64) - ), - - WholeUnit::AstronomicalUnit => $X!( - WholeUnit::AstronomicalUnit, "AU", - rational, "149597870700", - (WholeUnit::Meter, 1f64) - ), - - WholeUnit::Lightyear => $X!( - WholeUnit::Lightyear, "ly", - rational, "9460730472580800", - (WholeUnit::Meter, 1f64) - ), - - WholeUnit::Parsec => $X!( - WholeUnit::Parsec, "pc", - float, "3.085677581e16", - (WholeUnit::Meter, 1f64) - ), - - WholeUnit::Barn => $X!( - WholeUnit::Barn, "b", - rational, "1e-28", - (WholeUnit::Meter, 2f64) - ), - - WholeUnit::Hectare => $X!( - WholeUnit::Hectare, "ha", - rational, "10000", - (WholeUnit::Meter, 2f64) - ), - - WholeUnit::Acre => $X!( // 66 x 660 feet - WholeUnit::Acre, "acre", - rational, "4046.8564224", - (WholeUnit::Meter, 2f64) - ), - - - - // Volume - WholeUnit::Liter => $X!( - WholeUnit::Liter, "l", - rational, "0.001", - (WholeUnit::Meter, 3f64) - ), - - WholeUnit::Hogshead => $X!( - WholeUnit::Hogshead, "hogshead", - rational, "0.2385", // 63 gallons - (WholeUnit::Meter, 3f64) - ), - - WholeUnit::USGallon => $X!( - WholeUnit::USGallon, "gal", - rational, "0.003785411784", - (WholeUnit::Meter, 3f64) - ), - - WholeUnit::Quart => $X!( - WholeUnit::Quart, "qt", - rational, "0.000946352946", - (WholeUnit::Meter, 3f64) - ), - - WholeUnit::ImperialGallon => $X!( - WholeUnit::ImperialGallon, "impgal", - rational, "0.00454609", - (WholeUnit::Meter, 3f64) - ), - - WholeUnit::Cup => $X!( - WholeUnit::Cup, "cup", - rational, "0.0002365882365", - (WholeUnit::Meter, 3f64) - ), - - WholeUnit::Floz => $X!( - WholeUnit::Floz, "floz", - rational, "0.0000295735295625", - (WholeUnit::Meter, 3f64) - ), - - WholeUnit::Pint => $X!( - WholeUnit::Pint, "pint", - rational, "0.00056826125", - (WholeUnit::Meter, 3f64) - ), - - WholeUnit::Tablespoon => $X!( - WholeUnit::Tablespoon, "tbsp", - rational, "0.00001478676478125", - (WholeUnit::Meter, 3f64) - ), - - WholeUnit::Teaspoon => $X!( - WholeUnit::Teaspoon, "tsp", - rational, "0.000005", - (WholeUnit::Meter, 3f64) - ), - - - - // Pressure - - WholeUnit::Pascal => $X!( - WholeUnit::Pascal, "Pa", - rational, "1000", - (WholeUnit::Gram, 1f64), - (WholeUnit::Meter, -1f64), - (WholeUnit::Second, -2f64) - ), - - WholeUnit::Bar => $X!( - WholeUnit::Bar, "bar", - rational, "100000000", - (WholeUnit::Gram, 1f64), - (WholeUnit::Meter, -1f64), - (WholeUnit::Second, -2f64) - ), - - WholeUnit::Barye => $X!( - WholeUnit::Barye, "Ba", - rational, "100", - (WholeUnit::Gram, 1f64), - (WholeUnit::Meter, -1f64), - (WholeUnit::Second, -2f64) - ), - - WholeUnit::Atmosphere => $X!( - WholeUnit::Atmosphere, "atm", - rational, "101325000", - (WholeUnit::Gram, 1f64), - (WholeUnit::Meter, -1f64), - (WholeUnit::Second, -2f64) - ), - - WholeUnit::Psi => $X!( - WholeUnit::Psi, "psi", - rational, "6894757.2931783", - (WholeUnit::Gram, 1f64), - (WholeUnit::Meter, -1f64), - (WholeUnit::Second, -2f64) - ), - - WholeUnit::MillimeterMercury => $X!( - WholeUnit::MillimeterMercury, "mmHg", - rational, "133322.387415", - (WholeUnit::Gram, 1f64), - (WholeUnit::Meter, -1f64), - (WholeUnit::Second, -2f64) - ), - - WholeUnit::Torr => $X!( - WholeUnit::Torr, "torr", - rational_frac, (101325000, 760), - (WholeUnit::Gram, 1f64), - (WholeUnit::Meter, -1f64), - (WholeUnit::Second, -2f64) - ), - - WholeUnit::MeterSeaWater => $X!( - WholeUnit::MeterSeaWater, "MSW", - rational, "10000000", - (WholeUnit::Gram, 1f64), - (WholeUnit::Meter, -1f64), - (WholeUnit::Second, -2f64) - ), - - WholeUnit::FootSeaWater => $X!( - WholeUnit::FootSeaWater, "FSW", - rational, "3064330", - (WholeUnit::Gram, 1f64), - (WholeUnit::Meter, -1f64), - (WholeUnit::Second, -2f64) - ), - - } - - - } -} -pub (self) use unit_db; \ No newline at end of file +include!(concat!(env!("OUT_DIR"), "/units.rs")); \ No newline at end of file diff --git a/src/quantity/unit/prefix.rs b/src/quantity/unit/prefix.rs index 26bfa1a..7ea22cd 100644 --- a/src/quantity/unit/prefix.rs +++ b/src/quantity/unit/prefix.rs @@ -1,7 +1,6 @@ use crate::quantity::Quantity; - #[derive(Hash)] #[derive(Debug)] #[derive(Copy, Clone)] @@ -75,37 +74,6 @@ impl Prefix { } - -macro_rules! str_to_prefix { - ("") => {Prefix::None}; - ("Q") => {Prefix::Quetta}; - ("R") => {Prefix::Ronna}; - ("Y") => {Prefix::Yotta}; - ("Z") => {Prefix::Zetta}; - ("E") => {Prefix::Exa}; - ("P") => {Prefix::Peta}; - ("T") => {Prefix::Tera}; - ("G") => {Prefix::Giga}; - ("M") => {Prefix::Mega}; - ("k") => {Prefix::Kilo}; - ("h") => {Prefix::Hecto}; - ("da") => {Prefix::Deka}; - ("d") => {Prefix::Deci}; - ("c") => {Prefix::Centi}; - ("m") => {Prefix::Milli}; - ("u") => {Prefix::Micro}; - ("n") => {Prefix::Nano}; - ("p") => {Prefix::Pico}; - ("f") => {Prefix::Femto}; - ("a") => {Prefix::Atto}; - ("z") => {Prefix::Zepto}; - ("y") => {Prefix::Yocto}; - ("r") => {Prefix::Ronto}; - ("q") => {Prefix::Quecto}; -} -pub (super) use str_to_prefix; - - impl ToString for Prefix { fn to_string(&self) -> String { String::from(match self { diff --git a/src/quantity/unit/unit.rs b/src/quantity/unit/unit.rs index 48f3908..3a0e7e0 100644 --- a/src/quantity/unit/unit.rs +++ b/src/quantity/unit/unit.rs @@ -7,10 +7,7 @@ use std::ops::{ use crate::quantity::Scalar; use crate::quantity::Quantity; use super::FreeUnit; -use super::WholeUnit; -use super::Prefix; -use super::fromstring_db; -use super::str_to_prefix; +use super::freeunit_from_string; #[derive(Debug)] #[derive(Clone)] @@ -187,40 +184,8 @@ impl Unit { impl Unit { pub fn from_string(s: &str) -> Option { - macro_rules! unpack_fromstring { - ( - $( - ( - $unit:expr, - $string:literal - $(, ( - $( $prefix:tt ),* - ))? - ) - ),* - ) => { - // Build match statement for each unit and prefix - match s { - $( - // No prefix--every unit has this - $string => Some(FreeUnit::from_whole($unit)), - - // Arms for prefixes - $($( - concat!( - $prefix, - $string - ) => Some(FreeUnit::from_whole_prefix($unit, str_to_prefix!($prefix))), - )*)* - )* - _ => None - } - }; - } - - // Big match statement - let b = fromstring_db!(unpack_fromstring); + let b = freeunit_from_string(s); if b.is_none() { return None; } let b = Unit::from_free(b.unwrap()); let mut q = Quantity::new_rational(1f64).unwrap();