Initial Commit

This commit is contained in:
Max Känner 2023-02-18 11:10:18 +01:00
commit 3036856464
3 changed files with 183 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/target
/Cargo.lock

9
Cargo.toml Normal file
View File

@ -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"

172
src/lib.rs Normal file
View File

@ -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<T, Second, Meter, Kilogram, Ampere, Kelvin, Mole, Candela>
where
Second: Integer,
Meter: Integer,
Kilogram: Integer,
Ampere: Integer,
Kelvin: Integer,
Mole: Integer,
Candela: Integer,
{
value: T,
_s: PhantomData<Second>,
_m: PhantomData<Meter>,
_kg: PhantomData<Kilogram>,
_a: PhantomData<Ampere>,
_k: PhantomData<Kelvin>,
_mol: PhantomData<Mole>,
_cd: PhantomData<Candela>,
}
impl<T, Second, Meter, Kilogram, Ampere, Kelvin, Mole, Candela>
SiUnit<T, Second, Meter, Kilogram, Ampere, Kelvin, Mole, Candela>
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<SiUnit<T, Second1, Meter1, Kilogram1, Ampere1, Kelvin1, Mole1, Candela1>>
for SiUnit<T, Second2, Meter2, Kilogram2, Ampere2, Kelvin2, Mole2, Candela2>
where
Mole2: Integer,
Candela2: Integer,
Candela1: Integer + Add<Candela2>,
Mole1: Integer + Add<Mole2>,
Kelvin1: Integer + Add<Kelvin2>,
Ampere1: Integer + Add<Ampere2>,
Kilogram1: Integer + Add<Kilogram2>,
Meter1: Integer + Add<Meter2>,
Second1: Integer + Add<Second2>,
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<T, Second1, Meter1, Kilogram1, Ampere1, Kelvin1, Mole1, Candela1>,
) -> Self::Output {
Self::Output::new(self.value * rhs.value)
}
}
#[rustfmt::skip]
mod aliases {
use super::*;
// Base units
pub type Unit<T> = SiUnit<T, Z0, Z0, Z0, Z0, Z0, Z0, Z0>;
pub type Second<T> = SiUnit<T, P1, Z0, Z0, Z0, Z0, Z0, Z0>;
pub type Meter<T> = SiUnit<T, Z0, P1, Z0, Z0, Z0, Z0, Z0>;
pub type Kilogram<T> = SiUnit<T, Z0, Z0, P1, Z0, Z0, Z0, Z0>;
pub type Ampere<T> = SiUnit<T, Z0, Z0, Z0, P1, Z0, Z0, Z0>;
pub type Kelvin<T> = SiUnit<T, Z0, Z0, Z0, Z0, P1, Z0, Z0>;
pub type Mole<T> = SiUnit<T, Z0, Z0, Z0, Z0, Z0, P1, Z0>;
pub type Candela<T> = SiUnit<T, Z0, Z0, Z0, Z0, Z0, Z0, P1>;
// Derived units with special names
pub type Radian<T> = Unit<T>;
pub type Steradian<T> = Unit<T>;
pub type Herz<T> = SiUnit<T, N1, Z0, Z0, Z0, Z0, Z0, Z0>;
pub type Newton<T> = SiUnit<T, N2, P1, P1, Z0, Z0, Z0, Z0>;
pub type Pascal<T> = SiUnit<T, N2, N1, P1, Z0, Z0, Z0, Z0>;
pub type Joule<T> = SiUnit<T, N2, P2, P1, Z0, Z0, Z0, Z0>;
pub type Watt<T> = SiUnit<T, N3, P2, P1, Z0, Z0, Z0, Z0>;
pub type Coulomb<T> = SiUnit<T, P1, Z0, Z0, P1, Z0, Z0, Z0>;
pub type Volt<T> = SiUnit<T, N3, P2, P1, N1, Z0, Z0, Z0>;
pub type Farad<T> = SiUnit<T, P4, N2, N1, P2, Z0, Z0, Z0>;
pub type Ohm<T> = SiUnit<T, N3, P2, P1, N2, Z0, Z0, Z0>;
pub type Siemens<T> = SiUnit<T, P3, N2, N1, P2, Z0, Z0, Z0>;
pub type Weber<T> = SiUnit<T, N2, P2, P1, N1, Z0, Z0, Z0>;
pub type Tesla<T> = SiUnit<T, N2, Z0, P1, N1, Z0, Z0, Z0>;
pub type Henry<T> = SiUnit<T, N2, P2, P1, N2, Z0, Z0, Z0>;
pub type Lumen<T> = Candela<T>;
pub type Lux<T> = SiUnit<T, Z0, N2, Z0, Z0, Z0, Z0, P1>;
pub type Becquerel<T> = Herz<T>;
pub type Gray<T> = SiUnit<T, N2, P2, Z0, Z0, Z0, Z0, Z0>;
pub type Sievert<T> = Gray<T>;
pub type Katal<T> = SiUnit<T, N1, Z0, Z0, Z0, Z0, P1, Z0>;
pub type SquareMeter<T> = SiUnit<T, Z0, P2, Z0, Z0, Z0, Z0, Z0>;
pub type CubicMeter<T> = SiUnit<T, Z0, P3, Z0, Z0, Z0, Z0, Z0>;
}
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));
}
}