Added build script to generate units

pull/2/head
Mark 2023-06-12 15:01:44 -07:00
parent 28c1a84b80
commit 4f8ee660d7
Signed by: Mark
GPG Key ID: AD62BB059C2AAEE4
8 changed files with 887 additions and 754 deletions

87
Cargo.lock generated
View File

@ -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",
]

View File

@ -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"
rug = "1.19.2"
[build-dependencies]
toml = "0.7.4"

257
buildscript/main.rs Normal file
View File

@ -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<Value>) {
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<Value>) {
writeln!(file,
concat!(
"impl WholeUnit {{\n",
"\tfn base_factor(&self) -> Option<Quantity> {{\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<Value>) {
writeln!(file,
concat!(
"#[inline(always)]\n",
"fn freeunit_from_string(s: &str) -> Option<FreeUnit> {{\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::<Table>().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(());
}

530
buildscript/units.toml Normal file
View File

@ -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} ]

View File

@ -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

View File

@ -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;
include!(concat!(env!("OUT_DIR"), "/units.rs"));

View File

@ -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 {

View File

@ -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<Quantity> {
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();