Skip to content

Commit

Permalink
feat: use (U, Const<N>) as default generic types in type_array!
Browse files Browse the repository at this point in the history
* feat: use `i8` instead of `i32` for exponents
  • Loading branch information
Logarithmus committed Jul 24, 2022
1 parent 8b2ddf0 commit d0b41ec
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 38 deletions.
100 changes: 93 additions & 7 deletions src/base_unit.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use crate::{
ops::{Div as UnitDiv, Inv, Mul as UnitMul},
Name, Prefix, Root,
typenum::{Constant, ToConst, ToTypenum, Typenum},
Const, Name, Prefix, Root,
};
use const_default::ConstDefault;
use core::{
i32,
marker::PhantomData,
Expand All @@ -13,21 +15,27 @@ use typenum::{Diff, Negate, Sum};
pub struct Pre<P, R>(PhantomData<(P, R)>);

pub trait Exponent {
const EXP: i32;
const EXP: i8;
}

impl Exponent for () {
const EXP: i32 = 0;
const EXP: i8 = 0;
}

impl<R: Root> Exponent for R {
const EXP: i32 = 1;
const EXP: i8 = 1;
}

impl<P, R: Root> Exponent for Pre<P, R> {
const EXP: i32 = 1;
const EXP: i8 = 1;
}

impl<U, const E: i8> Exponent for Exp<U, E> {
const EXP: i8 = E;
}

pub struct Exp<U, const N: i8>(PhantomData<U>);

/// Base unit for system of units
pub trait BaseUnit {}

Expand Down Expand Up @@ -59,11 +67,23 @@ impl<U: crate::name::Debug, E> crate::name::Debug for (U, E) {
}
}

impl<U: BaseUnit, El: Add<Er>, Er> UnitMul<(U, Er)> for (U, El) {
impl<U: crate::name::Display, const E: i8> crate::name::Display for Exp<U, E> {
fn display() -> String {
U::display()
}
}

impl<U: crate::name::Debug, const E: i8> crate::name::Debug for Exp<U, E> {
fn debug() -> String {
U::debug()
}
}

impl<U, El: Add<Er>, Er> UnitMul<(U, Er)> for (U, El) {
type Output = (U, Sum<El, Er>);
}

impl<U: BaseUnit, El: Sub<Er>, Er> UnitDiv<(U, Er)> for (U, El) {
impl<U, El: Sub<Er>, Er> UnitDiv<(U, Er)> for (U, El) {
type Output = (U, Diff<El, Er>);
}

Expand Down Expand Up @@ -99,6 +119,72 @@ impl Inv for () {
type Output = ();
}

// -----------------------------------------

pub trait ToExp<U> {
type Output;
}

impl<U, const N: i8> ToExp<U> for Const<N> {
type Output = Exp<U, N>;
}

type ToExponent<U, E> = <E as ToExp<U>>::Output;

impl<U, const EL: i8, const ER: i8> UnitMul<Exp<U, ER>> for Exp<U, EL>
where
Const<EL>: ToTypenum,
Const<ER>: ToTypenum,
Typenum<Const<EL>>: Add<Typenum<Const<ER>>>,
Sum<Typenum<Const<EL>>, Typenum<Const<ER>>>: ToConst,
Constant<Sum<Typenum<Const<EL>>, Typenum<Const<ER>>>>: ToExp<U> + ConstDefault,
{
type Output = ToExponent<U, Sum<Const<EL>, Const<ER>>>;
}

impl<U, const EL: i8, const ER: i8> UnitDiv<Exp<U, ER>> for Exp<U, EL>
where
Const<EL>: ToTypenum,
Const<ER>: ToTypenum,
Typenum<Const<EL>>: Sub<Typenum<Const<ER>>>,
Diff<Typenum<Const<EL>>, Typenum<Const<ER>>>: ToConst,
Constant<Diff<Typenum<Const<EL>>, Typenum<Const<ER>>>>: ToExp<U> + ConstDefault,
{
type Output = ToExponent<U, Diff<Const<EL>, Const<ER>>>;
}

impl<U, const E: i8> Inv for Exp<U, E>
where
Const<E>: ToTypenum,
Typenum<Const<E>>: Neg,
Negate<Typenum<Const<E>>>: ToConst,
Constant<Negate<Typenum<Const<E>>>>: ToExp<U> + ConstDefault,
{
type Output = ToExponent<U, Negate<Const<E>>>;
}

impl<U, const E: i8> UnitMul<Exp<U, E>> for () {
type Output = Exp<U, E>;
}

impl<U, const E: i8> UnitMul<()> for Exp<U, E> {
type Output = Exp<U, E>;
}

impl<U, const E: i8> UnitDiv<()> for Exp<U, E> {
type Output = Exp<U, E>;
}

impl<U, const E: i8> UnitDiv<Exp<U, E>> for ()
where
Const<E>: ToTypenum,
Typenum<Const<E>>: Neg,
Negate<Typenum<Const<E>>>: ToConst,
Constant<Negate<Typenum<Const<E>>>>: ToExp<U> + ConstDefault,
{
type Output = ToExponent<U, Negate<Const<E>>>;
}

pub trait ConvertFrom<U, V> {
fn convert_from(value: V) -> V;
}
Expand Down
39 changes: 23 additions & 16 deletions src/isq.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{
base_unit::Exponent,
base_unit::{Exponent, Pre},
name::superscript,
ops::{Div as UnitDiv, Inv as UnitInv, Mul as UnitMul},
util::{impl_binary_op_for_type_array, impl_unary_op_for_type_array, type_array},
Expand All @@ -13,6 +13,11 @@ use core::{
};
use std::ops::Neg;

use self::{
prefix::kilo,
root::{ampere, candela, gram, meter, mole, second, Kelvin},
};

/// Metric prefixes
pub mod prefix {
use crate::prefix::prefixes;
Expand Down Expand Up @@ -99,7 +104,9 @@ pub mod root {
impl<P, R: Root + kind::LuminousIntensity> kind::LuminousIntensity for Pre<P, R> {}
}

type_array!(Unit<L, M, Ti, I, Te, N, J>);
type Kg = Pre<kilo, gram>;

type_array!(Unit<L = meter, M = Kg, Ti = second, I = ampere, Te = Kelvin, N = mole, J = candela>);
impl_binary_op_for_type_array!(Unit<L, M, Ti, I, Te, N, J>, Mul, UnitMul);
impl_binary_op_for_type_array!(Unit<L, M, Ti, I, Te, N, J>, Div, UnitDiv);
impl_unary_op_for_type_array!(Unit<L, M, Ti, I, Te, N, J>, UnitInv, UnitInv);
Expand All @@ -111,11 +118,11 @@ impl<L, M, Ti, I, Te, N, J> ConstDefault for Unit<L, M, Ti, I, Te, N, J> {
#[derive(Clone, Debug)]
struct ExpUnit {
pub name: String,
pub exp: i32,
pub exp: i8,
}

impl ExpUnit {
fn new(name: String, exp: i32) -> Self {
fn new(name: String, exp: i8) -> Self {
Self { name, exp }
}
}
Expand All @@ -131,7 +138,7 @@ impl Neg for ExpUnit {
impl Display for ExpUnit {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.name)?;
if self.exp.abs() != 1 {
if self.exp != 1 {
write!(f, "{}", superscript(self.exp))?;
}
Ok(())
Expand Down Expand Up @@ -200,7 +207,10 @@ pub mod unit {
root::{cd, g, gram, m, meter, mol, s, second, A, K},
Unit,
};
use crate::{base_unit::Pre, typenum::Const};
use crate::{
base_unit::{Exp, Pre},
typenum::Const,
};

macro_rules! unit_aliases {
($(($m:literal, $kg:literal, $s:literal, $A:literal, $K:literal, $mol:literal, $cd:literal) -> $alias:ident,)+) => {
Expand All @@ -211,20 +221,20 @@ pub mod unit {

unit_aliases! {
(0, 0, 0, 0, 0, 0, 0) -> Dimensionless,
(1, 0, 0, 0, 0, 0, 0) -> Meter,
// (1, 0, 0, 0, 0, 0, 0) -> Meter,
(0, 1, 0, 0, 0, 0, 0) -> Kilogram,
(0, 0, 1, 0, 0, 0, 0) -> Second,
// (0, 0, 1, 0, 0, 0, 0) -> Second,
(0, 0, 0, 1, 0, 0, 0) -> Ampere,
(0, 0, 0, 0, 1, 0, 0) -> Kelvin,
(0, 0, 0, 0, 0, 1, 0) -> Mole,
(0, 0, 0, 0, 0, 0, 1) -> Candela,
(1, 0,-1, 0, 0, 0, 0) -> MeterPerSecond,
(2, 0, 0, 0, 0, 0, 0) -> MeterSquared,
}
// pub type Meter = Unit<(meter, Const<1>)>;
pub type Meter = Unit<(meter, Const<1>)>;
// pub type Kilometer = Unit<(Pre<kilo, meter>, Const<1>)>;
// pub type MeterSquared = Unit<(meter, Const<2>)>;
// pub type Second = Unit<(), (), (second, Const<1>)>;
pub type Second = Unit<(), (), (second, Const<1>)>;
// pub type Kilogram = Unit<(), (Pre<kilo, gram>, Const<1>)>;
}

Expand Down Expand Up @@ -336,16 +346,13 @@ mod tests {
isq::{consts::kg, unit::Meter},
Quantity,
};
use nalgebra::{RowVector3, Vector3};
// use nalgebra::{RowVector3, Vector3};

#[test]
fn nalgebra_vec() {
let l1 = 12_f32 * m;
let l2 = 1_f32 * (m / s);
let l2 = 1_f32 * m;
let l3 = l1 + l2;
let v1 = Quantity::<Meter, _>::new(RowVector3::new(1, 2, -1));
let v2 = Quantity::<Meter, _>::new(RowVector3::new(-1, -2, 1));
println!("{}\n{}\n{}", v1.clone(), v2.clone(), v1 + v2);
println!("{}", RowVector3::<f32>::default())
println!("{l1}\n{l2}\n{l3}");
}
}
2 changes: 1 addition & 1 deletion src/name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ impl<N: Name> Debug for N {
}
}

pub fn superscript(num: i32) -> String {
pub fn superscript(num: i8) -> String {
let s = num.to_string();
s.bytes()
.map(|c| match c {
Expand Down
10 changes: 5 additions & 5 deletions src/typenum/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ pub trait ToConst {
pub type Constant<T> = <T as ToConst>::Const;

#[derive(Clone, Copy)]
pub struct Const<const N: i32>;
pub struct Const<const N: i8>;

impl<const N: i32> ConstDefault for Const<N> {
impl<const N: i8> ConstDefault for Const<N> {
const DEFAULT: Self = Self;
}

Expand All @@ -60,7 +60,7 @@ macro_rules! num_to_typenum_and_back {
}

impl<U> Exponent for (U, Const<$const>) {
const EXP: i32 = $const;
const EXP: i8 = $const;
})+
};
}
Expand All @@ -87,7 +87,7 @@ num_to_typenum_and_back! {

macro_rules! impl_binary_ops_for_num {
($(($op:ident, $fun:ident, $out:ident),)+) => {
$(impl<const L: i32, const R: i32> $op<Const<R>> for Const<L>
$(impl<const L: i8, const R: i8> $op<Const<R>> for Const<L>
where
Const<L>: ToTypenum,
Const<R>: ToTypenum,
Expand All @@ -111,7 +111,7 @@ impl_binary_ops_for_num! {
(Div, div, Quot),
}

impl<const N: i32> Neg for Const<N>
impl<const N: i8> Neg for Const<N>
where
Const<N>: ToTypenum,
Typenum<Const<N>>: Neg,
Expand Down
16 changes: 7 additions & 9 deletions src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ macro_rules! count_idents {
pub(crate) use count_idents;

macro_rules! type_array {
($name:ident<$($param:ident),+>) => {
pub struct $name<$($param = ()),+>(::core::marker::PhantomData<($($param),+)>);
($name:ident<$($param:ident = $default:ident),+>) => {
pub struct $name<$($param = ($default, crate::typenum::Const<0>)),+>(::core::marker::PhantomData<($($param),+)>);

impl<$($param),+> $name<$($param),+> {
const LEN: usize = $crate::util::count_idents!($($param),+);
Expand Down Expand Up @@ -103,17 +103,15 @@ macro_rules! trait_alias {

pub(crate) use trait_alias;

use crate::{
base_unit::Pre,
isq::{prefix::kilo, root::gram},
};

#[cfg(test)]
mod tests {
#[test]
fn count_idents() {
assert_eq!(count_idents!(A, B, C, D), 4);
}

#[test]
fn type_array_len() {
type_array!(Test<A, B, C, D, E, F>);
const LEN: usize = <Test>::len();
assert_eq!(LEN, 6);
}
}

0 comments on commit d0b41ec

Please sign in to comment.