From 3e4fb93a594f11a80904653396698d6c70e07cb0 Mon Sep 17 00:00:00 2001 From: Niklas Halle Date: Sat, 31 Oct 2020 20:44:44 +0100 Subject: Initial public release --- .gitignore | 3 + Cargo.lock | 5 + Cargo.toml | 9 ++ src/README.md | 0 src/lib.rs | 99 +++++++++++++++++ src/macros.rs | 205 ++++++++++++++++++++++++++++++++++++ src/metric.rs | 137 ++++++++++++++++++++++++ src/metric/absorbed_dose.rs | 10 ++ src/metric/acceleration.rs | 10 ++ src/metric/amount_of_substance.rs | 10 ++ src/metric/area.rs | 28 +++++ src/metric/capacitance.rs | 10 ++ src/metric/catalytic_activity.rs | 10 ++ src/metric/conductance.rs | 39 +++++++ src/metric/dose_equivalent.rs | 30 ++++++ src/metric/electric_charge.rs | 10 ++ src/metric/electric_current.rs | 10 ++ src/metric/electric_potential.rs | 10 ++ src/metric/electric_resistance.rs | 10 ++ src/metric/energy.rs | 32 ++++++ src/metric/force.rs | 10 ++ src/metric/frequency.rs | 59 +++++++++++ src/metric/illuminance.rs | 10 ++ src/metric/inductance.rs | 10 ++ src/metric/length.rs | 44 ++++++++ src/metric/luminous_flux.rs | 10 ++ src/metric/luminous_intensity.rs | 10 ++ src/metric/magnetic_flux.rs | 10 ++ src/metric/magnetic_flux_density.rs | 10 ++ src/metric/mass.rs | 36 +++++++ src/metric/plane_angle.rs | 28 +++++ src/metric/power.rs | 10 ++ src/metric/pressure.rs | 28 +++++ src/metric/solid_angle.rs | 10 ++ src/metric/temperature.rs | 89 ++++++++++++++++ src/metric/time.rs | 36 +++++++ src/metric/velocity.rs | 10 ++ src/metric/volume.rs | 32 ++++++ 38 files changed, 1129 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 src/README.md create mode 100644 src/lib.rs create mode 100644 src/macros.rs create mode 100644 src/metric.rs create mode 100644 src/metric/absorbed_dose.rs create mode 100644 src/metric/acceleration.rs create mode 100644 src/metric/amount_of_substance.rs create mode 100644 src/metric/area.rs create mode 100644 src/metric/capacitance.rs create mode 100644 src/metric/catalytic_activity.rs create mode 100644 src/metric/conductance.rs create mode 100644 src/metric/dose_equivalent.rs create mode 100644 src/metric/electric_charge.rs create mode 100644 src/metric/electric_current.rs create mode 100644 src/metric/electric_potential.rs create mode 100644 src/metric/electric_resistance.rs create mode 100644 src/metric/energy.rs create mode 100644 src/metric/force.rs create mode 100644 src/metric/frequency.rs create mode 100644 src/metric/illuminance.rs create mode 100644 src/metric/inductance.rs create mode 100644 src/metric/length.rs create mode 100644 src/metric/luminous_flux.rs create mode 100644 src/metric/luminous_intensity.rs create mode 100644 src/metric/magnetic_flux.rs create mode 100644 src/metric/magnetic_flux_density.rs create mode 100644 src/metric/mass.rs create mode 100644 src/metric/plane_angle.rs create mode 100644 src/metric/power.rs create mode 100644 src/metric/pressure.rs create mode 100644 src/metric/solid_angle.rs create mode 100644 src/metric/temperature.rs create mode 100644 src/metric/time.rs create mode 100644 src/metric/velocity.rs create mode 100644 src/metric/volume.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3d5af4d --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.idea/ +.vscode/ +target/ diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..250e506 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,5 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "units" +version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..9d9235e --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "units" +version = "0.1.0" +authors = [ + "Constantin Mauf-Clausen ", + "Stefan Zabka ", + "Niklas Halle " +] +edition = "2018" \ No newline at end of file diff --git a/src/README.md b/src/README.md new file mode 100644 index 0000000..e69de29 diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..b3a8853 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,99 @@ +mod macros; +pub mod metric; + +#[cfg(test)] +mod tests { + use crate::metric::*; + use crate::metric::Mass; + use crate::metric::Time; + use crate::metric::Force; + use crate::metric::Length; + use crate::metric::Pressure; + use crate::metric::CelsiusTemperature; + + /* + use crate::metric::Unit; + use crate::metric::Primitive; + */ + + fn avg_force(ds: Length, dt: Time, m: Mass) -> Force { + let dv = ds / dt; + let a = dv / dt; + m * a + } + + fn main() { + let dist = Mile(100.0); + let time = Minute(12.5); + let mass = Pound(800.0); + let force = avg_force(dist, time, mass); + let area = Litre(100.0) / Foot(5.0); + + let result = match Bar(0.0).to_si_unit() { + Pressure::Base(_, from_si, symbol) => format!("{}[{}]", from_si((force / area).to_si_primitive()), symbol), + _ => panic!("not base") + }; + + println!( + "Force on body with mass {m} that moves {d} in {t}: {f}\n\ + The pressure per {a} is {p}", + d = dist, t = time, m = mass, f = force, a = area, p = result + ); + } + + #[test] + fn it_works() { + println!(); + main(); + + println!(); + let single = Kilogram(1.0); + let mut double = single; + double *= 2.0; + let mut dived = double; + dived /= 2.0; + + println!("single: {}", single); + println!("double: {}", double); + println!("single * 2.0: {}", single * 2.0); + println!("2.0 * single: {}", 2.0 * single); + println!("double / 2.0: {}", double / 2.0); + println!("dived: {}", dived); + + println!("single + double: {}", single + double); + + println!(); + let gram = Gram(1000.0); + println!("gram: {}", gram); + println!("gram * 2.0: {}", gram * 2.0); + + println!(); + println!("gram + double = {}", gram + double); + println!("double + gram = {}", double + gram); + println!("gram - double = {}", gram - double); + println!("double - gram = {}", double - gram); + + println!(); + let k = Kelvin(20.0); + let c = Celsius(0.0) + k; + println!("{}", c); + + println!(); + let cel = Celsius(20.0); + let fah = match Fahrenheit(0.0).to_si_unit() { + CelsiusTemperature::Base(_, from_si, symbol) => CelsiusTemperature::Base(cel.to_si_primitive(), from_si, symbol), + _ => panic!("non si after to_si() call") + }; + println!("{} = {}", cel, fah); + + println!(); + let d = Degree(180.0); + let rad = Radian(0.0); + println!("{}", (rad + d).to_si_primitive() - std::f64::consts::PI); + + println!(); + let e = Kilocalorie(70.0); + let j = KiloJoule(0.0) + e; + println!("{} = {}", e, j); + } +} \ No newline at end of file diff --git a/src/macros.rs b/src/macros.rs new file mode 100644 index 0000000..f6925a0 --- /dev/null +++ b/src/macros.rs @@ -0,0 +1,205 @@ +#[macro_export] +macro_rules! declare_simple_unit { + ($unit_enum:ident, $si_unit:ident, $si_symbol:literal) => { + #[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] + pub enum $unit_enum { + Base(f64, fn(f64) -> f64, &'static str), + Canonical(f64), + $si_unit(f64) + } + + impl Unit<$unit_enum> for $unit_enum { + fn to_si_unit(&self) -> $unit_enum { + match self { + $unit_enum::Base(_, _, _) => self.clone(), + $unit_enum::Canonical(value) => $unit_enum::Base(value.clone(), |x| x, $si_symbol), + $unit_enum::$si_unit(value) => $unit_enum::Base(value.clone(), |x| x, $si_symbol), + } + } + } + + declare_unit_basics!($unit_enum); + }; +} + +#[macro_export] +macro_rules! declare_unit_basics { + ($unit_enum:ident) => { + impl Primitive for $unit_enum { + fn to_si_primitive(&self) -> f64 { + match self.to_si_unit() { + $unit_enum::Base(value, _, _) => value, + _ => panic!("non si unit post to_si_unit() call"), + } + } + } + + impl Add for $unit_enum { + type Output = $unit_enum; + + fn add(self, rhs: Self) -> Self::Output { + match self.to_si_unit() { + $unit_enum::Base(value, from_si, symbol) => $unit_enum::Base(value + rhs.to_si_primitive(), from_si, symbol), + _ => panic!("non si unit post to_si_unit() call"), + } + } + } + + impl AddAssign for $unit_enum { + fn add_assign(&mut self, rhs: Self) { + match self.to_si_unit() { + $unit_enum::Base(value, from_si, symbol) => *self = $unit_enum::Base(value + rhs.to_si_primitive(), from_si, symbol), + _ => panic!("non si unit post to_si_unit() call"), + } + } + } + + impl Sub for $unit_enum { + type Output = $unit_enum; + + fn sub(self, rhs: Self) -> Self::Output { + match self.to_si_unit() { + $unit_enum::Base(value, from_si, symbol) => $unit_enum::Base(value - rhs.to_si_primitive(), from_si, symbol), + _ => panic!("non si unit post to_si_unit() call"), + } + } + } + + impl SubAssign for $unit_enum { + fn sub_assign(&mut self, rhs: Self) { + match self.to_si_unit() { + $unit_enum::Base(value, from_si, symbol) => *self = $unit_enum::Base(value - rhs.to_si_primitive(), from_si, symbol), + _ => panic!("non si unit post to_si_unit() call"), + } + } + } + + impl Mul<$unit_enum> for f64 { + type Output = $unit_enum; + + fn mul(self, rhs: $unit_enum) -> Self::Output { + match rhs.to_si_unit() { + $unit_enum::Base(value, from_si, symbol) => $unit_enum::Base(self * value, from_si, symbol), + _ => panic!("non si unit post to_si_unit() call"), + } + } + } + + impl Mul for $unit_enum { + type Output = $unit_enum; + + fn mul(self, rhs: f64) -> Self::Output { + match self.to_si_unit() { + $unit_enum::Base(value, from_si, symbol) => $unit_enum::Base(value * rhs, from_si, symbol), + _ => panic!("non si unit post to_si_unit() call"), + } + } + } + + impl MulAssign for $unit_enum { + fn mul_assign(&mut self, rhs: f64) { + match self.to_si_unit() { + $unit_enum::Base(value, from_si, symbol) => *self = $unit_enum::Base(rhs * value, from_si, symbol), + _ => panic!("non si unit post to_si_unit() call"), + } + } + } + + impl Div for $unit_enum { + type Output = $unit_enum; + + fn div(self, rhs: f64) -> Self::Output { + match self.to_si_unit() { + $unit_enum::Base(value, from_si, symbol) => $unit_enum::Base(value / rhs, from_si, symbol), + _ => panic!("non si unit post to_si_unit() call"), + } + } + } + + impl DivAssign for $unit_enum { + fn div_assign(&mut self, rhs: f64) { + match self.to_si_unit() { + $unit_enum::Base(value, from_si, symbol) => *self = $unit_enum::Base(value / rhs, from_si, symbol), + _ => panic!("non si unit post to_si_unit() call"), + } + } + } + + impl Div<$unit_enum> for $unit_enum { + type Output = f64; + + fn div(self, rhs: $unit_enum) -> Self::Output { + self.to_si_primitive() / rhs.to_si_primitive() + } + } + + impl Display for $unit_enum { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + match self.to_si_unit() { + $unit_enum::Base(value, from_si, symbol) => write!(f, "{}[{}]", from_si(value), symbol), + _ => panic!("Display: non si unit post to_si_unit() call"), + } + } + } + + pub use $unit_enum::*; + }; +} + +#[macro_export] +macro_rules! declare_unit_square { + ($base:ident, $product:ident) => { + impl Mul<$base> for $base { + type Output = $product; + + fn mul(self, rhs: $base) -> Self::Output { + $product::Canonical(self.to_si_primitive() * rhs.to_si_primitive()) + } + } + + impl Div<$base> for $product { + type Output = $base; + + fn div(self, rhs: $base) -> Self::Output { + $base::Canonical(self.to_si_primitive() / rhs.to_si_primitive()) + } + } + }; +} + +#[macro_export] +macro_rules! declare_unit_multiplication { + ($factor_a:ident, $factor_b:ident, $product:ident) => { + impl Mul<$factor_a> for $factor_b { + type Output = $product; + + fn mul(self, rhs: $factor_a) -> Self::Output { + $product::Canonical(self.to_si_primitive() * rhs.to_si_primitive()) + } + } + + impl Mul<$factor_b> for $factor_a { + type Output = $product; + + fn mul(self, rhs: $factor_b) -> Self::Output { + $product::Canonical(self.to_si_primitive() * rhs.to_si_primitive()) + } + } + + impl Div<$factor_a> for $product { + type Output = $factor_b; + + fn div(self, rhs: $factor_a) -> Self::Output { + $factor_b::Canonical(self.to_si_primitive() / rhs.to_si_primitive()) + } + } + + impl Div<$factor_b> for $product { + type Output = $factor_a; + + fn div(self, rhs: $factor_b) -> Self::Output { + $factor_a::Canonical(self.to_si_primitive() / rhs.to_si_primitive()) + } + } + }; +} \ No newline at end of file diff --git a/src/metric.rs b/src/metric.rs new file mode 100644 index 0000000..209c31c --- /dev/null +++ b/src/metric.rs @@ -0,0 +1,137 @@ +pub mod area; +pub mod mass; +pub mod time; +pub mod force; +pub mod power; +pub mod energy; +pub mod length; +pub mod volume; +pub mod pressure; +pub mod velocity; +pub mod frequency; +pub mod inductance; +pub mod capacitance; +pub mod conductance; +pub mod illuminance; +pub mod plane_angle; +pub mod solid_angle; +pub mod temperature; +pub mod acceleration; +pub mod absorbed_dose; +pub mod luminous_flux; +pub mod magnetic_flux; +pub mod electric_charge; +pub mod dose_equivalent; +pub mod electric_current; +pub mod catalytic_activity; +pub mod electric_potential; +pub mod luminous_intensity; +pub mod electric_resistance; +pub mod amount_of_substance; +pub mod magnetic_flux_density; + +pub use area::*; +pub use mass::*; +pub use time::*; +pub use force::*; +pub use power::*; +pub use energy::*; +pub use length::*; +pub use volume::*; +pub use pressure::*; +pub use velocity::*; +pub use frequency::*; +pub use inductance::*; +pub use capacitance::*; +pub use illuminance::*; +pub use plane_angle::*; +pub use solid_angle::*; +pub use temperature::*; +pub use acceleration::*; +pub use luminous_flux::*; +pub use magnetic_flux::*; +pub use electric_charge::*; +pub use dose_equivalent::*; +pub use electric_current::*; +pub use catalytic_activity::*; +pub use electric_potential::*; +pub use luminous_intensity::*; +pub use electric_resistance::*; +pub use amount_of_substance::*; +pub use magnetic_flux_density::*; + +use crate::declare_unit_square; +use crate::declare_unit_multiplication; + +use std::ops::{Div, Mul}; + +/* ---------------------------------------- unit traits ---------------------------------------- */ + +pub trait Unit { + fn to_si_unit(&self) -> Physical; +} + +pub trait Primitive { + fn to_si_primitive(&self) -> f64; +} + +/* -------------------------------------- here be dragons -------------------------------------- */ +/* (unit-interoperability) */ + + +// derived units without special names +// m * m² => m³ +declare_unit_multiplication!(Length, Area, Volume); +// m * m => m² +declare_unit_square!(Length, Area); +// v = m/s * s => m +declare_unit_multiplication!(Velocity, Time, Length); +// accel * s = m/s² * s = m/s => v +declare_unit_multiplication!(Acceleration, Time, Velocity); + +// kg * m/s² => N +declare_unit_multiplication!(Mass, Acceleration, Force); +// N * m => J +declare_unit_multiplication!(Force, Length, Energy); +// katal * s = mol/s * s => mol +declare_unit_multiplication!(CatalyticActivity, Time, AmountOfSubstance); +// A * s => C +declare_unit_multiplication!(ElectricCurrent, Time, ElectricCharge); +// lux = lm/m² * m² => lm +declare_unit_multiplication!(Illuminance, Area, LuminousFlux); + +// Pa * m² = N/m² * m² => N +declare_unit_multiplication!(Pressure, Area, Force); +// W * s = J/s * s => J +declare_unit_multiplication!(Power, Time, Energy); +// Wb * s = V/s * s => V +declare_unit_multiplication!(MagneticFlux, Time, ElectricPotential); +// F * V = C/V * V => C +declare_unit_multiplication!(Capacitance, ElectricPotential, ElectricCharge); +// cd * sr => lumen +declare_unit_multiplication!(LuminousIntensity, SolidAngle, LuminousFlux); + +// gray * kg = J/kg * kg => J +// alias is DoseEquivalent, see below +// Activity is an alias to Frequency, which has both Hertz and Becquerel +// henry * A = Wb/A * A => Wb +declare_unit_multiplication!(Inductance, ElectricCurrent, MagneticFlux); +// V * A = W/A * A => W +declare_unit_multiplication!(ElectricPotential, ElectricCurrent, Power); +// Ω * A = V/A * A => V +declare_unit_multiplication!(ElectricResistance, ElectricCurrent, ElectricPotential); + +// sievert * kg = J/kg * kg => J +declare_unit_multiplication!(DoseEquivalent, Mass, Energy); +// Hertz is in its file +// tesla * m² = Wb/m² * m² => Wb +declare_unit_multiplication!(MagneticFluxDensity, Area, MagneticFlux); +// Conductance is in its file + +// extra conversions, because they work : TODO: add some more +// Hz * m = m/s => v +declare_unit_multiplication!(Frequency, Length, Velocity); +// Pa * m² = N/m² * m³ = N*m => J +declare_unit_multiplication!(Pressure, Volume, Energy); +// C * V = A*s * W/A = W/s = J/s * 1/s => J +declare_unit_multiplication!(ElectricCharge, ElectricPotential, Energy); \ No newline at end of file diff --git a/src/metric/absorbed_dose.rs b/src/metric/absorbed_dose.rs new file mode 100644 index 0000000..41ef508 --- /dev/null +++ b/src/metric/absorbed_dose.rs @@ -0,0 +1,10 @@ +use std::fmt::{Display, Formatter, Result}; +use std::ops::{Add, Sub, AddAssign, SubAssign, Div, Mul, DivAssign, MulAssign}; + +use crate::metric::Unit; +use crate::metric::Primitive; + +use crate::declare_unit_basics; +use crate::declare_simple_unit; + +declare_simple_unit!(AbsorbedDose, Gray, "Gy"); \ No newline at end of file diff --git a/src/metric/acceleration.rs b/src/metric/acceleration.rs new file mode 100644 index 0000000..3b3d50a --- /dev/null +++ b/src/metric/acceleration.rs @@ -0,0 +1,10 @@ +use std::fmt::{Display, Formatter, Result}; +use std::ops::{Add, Sub, AddAssign, SubAssign, Div, Mul, DivAssign, MulAssign}; + +use crate::metric::Unit; +use crate::metric::Primitive; + +use crate::declare_unit_basics; +use crate::declare_simple_unit; + +declare_simple_unit!(Acceleration, Accel, "m/s²"); \ No newline at end of file diff --git a/src/metric/amount_of_substance.rs b/src/metric/amount_of_substance.rs new file mode 100644 index 0000000..34058c7 --- /dev/null +++ b/src/metric/amount_of_substance.rs @@ -0,0 +1,10 @@ +use std::fmt::{Display, Formatter, Result}; +use std::ops::{Add, Sub, AddAssign, SubAssign, Div, Mul, DivAssign, MulAssign}; + +use crate::metric::Unit; +use crate::metric::Primitive; + +use crate::declare_unit_basics; +use crate::declare_simple_unit; + +declare_simple_unit!(AmountOfSubstance, Mole, "mol"); \ No newline at end of file diff --git a/src/metric/area.rs b/src/metric/area.rs new file mode 100644 index 0000000..eb2b0c3 --- /dev/null +++ b/src/metric/area.rs @@ -0,0 +1,28 @@ +use std::fmt::{Display, Formatter, Result}; +use std::ops::{Add, Sub, AddAssign, SubAssign, Div, Mul, DivAssign, MulAssign}; + +use crate::metric::Unit; +use crate::metric::Primitive; + +use crate::declare_unit_basics; + +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +pub enum Area { + Base(f64, fn(f64) -> f64, &'static str), + Canonical(f64), + SquareMeter(f64), + SquareMetre(f64), +} + +impl Unit for Area { + fn to_si_unit(&self) -> Area { + match self { + Area::Base(_, _, _) => self.clone(), + Area::Canonical(value) => Area::Base(value.clone(), |x| x, "m²"), + Area::SquareMeter(value) => Area::Base(value.clone(), |x| x, "m²"), + Area::SquareMetre(value) => Area::Base(value.clone(), |x| x, "m²"), + } + } +} + +declare_unit_basics!(Area); \ No newline at end of file diff --git a/src/metric/capacitance.rs b/src/metric/capacitance.rs new file mode 100644 index 0000000..a98c203 --- /dev/null +++ b/src/metric/capacitance.rs @@ -0,0 +1,10 @@ +use std::fmt::{Display, Formatter, Result}; +use std::ops::{Add, Sub, AddAssign, SubAssign, Div, Mul, DivAssign, MulAssign}; + +use crate::metric::Unit; +use crate::metric::Primitive; + +use crate::declare_unit_basics; +use crate::declare_simple_unit; + +declare_simple_unit!(Capacitance, Farad, "F"); \ No newline at end of file diff --git a/src/metric/catalytic_activity.rs b/src/metric/catalytic_activity.rs new file mode 100644 index 0000000..710a87a --- /dev/null +++ b/src/metric/catalytic_activity.rs @@ -0,0 +1,10 @@ +use std::fmt::{Display, Formatter, Result}; +use std::ops::{Add, Sub, AddAssign, SubAssign, Div, Mul, DivAssign, MulAssign}; + +use crate::metric::Unit; +use crate::metric::Primitive; + +use crate::declare_unit_basics; +use crate::declare_simple_unit; + +declare_simple_unit!(CatalyticActivity, Katal, "kat"); \ No newline at end of file diff --git a/src/metric/conductance.rs b/src/metric/conductance.rs new file mode 100644 index 0000000..29712e0 --- /dev/null +++ b/src/metric/conductance.rs @@ -0,0 +1,39 @@ +use std::fmt::{Display, Formatter, Result}; +use std::ops::{Add, Sub, AddAssign, SubAssign, Div, Mul, DivAssign, MulAssign}; + +use crate::metric::Unit; +use crate::metric::Primitive; + +use crate::declare_unit_basics; +use crate::declare_simple_unit; + +use crate::metric::electric_resistance::ElectricResistance; + +declare_simple_unit!(Conductance, Siemens, "S"); + +// 1/s = Hz +impl Div for f64 { + type Output = Conductance; + + fn div(self, rhs: ElectricResistance) -> Self::Output { + Conductance::Canonical(self * rhs.to_si_primitive()) + } +} + +// Hz * s = 1 +impl Mul for Conductance { + type Output = f64; + + fn mul(self, rhs: ElectricResistance) -> Self::Output { + self.to_si_primitive() * rhs.to_si_primitive() + } +} + +// s * Hz = 1 +impl Mul for ElectricResistance { + type Output = f64; + + fn mul(self, rhs: Conductance) -> Self::Output { + self.to_si_primitive() * rhs.to_si_primitive() + } +} \ No newline at end of file diff --git a/src/metric/dose_equivalent.rs b/src/metric/dose_equivalent.rs new file mode 100644 index 0000000..408c7de --- /dev/null +++ b/src/metric/dose_equivalent.rs @@ -0,0 +1,30 @@ +use std::fmt::{Display, Formatter, Result}; +use std::ops::{Add, Sub, AddAssign, SubAssign, Div, Mul, DivAssign, MulAssign}; + +use crate::metric::Unit; +use crate::metric::Primitive; + +use crate::declare_unit_basics; + +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +pub enum DoseEquivalent { + Base(f64, fn(f64) -> f64, &'static str), + Canonical(f64), + Sievert(f64), + Gray(f64), +} + +impl Unit for DoseEquivalent { + fn to_si_unit(&self) -> DoseEquivalent { + match self { + DoseEquivalent::Base(_, _, _) => self.clone(), + DoseEquivalent::Canonical(value) => DoseEquivalent::Base(value.clone(), |x| x, "Sv"), + DoseEquivalent::Sievert(value) => DoseEquivalent::Base(value.clone(), |x| x, "Sv"), + DoseEquivalent::Gray(value) => DoseEquivalent::Base(value.clone(), |x| x, "Gy"), + } + } +} + +declare_unit_basics!(DoseEquivalent); + +pub type AbsorbedDose = DoseEquivalent; \ No newline at end of file diff --git a/src/metric/electric_charge.rs b/src/metric/electric_charge.rs new file mode 100644 index 0000000..9e6e970 --- /dev/null +++ b/src/metric/electric_charge.rs @@ -0,0 +1,10 @@ +use std::fmt::{Display, Formatter, Result}; +use std::ops::{Add, Sub, AddAssign, SubAssign, Div, Mul, DivAssign, MulAssign}; + +use crate::metric::Unit; +use crate::metric::Primitive; + +use crate::declare_unit_basics; +use crate::declare_simple_unit; + +declare_simple_unit!(ElectricCharge, Coulomb, "C"); \ No newline at end of file diff --git a/src/metric/electric_current.rs b/src/metric/electric_current.rs new file mode 100644 index 0000000..376e426 --- /dev/null +++ b/src/metric/electric_current.rs @@ -0,0 +1,10 @@ +use std::fmt::{Display, Formatter, Result}; +use std::ops::{Add, Sub, AddAssign, SubAssign, Div, Mul, DivAssign, MulAssign}; + +use crate::metric::Unit; +use crate::metric::Primitive; + +use crate::declare_unit_basics; +use crate::declare_simple_unit; + +declare_simple_unit!(ElectricCurrent, Ampere, "A"); \ No newline at end of file diff --git a/src/metric/electric_potential.rs b/src/metric/electric_potential.rs new file mode 100644 index 0000000..9fdbde8 --- /dev/null +++ b/src/metric/electric_potential.rs @@ -0,0 +1,10 @@ +use std::fmt::{Display, Formatter, Result}; +use std::ops::{Add, Sub, AddAssign, SubAssign, Div, Mul, DivAssign, MulAssign}; + +use crate::metric::Unit; +use crate::metric::Primitive; + +use crate::declare_unit_basics; +use crate::declare_simple_unit; + +declare_simple_unit!(ElectricPotential, Volt, "V"); \ No newline at end of file diff --git a/src/metric/electric_resistance.rs b/src/metric/electric_resistance.rs new file mode 100644 index 0000000..3d3d9f8 --- /dev/null +++ b/src/metric/electric_resistance.rs @@ -0,0 +1,10 @@ +use std::fmt::{Display, Formatter, Result}; +use std::ops::{Add, Sub, AddAssign, SubAssign, Div, Mul, DivAssign, MulAssign}; + +use crate::metric::Unit; +use crate::metric::Primitive; + +use crate::declare_unit_basics; +use crate::declare_simple_unit; + +declare_simple_unit!(ElectricResistance, Ohm, "Ω"); \ No newline at end of file diff --git a/src/metric/energy.rs b/src/metric/energy.rs new file mode 100644 index 0000000..5884a2f --- /dev/null +++ b/src/metric/energy.rs @@ -0,0 +1,32 @@ +use std::fmt::{Display, Formatter, Result}; +use std::ops::{Add, Sub, AddAssign, SubAssign, Div, Mul, DivAssign, MulAssign}; + +use crate::metric::Unit; +use crate::metric::Primitive; + +use crate::declare_unit_basics; + +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +pub enum Energy { + Base(f64, fn(f64) -> f64, &'static str), + Canonical(f64), + Joule(f64), + KiloJoule(f64), + Calorie(f64), + Kilocalorie(f64), +} + +impl Unit for Energy { + fn to_si_unit(&self) -> Energy { + match self { + Energy::Base(_, _, _) => self.clone(), + Energy::Canonical(value) => Energy::Base(value.clone(), |x| x, "J"), + Energy::Joule(value) => Energy::Base(value.clone(), |x| x, "J"), + Energy::KiloJoule(value) => Energy::Base(value * 1000.0, |x| x / 1000.0, "kJ"), + Energy::Calorie(value) => Energy::Base(value * 4.184, |x| x / 4.184, "cal"), + Energy::Kilocalorie(value) => Energy::Base(value * 4184.0, |x| x / 4184.0, "kcal"), + } + } +} + +declare_unit_basics!(Energy); \ No newline at end of file diff --git a/src/metric/force.rs b/src/metric/force.rs new file mode 100644 index 0000000..5011ce6 --- /dev/null +++ b/src/metric/force.rs @@ -0,0 +1,10 @@ +use std::fmt::{Display, Formatter, Result}; +use std::ops::{Add, Sub, AddAssign, SubAssign, Div, Mul, DivAssign, MulAssign}; + +use crate::metric::Unit; +use crate::metric::Primitive; + +use crate::declare_unit_basics; +use crate::declare_simple_unit; + +declare_simple_unit!(Force, Newton, "N"); \ No newline at end of file diff --git a/src/metric/frequency.rs b/src/metric/frequency.rs new file mode 100644 index 0000000..c35f874 --- /dev/null +++ b/src/metric/frequency.rs @@ -0,0 +1,59 @@ +use std::fmt::{Display, Formatter, Result}; +use std::ops::{Add, Sub, AddAssign, SubAssign, Div, Mul, DivAssign, MulAssign}; + +use crate::metric::Unit; +use crate::metric::Primitive; + +use crate::declare_unit_basics; + +use crate::metric::time::Time; + +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +pub enum Frequency { + Base(f64, fn(f64) -> f64, &'static str), + Canonical(f64), + Hertz(f64), + Becquerel(f64), +} + +impl Unit for Frequency { + fn to_si_unit(&self) -> Frequency { + match self { + Frequency::Base(_, _, _) => self.clone(), + Frequency::Canonical(value) => Frequency::Base(value.clone(), |x| x, "Hz"), + Frequency::Hertz(value) => Frequency::Base(value.clone(), |x| x, "Hz"), + Frequency::Becquerel(value) => Frequency::Base(value.clone(), |x| x, "Bq"), + } + } +} + +declare_unit_basics!(Frequency); + +// 1/s = Hz +impl Div