From 882fe4ae407135455a0df6f9d6b96051194bd52d Mon Sep 17 00:00:00 2001 From: tehforsch Date: Sat, 13 Jan 2024 10:26:07 +0100 Subject: [PATCH 1/5] clean up dimension codegen --- .../src/codegen/dimension_type.rs | 60 +++++-------------- 1 file changed, 15 insertions(+), 45 deletions(-) diff --git a/crates/diman_unit_system/src/codegen/dimension_type.rs b/crates/diman_unit_system/src/codegen/dimension_type.rs index 80b3386..ba528cf 100644 --- a/crates/diman_unit_system/src/codegen/dimension_type.rs +++ b/crates/diman_unit_system/src/codegen/dimension_type.rs @@ -1,4 +1,4 @@ -use proc_macro2::TokenStream; +use proc_macro2::{Ident, TokenStream}; use quote::quote; use crate::types::Defs; @@ -33,50 +33,20 @@ impl Defs { fn dimension_methods_impl(&self) -> TokenStream { let type_name = &self.dimension_type; - let none_gen: proc_macro2::TokenStream = self - .base_dimensions() - .map(|ident| self.zero_entry(ident)) - .collect(); - - let mul_gen: proc_macro2::TokenStream = self - .base_dimensions() - .map(|ident| self.add_entry(ident)) - .collect(); - - let div_gen: proc_macro2::TokenStream = self - .base_dimensions() - .map(|ident| self.sub_entry(ident)) - .collect(); - - let inv_gen: proc_macro2::TokenStream = self - .base_dimensions() - .map(|ident| self.neg_entry(ident)) - .collect(); - - let powi_gen: proc_macro2::TokenStream = self - .base_dimensions() - .map(|ident| self.mul_entry(ident)) - .collect(); - - let sqrt_gen: proc_macro2::TokenStream = self - .base_dimensions() - .map(|ident| self.sqrt_entry(ident)) - .collect(); - - let cbrt_gen: proc_macro2::TokenStream = self - .base_dimensions() - .map(|ident| self.cbrt_entry(ident)) - .collect(); - - let sqrt_safety_gen: proc_macro2::TokenStream = self - .base_dimensions() - .map(|ident| self.sqrt_safety(ident)) - .collect(); - - let cbrt_safety_gen: proc_macro2::TokenStream = self - .base_dimensions() - .map(|ident| self.cbrt_safety(ident)) - .collect(); + let gen = |f: &dyn Fn(&Defs, &Ident) -> TokenStream| { + self.base_dimensions() + .map(|ident| f(self, ident)) + .collect::() + }; + let none_gen = gen(&Self::zero_entry); + let mul_gen = gen(&Self::add_entry); + let div_gen = gen(&Self::sub_entry); + let inv_gen = gen(&Self::neg_entry); + let powi_gen = gen(&Self::mul_entry); + let sqrt_gen = gen(&Self::sqrt_entry); + let cbrt_gen = gen(&Self::cbrt_entry); + let sqrt_safety_gen = gen(&Self::sqrt_safety); + let cbrt_safety_gen = gen(&Self::cbrt_safety); quote! { impl #type_name { From 135426b6f024ec0260a45049d2ef2f69c0b2a312 Mon Sep 17 00:00:00 2001 From: tehforsch Date: Sat, 13 Jan 2024 10:34:07 +0100 Subject: [PATCH 2/5] rename the dimension methods to be clearer about what they do to the dimension and remove the dimension_ prefix (dimension_mul -> add, ...) --- .../src/codegen/dimension_type.rs | 12 ++++----- .../src/codegen/float_methods.rs | 26 +++++++++---------- .../src/codegen/num_traits/operator_trait.rs | 6 ++--- crates/diman_unit_system/src/codegen/serde.rs | 4 +-- .../src/codegen/vector_methods.rs | 8 +++--- 5 files changed, 28 insertions(+), 28 deletions(-) diff --git a/crates/diman_unit_system/src/codegen/dimension_type.rs b/crates/diman_unit_system/src/codegen/dimension_type.rs index ba528cf..125a132 100644 --- a/crates/diman_unit_system/src/codegen/dimension_type.rs +++ b/crates/diman_unit_system/src/codegen/dimension_type.rs @@ -56,38 +56,38 @@ impl Defs { } } - pub const fn dimension_mul(self, other: Self) -> Self { + pub const fn add(self, other: Self) -> Self { Self { #mul_gen } } - pub const fn dimension_div(self, other: Self) -> Self { + pub const fn sub(self, other: Self) -> Self { Self { #div_gen } } - pub const fn dimension_inv(self) -> Self { + pub const fn neg(self) -> Self { Self { #inv_gen } } - pub const fn dimension_powi(self, other: i32) -> Self { + pub const fn mul(self, other: i32) -> Self { Self { #powi_gen } } - pub const fn dimension_sqrt(self) -> Self { + pub const fn div_2(self) -> Self { #sqrt_safety_gen Self { #sqrt_gen } } - pub const fn dimension_cbrt(self) -> Self { + pub const fn div_3(self) -> Self { #cbrt_safety_gen Self { #cbrt_gen diff --git a/crates/diman_unit_system/src/codegen/float_methods.rs b/crates/diman_unit_system/src/codegen/float_methods.rs index 6d999ca..8d294ed 100644 --- a/crates/diman_unit_system/src/codegen/float_methods.rs +++ b/crates/diman_unit_system/src/codegen/float_methods.rs @@ -103,37 +103,37 @@ impl Defs { } = &self; quote! { impl #quantity_type<#float_type, D> { - pub fn squared(&self) -> #quantity_type<#float_type, { D.dimension_powi(2) }> + pub fn squared(&self) -> #quantity_type<#float_type, { D.mul(2) }> where - #quantity_type::<#float_type, { D.dimension_powi(2) }>: + #quantity_type::<#float_type, { D.mul(2) }>: { - #quantity_type::<#float_type, { D.dimension_powi(2) }>(self.0.powi(2)) + #quantity_type::<#float_type, { D.mul(2) }>(self.0.powi(2)) } - pub fn cubed(&self) -> #quantity_type<#float_type, { D.dimension_powi(3) }> + pub fn cubed(&self) -> #quantity_type<#float_type, { D.mul(3) }> where - #quantity_type::<#float_type, { D.dimension_powi(3) }>: + #quantity_type::<#float_type, { D.mul(3) }>: { - #quantity_type::<#float_type, { D.dimension_powi(3) }>(self.0.powi(3)) + #quantity_type::<#float_type, { D.mul(3) }>(self.0.powi(3)) } - pub fn powi(&self) -> #quantity_type<#float_type, { D.dimension_powi(I) }> + pub fn powi(&self) -> #quantity_type<#float_type, { D.mul(I) }> where - #quantity_type::<#float_type, { D.dimension_powi(I) }>: + #quantity_type::<#float_type, { D.mul(I) }>: { - #quantity_type::<#float_type, { D.dimension_powi(I) }>(self.0.powi(I)) + #quantity_type::<#float_type, { D.mul(I) }>(self.0.powi(I)) } #[cfg(any(feature = "std", feature = "num-traits-libm"))] - pub fn sqrt(&self) -> #quantity_type<#float_type, { D.dimension_sqrt() }> + pub fn sqrt(&self) -> #quantity_type<#float_type, { D.div_2() }> { - #quantity_type::<#float_type, { D.dimension_sqrt() }>(self.0.sqrt()) + #quantity_type::<#float_type, { D.div_2() }>(self.0.sqrt()) } #[cfg(any(feature = "std", feature = "num-traits-libm"))] - pub fn cbrt(&self) -> #quantity_type<#float_type, { D.dimension_cbrt() }> + pub fn cbrt(&self) -> #quantity_type<#float_type, { D.div_3() }> { - #quantity_type::<#float_type, { D.dimension_cbrt() }>(self.0.cbrt()) + #quantity_type::<#float_type, { D.div_3() }>(self.0.cbrt()) } pub fn min>(self, other: Q) -> Self { diff --git a/crates/diman_unit_system/src/codegen/num_traits/operator_trait.rs b/crates/diman_unit_system/src/codegen/num_traits/operator_trait.rs index 51e2db6..6cb6dd6 100644 --- a/crates/diman_unit_system/src/codegen/num_traits/operator_trait.rs +++ b/crates/diman_unit_system/src/codegen/num_traits/operator_trait.rs @@ -432,14 +432,14 @@ impl OperatorTrait { let existing = Existing(quote_spanned! { span=> D }); match (&self.lhs.type_, &self.rhs.type_) { (Quantity, Quantity) => match self.name { - Mul => New(quote_spanned! {span=> { DL.dimension_mul(DR) } }), - Div => New(quote_spanned! {span=> { DL.dimension_div(DR) } }), + Mul => New(quote_spanned! {span=> { DL.add(DR) } }), + Div => New(quote_spanned! {span=> { DL.sub(DR) } }), _ => existing, }, (Quantity, Storage) => existing, (Storage, Quantity) => match self.name { Mul => existing, - Div => New(quote_spanned! {span=> { D.dimension_inv() } }), + Div => New(quote_spanned! {span=> { D.neg() } }), _ => unreachable!(), }, (Dimensionless, Storage) | (Storage, Dimensionless) => { diff --git a/crates/diman_unit_system/src/codegen/serde.rs b/crates/diman_unit_system/src/codegen/serde.rs index 5573df5..0d699f6 100644 --- a/crates/diman_unit_system/src/codegen/serde.rs +++ b/crates/diman_unit_system/src/codegen/serde.rs @@ -53,7 +53,7 @@ impl Defs { let mut total_factor = 1.0; for unit in split { let (dimension, factor) = read_single_unit_str(unit)?; - total_dimension = total_dimension.dimension_mul(dimension.clone()); + total_dimension = total_dimension.add(dimension.clone()); total_factor *= factor; } Ok((total_dimension, total_factor)) @@ -83,7 +83,7 @@ impl Defs { .find(|(_, known_unit_name, _)| &unit == known_unit_name) .ok_or_else(|| E::custom(format!("unknown unit: {}", &unit)))?; Ok(( - dimension.clone().dimension_powi(exponent), + dimension.clone().mul(exponent), factor.powi(exponent), )) } diff --git a/crates/diman_unit_system/src/codegen/vector_methods.rs b/crates/diman_unit_system/src/codegen/vector_methods.rs index 09f9dc9..a2dc5d6 100644 --- a/crates/diman_unit_system/src/codegen/vector_methods.rs +++ b/crates/diman_unit_system/src/codegen/vector_methods.rs @@ -130,11 +130,11 @@ impl Defs { pub fn distance_squared( &self, other: &Self, - ) -> #quantity_type<#float_type, { D.dimension_powi(2) }> + ) -> #quantity_type<#float_type, { D.mul(2) }> where - #quantity_type<#float_type, { D.dimension_powi(2) }>:, + #quantity_type<#float_type, { D.mul(2) }>:, { - #quantity_type::<#float_type, { D.dimension_powi(2) }>(self.0.distance_squared(other.0)) + #quantity_type::<#float_type, { D.mul(2) }>(self.0.distance_squared(other.0)) } pub fn normalize(&self) -> #quantity_type<#vector_type_name, { #dimension_type::none() }> { @@ -144,7 +144,7 @@ impl Defs { pub fn dot( self, rhs: Quantity<#vector_type_name, DR>, - ) -> #quantity_type<#float_type, { D.dimension_mul(DR) }> { + ) -> #quantity_type<#float_type, { D.add(DR) }> { #quantity_type(self.0.dot(rhs.0)) } } From f2fb1f22b3c80a235941e5e4ff387f9ba2c25739 Mon Sep 17 00:00:00 2001 From: tehforsch Date: Sat, 13 Jan 2024 11:17:38 +0100 Subject: [PATCH 3/5] add diman_lib, move ratio into it and import it from calling crate --- Cargo.toml | 1 + crates/diman_lib/Cargo.toml | 12 ++ crates/diman_lib/src/lib.rs | 4 + crates/diman_lib/src/ratio.rs | 132 ++++++++++++++++++ crates/diman_unit_system/Cargo.toml | 1 + .../src/codegen/base_dimension_type.rs | 6 +- .../src/codegen/dimension_type.rs | 97 +------------ .../diman_unit_system/src/dimension_math.rs | 2 +- crates/diman_unit_system/src/parse/mod.rs | 5 +- .../src/types/base_dimension_exponent.rs | 86 +----------- src/lib.rs | 6 + 11 files changed, 167 insertions(+), 185 deletions(-) create mode 100644 crates/diman_lib/Cargo.toml create mode 100644 crates/diman_lib/src/lib.rs create mode 100644 crates/diman_lib/src/ratio.rs diff --git a/Cargo.toml b/Cargo.toml index 96c879d..33441f3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,6 +45,7 @@ once_cell = { version = "1.18.0", optional = true } num-traits = { version = "0.2.17", default-features = false } diman_unit_system = { path = "crates/diman_unit_system", version = "0.4", default-features = false } +diman_lib = { path = "crates/diman_lib", version = "0.4" } [dev-dependencies] serde_yaml = "0.9.27" diff --git a/crates/diman_lib/Cargo.toml b/crates/diman_lib/Cargo.toml new file mode 100644 index 0000000..2c6681f --- /dev/null +++ b/crates/diman_lib/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "diman_lib" +version = "0.4.0" +edition = "2021" +authors = [ + "Toni Peter ", +] +description = "Commonly used types for internal use in diman." +license = "MIT OR Apache-2.0" +repository = "https://github.com/tehforsch/diman" + +[dependencies] diff --git a/crates/diman_lib/src/lib.rs b/crates/diman_lib/src/lib.rs new file mode 100644 index 0000000..1a77b12 --- /dev/null +++ b/crates/diman_lib/src/lib.rs @@ -0,0 +1,4 @@ +#![allow(incomplete_features)] +#![feature(generic_const_exprs, adt_const_params)] + +pub mod ratio; diff --git a/crates/diman_lib/src/ratio.rs b/crates/diman_lib/src/ratio.rs new file mode 100644 index 0000000..cbcf4f4 --- /dev/null +++ b/crates/diman_lib/src/ratio.rs @@ -0,0 +1,132 @@ +#[derive( + ::core::cmp::PartialEq, + ::core::cmp::Eq, + ::core::clone::Clone, + ::core::marker::Copy, + ::core::fmt::Debug, + ::core::marker::ConstParamTy, +)] +pub struct Ratio { + num: i64, + denom: i64, +} + +const fn gcd(mut a: i64, mut b: i64) -> i64 { + while b != 0 { + let temp = b; + b = a % b; + a = temp; + } + a.abs() +} + +impl Ratio { + pub fn one() -> Self { + Self { num: 1, denom: 1 } + } + + pub fn zero() -> Self { + Self { num: 0, denom: 1 } + } + + pub const fn int(num: i64) -> Self { + Self { num, denom: 1 } + } + + pub const fn num(&self) -> i64 { + self.num + } + + pub const fn denom(&self) -> i64 { + self.denom + } + + pub const fn new(num: i64, denom: i64) -> Self { + let gcd = gcd(num, denom); + Self { + num: num / gcd, + denom: denom / gcd, + } + } + + pub const fn powi(self, exp: i32) -> Self { + let num = self.num * exp as i64; + let denom = self.denom * exp as i64; + Self::new(num, denom) + } + + pub const fn add(self, rhs: Self) -> Self { + let num = self.num * rhs.denom + rhs.num * self.denom; + let denom = self.denom * rhs.denom; + Self::new(num, denom) + } + + pub const fn sub(self, rhs: Self) -> Self { + self.add(rhs.neg()) + } + + pub const fn neg(self) -> Self { + Self { + num: -self.num, + denom: self.denom, + } + } + + pub const fn mul(self, rhs: Self) -> Self { + let num = self.num * rhs.num; + let denom = self.denom * rhs.denom; + Self::new(num, denom) + } + + pub const fn div(self, rhs: Self) -> Self { + self.mul(rhs.inv()) + } + + const fn inv(self) -> Self { + Self { + num: self.denom, + denom: self.num, + } + } + + pub fn float_pow(num: f64, exponent: Self) -> f64 { + num.powf(exponent.num as f64 / exponent.denom as f64) + } +} + +impl core::fmt::Display for Ratio { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + if self.denom == 1 { + write!(f, "{}", self.num) + } else { + write!(f, "{}/{}", self.num, self.denom) + } + } +} + +impl core::ops::Mul for Ratio { + type Output = Self; + + fn mul(self, rhs: Self) -> Self::Output { + Self::new(self.num * rhs.num, self.denom * rhs.denom) + } +} + +impl core::ops::AddAssign for Ratio { + fn add_assign(&mut self, rhs: Self) { + let num = self.num * rhs.denom + rhs.num * self.denom; + let denom = self.denom * rhs.denom; + *self = Self::new(num, denom) + } +} + +impl core::ops::Neg for Ratio { + type Output = Self; + + fn neg(self) -> Self::Output { + Self { + num: -self.num, + denom: self.denom, + } + } +} diff --git a/crates/diman_unit_system/Cargo.toml b/crates/diman_unit_system/Cargo.toml index a46ae7f..a66a7e3 100644 --- a/crates/diman_unit_system/Cargo.toml +++ b/crates/diman_unit_system/Cargo.toml @@ -32,6 +32,7 @@ default = ["f32", "f64"] syn = { version = "2.0", features = ["full", "extra-traits"] } quote = "1.0" proc-macro2 = "1.0" +diman_lib = { path = "../diman_lib", version = "0.4" } [lib] proc-macro = true diff --git a/crates/diman_unit_system/src/codegen/base_dimension_type.rs b/crates/diman_unit_system/src/codegen/base_dimension_type.rs index 1718e1b..c487800 100644 --- a/crates/diman_unit_system/src/codegen/base_dimension_type.rs +++ b/crates/diman_unit_system/src/codegen/base_dimension_type.rs @@ -10,9 +10,9 @@ impl Defs { field: &Ident, value: &BaseDimensionExponent, ) -> TokenStream { - let num = value.num; - let denom = value.denom; - quote! { #field: Ratio { num: #num, denom: #denom }, } + let num = value.num(); + let denom = value.denom(); + quote! { #field: Ratio::new(#num, #denom), } } pub fn base_dimension_type(&self) -> TokenStream { diff --git a/crates/diman_unit_system/src/codegen/dimension_type.rs b/crates/diman_unit_system/src/codegen/dimension_type.rs index 125a132..012d073 100644 --- a/crates/diman_unit_system/src/codegen/dimension_type.rs +++ b/crates/diman_unit_system/src/codegen/dimension_type.rs @@ -19,9 +19,9 @@ impl Defs { }) .collect(); let methods_impl: proc_macro2::TokenStream = self.dimension_methods_impl(); - let ratio_impl = self.ratio_impl(); quote! { - #ratio_impl + use ::diman::Ratio; + #[derive(::core::cmp::PartialEq, ::core::cmp::Eq, ::core::clone::Clone, ::core::fmt::Debug, ::core::marker::ConstParamTy)] pub struct #name { #dimensions @@ -96,97 +96,4 @@ impl Defs { } } } - - #[cfg(not(feature = "rational-dimensions"))] - fn ratio_impl(&self) -> proc_macro2::TokenStream { - quote! {} - } - - /// Defines the `Ratio` type inside the calling crate. - /// This is done to improve error messages, since the - /// messages would otherwise show diman::Ratio everywhere. - #[cfg(feature = "rational-dimensions")] - fn ratio_impl(&self) -> proc_macro2::TokenStream { - quote! { - #[derive(::core::cmp::PartialEq, ::core::cmp::Eq, ::core::clone::Clone, ::core::fmt::Debug, ::core::marker::ConstParamTy)] - struct Ratio { - num: i64, - denom: i64, - } - - const fn gcd(mut a: i64, mut b: i64) -> i64 { - while b != 0 { - let temp = b; - b = a % b; - a = temp; - } - a.abs() - } - - impl Ratio { - const fn int(num: i64) -> Self { - Self { num, denom: 1 } - } - - const fn new(num: i64, denom: i64) -> Self { - let gcd = gcd(num, denom); - Self { - num: num / gcd, - denom: denom / gcd, - } - } - - pub const fn powi(self, exp: i32) -> Self { - let num = self.num * exp as i64; - let denom = self.denom * exp as i64; - Self::new(num, denom) - } - - const fn add(self, rhs: Self) -> Self { - let num = self.num * rhs.denom + rhs.num * self.denom; - let denom = self.denom * rhs.denom; - Self::new(num, denom) - } - - const fn sub(self, rhs: Self) -> Self { - self.add(rhs.neg()) - } - - const fn neg(self) -> Self { - Self { - num: -self.num, - denom: self.denom, - } - } - - const fn mul(self, rhs: Self) -> Self { - let num = self.num * rhs.num; - let denom = self.denom * rhs.denom; - Self::new(num, denom) - } - - const fn div(self, rhs: Self) -> Self { - self.mul(rhs.inv()) - } - - const fn inv(self) -> Self { - Self { - num: self.denom, - denom: self.num, - } - } - } - - impl core::fmt::Display for Ratio { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - if self.denom == 1 { - write!(f, "{}", self.num) - } else { - write!(f, "{}/{}", self.num, self.denom) - } - } - } - - } - } } diff --git a/crates/diman_unit_system/src/dimension_math.rs b/crates/diman_unit_system/src/dimension_math.rs index 97b598f..7a22e78 100644 --- a/crates/diman_unit_system/src/dimension_math.rs +++ b/crates/diman_unit_system/src/dimension_math.rs @@ -148,7 +148,7 @@ impl core::ops::Div for DimensionsAndMagnitude { impl MulDiv for DimensionsAndMagnitude { fn pow(self, pow: BaseDimensionExponent) -> Self { Self { - magnitude: BaseDimensionExponent::pow(self.magnitude, pow), + magnitude: BaseDimensionExponent::float_pow(self.magnitude, pow), dimensions: self.dimensions.pow(pow), } } diff --git a/crates/diman_unit_system/src/parse/mod.rs b/crates/diman_unit_system/src/parse/mod.rs index 29b99e1..890cb9b 100644 --- a/crates/diman_unit_system/src/parse/mod.rs +++ b/crates/diman_unit_system/src/parse/mod.rs @@ -176,10 +176,7 @@ impl Parse for DimensionFactor { #[cfg(feature = "rational-dimensions")] fn read_exponent(e: Exponent) -> BaseDimensionExponent { - BaseDimensionExponent { - num: e.num.int, - denom: e.denom.map(|denom| denom.int).unwrap_or(1), - } + BaseDimensionExponent::new(e.num.int, e.denom.map(|denom| denom.int).unwrap_or(1)) } #[cfg(not(feature = "rational-dimensions"))] diff --git a/crates/diman_unit_system/src/types/base_dimension_exponent.rs b/crates/diman_unit_system/src/types/base_dimension_exponent.rs index 03585d4..cba25e8 100644 --- a/crates/diman_unit_system/src/types/base_dimension_exponent.rs +++ b/crates/diman_unit_system/src/types/base_dimension_exponent.rs @@ -1,84 +1,8 @@ #[cfg(feature = "rational-dimensions")] -mod reexport { - /// Represents a ratio between two numbers. - /// This is an even smaller reimplementation of the - /// `Ratio` type that `unit_system` implements for the calling crate. - /// Unfortunately, using the ratio type here is not possible, since - /// that would require another proc macro crate. - #[derive(Clone, PartialEq, Copy)] - pub struct BaseDimensionExponent { - pub num: i64, - pub denom: i64, - } - - fn gcd(mut a: i64, mut b: i64) -> i64 { - while b != 0 { - let temp = b; - b = a % b; - a = temp; - } - a.abs() - } - - impl BaseDimensionExponent { - pub fn one() -> BaseDimensionExponent { - Self { num: 1, denom: 1 } - } - - pub fn zero() -> BaseDimensionExponent { - Self { num: 0, denom: 1 } - } - - pub fn pow(num: f64, exponent: Self) -> f64 { - num.powf(exponent.num as f64 / exponent.denom as f64) - } - - fn new(num: i64, denom: i64) -> Self { - let gcd = gcd(num, denom); - Self { - num: num / gcd, - denom: denom / gcd, - } - } - } - - impl core::fmt::Display for BaseDimensionExponent { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - if self.denom == 1 { - write!(f, "{}", self.num) - } else { - write!(f, "{}/{}", self.num, self.denom) - } - } - } +pub use diman_lib::ratio::Ratio as BaseDimensionExponent; - impl core::ops::Mul for BaseDimensionExponent { - type Output = Self; - - fn mul(self, rhs: Self) -> Self::Output { - Self::new(self.num * rhs.num, self.denom * rhs.denom) - } - } - - impl core::ops::AddAssign for BaseDimensionExponent { - fn add_assign(&mut self, rhs: Self) { - let num = self.num * rhs.denom + rhs.num * self.denom; - let denom = self.denom * rhs.denom; - *self = Self::new(num, denom) - } - } - - impl core::ops::Neg for BaseDimensionExponent { - type Output = Self; - - fn neg(self) -> Self::Output { - Self { - num: -self.num, - denom: self.denom, - } - } - } -} +#[cfg(not(feature = "rational-dimensions"))] +pub use reexport::BaseDimensionExponent; #[cfg(not(feature = "rational-dimensions"))] mod reexport { @@ -94,7 +18,7 @@ mod reexport { Self(0) } - pub fn pow(num: f64, exponent: Self) -> f64 { + pub fn float_pow(num: f64, exponent: Self) -> f64 { num.powi(exponent.0 as i32) } } @@ -127,5 +51,3 @@ mod reexport { } } } - -pub use reexport::BaseDimensionExponent; diff --git a/src/lib.rs b/src/lib.rs index 24506eb..2f811b5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,10 @@ #![feature(generic_const_exprs, adt_const_params)] #![doc = include_str!("../README.md")] +// This ensures we don't have to differentiate between +// imports via `crate::` and `diman::` in the proc macro. +extern crate self as diman; + #[cfg(all( feature = "rational-dimensions", not(any(feature = "std", feature = "num-traits-libm")) @@ -129,3 +133,5 @@ pub type Product = >::Output; /// let x: Quotient = Length::meters(10.0) / Time::seconds(2.0); /// ``` pub type Quotient = >::Output; + +pub use diman_lib::ratio::Ratio; From c0c637734de7e35941c66146bfdad66fb51a2790 Mon Sep 17 00:00:00 2001 From: tehforsch Date: Sat, 13 Jan 2024 11:28:55 +0100 Subject: [PATCH 4/5] fix CI not running tests with --workspace --- .github/workflows/rust.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index b8b0cb9..8aa35c7 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -30,17 +30,17 @@ jobs: - name: Build run: cargo build --verbose --all-targets - name: Run tests (default features) - run: cargo test --tests + run: cargo test --tests --workspace - name: Run tests (all features, no rational dimensions) - run: cargo test --tests --features glam,glam-vec2,glam-dvec2,glam-vec3,glam-dvec3,f32,f64,gen-vec-names,si,mpi,hdf5,rand,serde + run: cargo test --tests --features glam,glam-vec2,glam-dvec2,glam-vec3,glam-dvec3,f32,f64,gen-vec-names,si,mpi,hdf5,rand,serde --workspace - name: Run tests (all features) - run: cargo test --tests --all-features + run: cargo test --tests --all-features --workspace - name: Run tests (no std, no libm) - run: cargo test --tests --no-default-features --features f32,f64,si + run: cargo test --tests --no-default-features --features f32,f64,si --workspace - name: Run tests (no std, libm) - run: cargo test --tests --no-default-features --features f32,f64,num-traits-libm,si + run: cargo test --tests --no-default-features --features f32,f64,num-traits-libm,si --workspace - name: Doctests - run: cargo test --doc --all-features + run: cargo test --doc --all-features --workspace clippy: runs-on: ubuntu-latest From fa5a025e8e04d876cf8c47b4a5b11d58a3283e53 Mon Sep 17 00:00:00 2001 From: tehforsch Date: Sat, 13 Jan 2024 12:01:59 +0100 Subject: [PATCH 5/5] fix the import mess from within diman_unit_system by adding an internal diman_unit_system macro and moving codegen to a Codegen struct (instead of defs) --- README.md | 2 +- .../src/codegen/base_dimension_type.rs | 7 ++- .../src/codegen/debug_trait.rs | 16 +++--- .../src/codegen/dimension_type.rs | 28 ++++++--- .../src/codegen/dimensions.rs | 57 +++++++------------ .../src/codegen/float_methods.rs | 20 ++----- .../src/codegen/generic_methods.rs | 11 ++-- crates/diman_unit_system/src/codegen/hdf5.rs | 18 ++---- crates/diman_unit_system/src/codegen/mod.rs | 17 +++++- crates/diman_unit_system/src/codegen/mpi.rs | 19 +++---- .../src/codegen/num_traits/mod.rs | 25 +++----- .../src/codegen/num_traits/operator_trait.rs | 19 +++---- crates/diman_unit_system/src/codegen/rand.rs | 13 ++--- crates/diman_unit_system/src/codegen/serde.rs | 33 ++++------- .../src/codegen/storage_types.rs | 4 +- crates/diman_unit_system/src/codegen/units.rs | 24 +++++--- .../src/codegen/vector_methods.rs | 13 ++--- crates/diman_unit_system/src/lib.rs | 25 +++++++- .../dimension_annotation_violated_constant.rs | 4 +- .../dimension_annotation_violated_unit.rs | 4 +- ...ension_annotation_with_unit_not_allowed.rs | 4 +- ...imension_definition_with_numeric_factor.rs | 4 +- .../tests/compile_fail/example_system/mod.rs | 5 +- ...sion_in_constant_expression_not_allowed.rs | 4 +- ...imension_in_unit_expression_not_allowed.rs | 4 +- .../resolver_duplicate_base_unit.rs | 4 +- .../resolver_duplicate_definition.rs | 4 +- .../compile_fail/resolver_duplicate_symbol.rs | 4 +- .../resolver_partial_resolution.rs | 4 +- ...sed_units_dont_generate_multiple_errors.rs | 4 +- .../resolver_undefined_identifier.rs | 4 +- ...its_in_dimension_expression_not_allowed.rs | 4 +- .../compile_fail/resolver_unresolvable.rs | 4 +- crates/diman_unit_system/tests/mod.rs | 1 + 34 files changed, 200 insertions(+), 213 deletions(-) diff --git a/README.md b/README.md index 9469451..d09cff7 100644 --- a/README.md +++ b/README.md @@ -81,7 +81,7 @@ The `unit_system!` macro also allows defining derived dimensions and units: ```rust ignore #![allow(incomplete_features)] #![feature(generic_const_exprs, adt_const_params)] -use diman_unit_system::unit_system; +use diman::unit_system; unit_system!( quantity_type Quantity; dimension_type Dimension; diff --git a/crates/diman_unit_system/src/codegen/base_dimension_type.rs b/crates/diman_unit_system/src/codegen/base_dimension_type.rs index c487800..d12b072 100644 --- a/crates/diman_unit_system/src/codegen/base_dimension_type.rs +++ b/crates/diman_unit_system/src/codegen/base_dimension_type.rs @@ -1,10 +1,11 @@ use proc_macro2::{Ident, TokenStream}; use quote::quote; -use crate::types::{BaseDimensionExponent, Defs}; +use super::Codegen; +use crate::types::BaseDimensionExponent; #[cfg(feature = "rational-dimensions")] -impl Defs { +impl Codegen { pub fn get_base_dimension_entry( &self, field: &Ident, @@ -78,7 +79,7 @@ impl Defs { } #[cfg(not(feature = "rational-dimensions"))] -impl Defs { +impl Codegen { pub fn get_base_dimension_entry( &self, field: &Ident, diff --git a/crates/diman_unit_system/src/codegen/debug_trait.rs b/crates/diman_unit_system/src/codegen/debug_trait.rs index 11e1212..aee73a3 100644 --- a/crates/diman_unit_system/src/codegen/debug_trait.rs +++ b/crates/diman_unit_system/src/codegen/debug_trait.rs @@ -3,10 +3,12 @@ use quote::quote; use crate::{ dimension_math::BaseDimensions, - types::{base_dimension::BaseDimension, Defs, Unit}, + types::{base_dimension::BaseDimension, Unit}, }; -impl Defs { +use super::Codegen; + +impl Codegen { pub fn units_array<'a>(&self, units: impl Iterator) -> TokenStream { let units: TokenStream = units .filter_map(|unit| { @@ -22,13 +24,11 @@ impl Defs { } pub fn gen_debug_trait_impl(&self) -> TokenStream { - let Defs { - quantity_type, - dimension_type, - .. - } = &self; - let units = self.units_array(self.units.iter().filter(|unit| unit.magnitude == 1.0)); + let dimension_type = &self.defs.dimension_type; + let quantity_type = &self.defs.quantity_type; + let units = self.units_array(self.defs.units.iter().filter(|unit| unit.magnitude == 1.0)); let get_base_dimension_symbols = self + .defs .base_dimensions .iter() .map(|base_dim| self.get_base_dimension_symbol(base_dim)) diff --git a/crates/diman_unit_system/src/codegen/dimension_type.rs b/crates/diman_unit_system/src/codegen/dimension_type.rs index 012d073..a86ef6b 100644 --- a/crates/diman_unit_system/src/codegen/dimension_type.rs +++ b/crates/diman_unit_system/src/codegen/dimension_type.rs @@ -1,14 +1,15 @@ use proc_macro2::{Ident, TokenStream}; use quote::quote; -use crate::types::Defs; +use super::{CallerType, Codegen}; -impl Defs { +impl Codegen { pub(crate) fn gen_dimension(&self) -> TokenStream { - let name = &self.dimension_type; + let name = &self.defs.dimension_type; let dim_type = self.base_dimension_type(); let dimensions: proc_macro2::TokenStream = self + .defs .base_dimensions .iter() .map(|dim| { @@ -19,8 +20,9 @@ impl Defs { }) .collect(); let methods_impl: proc_macro2::TokenStream = self.dimension_methods_impl(); + let use_ratio = self.use_ratio(); quote! { - use ::diman::Ratio; + #use_ratio #[derive(::core::cmp::PartialEq, ::core::cmp::Eq, ::core::clone::Clone, ::core::fmt::Debug, ::core::marker::ConstParamTy)] pub struct #name { @@ -31,10 +33,22 @@ impl Defs { } } + fn use_ratio(&self) -> TokenStream { + match self.caller_type { + CallerType::External => { + quote! { use ::diman::Ratio; } + } + CallerType::Internal => { + quote! { use ::diman_lib::ratio::Ratio; } + } + } + } + fn dimension_methods_impl(&self) -> TokenStream { - let type_name = &self.dimension_type; - let gen = |f: &dyn Fn(&Defs, &Ident) -> TokenStream| { - self.base_dimensions() + let type_name = &self.defs.dimension_type; + let gen = |f: &dyn Fn(&Codegen, &Ident) -> TokenStream| { + self.defs + .base_dimensions() .map(|ident| f(self, ident)) .collect::() }; diff --git a/crates/diman_unit_system/src/codegen/dimensions.rs b/crates/diman_unit_system/src/codegen/dimensions.rs index 8e2c065..e63a6b8 100644 --- a/crates/diman_unit_system/src/codegen/dimensions.rs +++ b/crates/diman_unit_system/src/codegen/dimensions.rs @@ -1,16 +1,13 @@ -use crate::{dimension_math::BaseDimensions, types::Defs}; +use crate::dimension_math::BaseDimensions; use proc_macro2::TokenStream; use quote::{quote, quote_spanned}; -use super::storage_types::StorageType; +use super::{storage_types::StorageType, Codegen}; -impl Defs { +impl Codegen { pub(crate) fn gen_quantity(&self) -> TokenStream { - let Self { - quantity_type, - dimension_type, - .. - } = &self; + let dimension_type = &self.defs.dimension_type; + let quantity_type = &self.defs.quantity_type; let span = quantity_type.span(); let functions = self.quantity_functions(); quote_spanned! {span => @@ -22,11 +19,8 @@ impl Defs { } fn quantity_functions(&self) -> TokenStream { - let Self { - quantity_type, - dimension_type, - .. - } = &self; + let dimension_type = &self.defs.dimension_type; + let quantity_type = &self.defs.quantity_type; quote! { impl #quantity_type { /// Get the value of a dimensionless quantity @@ -67,13 +61,13 @@ impl Defs { } pub fn get_dimension_expr(&self, dim: &BaseDimensions) -> TokenStream { - let dimension_type = &self.dimension_type; + let dimension_type = &self.defs.dimension_type; let field_updates: TokenStream = dim .fields() .map(|(field, value)| self.get_base_dimension_entry(field, value)) .collect(); - let span = self.quantity_type.span(); - let none_update = if dim.num_fields() < self.base_dimensions.len() { + let span = self.defs.quantity_type.span(); + let none_update = if dim.num_fields() < self.defs.base_dimensions.len() { quote! { ..#dimension_type::none() } } else { quote! {} @@ -98,39 +92,25 @@ impl Defs { .collect() } - #[cfg(feature = "rational-dimensions")] - fn use_ratio(&self) -> TokenStream { - quote! { use super::Ratio; } - } - - #[cfg(not(feature = "rational-dimensions"))] - fn use_ratio(&self) -> TokenStream { - quote! {} - } - fn definitions_for_storage_type( &self, type_: &dyn StorageType, module_name: &TokenStream, gen_constants: bool, ) -> TokenStream { - let Self { - dimension_type, - quantity_type, - .. - } = &self; + let dimension_type = &self.defs.dimension_type; + let quantity_type = &self.defs.quantity_type; let quantities = self.quantity_definitions_for_storage_type(type_); let constants = if gen_constants { self.constant_definitions_for_storage_type(type_) } else { quote! {} }; - let use_ratio = self.use_ratio(); quote! { pub mod #module_name { use super::#dimension_type; use super::#quantity_type; - #use_ratio + use super::Ratio; #quantities #constants } @@ -138,14 +118,15 @@ impl Defs { } fn quantity_definitions_for_storage_type(&self, type_: &dyn StorageType) -> TokenStream { - self.dimensions + self.defs + .dimensions .iter() .map(|quantity| { let dimension = self.get_dimension_expr(&quantity.dimensions); - let quantity_type = &self.quantity_type; + let quantity_type = &self.defs.quantity_type; let quantity_name = &quantity.name; let type_ = type_.name(); - let span = self.dimension_type.span(); + let span = self.defs.dimension_type.span(); quote_spanned! {span => pub type #quantity_name = #quantity_type::<#type_, { #dimension }>; } @@ -155,11 +136,11 @@ impl Defs { fn constant_definitions_for_storage_type(&self, type_: &dyn StorageType) -> TokenStream { self - .constants + .defs.constants .iter() .map(|constant| { let dimension = self.get_dimension_expr(&constant.dimensions); - let quantity_type = &self.quantity_type; + let quantity_type = &self.defs.quantity_type; let constant_name = &constant.name; let value = constant.magnitude; let float_type = &type_.base_storage().name; diff --git a/crates/diman_unit_system/src/codegen/float_methods.rs b/crates/diman_unit_system/src/codegen/float_methods.rs index 8d294ed..8012197 100644 --- a/crates/diman_unit_system/src/codegen/float_methods.rs +++ b/crates/diman_unit_system/src/codegen/float_methods.rs @@ -1,11 +1,9 @@ use proc_macro2::TokenStream; use quote::quote; -use crate::types::Defs; +use super::{join, storage_types::FloatType, Codegen}; -use super::{join, storage_types::FloatType}; - -impl Defs { +impl Codegen { fn ensure_float_traits(&self) -> TokenStream { if cfg!(feature = "num-traits-libm") { quote! { @@ -24,11 +22,8 @@ impl Defs { method_name: &TokenStream, ) -> TokenStream { let float_type_name = &float_type.name; - let Self { - dimension_type, - quantity_type, - .. - } = &self; + let dimension_type = &self.defs.dimension_type; + let quantity_type = &self.defs.quantity_type; quote! { impl #quantity_type<#float_type_name, {#dimension_type::none()} > { pub fn #method_name(&self) -> #quantity_type<#float_type_name, {#dimension_type::none()}> { @@ -96,11 +91,8 @@ impl Defs { fn specific_float_methods(&self, float_type: &FloatType) -> TokenStream { let float_type = &float_type.name; - let Self { - dimension_type, - quantity_type, - .. - } = &self; + let dimension_type = &self.defs.dimension_type; + let quantity_type = &self.defs.quantity_type; quote! { impl #quantity_type<#float_type, D> { pub fn squared(&self) -> #quantity_type<#float_type, { D.mul(2) }> diff --git a/crates/diman_unit_system/src/codegen/generic_methods.rs b/crates/diman_unit_system/src/codegen/generic_methods.rs index 725819f..cb701f4 100644 --- a/crates/diman_unit_system/src/codegen/generic_methods.rs +++ b/crates/diman_unit_system/src/codegen/generic_methods.rs @@ -2,9 +2,9 @@ use proc_macro2::TokenStream; use quote::quote; use syn::Type; -use crate::types::Defs; +use super::Codegen; -impl Defs { +impl Codegen { pub fn gen_generic_methods(&self) -> TokenStream { self.storage_type_names() .map(|name| self.impl_method_for_generic_storage_type(&name, "e! { abs })) @@ -16,11 +16,8 @@ impl Defs { storage_type: &Type, name: &TokenStream, ) -> TokenStream { - let Self { - dimension_type, - quantity_type, - .. - } = &self; + let dimension_type = &self.defs.dimension_type; + let quantity_type = &self.defs.quantity_type; quote! { impl #quantity_type<#storage_type, D> { pub fn #name(&self) -> #quantity_type<#storage_type, D> { diff --git a/crates/diman_unit_system/src/codegen/hdf5.rs b/crates/diman_unit_system/src/codegen/hdf5.rs index 57acc50..8cac75f 100644 --- a/crates/diman_unit_system/src/codegen/hdf5.rs +++ b/crates/diman_unit_system/src/codegen/hdf5.rs @@ -3,9 +3,9 @@ use quote::quote; use super::join; use super::storage_types::{FloatType, VectorType}; -use crate::types::Defs; +use super::Codegen; -impl Defs { +impl Codegen { pub fn gen_hdf5_impl(&self) -> TokenStream { join([self.hdf5_floats_impl(), self.hdf5_vectors_impl()]) } @@ -20,11 +20,8 @@ impl Defs { fn hdf5_float_impl(&self, float_type: &FloatType) -> TokenStream { let float_type_name = &float_type.name; let hdf5_type = &float_type.hdf5_type; - let Defs { - dimension_type, - quantity_type, - .. - } = self; + let dimension_type = &self.defs.dimension_type; + let quantity_type = &self.defs.quantity_type; quote! { unsafe impl hdf5::H5Type for #quantity_type<#float_type_name, D> { fn type_descriptor() -> hdf5::types::TypeDescriptor { @@ -45,11 +42,8 @@ impl Defs { let vector_type_name = &vector_type.name; let hdf5_type = &vector_type.float_type.hdf5_type; let num_dims = vector_type.num_dims; - let Defs { - dimension_type, - quantity_type, - .. - } = self; + let dimension_type = &self.defs.dimension_type; + let quantity_type = &self.defs.quantity_type; quote! { unsafe impl hdf5::H5Type for #quantity_type<#vector_type_name, D> { fn type_descriptor() -> hdf5::types::TypeDescriptor { diff --git a/crates/diman_unit_system/src/codegen/mod.rs b/crates/diman_unit_system/src/codegen/mod.rs index c6442f9..fe3b486 100644 --- a/crates/diman_unit_system/src/codegen/mod.rs +++ b/crates/diman_unit_system/src/codegen/mod.rs @@ -21,11 +21,26 @@ use proc_macro2::TokenStream; use crate::types::Defs; +pub enum CallerType { + /// The macro is called from within this crate (`diman_unit_system`) + /// and imports need to be directly from `diman_lib`. + #[allow(dead_code)] + Internal, + /// The macro is called from somewhere else (`diman` or a user's crate) + /// and imports need to be from `diman`. + External, +} + +pub struct Codegen { + pub defs: Defs, + pub caller_type: CallerType, +} + fn join(streams: [TokenStream; D]) -> TokenStream { streams.into_iter().collect() } -impl Defs { +impl Codegen { pub fn code_gen(&self) -> TokenStream { join([ self.gen_dimension(), diff --git a/crates/diman_unit_system/src/codegen/mpi.rs b/crates/diman_unit_system/src/codegen/mpi.rs index 3ac9abb..43e530b 100644 --- a/crates/diman_unit_system/src/codegen/mpi.rs +++ b/crates/diman_unit_system/src/codegen/mpi.rs @@ -2,11 +2,12 @@ use proc_macro2::TokenStream; use quote::quote; use super::storage_types::{FloatType, VectorType}; -use crate::types::Defs; use super::join; -impl Defs { +use super::Codegen; + +impl Codegen { pub fn gen_mpi_impl(&self) -> TokenStream { join([self.mpi_floats_impl(), self.mpi_vectors_impl()]) } @@ -21,11 +22,8 @@ impl Defs { fn mpi_float_impl(&self, float_type: &FloatType) -> TokenStream { let float_type_name = &float_type.name; let mpi_type = &float_type.mpi_type; - let Defs { - dimension_type, - quantity_type, - .. - } = self; + let dimension_type = &self.defs.dimension_type; + let quantity_type = &self.defs.quantity_type; quote! { unsafe impl ::mpi::traits::Equivalence for #quantity_type<#float_type_name, D> { type Out = ::mpi::datatype::SystemDatatype; @@ -50,11 +48,8 @@ impl Defs { let vector_type_name = &vector_type.name; let float_type = &vector_type.float_type.name; let num_dims = vector_type.num_dims as i32; - let Defs { - dimension_type, - quantity_type, - .. - } = self; + let dimension_type = &self.defs.dimension_type; + let quantity_type = &self.defs.quantity_type; quote! { unsafe impl ::mpi::traits::Equivalence for #quantity_type<#vector_type_name, D> { type Out = ::mpi::datatype::DatatypeRef<'static>; diff --git a/crates/diman_unit_system/src/codegen/num_traits/mod.rs b/crates/diman_unit_system/src/codegen/num_traits/mod.rs index f520c75..0212773 100644 --- a/crates/diman_unit_system/src/codegen/num_traits/mod.rs +++ b/crates/diman_unit_system/src/codegen/num_traits/mod.rs @@ -3,9 +3,9 @@ mod operator_trait; use proc_macro2::TokenStream; use quote::quote; -use crate::types::Defs; +use super::Codegen; -impl Defs { +impl Codegen { pub fn gen_numeric_trait_impls(&self) -> TokenStream { let operators = self.gen_operator_trait_impls(); let sum = self.gen_sum_impl(); @@ -20,11 +20,8 @@ impl Defs { } fn gen_sum_impl(&self) -> TokenStream { - let Self { - quantity_type, - dimension_type, - .. - } = self; + let dimension_type = &self.defs.dimension_type; + let quantity_type = &self.defs.quantity_type; quote! { impl> core::iter::Sum for #quantity_type @@ -42,11 +39,8 @@ impl Defs { } fn gen_neg_impl(&self) -> TokenStream { - let Self { - quantity_type, - dimension_type, - .. - } = self; + let dimension_type = &self.defs.dimension_type; + let quantity_type = &self.defs.quantity_type; quote! { impl> core::ops::Neg for #quantity_type { type Output = Self; @@ -59,11 +53,8 @@ impl Defs { } fn gen_from_impl(&self) -> TokenStream { - let Self { - quantity_type, - dimension_type, - .. - } = self; + let dimension_type = &self.defs.dimension_type; + let quantity_type = &self.defs.quantity_type; quote! { impl From for #quantity_type diff --git a/crates/diman_unit_system/src/codegen/num_traits/operator_trait.rs b/crates/diman_unit_system/src/codegen/num_traits/operator_trait.rs index 6cb6dd6..33917ab 100644 --- a/crates/diman_unit_system/src/codegen/num_traits/operator_trait.rs +++ b/crates/diman_unit_system/src/codegen/num_traits/operator_trait.rs @@ -1,3 +1,4 @@ +use super::super::Codegen; use proc_macro2::{Ident, TokenStream}; use quote::{quote, quote_spanned}; use syn::Type; @@ -18,8 +19,6 @@ pub enum Trait { use Trait::*; -use crate::types::Defs; - impl Trait { pub fn name(&self) -> TokenStream { match self { @@ -544,7 +543,7 @@ macro_rules! add_trait { } } -impl Defs { +impl Codegen { pub fn gen_operator_trait_impls(&self) -> TokenStream { self.iter_numeric_traits() .map(|num_trait| self.gen_operator_trait_impl(num_trait)) @@ -637,20 +636,20 @@ impl Defs { let fn_name = name.fn_name(); let trait_name = name.name(); let fn_return_type = name.fn_return_type(); - let lhs = numeric_trait.lhs_type(&self.quantity_type, &self.dimension_type); - let rhs = numeric_trait.rhs_type(&self.quantity_type, &self.dimension_type); + let lhs = numeric_trait.lhs_type(&self.defs.quantity_type, &self.defs.dimension_type); + let rhs = numeric_trait.rhs_type(&self.defs.quantity_type, &self.defs.dimension_type); let lhs_arg = name.lhs_arg(); let rhs_arg = name.rhs_arg_type(&rhs); let fn_args = quote! { #lhs_arg, rhs: #rhs_arg }; - let impl_generics = numeric_trait.generics_gen(&self.dimension_type); + let impl_generics = numeric_trait.generics_gen(&self.defs.dimension_type); - let output_type = numeric_trait.output_type(&self.dimension_type); + let output_type = numeric_trait.output_type(&self.defs.dimension_type); let output_type_def = output_type .as_ref() - .map(|output_type| output_type.output_type_def(&self.quantity_type)); + .map(|output_type| output_type.output_type_def(&self.defs.quantity_type)); - let trait_bounds = numeric_trait.trait_bounds(&self.quantity_type, &output_type); - let fn_return_expr = numeric_trait.fn_return_expr(&self.quantity_type, &output_type); + let trait_bounds = numeric_trait.trait_bounds(&self.defs.quantity_type, &output_type); + let fn_return_expr = numeric_trait.fn_return_expr(&self.defs.quantity_type, &output_type); quote! { impl #impl_generics #trait_name::<#rhs> for #lhs where diff --git a/crates/diman_unit_system/src/codegen/rand.rs b/crates/diman_unit_system/src/codegen/rand.rs index 43c393c..832e5bf 100644 --- a/crates/diman_unit_system/src/codegen/rand.rs +++ b/crates/diman_unit_system/src/codegen/rand.rs @@ -3,16 +3,16 @@ use quote::quote; use proc_macro2::TokenStream; use super::storage_types::FloatType; -use crate::types::Defs; +use super::Codegen; -impl Defs { +impl Codegen { pub fn gen_rand_impl(&self) -> TokenStream { let float_impls: TokenStream = self .float_types() .iter() .map(|float_type| self.rand_impl_float(float_type)) .collect(); - let Defs { dimension_type, .. } = self; + let dimension_type = &self.defs.dimension_type; quote! { use ::rand::distributions::uniform::SampleBorrow; use ::rand::distributions::uniform::SampleUniform; @@ -28,11 +28,8 @@ impl Defs { } fn rand_impl_float(&self, float_type: &FloatType) -> TokenStream { - let Defs { - dimension_type, - quantity_type, - .. - } = self; + let dimension_type = &self.defs.dimension_type; + let quantity_type = &self.defs.quantity_type; let float_type = &float_type.name; quote! { impl UniformSampler for UniformQuantity<#float_type, D> { diff --git a/crates/diman_unit_system/src/codegen/serde.rs b/crates/diman_unit_system/src/codegen/serde.rs index 0d699f6..7cde276 100644 --- a/crates/diman_unit_system/src/codegen/serde.rs +++ b/crates/diman_unit_system/src/codegen/serde.rs @@ -2,11 +2,12 @@ use proc_macro2::TokenStream; use quote::quote; use super::storage_types::{FloatType, VectorType}; -use crate::types::Defs; use super::join; -impl Defs { +use super::Codegen; + +impl Codegen { pub fn gen_serde_impl(&self) -> TokenStream { join([ self.serde_helpers_impl(), @@ -16,13 +17,9 @@ impl Defs { } fn serde_helpers_impl(&self) -> TokenStream { - let Defs { - dimension_type, - quantity_type, - .. - } = self; - - let units = self.units_array(self.units.iter()); + let dimension_type = &self.defs.dimension_type; + let quantity_type = &self.defs.quantity_type; + let units = self.units_array(self.defs.units.iter()); quote! { use std::marker::PhantomData; @@ -98,12 +95,9 @@ impl Defs { } fn serde_float_impl(&self, float_type: &FloatType) -> TokenStream { - let Defs { - dimension_type, - quantity_type, - .. - } = self; - let units = self.units_array(self.units.iter()); + let dimension_type = &self.defs.dimension_type; + let quantity_type = &self.defs.quantity_type; + let units = self.units_array(self.defs.units.iter()); let serialize_method = &float_type.serialize_method; let float_type = &float_type.name; quote! { @@ -224,12 +218,9 @@ impl Defs { let float_type = &vector_type.float_type.name; let num_dims = vector_type.num_dims; let vector_type = &vector_type.name; - let Defs { - dimension_type, - quantity_type, - .. - } = self; - let units = self.units_array(self.units.iter()); + let dimension_type = &self.defs.dimension_type; + let quantity_type = &self.defs.quantity_type; + let units = self.units_array(self.defs.units.iter()); quote! { impl<'de, const D: #dimension_type> serde::Deserialize<'de> for #quantity_type<#vector_type, D> { fn deserialize(deserializer: DE) -> Result<#quantity_type<#vector_type, D>, DE::Error> diff --git a/crates/diman_unit_system/src/codegen/storage_types.rs b/crates/diman_unit_system/src/codegen/storage_types.rs index 44ac163..1e30394 100644 --- a/crates/diman_unit_system/src/codegen/storage_types.rs +++ b/crates/diman_unit_system/src/codegen/storage_types.rs @@ -2,7 +2,7 @@ use proc_macro2::TokenStream; use quote::quote; use syn::Type; -use crate::types::Defs; +use super::Codegen; pub struct VectorType { pub name: Type, @@ -71,7 +71,7 @@ impl StorageType for FloatType { } } -impl Defs { +impl Codegen { pub fn storage_types(&self) -> impl Iterator> { self.float_types() .into_iter() diff --git a/crates/diman_unit_system/src/codegen/units.rs b/crates/diman_unit_system/src/codegen/units.rs index 0eca456..4662ac4 100644 --- a/crates/diman_unit_system/src/codegen/units.rs +++ b/crates/diman_unit_system/src/codegen/units.rs @@ -2,12 +2,16 @@ use proc_macro2::TokenStream; use quote::{format_ident, quote, quote_spanned}; use syn::Type; -use super::storage_types::{FloatType, VectorType}; -use crate::types::{Defs, Unit}; +use super::{ + storage_types::{FloatType, VectorType}, + Codegen, +}; +use crate::types::Unit; -impl Defs { +impl Codegen { pub fn gen_unit_constructors(&self) -> TokenStream { - self.units + self.defs + .units .iter() .map(|unit| { let dimension = self.get_dimension_expr(&unit.dimensions); @@ -45,7 +49,7 @@ impl Defs { unit: &Unit, dimension: &TokenStream, ) -> TokenStream { - let quantity_type = &self.quantity_type; + let quantity_type = &self.defs.quantity_type; let unit_name = &unit.name; let conversion_method_name = format_ident!("in_{}", unit_name); let magnitude = unit.magnitude; @@ -66,14 +70,15 @@ impl Defs { unit: &Unit, quantity_dimension: &TokenStream, ) -> TokenStream { - let Defs { quantity_type, .. } = &self; + let dimension_type = &self.defs.dimension_type; + let quantity_type = &self.defs.quantity_type; let Unit { name: unit_name, magnitude, .. } = unit; let name = &float_type.name; - let span = self.dimension_type.span(); + let span = dimension_type.span(); // Without const_fn_floating_point_arithmetic (https://github.com/rust-lang/rust/issues/57241) // we cannot make unit constructors a const fn in general (since it requires the unstable // const_fn_floating_point_arithmetic feature). The following allows the constructor with 1.0 @@ -104,7 +109,8 @@ impl Defs { unit: &Unit, quantity_dimension: &TokenStream, ) -> TokenStream { - let Defs { quantity_type, .. } = &self; + let dimension_type = &self.defs.dimension_type; + let quantity_type = &self.defs.quantity_type; let Unit { name: unit_name, magnitude, @@ -127,7 +133,7 @@ impl Defs { 3 => quote! { x, y, z }, _ => unreachable!(), }; - let span = self.dimension_type.span(); + let span = dimension_type.span(); quote_spanned! {span => impl #quantity_type<#name, {#quantity_dimension}> { pub fn #unit_name(#fn_args) -> #quantity_type<#name, {#quantity_dimension}> { diff --git a/crates/diman_unit_system/src/codegen/vector_methods.rs b/crates/diman_unit_system/src/codegen/vector_methods.rs index a2dc5d6..da73e96 100644 --- a/crates/diman_unit_system/src/codegen/vector_methods.rs +++ b/crates/diman_unit_system/src/codegen/vector_methods.rs @@ -1,11 +1,9 @@ use proc_macro2::TokenStream; use quote::quote; -use crate::types::Defs; +use super::{storage_types::VectorType, Codegen}; -use super::storage_types::VectorType; - -impl Defs { +impl Codegen { pub fn gen_vector_methods(&self) -> TokenStream { self.vector_types() .iter() @@ -14,11 +12,8 @@ impl Defs { } fn impl_vector_methods(&self, vector_type: &VectorType) -> TokenStream { - let Defs { - dimension_type, - quantity_type, - .. - } = self; + let dimension_type = &self.defs.dimension_type; + let quantity_type = &self.defs.quantity_type; let VectorType { name: vector_type_name, float_type, diff --git a/crates/diman_unit_system/src/lib.rs b/crates/diman_unit_system/src/lib.rs index dd7a756..33b03c9 100644 --- a/crates/diman_unit_system/src/lib.rs +++ b/crates/diman_unit_system/src/lib.rs @@ -6,14 +6,33 @@ mod parse; mod resolve; mod types; +use codegen::{CallerType, Codegen}; use proc_macro2::TokenStream; use syn::*; -#[proc_macro] -pub fn unit_system(item: proc_macro::TokenStream) -> proc_macro::TokenStream { +fn run_unit_system( + item: proc_macro::TokenStream, + caller_type: CallerType, +) -> proc_macro::TokenStream { let defs = parse_macro_input!(item as types::UnresolvedTemplates); let expanded = defs.expand_templates(); let resolved = expanded.resolve(); - let impls: TokenStream = resolved.code_gen(); + let impls: TokenStream = Codegen { + defs: resolved, + caller_type, + } + .code_gen(); impls.into() } + +#[proc_macro] +pub fn unit_system(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + run_unit_system(input, CallerType::External) +} + +// I would like to make this private, but I am not allowed. +// Also #[cfg(test)] doesn't apply here. +#[proc_macro] +pub fn unit_system_internal(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + run_unit_system(input, CallerType::Internal) +} diff --git a/crates/diman_unit_system/tests/compile_fail/dimension_annotation_violated_constant.rs b/crates/diman_unit_system/tests/compile_fail/dimension_annotation_violated_constant.rs index 4068f23..d222d40 100644 --- a/crates/diman_unit_system/tests/compile_fail/dimension_annotation_violated_constant.rs +++ b/crates/diman_unit_system/tests/compile_fail/dimension_annotation_violated_constant.rs @@ -1,8 +1,8 @@ #![allow(incomplete_features)] #![feature(generic_const_exprs, adt_const_params)] -use diman_unit_system::unit_system; -unit_system!( +use diman_unit_system::unit_system_internal; +unit_system_internal!( quantity_type Quantity; dimension_type Dimension; dimension Mass; diff --git a/crates/diman_unit_system/tests/compile_fail/dimension_annotation_violated_unit.rs b/crates/diman_unit_system/tests/compile_fail/dimension_annotation_violated_unit.rs index e995874..f3f6d66 100644 --- a/crates/diman_unit_system/tests/compile_fail/dimension_annotation_violated_unit.rs +++ b/crates/diman_unit_system/tests/compile_fail/dimension_annotation_violated_unit.rs @@ -1,8 +1,8 @@ #![allow(incomplete_features)] #![feature(generic_const_exprs, adt_const_params)] -use diman_unit_system::unit_system; -unit_system!( +use diman_unit_system::unit_system_internal; +unit_system_internal!( quantity_type Quantity; dimension_type Dimension; dimension Mass; diff --git a/crates/diman_unit_system/tests/compile_fail/dimension_annotation_with_unit_not_allowed.rs b/crates/diman_unit_system/tests/compile_fail/dimension_annotation_with_unit_not_allowed.rs index 3771c64..5950ec1 100644 --- a/crates/diman_unit_system/tests/compile_fail/dimension_annotation_with_unit_not_allowed.rs +++ b/crates/diman_unit_system/tests/compile_fail/dimension_annotation_with_unit_not_allowed.rs @@ -1,8 +1,8 @@ #![allow(incomplete_features)] #![feature(generic_const_exprs, adt_const_params)] -use diman_unit_system::unit_system; -unit_system!( +use diman_unit_system::unit_system_internal; +unit_system_internal!( quantity_type Quantity; dimension_type Dimension; dimension Mass; diff --git a/crates/diman_unit_system/tests/compile_fail/dimension_definition_with_numeric_factor.rs b/crates/diman_unit_system/tests/compile_fail/dimension_definition_with_numeric_factor.rs index 4e809c7..07358a5 100644 --- a/crates/diman_unit_system/tests/compile_fail/dimension_definition_with_numeric_factor.rs +++ b/crates/diman_unit_system/tests/compile_fail/dimension_definition_with_numeric_factor.rs @@ -1,9 +1,9 @@ #![allow(incomplete_features)] #![feature(generic_const_exprs, adt_const_params)] -use diman_unit_system::unit_system; +use diman_unit_system::unit_system_internal; -unit_system!( +unit_system_internal!( quantity_type Quantity; dimension_type Dimension; dimension Dimensionless = 1; diff --git a/crates/diman_unit_system/tests/compile_fail/example_system/mod.rs b/crates/diman_unit_system/tests/compile_fail/example_system/mod.rs index 174d31f..f0e537d 100644 --- a/crates/diman_unit_system/tests/compile_fail/example_system/mod.rs +++ b/crates/diman_unit_system/tests/compile_fail/example_system/mod.rs @@ -1,7 +1,6 @@ -use diman_unit_system::unit_system; +use diman_unit_system::unit_system_internal; - -unit_system!( +unit_system_internal!( quantity_type Quantity; dimension_type Dimension; dimension Length; diff --git a/crates/diman_unit_system/tests/compile_fail/resolver_dimension_in_constant_expression_not_allowed.rs b/crates/diman_unit_system/tests/compile_fail/resolver_dimension_in_constant_expression_not_allowed.rs index e250458..2e8fdbd 100644 --- a/crates/diman_unit_system/tests/compile_fail/resolver_dimension_in_constant_expression_not_allowed.rs +++ b/crates/diman_unit_system/tests/compile_fail/resolver_dimension_in_constant_expression_not_allowed.rs @@ -1,8 +1,8 @@ #![allow(incomplete_features)] #![feature(generic_const_exprs, adt_const_params)] -use diman_unit_system::unit_system; -unit_system!( +use diman_unit_system::unit_system_internal; +unit_system_internal!( quantity_type Quantity; dimension_type Dimension; dimension Mass; diff --git a/crates/diman_unit_system/tests/compile_fail/resolver_dimension_in_unit_expression_not_allowed.rs b/crates/diman_unit_system/tests/compile_fail/resolver_dimension_in_unit_expression_not_allowed.rs index 7b67427..34f4a77 100644 --- a/crates/diman_unit_system/tests/compile_fail/resolver_dimension_in_unit_expression_not_allowed.rs +++ b/crates/diman_unit_system/tests/compile_fail/resolver_dimension_in_unit_expression_not_allowed.rs @@ -1,8 +1,8 @@ #![allow(incomplete_features)] #![feature(generic_const_exprs, adt_const_params)] -use diman_unit_system::unit_system; -unit_system!( +use diman_unit_system::unit_system_internal; +unit_system_internal!( quantity_type Quantity; dimension_type Dimension; dimension Mass; diff --git a/crates/diman_unit_system/tests/compile_fail/resolver_duplicate_base_unit.rs b/crates/diman_unit_system/tests/compile_fail/resolver_duplicate_base_unit.rs index 36086d5..1176545 100644 --- a/crates/diman_unit_system/tests/compile_fail/resolver_duplicate_base_unit.rs +++ b/crates/diman_unit_system/tests/compile_fail/resolver_duplicate_base_unit.rs @@ -1,9 +1,9 @@ #![allow(incomplete_features)] #![feature(generic_const_exprs, adt_const_params)] -use diman_unit_system::unit_system; +use diman_unit_system::unit_system_internal; -unit_system!( +unit_system_internal!( quantity_type Quantity; dimension_type Dimension; dimension Length; diff --git a/crates/diman_unit_system/tests/compile_fail/resolver_duplicate_definition.rs b/crates/diman_unit_system/tests/compile_fail/resolver_duplicate_definition.rs index 6160c3f..49658cd 100644 --- a/crates/diman_unit_system/tests/compile_fail/resolver_duplicate_definition.rs +++ b/crates/diman_unit_system/tests/compile_fail/resolver_duplicate_definition.rs @@ -1,9 +1,9 @@ #![allow(incomplete_features)] #![feature(generic_const_exprs, adt_const_params)] -use diman_unit_system::unit_system; +use diman_unit_system::unit_system_internal; -unit_system!( +unit_system_internal!( quantity_type Quantity; dimension_type Dimension; dimension Length; diff --git a/crates/diman_unit_system/tests/compile_fail/resolver_duplicate_symbol.rs b/crates/diman_unit_system/tests/compile_fail/resolver_duplicate_symbol.rs index 4e21e18..e4a8cdb 100644 --- a/crates/diman_unit_system/tests/compile_fail/resolver_duplicate_symbol.rs +++ b/crates/diman_unit_system/tests/compile_fail/resolver_duplicate_symbol.rs @@ -1,9 +1,9 @@ #![allow(incomplete_features)] #![feature(generic_const_exprs, adt_const_params)] -use diman_unit_system::unit_system; +use diman_unit_system::unit_system_internal; -unit_system!( +unit_system_internal!( quantity_type Quantity; dimension_type Dimension; dimension Length; diff --git a/crates/diman_unit_system/tests/compile_fail/resolver_partial_resolution.rs b/crates/diman_unit_system/tests/compile_fail/resolver_partial_resolution.rs index d2c62f3..4791e59 100644 --- a/crates/diman_unit_system/tests/compile_fail/resolver_partial_resolution.rs +++ b/crates/diman_unit_system/tests/compile_fail/resolver_partial_resolution.rs @@ -1,9 +1,9 @@ #![allow(incomplete_features)] #![feature(generic_const_exprs, adt_const_params)] -use diman_unit_system::unit_system; +use diman_unit_system::unit_system_internal; -unit_system!( +unit_system_internal!( quantity_type Quantity; dimension_type Dimension; dimension Length; diff --git a/crates/diman_unit_system/tests/compile_fail/resolver_prefixed_or_aliased_units_dont_generate_multiple_errors.rs b/crates/diman_unit_system/tests/compile_fail/resolver_prefixed_or_aliased_units_dont_generate_multiple_errors.rs index 536d5ce..4fd6bfc 100644 --- a/crates/diman_unit_system/tests/compile_fail/resolver_prefixed_or_aliased_units_dont_generate_multiple_errors.rs +++ b/crates/diman_unit_system/tests/compile_fail/resolver_prefixed_or_aliased_units_dont_generate_multiple_errors.rs @@ -1,9 +1,9 @@ #![allow(incomplete_features)] #![feature(generic_const_exprs, adt_const_params)] -use diman_unit_system::unit_system; +use diman_unit_system::unit_system_internal; -unit_system!( +unit_system_internal!( quantity_type Quantity; dimension_type Dimension; #[prefix(kilo)] diff --git a/crates/diman_unit_system/tests/compile_fail/resolver_undefined_identifier.rs b/crates/diman_unit_system/tests/compile_fail/resolver_undefined_identifier.rs index 90e5c86..1c8772c 100644 --- a/crates/diman_unit_system/tests/compile_fail/resolver_undefined_identifier.rs +++ b/crates/diman_unit_system/tests/compile_fail/resolver_undefined_identifier.rs @@ -1,9 +1,9 @@ #![allow(incomplete_features)] #![feature(generic_const_exprs, adt_const_params)] -use diman_unit_system::unit_system; +use diman_unit_system::unit_system_internal; -unit_system!( +unit_system_internal!( quantity_type Quantity; dimension_type Dimension; dimension Length; diff --git a/crates/diman_unit_system/tests/compile_fail/resolver_units_in_dimension_expression_not_allowed.rs b/crates/diman_unit_system/tests/compile_fail/resolver_units_in_dimension_expression_not_allowed.rs index c8ac76f..98d0fa4 100644 --- a/crates/diman_unit_system/tests/compile_fail/resolver_units_in_dimension_expression_not_allowed.rs +++ b/crates/diman_unit_system/tests/compile_fail/resolver_units_in_dimension_expression_not_allowed.rs @@ -1,8 +1,8 @@ #![allow(incomplete_features)] #![feature(generic_const_exprs, adt_const_params)] -use diman_unit_system::unit_system; -unit_system!( +use diman_unit_system::unit_system_internal; +unit_system_internal!( quantity_type Quantity; dimension_type Dimension; dimension Mass; diff --git a/crates/diman_unit_system/tests/compile_fail/resolver_unresolvable.rs b/crates/diman_unit_system/tests/compile_fail/resolver_unresolvable.rs index c8b5f18..f15d8b2 100644 --- a/crates/diman_unit_system/tests/compile_fail/resolver_unresolvable.rs +++ b/crates/diman_unit_system/tests/compile_fail/resolver_unresolvable.rs @@ -1,9 +1,9 @@ #![allow(incomplete_features)] #![feature(generic_const_exprs, adt_const_params)] -use diman_unit_system::unit_system; +use diman_unit_system::unit_system_internal; -unit_system!( +unit_system_internal!( quantity_type Quantity; dimension_type Dimension; dimension Length; diff --git a/crates/diman_unit_system/tests/mod.rs b/crates/diman_unit_system/tests/mod.rs index 13de6db..c355eab 100644 --- a/crates/diman_unit_system/tests/mod.rs +++ b/crates/diman_unit_system/tests/mod.rs @@ -9,6 +9,7 @@ feature = "mpi", feature = "hdf5", feature = "rand", + feature = "num-traits-libm", )))] mod tests { #[test]