Added build script to generate units

This commit is contained in:
2023-06-12 15:01:44 -07:00
parent 28c1a84b80
commit 4f8ee660d7
8 changed files with 887 additions and 754 deletions

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