#![cfg_attr(not(feature = "std"), no_std)] mod display; pub mod types; #[cfg(not(feature = "std"))] use core::{ marker::PhantomData, ops::{ Add, AddAssign, Deref, DerefMut, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign, }, }; #[cfg(feature = "std")] use std::{ marker::PhantomData, ops::{ Add, AddAssign, Deref, DerefMut, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign, }, }; use num_traits::{Num, One, Zero}; use typenum::{int::Z0, op, Integer}; use types::Unit; #[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 Deref for SiUnit where Second: Integer, Meter: Integer, Kilogram: Integer, Ampere: Integer, Kelvin: Integer, Mole: Integer, Candela: Integer, { type Target = T; fn deref(&self) -> &Self::Target { &self.value } } impl DerefMut for SiUnit where Second: Integer, Meter: Integer, Kilogram: Integer, Ampere: Integer, Kelvin: Integer, Mole: Integer, Candela: Integer, { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.value } } impl Neg for SiUnit where Second: Integer, Meter: Integer, Kilogram: Integer, Ampere: Integer, Kelvin: Integer, Mole: Integer, Candela: Integer, T: Neg, { type Output = SiUnit; fn neg(self) -> Self::Output { Self::Output::new(-self.value) } } impl Zero for SiUnit where Second: Integer, Meter: Integer, Kilogram: Integer, Ampere: Integer, Kelvin: Integer, Mole: Integer, Candela: Integer, T: Zero, { fn zero() -> Self { Self::new(T::zero()) } fn is_zero(&self) -> bool { self.value.is_zero() } } impl One for SiUnit where Second: Integer + Add, Meter: Integer + Add, Kilogram: Integer + Add, Ampere: Integer + Add, Kelvin: Integer + Add, Mole: Integer + Add, Candela: Integer + Add, T: One, ::Output: Integer, ::Output: Integer, ::Output: Integer, ::Output: Integer, ::Output: Integer, ::Output: Integer, ::Output: Integer, { fn one() -> Self { Self::new(T::one()) } } impl Num for SiUnit where Second: Integer + Add + Sub + PartialEq, Meter: Integer + Add + Sub + PartialEq, Kilogram: Integer + Add + Sub + PartialEq, Ampere: Integer + Add + Sub + PartialEq, Kelvin: Integer + Add + Sub + PartialEq, Mole: Integer + Add + Sub + PartialEq, Candela: Integer + Add + Sub + PartialEq, T: Num, { type FromStrRadixErr = T::FromStrRadixErr; fn from_str_radix(str: &str, radix: u32) -> Result { T::from_str_radix(str, radix).map(Self::new) } } impl Add for SiUnit where Second: Integer, Meter: Integer, Kilogram: Integer, Ampere: Integer, Kelvin: Integer, Mole: Integer, Candela: Integer, T: Add, { type Output = SiUnit; fn add(self, rhs: Self) -> Self::Output { Self::Output::new(self.value + rhs.value) } } impl AddAssign for SiUnit where Second: Integer, Meter: Integer, Kilogram: Integer, Ampere: Integer, Kelvin: Integer, Mole: Integer, Candela: Integer, T: AddAssign, { fn add_assign(&mut self, rhs: Self) { self.value += rhs.value; } } impl Sub for SiUnit where Second: Integer, Meter: Integer, Kilogram: Integer, Ampere: Integer, Kelvin: Integer, Mole: Integer, Candela: Integer, T: Sub, { type Output = SiUnit; fn sub(self, rhs: Self) -> Self::Output { Self::Output::new(self.value - rhs.value) } } impl SubAssign for SiUnit where Second: Integer, Meter: Integer, Kilogram: Integer, Ampere: Integer, Kelvin: Integer, Mole: Integer, Candela: Integer, T: SubAssign, { fn sub_assign(&mut self, rhs: Self) { self.value -= rhs.value; } } impl Mul for SiUnit where Second: Integer, Meter: Integer, Kilogram: Integer, Ampere: Integer, Kelvin: Integer, Mole: Integer, Candela: Integer, T: Mul, { type Output = >>::Output; fn mul(self, rhs: T) -> Self::Output { self * Unit::new(rhs) } } impl MulAssign for SiUnit where Second: Integer, Meter: Integer, Kilogram: Integer, Ampere: Integer, Kelvin: Integer, Mole: Integer, Candela: Integer, T: MulAssign, { fn mul_assign(&mut self, rhs: T) { self.value *= rhs; } } impl Div for SiUnit where Second: Integer + Sub, Meter: Integer + Sub, Kilogram: Integer + Sub, Ampere: Integer + Sub, Kelvin: Integer + Sub, Mole: Integer + Sub, Candela: Integer + Sub, T: Div, >::Output: Integer, >::Output: Integer, >::Output: Integer, >::Output: Integer, >::Output: Integer, >::Output: Integer, >::Output: Integer, { type Output = >>::Output; fn div(self, rhs: T) -> Self::Output { self / Unit::new(rhs) } } impl DivAssign for SiUnit where Second: Integer, Meter: Integer, Kilogram: Integer, Ampere: Integer, Kelvin: Integer, Mole: Integer, Candela: Integer, T: DivAssign, { fn div_assign(&mut self, rhs: T) { self.value /= rhs; } } impl Rem for SiUnit where Second: Integer + Sub, Meter: Integer + Sub, Kilogram: Integer + Sub, Ampere: Integer + Sub, Kelvin: Integer + Sub, Mole: Integer + Sub, Candela: Integer + Sub, T: Rem, >::Output: Integer, >::Output: Integer, >::Output: Integer, >::Output: Integer, >::Output: Integer, >::Output: Integer, >::Output: Integer, { type Output = >>::Output; fn rem(self, rhs: T) -> Self::Output { self % Unit::new(rhs) } } impl RemAssign for SiUnit where Second: Integer, Meter: Integer, Kilogram: Integer, Ampere: Integer, Kelvin: Integer, Mole: Integer, Candela: Integer, T: RemAssign, { fn rem_assign(&mut self, rhs: T) { self.value %= rhs; } } 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) } } impl< T, Second1, Meter1, Kilogram1, Ampere1, Kelvin1, Mole1, Candela1, Second2, Meter2, Kilogram2, Ampere2, Kelvin2, Mole2, Candela2, > Div> for SiUnit where Second1: Integer, Meter1: Integer, Kilogram1: Integer, Ampere1: Integer, Kelvin1: Integer, Mole1: Integer, Candela1: Integer, Second2: Integer + Sub, Meter2: Integer + Sub, Kilogram2: Integer + Sub, Ampere2: Integer + Sub, Kelvin2: Integer + Sub, Mole2: Integer + Sub, Candela2: Integer + Sub, T: Div, Second2::Output: Integer, Meter2::Output: Integer, Kilogram2::Output: Integer, Ampere2::Output: Integer, Kelvin2::Output: Integer, Mole2::Output: Integer, Candela2::Output: Integer, { type Output = SiUnit< T::Output, op!(Second2 - Second1), op!(Meter2 - Meter1), op!(Kilogram2 - Kilogram1), op!(Ampere2 - Ampere1), op!(Kelvin2 - Kelvin1), op!(Mole2 - Mole1), op!(Candela2 - Candela1), >; fn div( self, rhs: SiUnit, ) -> Self::Output { Self::Output::new(self.value / rhs.value) } } impl< T, Second1, Meter1, Kilogram1, Ampere1, Kelvin1, Mole1, Candela1, Second2, Meter2, Kilogram2, Ampere2, Kelvin2, Mole2, Candela2, > Rem> for SiUnit where Second1: Integer, Meter1: Integer, Kilogram1: Integer, Ampere1: Integer, Kelvin1: Integer, Mole1: Integer, Candela1: Integer, Second2: Integer + Sub, Meter2: Integer + Sub, Kilogram2: Integer + Sub, Ampere2: Integer + Sub, Kelvin2: Integer + Sub, Mole2: Integer + Sub, Candela2: Integer + Sub, T: Rem, Second2::Output: Integer, Meter2::Output: Integer, Kilogram2::Output: Integer, Ampere2::Output: Integer, Kelvin2::Output: Integer, Mole2::Output: Integer, Candela2::Output: Integer, { type Output = SiUnit< T::Output, op!(Second2 - Second1), op!(Meter2 - Meter1), op!(Kilogram2 - Kilogram1), op!(Ampere2 - Ampere1), op!(Kelvin2 - Kelvin1), op!(Mole2 - Mole1), op!(Candela2 - Candela1), >; fn rem( self, rhs: SiUnit, ) -> Self::Output { Self::Output::new(self.value % rhs.value) } } #[cfg(test)] mod test { use super::types::{ Ampere, Coulomb, CubicMeter, Meter, ReciprocalMeter, Second, SquareMeter, Unit, Volt, Watt, }; use num_traits::{Num, One, Zero}; #[test] fn clone() { let m = Meter::new(2); assert_eq!(m.clone(), m); } #[test] fn ord() { let a = Meter::new(2); let b = Meter::new(3); assert!(a < b); assert!(b > a); assert!(a == a); assert!(a != b); assert_eq!(a.max(b), b); assert_eq!(a.min(b), a); } #[test] fn deref() { let m = Meter::new(2); assert_eq!(*m, 2); } #[test] fn deref_mut() { let mut m = Meter::new(2); *m = 3; assert_eq!(*m, 3); } #[test] fn neg() { let m = Meter::new(2); assert_eq!(-m, Meter::new(-2)); } #[test] fn zero() { let z = Meter::zero(); assert_eq!(z, Meter::new(0)); assert!(z.is_zero()); } #[test] fn one() { let o = Unit::one(); assert_eq!(o, Unit::new(1)); } #[test] fn from_str_radix() { assert_eq!(Unit::from_str_radix("24", 10), Ok(Unit::new(24))); } #[test] fn add() { let m = Meter::new(2); assert_eq!(m + m, Meter::new(4)); assert_eq!(m + m + m, Meter::new(6)); } #[test] fn add_assign() { let mut m = Meter::new(2); m += m; assert_eq!(m, Meter::new(4)); } #[test] fn sub() { let m = Meter::new(2); assert_eq!(m - m, Meter::new(0)); assert_eq!(m - m - m, Meter::new(-2)); } #[test] fn sub_assign() { let mut m = Meter::new(2); m -= m; assert_eq!(m, Meter::new(0)); } #[test] fn mul() { 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)); assert_eq!(m * 2, Meter::new(4)); } #[test] fn mul_assign() { let mut m = Meter::new(2); m *= 2; assert_eq!(m, Meter::new(4)); } #[test] fn div() { let m = Meter::new(2); assert_eq!(m / m, Unit::new(1)); assert_eq!(m / m / m, ReciprocalMeter::new(0)); let c = Coulomb::new(4); let a = Ampere::new(2); assert_eq!(c / a, Second::new(2)); let w = Watt::new(2); assert_eq!(w / a, Volt::new(1)); assert_eq!(m / 2, Meter::new(1)); } #[test] fn div_assign() { let mut m = Meter::new(2); m /= 2; assert_eq!(m, Meter::new(1)); } #[test] fn rem() { let m = Meter::new(2); assert_eq!(m % m, Unit::new(0)); assert_eq!(m / m % m, ReciprocalMeter::new(1)); let c = Coulomb::new(4); let a = Ampere::new(2); assert_eq!(c % a, Second::new(0)); let w = Watt::new(2); assert_eq!(w % a, Volt::new(0)); assert_eq!(m % 2, Meter::new(0)); } #[test] fn rem_assign() { let mut m = Meter::new(2); m %= 2; assert_eq!(m, Meter::new(0)); } }