complete rewrite

master
elfeiin 2024-04-27 21:39:55 -07:00
parent b4f08b7ead
commit 5da5d770d9
Signed by: elfein
GPG Key ID: A53FDD4FD091A276
3 changed files with 558 additions and 593 deletions

View File

@ -6,3 +6,4 @@ edition = "2021"
[build-dependencies]
quote = "1.0"
proc-macro2 = "1.0"
map-macro = "0.3.0"

923
build.rs
View File

@ -1,149 +1,280 @@
#![allow(non_upper_case_globals)]
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use quote::{
format_ident,
quote,
};
use std::collections::HashMap;
use std::env;
use std::fs::File;
use std::io::Write;
use std::ops::{Add, Div, Mul, Sub};
use std::path::Path;
use map_macro::hash_map;
#[derive(Default, Hash, Eq, PartialEq, PartialOrd, Ord, Clone, Copy)]
pub struct Matrix([i8; 7]);
struct Dimension {
name: &'static str,
units: Vec<(&'static str, (f64, f64))>,
}
impl Mul<i8> for Matrix {
type Output = Matrix;
fn mul(self, rhs: i8) -> Self::Output {
let mut output = Matrix::default();
for (i, v) in self.0.iter().enumerate() {
output.0[i] = v * rhs;
}
output
mod matricies {
pub const Scalar: [i8; 7] = [0, 0, 0, 0, 0, 0, 0];
pub const Time: [i8; 7] = [1, 0, 0, 0, 0, 0, 0];
pub const Frequency: [i8; 7] = [-1, 0, 0, 0, 0, 0, 0];
pub const Length: [i8; 7] = [0, 1, 0, 0, 0, 0, 0];
pub const Area: [i8; 7] = [0, 2, 0, 0, 0, 0, 0];
pub const Speed: [i8; 7] = [-1, 1, 0, 0, 0, 0, 0];
pub const Acceleration: [i8; 7] = [-2, 1, 0, 0, 0, 0, 0];
pub const Mass: [i8; 7] = [0, 0, 1, 0, 0, 0, 0];
pub const MassPerDist: [i8; 7] = [0, -1, 1, 0, 0, 0, 0];
pub const Density: [i8; 7] = [0, -3, 1, 0, 0, 0, 0];
pub const MassMoment: [i8; 7] = [0, 2, 1, 0, 0, 0, 0];
pub const Force: [i8; 7] = [-2, 1, 1, 0, 0, 0, 0];
pub const ForceMoment: [i8; 7] = [-2, 2, 1, 0, 0, 0, 0];
pub const Pressure: [i8; 7] = [-2, -1, 1, 0, 0, 0, 0];
pub const Energy: [i8; 7] = [-2, 2, 1, 0, 0, 0, 0];
pub const Power: [i8; 7] = [-3, 2, 1, 0, 0, 0, 0];
pub const Current: [i8; 7] = [0, 0, 0, 1, 0, 0, 0];
pub const Charge: [i8; 7] = [1, 0, 0, 1, 0, 0, 0];
pub const Capacitance: [i8; 7] = [4, -2, -1, 1, 0, 0, 0];
pub const Potential: [i8; 7] = [-3, -2, 1, -1, 0, 0, 0];
pub const Resistance: [i8; 7] = [-3, 2, 1, -2, 0, 0, 0];
pub const Conductance: [i8; 7] = [3, -2, -1, 2, 0, 0, 0];
pub const Flux: [i8; 7] = [-2, 2, 1, -1, 0, 0, 0];
pub const FluxDensity: [i8; 7] = [2, 0, 1, -1, 0, 0, 0];
pub const Inductance: [i8; 7] = [-2, 2, 1, -2, 0, 0, 0];
pub const Temperature: [i8; 7] = [0, 0, 0, 0, 1, 0, 0];
pub const Amount: [i8; 7] = [0, 0, 0, 0, 0, 1, 0];
pub const Catalytic: [i8; 7] = [-1, 0, 0, 0, 0, 1, 0];
pub const Intensity: [i8; 7] = [0, 0, 0, 0, 0, 0, 1];
}
fn gen_units_list() -> HashMap<[i8; 7], Dimension> {
use matricies::*;
const YEAR: f64 = 31_557_600.0;
const DAY: f64 = 60.0 * 60.0 * 24.0;
hash_map!{
Scalar => Dimension {
name: "Scalar",
units: vec![],
},
Time => Dimension {
name: "Time",
units:
vec![
("Second", (1.0, 0.0)),
("Kalpa", (YEAR * 1e9 * 4.32, 0.0)),
("Eon", (YEAR * 1e9, 0.0)),
("GalacticYear", (YEAR * 2.3e8, 0.0)),
("Age", (YEAR * (2148.0 + 1.0 / 3.0), 0.0)),
("Millenium", (YEAR * 1000.0, 0.0)),
("Centurie", (YEAR * 100.0, 0.0)),
("Jubilee", (YEAR * 50.0, 0.0)),
("Indiction", (YEAR * 15.0, 0.0)),
("Decade", (YEAR * 10.0, 0.0)),
("Lustrum", (YEAR * 5.0, 0.0)),
("Olympiad", (YEAR * 4.0, 0.0)),
("LeapYear", (YEAR + DAY, 0.0)),
("LunarYear", (DAY * 354.37, 0.0)),
("Semester", (DAY * 7.0 * 18.0, 0.0)),
("Quarantine", (DAY * 40.0, 0.0)),
("Month", (DAY * 30.0, 0.0)),
("Fortnight", (DAY * 7.0, 0.0)),
("Week", (60.0e2 * 24.0 * 7.0, 0.0)),
("Milliday", (DAY * 0.001, 0.0)),
("Day", (60.0e2 * 24.0, 0.0)),
("Hour", (60.0e2, 0.0)),
("Minute", (60.0, 0.0)),
("Jiffy", (3e-24, 0.0)),
("Shake", (1e-08, 0.0)),
("PlanckTime", (5.39e-44, 0.0))
]
},
Frequency => Dimension {
name: "Frequency",
units: vec![("Hertz", (1.0, 0.0)), ("Rpm", (1.0 / 60.0, 0.0))],
},
Length => Dimension {
name: "Length",
units:
vec![
("Meter", (1.0, 0.0)),
("Planck", (1.6e-35, 0.0)),
("Yard", (0.9144, 0.0)),
("Feet", (0.3048, 0.0)),
("Inche", (0.0254, 0.0)),
("Angstrom", (10e-10, 0.0))
],
},
Area => Dimension {
name: "Area",
units:
vec![
("SqMeter", (1.0, 0.0)),
("SqPlanck", (1.6e-35, 0.0)),
("SqYard", (0.9144, 0.0)),
("SqInche", (0.0254, 0.0)),
("SqAngstrom", (1e-10, 0.0))
],
},
Speed => Dimension {
name: "Speed",
units: vec![("MetersPerSecond", (1.0, 0.0)), ("Kmph", (3_600.0, 0.0)), ("Mph", (2_237.0, 0.0))],
},
Acceleration => Dimension {
name: "Acceleration",
units: vec![("MetersPerSecondPerSecond", (1.0, 0.0)), ("Gee", (9.80665, 0.0))],
},
Mass => Dimension {
name: "Mass",
units: vec![("Gram", (1e-03, 0.0))],
},
MassPerDist => Dimension {
name: "MassPerDist",
units: vec![("KgPerMeter", (1.0, 0.0))],
},
Density => Dimension {
name: "Density",
units: vec![("KgPerCubicMeter", (1.0, 0.0))],
},
MassMoment => Dimension {
name: "MassMoment",
units: vec![("KgSqMeter", (1.0, 0.0))],
},
Force => Dimension {
name: "Force",
units: vec![("Newton", (1.0, 0.0))],
},
ForceMoment => Dimension {
name: "ForceMoment",
units: vec![("NewtonMeter", (1.0, 0.0))],
},
Pressure => Dimension {
name: "Pressure",
units: vec![("Pascal", (1.0, 0.0))],
},
Energy => Dimension {
name: "Energy",
units: vec![("Joule", (1.0, 0.0)), ("Watthour", (3600.0, 0.0))],
},
Power => Dimension {
name: "Power",
units: vec![("Watt", (1.0, 0.0))],
},
Current => Dimension {
name: "Current",
units: vec![("Amp", (1.0, 0.0))],
},
Charge => Dimension {
name: "Charge",
units: vec![("Coulomb", (1.0, 0.0))],
},
Potential => Dimension {
name: "Potential",
units: vec![("Volt", (1.0, 0.0))],
},
Capacitance => Dimension {
name: "Capacitance",
units: vec![("Farad", (1.0, 0.0))],
},
Resistance => Dimension {
name: "Resistance",
units: vec![("Ohm", (1.0, 0.0))],
},
Conductance => Dimension {
name: "Conductance",
units: vec![("Siemen", (1.0, 0.0))],
},
Flux => Dimension {
name: "Flux",
units: vec![("Weber", (1.0, 0.0))],
},
FluxDensity => Dimension {
name: "FluxDensity",
units: vec![("Tesla", (1.0, 0.0))],
},
Inductance => Dimension {
name: "Inductance",
units: vec![("Henry", (1.0, 0.0))],
},
Catalytic => Dimension {
name: "Catalytic",
units: vec![("Katal", (1.0, 0.0))],
},
Temperature => Dimension {
name: "Temperature",
units: vec![("Kelvin", (1.0, 0.0)), ("Celsius", (1.0, 273.15)), ("Fahrenheit", (5.0 / 9.0, 459.67))],
},
}
}
impl Div<i8> for Matrix {
type Output = Matrix;
fn div(self, rhs: i8) -> Self::Output {
let mut output = Matrix::default();
for (i, v) in self.0.iter().enumerate() {
output.0[i] = v / rhs;
}
output
}
}
impl Add for Matrix {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
let mut output = Matrix::default();
for (i, (a, b)) in self.0.iter().zip(&rhs.0).enumerate() {
output.0[i] = a + b;
}
output
}
}
impl Sub for Matrix {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
let mut output = Matrix::default();
for (i, (a, b)) in self.0.iter().zip(&rhs.0).enumerate() {
output.0[i] = a - b;
}
output
}
}
fn impl_convert(dimension: &str) -> TokenStream {
let dim_ident = format_ident!["{dimension}"];
if dimension == "Scalar" {
quote! {
pub fn new(v: f64) -> Self {
Self(v)
}
pub fn val(self) -> f64 {
self.0
}
}
} else {
quote! {
pub fn new<T: Scale<#dim_ident>>(v: f64) -> Self {
Self(v * T::scale().0 + T::scale().1)
}
pub fn val<T: Scale<#dim_ident>>(self) -> f64 {
(self.0 - T::scale().1) / T::scale().0
}
}
}
}
fn impl_simple_traits(unit: &str) -> TokenStream {
let unit = format_ident!["{unit}"];
quote! {
impl Add for #unit {
type Output = #unit;
fn add(self, rhs: #unit) -> Self::Output {
#unit(self.0 + rhs.0)
}
}
impl Sub for #unit {
type Output = #unit;
fn sub(self, rhs: #unit) -> Self::Output {
#unit(self.0 - rhs.0)
}
}
}
}
fn impl_mul(lhs: &str, rhs: &str, output: &str) -> TokenStream {
let lhs = format_ident!["{lhs}"];
let rhs = format_ident!["{rhs}"];
let output = format_ident!["{output}"];
quote! {
impl Mul<#rhs> for #lhs {
type Output = #output;
fn mul(self, rhs: #rhs) -> Self::Output {
#output(self.0 * rhs.0)
}
}
}
}
fn impl_div(lhs: &str, rhs: &str, output: &str) -> TokenStream {
let lhs = format_ident!["{lhs}"];
let rhs = format_ident!["{rhs}"];
let output = format_ident!["{output}"];
quote! {
impl Div<#rhs> for #lhs {
type Output = #output;
fn div(self, rhs: #rhs) -> Self::Output {
#output(self.0 / rhs.0)
}
}
}
}
fn gen_unit_structs(units_list: &[(&str, (f64, f64))], dimension: &str) -> TokenStream {
let dim_ident = format_ident!["{dimension}"];
let mut units = quote! {};
for (nym, (scale, offset)) in units_list {
let ident = format_ident!["{nym}"];
units.extend(quote! {
pub struct #ident;
impl Scale<#dim_ident> for #ident {
fn scale() -> (f64, f64) {
(#scale, #offset)
fn gen_units() -> (TokenStream, TokenStream) {
let dimensions = gen_units_list();
let mut dimension_decls = quote!{
};
let mut unit_decls = quote!{
};
for (matrix, Dimension { name: basename, units }) in dimensions.iter() {
let time = matrix[0];
let length = matrix[0];
let mass = matrix[0];
let current = matrix[0];
let temperature = matrix[0];
let amount = matrix[0];
let intensity = matrix[0];
let unit_type = quote!{
Measurement < #time,
#length,
#mass,
#current,
#temperature,
#amount,
#intensity >
};
let unit_type_path = quote!{
Measurement::< #time,
#length,
#mass,
#current,
#temperature,
#amount,
#intensity >
};
let basename_ident = format_ident!["{basename}"];
dimension_decls.extend(quote!{
pub type #basename_ident = #unit_type;
});
for (unit_nym, (scale, offset)) in units {
let ident = format_ident!["{unit_nym}"];
unit_decls.extend(quote!{
pub struct #ident;
impl Unit < #unit_type > for #ident {
fn new(v: f64) -> #unit_type {
#unit_type_path:: new::< Self >(v)
}
fn scale() -> f64 {
#scale
}
fn offset() -> f64 {
#offset
}
}
}
})
});
}
}
units
(dimension_decls, unit_decls)
}
fn gen_prefixes() -> TokenStream {
let mut prefixes = quote! {};
for (nym, scale) in [
let mut prefix_decls = quote!{
use std::marker::PhantomData;
};
for (
nym,
scale,
) in [
("Quetta", 1e30),
("Ronna", 1e27),
("Yotta", 1e24),
@ -170,485 +301,93 @@ fn gen_prefixes() -> TokenStream {
("Quecto", 1e-30),
] {
let ident = format_ident!["{nym}"];
prefixes.extend(quote! {
pub struct #ident<T>(PhantomData<T>);
impl<T: Scale<D>, D> Scale<D> for #ident<T> {
fn scale() -> (f64, f64) {
(#scale * T::scale().0, T::scale().1)
prefix_decls.extend(quote!{
pub struct #ident < T >(PhantomData < T >);
impl < const TIME: i8,
const LENGTH: i8,
const MASS: i8,
const CHARGE: i8,
const TEMPERATURE: i8,
const AMOUNT: i8,
const INTENSITY: i8,
T: Unit < Measurement < TIME,
LENGTH,
MASS,
CHARGE,
TEMPERATURE,
AMOUNT,
INTENSITY >>,
> Unit < Measurement < TIME,
LENGTH,
MASS,
CHARGE,
TEMPERATURE,
AMOUNT,
INTENSITY >> for #ident < T > {
fn new(v: f64) -> Measurement < TIME,
LENGTH,
MASS,
CHARGE,
TEMPERATURE,
AMOUNT,
INTENSITY > {
Measurement::<TIME, LENGTH, MASS, CHARGE, TEMPERATURE, AMOUNT, INTENSITY>::new::<Self>(v)
}
fn scale() -> f64 {
#scale * T:: scale()
}
fn offset() -> f64 {
T::offset()
}
}
});
}
prefixes
}
struct Dimension {
basename: &'static str,
conversions: Vec<(&'static str, (f64, f64))>,
prefix_decls
}
fn main() {
let out_dir = env::var_os("OUT_DIR").unwrap();
let dest_path = Path::new(&out_dir).join("units.rs");
let dimensions: HashMap<Matrix, Dimension> = gen_units_list();
let mut code = quote! {
pub trait Scale<D> {
fn scale() -> (f64, f64);
let mut code = quote!{
pub trait Unit<D> {
fn new(v: f64) -> D;
fn scale() -> f64;
fn offset() -> f64;
}
};
let prefixes = gen_prefixes();
let prefixes_mod = quote! {
pub mod prefixes {
use crate::Scale;
use core::marker::PhantomData;
#prefixes
}
};
code.extend(prefixes_mod);
let mut dims_mod = quote! {};
let mut units_mod = quote! {};
for (
matrix,
Dimension {
basename,
conversions: subunits,
},
) in dimensions.iter()
{
let basename_ident = format_ident!["{basename}"];
let decl = quote! {
#[derive(Copy, Clone, Debug, Default)]
pub struct #basename_ident(f64);
impl Mul<f64> for #basename_ident {
type Output = Self;
fn mul(self, rhs: f64) -> Self::Output {
Self(self.0 * rhs)
}
}
impl Mul<#basename_ident> for f64 {
type Output = #basename_ident;
fn mul(self, rhs: #basename_ident) -> Self::Output {
#basename_ident(self * rhs.0)
}
}
impl Div<f64> for #basename_ident {
type Output = Self;
fn div(self, rhs: f64) -> Self::Output {
Self(self.0 / rhs)
}
}
impl Div<#basename_ident> for f64 {
type Output = #basename_ident;
fn div(self, rhs: #basename_ident) -> Self::Output {
#basename_ident(self * rhs.0)
}
}
};
dims_mod.extend(decl);
let mut exponentiation = quote! {};
for (method_name, n) in [
("square", 2),
("cube", 3),
("square_root", -2),
("cube_root", -3),
] {
if n == 0 {
continue;
}
let matrix = if n > 0 {
*matrix * n
} else {
if matrix.0.iter().fold(false, |a, v| a || (v % n.abs() != 0)) {
continue;
}
*matrix / n.abs()
let (dimensions, units) = gen_units();
let modules = quote!{
pub mod prelude {
pub use crate::units::{
Gram,
Hour,
Meter,
MetersPerSecond,
MetersPerSecondPerSecond,
Second,
};
pub use crate::{
Centi,
Kilo,
Micro,
Milli,
Nano,
};
if let Some(derived) = dimensions.get(&matrix) {
let ident = format_ident!["{method_name}"];
let derived_ident = format_ident!["{}", derived.basename];
exponentiation.extend(if n > 0 {
quote! {
pub fn #ident(self) -> #derived_ident {
#derived_ident(self.0.powf(#n.abs() as f64))
}
}
} else {
quote! {
pub fn #ident(self) -> #derived_ident {
#derived_ident(self.0.powf(1.0 / (#n.abs() as f64)))
}
}
});
}
}
let mut conversion = quote! {};
conversion.extend(impl_convert(basename));
dims_mod.extend(quote! {
impl #basename_ident {
#exponentiation
#conversion
}
});
dims_mod.extend(impl_simple_traits(basename));
if let Some(derived) = dimensions.get(&(*matrix + *matrix)) {
dims_mod.extend(impl_mul(basename, basename, derived.basename));
}
if let Some(derived) = dimensions.get(&(*matrix - *matrix)) {
dims_mod.extend(impl_div(basename, basename, derived.basename));
}
for (
other_matrix,
Dimension {
basename: other_basename,
..
},
) in dimensions.iter()
{
if matrix == other_matrix {
continue;
}
if let Some(derived) = dimensions.get(&(*matrix + *other_matrix)) {
dims_mod.extend(impl_mul(basename, other_basename, derived.basename));
}
if let Some(derived) = dimensions.get(&(*matrix - *other_matrix)) {
dims_mod.extend(impl_div(basename, other_basename, derived.basename));
}
}
let submod_ident = format_ident!["{}", basename.to_lowercase()];
let unit_structs = gen_unit_structs(subunits, basename);
units_mod.extend(quote! {
pub mod #submod_ident {
use crate::Scale;
use crate::dimensions::#basename_ident;
#unit_structs
}
pub use #submod_ident::*;
});
}
code.extend(quote! {
pub mod dimensions {
use crate::Scale;
use std::ops::{Add, Div, Mul, Sub};
#dims_mod
use crate::Measurement;
#dimensions
}
pub mod units {
#units_mod
use crate::{
Measurement,
Unit,
};
#units
}
});
File::create(&dest_path)
.unwrap()
.write_all(code.to_string().as_bytes())
.unwrap();
};
code.extend(modules);
code.extend(gen_prefixes());
File::create(&dest_path).unwrap().write_all(code.to_string().as_bytes()).unwrap();
println!["cargo:rerun-if-changed=build.rs"];
}
#[rustfmt::skip]
mod matricies {
use super::Matrix;
pub const Scalar: Matrix = Matrix([ 0, 0, 0, 0, 0, 0, 0]);
pub const Time: Matrix = Matrix([ 1, 0, 0, 0, 0, 0, 0]);
pub const Frequency: Matrix = Matrix([-1, 0, 0, 0, 0, 0, 0]);
pub const Tempoflux: Matrix = Matrix([-2, 0, 0, 0, 0, 0, 0]);
pub const Length: Matrix = Matrix([ 0, 1, 0, 0, 0, 0, 0]);
pub const Area: Matrix = Matrix([ 0, 2, 0, 0, 0, 0, 0]);
pub const Speed: Matrix = Matrix([-1, 1, 0, 0, 0, 0, 0]);
pub const SquareSpeed: Matrix = Matrix([-2, 2, 0, 0, 0, 0, 0]);
pub const Acceleration: Matrix = Matrix([-2, 1, 0, 0, 0, 0, 0]);
pub const Mass: Matrix = Matrix([ 0, 0, 1, 0, 0, 0, 0]);
pub const MassPerSqTime: Matrix = Matrix([-2, 0, 1, 0, 0, 0, 0]);
pub const MassPerDist: Matrix = Matrix([ 0,-1, 1, 0, 0, 0, 0]);
pub const Dispersion: Matrix = Matrix([ 0,-2, 1, 0, 0, 0, 0]);
pub const Density: Matrix = Matrix([ 0,-3, 1, 0, 0, 0, 0]);
pub const MassMoment: Matrix = Matrix([ 0, 2, 1, 0, 0, 0, 0]);
pub const Force: Matrix = Matrix([-2, 1, 1, 0, 0, 0, 0]);
pub const ForceMoment: Matrix = Matrix([-2, 2, 1, 0, 0, 0, 0]);
pub const Pressure: Matrix = Matrix([-2,-1, 1, 0, 0, 0, 0]);
pub const Energy: Matrix = Matrix([-2, 2, 1, 0, 0, 0, 0]);
pub const Power: Matrix = Matrix([-3, 2, 1, 0, 0, 0, 0]);
pub const Current: Matrix = Matrix([ 0, 0, 0, 1, 0, 0, 0]);
pub const Charge: Matrix = Matrix([ 1, 0, 0, 1, 0, 0, 0]);
pub const Capacitance: Matrix = Matrix([ 4,-2,-1, 1, 0, 0, 0]);
pub const Potential: Matrix = Matrix([-3,-2, 1,-1, 0, 0, 0]);
pub const Resistance: Matrix = Matrix([-3, 2, 1,-2, 0, 0, 0]);
pub const Conductance: Matrix = Matrix([ 3,-2,-1, 2, 0, 0, 0]);
pub const Flux: Matrix = Matrix([-2, 2, 1,-1, 0, 0, 0]);
pub const FluxDensity: Matrix = Matrix([ 2, 0, 1,-1, 0, 0, 0]);
pub const Inductance: Matrix = Matrix([-2, 2, 1,-2, 0, 0, 0]);
pub const Temperature: Matrix = Matrix([ 0, 0, 0, 0, 1, 0, 0]);
pub const Amount: Matrix = Matrix([ 0, 0, 0, 0, 0, 1, 0]);
pub const Catalytic: Matrix = Matrix([-1, 0, 0, 0, 0, 1, 0]);
pub const Intensity: Matrix = Matrix([ 0, 0, 0, 0, 0, 0, 1]);
}
use matricies::*;
fn gen_units_list() -> HashMap<Matrix, Dimension> {
let mut output = HashMap::new();
const YEAR: f64 = 31_557_600.0;
const DAY: f64 = 60.0 * 60.0 * 24.0;
output.insert(
Scalar,
Dimension {
basename: "Scalar",
conversions: vec![],
},
);
output.insert(
Time,
Dimension {
basename: "Time",
conversions: vec![
("Seconds", (1.0, 0.0)),
("Kalpas", (YEAR * 1e9 * 4.32, 0.0)),
("Eons", (YEAR * 1e9, 0.0)),
("GalacticYears", (YEAR * 2.3e8, 0.0)),
("Ages", (YEAR * (2148.0 + 1.0 / 3.0), 0.0)),
("Milleniums", (YEAR * 1000.0, 0.0)),
("Centuries", (YEAR * 100.0, 0.0)),
("Jubilees", (YEAR * 50.0, 0.0)),
("Indictions", (YEAR * 15.0, 0.0)),
("Decades", (YEAR * 10.0, 0.0)),
("Lustrums", (YEAR * 5.0, 0.0)),
("Olympiads", (YEAR * 4.0, 0.0)),
("LeapYears", (YEAR + DAY, 0.0)),
("LunarYears", (DAY * 354.37, 0.0)),
("Semesters", (DAY * 7.0 * 18.0, 0.0)),
("Quarantines", (DAY * 40.0, 0.0)),
("Months", (DAY * 30.0, 0.0)),
("Fortnights", (DAY * 7.0, 0.0)),
("Weeks", (60.0e2 * 24.0 * 7.0, 0.0)),
("Millidays", (DAY * 0.001, 0.0)),
("Days", (60.0e2 * 24.0, 0.0)),
("Hours", (60.0e2, 0.0)),
("Minutes", (60.0, 0.0)),
("Jiffys", (3e-24, 0.0)),
("Shakes", (1e-08, 0.0)),
("PlanckTimes", (5.39e-44, 0.0)),
],
},
);
output.insert(
Frequency,
Dimension {
basename: "Frequency",
conversions: vec![("Hertz", (1.0, 0.0)), ("Rpm", (1.0 / 60.0, 0.0))],
},
);
output.insert(
Tempoflux,
Dimension {
basename: "Tempoflux",
conversions: vec![("SqHertz", (1.0, 0.0))],
},
);
output.insert(
Length,
Dimension {
basename: "Length",
conversions: vec![
("Meters", (1.0, 0.0)),
("Plancks", (1.6e-35, 0.0)),
("Yards", (0.9144, 0.0)),
("Feet", (0.3048, 0.0)),
("Inches", (0.0254, 0.0)),
("Angstroms", (10e-10, 0.0)),
],
},
);
output.insert(
Area,
Dimension {
basename: "Area",
conversions: vec![
("SqMeters", (1.0, 0.0)),
("SqPlancks", (1.6e-35, 0.0)),
("SqYards", (0.9144, 0.0)),
("SqInches", (0.0254, 0.0)),
("SqAngstroms", (1e-10, 0.0)),
],
},
);
output.insert(
Speed,
Dimension {
basename: "Speed",
conversions: vec![
("MetersPerSecond", (1.0, 0.0)),
("Kmph", (3_600.0, 0.0)),
("Mph", (2_237.0, 0.0)),
],
},
);
output.insert(
SquareSpeed,
Dimension {
basename: "SquareSpeed",
conversions: vec![("SqMetersPerSqTime", (2_237.0, 0.0))],
},
);
output.insert(
Acceleration,
Dimension {
basename: "Acceleration",
conversions: vec![("MetersPerSqTime", (1.0, 0.0)), ("Gees", (9.80665, 0.0))],
},
);
output.insert(
Mass,
Dimension {
basename: "Mass",
conversions: vec![("Grams", (1e-03, 0.0))],
},
);
output.insert(
MassPerSqTime,
Dimension {
basename: "MassPerSqTime",
conversions: vec![("GramsPerS2", (1e-03, 0.0))],
},
);
output.insert(
MassPerDist,
Dimension {
basename: "MassPerDist",
conversions: vec![("KgPerMeter", (1.0, 0.0))],
},
);
output.insert(
Dispersion,
Dimension {
basename: "Dispersion",
conversions: vec![("KgPerSqMeter", (1.0, 0.0))],
},
);
output.insert(
Density,
Dimension {
basename: "Density",
conversions: vec![("KgPerCubicMeter", (1.0, 0.0))],
},
);
output.insert(
MassMoment,
Dimension {
basename: "MassMoment",
conversions: vec![("KgSqMeters", (1.0, 0.0))],
},
);
output.insert(
Force,
Dimension {
basename: "Force",
conversions: vec![("Newtons", (1.0, 0.0))],
},
);
output.insert(
ForceMoment,
Dimension {
basename: "ForceMoment",
conversions: vec![("NewtonMeters", (1.0, 0.0))],
},
);
output.insert(
Pressure,
Dimension {
basename: "Pressure",
conversions: vec![("Pascals", (1.0, 0.0))],
},
);
output.insert(
Energy,
Dimension {
basename: "Energy",
conversions: vec![("Joules", (1.0, 0.0)), ("Watthours", (3600.0, 0.0))],
},
);
output.insert(
Power,
Dimension {
basename: "Power",
conversions: vec![("Watts", (1.0, 0.0))],
},
);
output.insert(
Current,
Dimension {
basename: "Current",
conversions: vec![("Amps", (1.0, 0.0))],
},
);
output.insert(
Charge,
Dimension {
basename: "Charge",
conversions: vec![("Coulombs", (1.0, 0.0))],
},
);
output.insert(
Potential,
Dimension {
basename: "Potential",
conversions: vec![("Volts", (1.0, 0.0))],
},
);
output.insert(
Capacitance,
Dimension {
basename: "Capacitance",
conversions: vec![("Farads", (1.0, 0.0))],
},
);
output.insert(
Resistance,
Dimension {
basename: "Resistance",
conversions: vec![("Ohms", (1.0, 0.0))],
},
);
output.insert(
Conductance,
Dimension {
basename: "Conductance",
conversions: vec![("Siemens", (1.0, 0.0))],
},
);
output.insert(
Flux,
Dimension {
basename: "Flux",
conversions: vec![("Webers", (1.0, 0.0))],
},
);
output.insert(
FluxDensity,
Dimension {
basename: "FluxDensity",
conversions: vec![("Teslas", (1.0, 0.0))],
},
);
output.insert(
Inductance,
Dimension {
basename: "Inductance",
conversions: vec![("Henrys", (1.0, 0.0))],
},
);
output.insert(
Catalytic,
Dimension {
basename: "Catalytic",
conversions: vec![("Katals", (1.0, 0.0))],
},
);
output.insert(
Temperature,
Dimension {
basename: "Temperature",
conversions: vec![
("Kelvin", (1.0, 0.0)),
("Celsius", (1.0, 273.15)),
("Fahrenheit", (5.0 / 9.0, 459.67)),
],
},
);
output
}

View File

@ -1 +1,226 @@
include!(concat!(env!("OUT_DIR"), "/units.rs"));
#![feature(generic_const_exprs)]
include![concat![env!["OUT_DIR"], "/units.rs"]];
pub use units::*;
use std::ops::{
Add,
Div,
Mul,
Sub,
};
#[derive(Copy, Clone)]
pub struct Measurement<
const TIME: i8,
const LENGTH: i8,
const MASS: i8,
const CURRENT: i8,
const TEMPERATURE: i8,
const AMOUNT: i8,
const INTENSITY: i8,
>(
f64,
);
impl<
const TIME: i8,
const LENGTH: i8,
const MASS: i8,
const CURRENT: i8,
const TEMPERATURE: i8,
const AMOUNT: i8,
const INTENSITY: i8,
> Measurement<TIME, LENGTH, MASS, CURRENT, TEMPERATURE, AMOUNT, INTENSITY> {
pub fn new<U>(v: f64) -> Self
where
U: Unit<Self> {
Self(v.mul(U::scale()).add(U::offset()))
}
pub fn to_units<U>(self) -> f64
where
U: Unit<Self> {
self.0.sub(U::offset()).div(U::scale())
}
}
impl<
const A_TIME: i8,
const A_LENGTH: i8,
const A_MASS: i8,
const A_CURRENT: i8,
const A_TEMPERATURE: i8,
const A_AMOUNT: i8,
const A_INTENSITY: i8,
const B_TIME: i8,
const B_LENGTH: i8,
const B_MASS: i8,
const B_CURRENT: i8,
const B_TEMPERATURE: i8,
const B_AMOUNT: i8,
const B_INTENSITY: i8,
> Mul<
Measurement<B_TIME, B_LENGTH, B_MASS, B_CURRENT, B_TEMPERATURE, B_AMOUNT, B_INTENSITY>,
> for Measurement<A_TIME, A_LENGTH, A_MASS, A_CURRENT, A_TEMPERATURE, A_AMOUNT, A_INTENSITY>
where
Measurement<{
A_TIME + B_TIME
}, {
A_LENGTH + B_LENGTH
}, {
A_MASS + B_MASS
}, {
A_CURRENT + B_CURRENT
}, {
A_TEMPERATURE + B_TEMPERATURE
}, {
A_AMOUNT + B_AMOUNT
}, {
A_INTENSITY + B_INTENSITY
}>: Sized {
type Output = Measurement<{
A_TIME + B_TIME
}, {
A_LENGTH + B_LENGTH
}, {
A_MASS + B_MASS
}, {
A_CURRENT + B_CURRENT
}, {
A_TEMPERATURE + B_TEMPERATURE
}, {
A_AMOUNT + B_AMOUNT
}, {
A_INTENSITY + B_INTENSITY
}>;
fn mul(
self,
rhs: Measurement<B_TIME, B_LENGTH, B_MASS, B_CURRENT, B_TEMPERATURE, B_AMOUNT, B_INTENSITY>,
) -> Self::Output {
Measurement::<{
A_TIME + B_TIME
}, {
A_LENGTH + B_LENGTH
}, {
A_MASS + B_MASS
}, {
A_CURRENT + B_CURRENT
}, {
A_TEMPERATURE + B_TEMPERATURE
}, {
A_AMOUNT + B_AMOUNT
}, {
A_INTENSITY + B_INTENSITY
}>(self.0 * rhs.0)
}
}
impl<
const A_TIME: i8,
const A_LENGTH: i8,
const A_MASS: i8,
const A_CURRENT: i8,
const A_TEMPERATURE: i8,
const A_AMOUNT: i8,
const A_INTENSITY: i8,
const B_TIME: i8,
const B_LENGTH: i8,
const B_MASS: i8,
const B_CURRENT: i8,
const B_TEMPERATURE: i8,
const B_AMOUNT: i8,
const B_INTENSITY: i8,
> Div<
Measurement<B_TIME, B_LENGTH, B_MASS, B_CURRENT, B_TEMPERATURE, B_AMOUNT, B_INTENSITY>,
> for Measurement<A_TIME, A_LENGTH, A_MASS, A_CURRENT, A_TEMPERATURE, A_AMOUNT, A_INTENSITY>
where
Measurement<{
A_TIME + B_TIME
}, {
A_LENGTH + B_LENGTH
}, {
A_MASS + B_MASS
}, {
A_CURRENT + B_CURRENT
}, {
A_TEMPERATURE + B_TEMPERATURE
}, {
A_AMOUNT + B_AMOUNT
}, {
A_INTENSITY + B_INTENSITY
}>: Sized {
type Output = Measurement<{
A_TIME + B_TIME
}, {
A_LENGTH + B_LENGTH
}, {
A_MASS + B_MASS
}, {
A_CURRENT + B_CURRENT
}, {
A_TEMPERATURE + B_TEMPERATURE
}, {
A_AMOUNT + B_AMOUNT
}, {
A_INTENSITY + B_INTENSITY
}>;
fn div(
self,
rhs: Measurement<B_TIME, B_LENGTH, B_MASS, B_CURRENT, B_TEMPERATURE, B_AMOUNT, B_INTENSITY>,
) -> Self::Output {
Measurement::<{
A_TIME + B_TIME
}, {
A_LENGTH + B_LENGTH
}, {
A_MASS + B_MASS
}, {
A_CURRENT + B_CURRENT
}, {
A_TEMPERATURE + B_TEMPERATURE
}, {
A_AMOUNT + B_AMOUNT
}, {
A_INTENSITY + B_INTENSITY
}>(self.0 / rhs.0)
}
}
impl<
const TIME: i8,
const LENGTH: i8,
const MASS: i8,
const CURRENT: i8,
const TEMPERATURE: i8,
const AMOUNT: i8,
const INTENSITY: i8,
> Add for Measurement<TIME, LENGTH, MASS, CURRENT, TEMPERATURE, AMOUNT, INTENSITY>
where
Self: Sized {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self(self.0 + rhs.0)
}
}
impl<
const TIME: i8,
const LENGTH: i8,
const MASS: i8,
const CURRENT: i8,
const TEMPERATURE: i8,
const AMOUNT: i8,
const INTENSITY: i8,
> Sub for Measurement<TIME, LENGTH, MASS, CURRENT, TEMPERATURE, AMOUNT, INTENSITY>
where
Self: Sized {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Self(self.0 - rhs.0)
}
}