Some fixes. Rewrite to use decl macro. History repeats.

master
elfeiin 2024-05-04 20:51:08 -07:00
parent 95897ac5fd
commit 95084f3b8c
Signed by: elfein
GPG Key ID: A53FDD4FD091A276
7 changed files with 594 additions and 707 deletions

View File

@ -1,9 +1,4 @@
[package]
name = "unidades"
version = "1.1.0"
version = "1.1.1"
edition = "2021"
[build-dependencies]
quote = "1.0"
proc-macro2 = "1.0"
map-macro = "0.3.0"

404
build.rs
View File

@ -1,404 +0,0 @@
#![allow(non_upper_case_globals)]
use proc_macro2::TokenStream;
use quote::{
format_ident,
quote,
};
use std::collections::HashMap;
use std::env;
use std::fs::File;
use std::io::Write;
use std::path::Path;
use map_macro::hash_map;
struct Dimension {
name: &'static str,
units: Vec<(&'static str, (f64, f64))>,
}
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)),
("Century", (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)),
("Inch", (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)),
("SqInch", (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))],
},
}
}
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
}
}
});
}
}
(dimension_decls, unit_decls)
}
fn gen_prefixes() -> TokenStream {
let mut prefix_decls = quote!{
use std::marker::PhantomData;
};
for (
nym,
scale,
) in [
("Quetta", 1e30),
("Ronna", 1e27),
("Yotta", 1e24),
("Zetta", 1e21),
("Exa", 1e18),
("Peta", 1e15),
("Tetra", 1e12),
("Giga", 1e9),
("Mega", 1e6),
("Kilo", 1e3),
("Hecto", 1e2),
("Deca", 1e1),
("Deci", 1e-1),
("Centi", 1e-2),
("Milli", 1e-3),
("Micro", 1e-6),
("Nano", 1e-9),
("Pico", 1e-12),
("Femto", 1e-15),
("Atto", 1e-18),
("Zepto", 1e-21),
("Yocto", 1e-24),
("Ronto", 1e-27),
("Quecto", 1e-30),
] {
let ident = format_ident!["{nym}"];
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()
}
}
});
}
prefix_decls
}
fn main() {
let out_dir = env::var_os("OUT_DIR").unwrap();
let dest_path = Path::new(&out_dir).join("units.rs");
let mut code = quote!{
pub trait Unit<D> {
fn new(v: f64) -> D;
fn scale() -> f64;
fn offset() -> f64;
}
};
let (dimensions, units) = gen_units();
let prefixes = gen_prefixes();
let modules = quote!{
pub mod prelude {
pub use crate::units::{
Gram,
Hour,
Meter,
MetersPerSecond,
MetersPerSecondPerSecond,
Second,
};
pub use crate::prefixes::{
Centi,
Kilo,
Micro,
Milli,
Nano,
};
pub use crate::{
Unit,
Measurement,
};
}
pub mod dimensions {
use crate::Measurement;
#dimensions
}
pub mod units {
use crate::{
Measurement,
Unit,
};
#units
}
pub mod prefixes {
use crate::{
Measurement,
Unit,
};
#prefixes
}
};
code.extend(modules);
File::create(&dest_path).unwrap().write_all(code.to_string().as_bytes()).unwrap();
println!["cargo:rerun-if-changed=build.rs"];
}

31
src/dimensions.rs Normal file
View File

@ -0,0 +1,31 @@
use crate::measurement::Measurement;
pub type Scalar = Measurement<0, 0, 0, 0, 0, 0, 0>;
pub type Time = Measurement<1, 0, 0, 0, 0, 0, 0>;
pub type Frequency = Measurement<-1, 0, 0, 0, 0, 0, 0>;
pub type Length = Measurement<0, 1, 0, 0, 0, 0, 0>;
pub type Area = Measurement<0, 2, 0, 0, 0, 0, 0>;
pub type Speed = Measurement<-1, 1, 0, 0, 0, 0, 0>;
pub type Acceleration = Measurement<-2, 1, 0, 0, 0, 0, 0>;
pub type Mass = Measurement<0, 0, 1, 0, 0, 0, 0>;
pub type MassPerDist = Measurement<0, -1, 1, 0, 0, 0, 0>;
pub type Density = Measurement<0, -3, 1, 0, 0, 0, 0>;
pub type MassMoment = Measurement<0, 2, 1, 0, 0, 0, 0>;
pub type Force = Measurement<-2, 1, 1, 0, 0, 0, 0>;
pub type ForceMoment = Measurement<-2, 2, 1, 0, 0, 0, 0>;
pub type Pressure = Measurement<-2, -1, 1, 0, 0, 0, 0>;
pub type Energy = Measurement<-2, 2, 1, 0, 0, 0, 0>;
pub type Power = Measurement<-3, 2, 1, 0, 0, 0, 0>;
pub type Current = Measurement<0, 0, 0, 1, 0, 0, 0>;
pub type Charge = Measurement<1, 0, 0, 1, 0, 0, 0>;
pub type Capacitance = Measurement<4, -2, -1, 1, 0, 0, 0>;
pub type Potential = Measurement<-3, -2, 1, -1, 0, 0, 0>;
pub type Resistance = Measurement<-3, 2, 1, -2, 0, 0, 0>;
pub type Conductance = Measurement<3, -2, -1, 2, 0, 0, 0>;
pub type Flux = Measurement<-2, 2, 1, -1, 0, 0, 0>;
pub type FluxDensity = Measurement<2, 0, 1, -1, 0, 0, 0>;
pub type Inductance = Measurement<-2, 2, 1, -2, 0, 0, 0>;
pub type Temperature = Measurement<0, 0, 0, 0, 1, 0, 0>;
pub type Amount = Measurement<0, 0, 0, 0, 0, 1, 0>;
pub type Catalytic = Measurement<-1, 0, 0, 0, 0, 1, 0>;
pub type Intensity = Measurement<0, 0, 0, 0, 0, 0, 1>;

View File

@ -1,301 +1,12 @@
#![feature(generic_const_exprs)]
include![concat![env!["OUT_DIR"], "/units.rs"]];
pub mod dimensions;
pub mod units;
pub mod prefixes;
pub mod measurement;
use std::ops::{
Add,
Div,
Mul,
Sub,
};
#[derive(Copy, Clone, Debug)]
pub struct Measurement<
const TIME: i8,
const LENGTH: i8,
const MASS: i8,
const CURRENT: i8,
const TEMPERATURE: i8,
const AMOUNT: i8,
const INTENSITY: i8,
>(
pub 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())
}
pub fn square(self) -> Self {
Self(self.0.powf(2.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,
> 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 TIME: i8,
const LENGTH: i8,
const MASS: i8,
const CURRENT: i8,
const TEMPERATURE: i8,
const AMOUNT: i8,
const INTENSITY: i8,
> Mul<f64> for Measurement<TIME, LENGTH, MASS, CURRENT, TEMPERATURE, AMOUNT, INTENSITY>
where
Self: Sized {
type Output = Self;
fn mul(self, rhs: f64) -> Self::Output {
Self(self.0 * rhs)
}
}
impl<
const TIME: i8,
const LENGTH: i8,
const MASS: i8,
const CURRENT: i8,
const TEMPERATURE: i8,
const AMOUNT: i8,
const INTENSITY: i8,
> Mul<Measurement<TIME, LENGTH, MASS, CURRENT, TEMPERATURE, AMOUNT, INTENSITY>> for f64
where
Measurement<TIME, LENGTH, MASS, CURRENT, TEMPERATURE, AMOUNT, INTENSITY>: Sized {
type Output = Measurement<TIME, LENGTH, MASS, CURRENT, TEMPERATURE, AMOUNT, INTENSITY>;
fn mul(self, rhs: Measurement<TIME, LENGTH, MASS, CURRENT, TEMPERATURE, AMOUNT, INTENSITY>) -> Self::Output {
Measurement::<TIME, LENGTH, MASS, CURRENT, TEMPERATURE, AMOUNT, INTENSITY>(self * 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,
> Div<f64> for Measurement<TIME, LENGTH, MASS, CURRENT, TEMPERATURE, AMOUNT, INTENSITY>
where
Self: Sized {
type Output = Self;
fn div(self, rhs: f64) -> Self::Output {
Self(self.0 / rhs)
}
}
impl<
const TIME: i8,
const LENGTH: i8,
const MASS: i8,
const CURRENT: i8,
const TEMPERATURE: i8,
const AMOUNT: i8,
const INTENSITY: i8,
> Div<Measurement<TIME, LENGTH, MASS, CURRENT, TEMPERATURE, AMOUNT, INTENSITY>> for f64
where
Measurement<TIME, LENGTH, MASS, CURRENT, TEMPERATURE, AMOUNT, INTENSITY>: Sized {
type Output = Measurement<TIME, LENGTH, MASS, CURRENT, TEMPERATURE, AMOUNT, INTENSITY>;
fn div(self, rhs: Measurement<TIME, LENGTH, MASS, CURRENT, TEMPERATURE, AMOUNT, INTENSITY>) -> Self::Output {
Measurement::<TIME, LENGTH, MASS, CURRENT, TEMPERATURE, AMOUNT, INTENSITY>(self * 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)
}
pub trait Unit<D> {
fn new(v: f64) -> D;
fn scale() -> f64;
fn offset() -> f64;
}

298
src/measurement.rs Normal file
View File

@ -0,0 +1,298 @@
use std::ops::{
Add,
Div,
Mul,
Sub,
};
use crate::Unit;
#[derive(Copy, Clone, Debug)]
pub struct Measurement<
const TIME: i8,
const LENGTH: i8,
const MASS: i8,
const CURRENT: i8,
const TEMPERATURE: i8,
const AMOUNT: i8,
const INTENSITY: i8,
>(
pub 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())
}
pub fn square(self) -> Self {
Self(self.0.powf(2.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,
> 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 TIME: i8,
const LENGTH: i8,
const MASS: i8,
const CURRENT: i8,
const TEMPERATURE: i8,
const AMOUNT: i8,
const INTENSITY: i8,
> Mul<f64> for Measurement<TIME, LENGTH, MASS, CURRENT, TEMPERATURE, AMOUNT, INTENSITY>
where
Self: Sized {
type Output = Self;
fn mul(self, rhs: f64) -> Self::Output {
Self(self.0 * rhs)
}
}
impl<
const TIME: i8,
const LENGTH: i8,
const MASS: i8,
const CURRENT: i8,
const TEMPERATURE: i8,
const AMOUNT: i8,
const INTENSITY: i8,
> Mul<Measurement<TIME, LENGTH, MASS, CURRENT, TEMPERATURE, AMOUNT, INTENSITY>> for f64
where
Measurement<TIME, LENGTH, MASS, CURRENT, TEMPERATURE, AMOUNT, INTENSITY>: Sized {
type Output = Measurement<TIME, LENGTH, MASS, CURRENT, TEMPERATURE, AMOUNT, INTENSITY>;
fn mul(self, rhs: Measurement<TIME, LENGTH, MASS, CURRENT, TEMPERATURE, AMOUNT, INTENSITY>) -> Self::Output {
Measurement::<TIME, LENGTH, MASS, CURRENT, TEMPERATURE, AMOUNT, INTENSITY>(self * 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,
> Div<f64> for Measurement<TIME, LENGTH, MASS, CURRENT, TEMPERATURE, AMOUNT, INTENSITY>
where
Self: Sized {
type Output = Self;
fn div(self, rhs: f64) -> Self::Output {
Self(self.0 / rhs)
}
}
impl<
const TIME: i8,
const LENGTH: i8,
const MASS: i8,
const CURRENT: i8,
const TEMPERATURE: i8,
const AMOUNT: i8,
const INTENSITY: i8,
> Div<Measurement<TIME, LENGTH, MASS, CURRENT, TEMPERATURE, AMOUNT, INTENSITY>> for f64
where
Measurement<TIME, LENGTH, MASS, CURRENT, TEMPERATURE, AMOUNT, INTENSITY>: Sized {
type Output = Measurement<TIME, LENGTH, MASS, CURRENT, TEMPERATURE, AMOUNT, INTENSITY>;
fn div(self, rhs: Measurement<TIME, LENGTH, MASS, CURRENT, TEMPERATURE, AMOUNT, INTENSITY>) -> Self::Output {
Measurement::<TIME, LENGTH, MASS, CURRENT, TEMPERATURE, AMOUNT, INTENSITY>(self * 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)
}
}

76
src/prefixes.rs Normal file
View File

@ -0,0 +1,76 @@
use crate::{
Unit,
measurement::Measurement,
};
use core::marker::PhantomData;
macro_rules! prefixes{
($(($nym: ident, $scale: expr)), *) => {
$(
pub struct $nym < 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 $nym < T > {
fn new(v: f64) -> Measurement < TIME,
LENGTH,
MASS,
CHARGE,
TEMPERATURE,
AMOUNT,
INTENSITY > {
Measurement::new::<Self>(v)
}
fn scale() -> f64 {
$scale * T:: scale()
}
fn offset() -> f64 {
T::offset()
}
}
) *
};
}
prefixes!{
(Quetta, 1e30),
(Ronna, 1e27),
(Yotta, 1e24),
(Zetta, 1e21),
(Exa, 1e18),
(Peta, 1e15),
(Tetra, 1e12),
(Giga, 1e9),
(Mega, 1e6),
(Kilo, 1e3),
(Hecto, 1e2),
(Deca, 1e1),
(Deci, 1e-1),
(Centi, 1e-2),
(Milli, 1e-3),
(Micro, 1e-6),
(Nano, 1e-9),
(Pico, 1e-12),
(Femto, 1e-15),
(Atto, 1e-18),
(Zepto, 1e-21),
(Yocto, 1e-24),
(Ronto, 1e-27),
(Quecto, 1e-30)
}

180
src/units.rs Normal file
View File

@ -0,0 +1,180 @@
use crate::{
Unit,
dimensions::*,
};
const YEAR: f64 = 31_557_600.0;
const DAY: f64 = 60.0 * 60.0 * 24.0;
macro_rules! unit{
($dimension: ident => $(($nym: ident, ($scale: expr, $offset: expr))), *) => {
$(pub struct $nym; impl Unit < $dimension > for $nym {
fn new(v: f64) -> $dimension {
$dimension:: new::< Self >(v)
}
fn scale() -> f64 {
$scale
}
fn offset() -> f64 {
$offset
}
}) *
};
}
unit!{
Scalar =>
}
unit!{
Time =>(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)),
(Century, (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))
}
unit!{
Frequency =>(Hertz, (1.0, 0.0)),
(Rpm, (1.0 / 60.0, 0.0))
}
unit!{
Length =>(Meter, (1.0, 0.0)),
(Planck, (1.6e-35, 0.0)),
(Yard, (0.9144, 0.0)),
(Feet, (0.3048, 0.0)),
(Inch, (0.0254, 0.0)),
(Angstrom, (10e-10, 0.0))
}
unit!{
Area =>(SqMeter, (1.0, 0.0)),
(SqPlanck, (1.6e-35, 0.0)),
(SqYard, (0.9144, 0.0)),
(SqInch, (0.0254, 0.0)),
(SqAngstrom, (1e-10, 0.0))
}
unit!{
Speed =>(MetersPerSecond, (1.0, 0.0)),
(Kmph, (3_600.0, 0.0)),
(Mph, (2_237.0, 0.0))
}
unit!{
Acceleration =>(MetersPerSecondPerSecond, (1.0, 0.0)),
(Gee, (9.80665, 0.0))
}
unit!{
Mass =>(Gram, (1e-03, 0.0))
}
unit!{
MassPerDist =>(KgPerMeter, (1.0, 0.0))
}
unit!{
Density =>(KgPerCubicMeter, (1.0, 0.0))
}
unit!{
MassMoment =>(KgSqMeter, (1.0, 0.0))
}
unit!{
Force =>(Newton, (1.0, 0.0))
}
unit!{
ForceMoment =>(NewtonMeter, (1.0, 0.0))
}
unit!{
Pressure =>(Pascal, (1.0, 0.0))
}
unit!{
Energy =>(Joule, (1.0, 0.0)),
(Watthour, (3600.0, 0.0))
}
unit!{
Power =>(Watt, (1.0, 0.0))
}
unit!{
Current =>(Amp, (1.0, 0.0))
}
unit!{
Charge =>(Coulomb, (1.0, 0.0))
}
unit!{
Potential =>(Volt, (1.0, 0.0))
}
unit!{
Capacitance =>(Farad, (1.0, 0.0))
}
unit!{
Resistance =>(Ohm, (1.0, 0.0))
}
unit!{
Conductance =>(Siemen, (1.0, 0.0))
}
unit!{
Flux =>(Weber, (1.0, 0.0))
}
unit!{
FluxDensity =>(Tesla, (1.0, 0.0))
}
unit!{
Inductance =>(Henry, (1.0, 0.0))
}
unit!{
Amount =>
}
unit!{
Catalytic =>(Katal, (1.0, 0.0))
}
unit!{
Temperature =>(Kelvin, (1.0, 0.0)),
(Celsius, (1.0, 273.15)),
(Fahrenheit, (5.0 / 9.0, 459.67))
}
unit!{
Intensity =>
}