From 303685646476e32a52d16508d2d4e93d49be3410 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20K=C3=A4nner?= Date: Sat, 18 Feb 2023 11:10:18 +0100 Subject: [PATCH] Initial Commit --- .gitignore | 2 + Cargo.toml | 9 +++ src/lib.rs | 172 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 183 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 src/lib.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4fffb2f --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +/Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..9cc3460 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "units" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +typenum = "1.16" diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..1fd0b3d --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,172 @@ +use std::{ + marker::PhantomData, + ops::{Add, Mul}, +}; + +use typenum::consts::*; +use typenum::{op, Integer}; + +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] +pub struct SiUnit +where + Second: Integer, + Meter: Integer, + Kilogram: Integer, + Ampere: Integer, + Kelvin: Integer, + Mole: Integer, + Candela: Integer, +{ + value: T, + _s: PhantomData, + _m: PhantomData, + _kg: PhantomData, + _a: PhantomData, + _k: PhantomData, + _mol: PhantomData, + _cd: PhantomData, +} + +impl + SiUnit +where + Second: Integer, + Meter: Integer, + Kilogram: Integer, + Ampere: Integer, + Kelvin: Integer, + Mole: Integer, + Candela: Integer, +{ + pub const fn new(value: T) -> Self { + Self { + value, + _s: PhantomData, + _m: PhantomData, + _kg: PhantomData, + _a: PhantomData, + _k: PhantomData, + _mol: PhantomData, + _cd: PhantomData, + } + } +} + +impl< + T, + Second1, + Meter1, + Kilogram1, + Ampere1, + Kelvin1, + Mole1, + Candela1, + Second2, + Meter2, + Kilogram2, + Ampere2, + Kelvin2, + Mole2, + Candela2, + > Mul> + for SiUnit +where + Mole2: Integer, + Candela2: Integer, + Candela1: Integer + Add, + Mole1: Integer + Add, + Kelvin1: Integer + Add, + Ampere1: Integer + Add, + Kilogram1: Integer + Add, + Meter1: Integer + Add, + Second1: Integer + Add, + Kelvin2: Integer, + Ampere2: Integer, + Kilogram2: Integer, + Meter2: Integer, + Second2: Integer, + T: Mul, + Second1::Output: Integer, + Meter1::Output: Integer, + Kilogram1::Output: Integer, + Ampere1::Output: Integer, + Kelvin1::Output: Integer, + Mole1::Output: Integer, + Candela1::Output: Integer, +{ + type Output = SiUnit< + T::Output, + op!(Second1 + Second2), + op!(Meter1 + Meter2), + op!(Kilogram1 + Kilogram2), + op!(Ampere1 + Ampere2), + op!(Kelvin1 + Kelvin2), + op!(Mole1 + Mole2), + op!(Candela1 + Candela2), + >; + + fn mul( + self, + rhs: SiUnit, + ) -> Self::Output { + Self::Output::new(self.value * rhs.value) + } +} + +#[rustfmt::skip] +mod aliases { + use super::*; + // Base units + pub type Unit = SiUnit; + pub type Second = SiUnit; + pub type Meter = SiUnit; + pub type Kilogram = SiUnit; + pub type Ampere = SiUnit; + pub type Kelvin = SiUnit; + pub type Mole = SiUnit; + pub type Candela = SiUnit; + + // Derived units with special names + pub type Radian = Unit; + pub type Steradian = Unit; + pub type Herz = SiUnit; + pub type Newton = SiUnit; + pub type Pascal = SiUnit; + pub type Joule = SiUnit; + pub type Watt = SiUnit; + pub type Coulomb = SiUnit; + pub type Volt = SiUnit; + pub type Farad = SiUnit; + pub type Ohm = SiUnit; + pub type Siemens = SiUnit; + pub type Weber = SiUnit; + pub type Tesla = SiUnit; + pub type Henry = SiUnit; + pub type Lumen = Candela; + pub type Lux = SiUnit; + pub type Becquerel = Herz; + pub type Gray = SiUnit; + pub type Sievert = Gray; + pub type Katal = SiUnit; + + pub type SquareMeter = SiUnit; + pub type CubicMeter = SiUnit; +} +pub use aliases::*; + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn multiply() { + let m = Meter::new(2); + assert_eq!(m * m, SquareMeter::new(4)); + assert_eq!(m * m * m, CubicMeter::new(8)); + let s = Second::new(1); + let a = Ampere::new(2); + assert_eq!(s * a, Coulomb::new(2)); + let v = Volt::new(2); + assert_eq!(v * a, Watt::new(4)); + } +}