From 303c2acff17a8bcc56659fbe7e74aafdf0f0f11d Mon Sep 17 00:00:00 2001 From: tehforsch Date: Sat, 13 Jan 2024 12:55:52 +0100 Subject: [PATCH 01/10] add failing test for serde serialization and passing ones for deserialization --- tests/serde/mod.rs | 57 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/tests/serde/mod.rs b/tests/serde/mod.rs index 6f0de28..21c5ffa 100644 --- a/tests/serde/mod.rs +++ b/tests/serde/mod.rs @@ -1,3 +1,54 @@ +#[cfg(any(feature = "f32", feature = "f64"))] +macro_rules! gen_tests_for_float { + ($float_name: ident, $assert_is_close: path) => { + mod $float_name { + use crate::example_system::$float_name::Energy; + use crate::example_system::$float_name::Length; + use crate::example_system::$float_name::Time; + use crate::example_system::$float_name::Velocity; + use $assert_is_close as assert_is_close; + + #[test] + fn deserialize_float() { + let q: Length = serde_yaml::from_str("5.0 km").unwrap(); + assert_is_close(q, Length::kilometers(5.0)); + let q: Velocity = serde_yaml::from_str("5.0 km s^-1").unwrap(); + assert_is_close(q, Length::kilometers(5.0) / Time::seconds(1.0)); + } + + #[test] + #[should_panic(expected = "mismatch in dimensions")] + fn deserialize_float_dimension_mismatch() { + let q: Length = serde_yaml::from_str("5.0 kg").unwrap(); + assert_is_close(q, Length::kilometers(5.0)); + } + + #[test] + fn serialize_float() { + assert_eq!( + serde_yaml::to_string(&Length::kilometers(5.0)) + .unwrap() + .trim(), + "5000 m" + ); + assert_eq!( + serde_yaml::to_string(&Energy::joules(5.0)).unwrap().trim(), + "5 J" + ); + } + + #[test] + fn serialize_float_unnamed_dimension() { + let unnamed_dimension = Energy::joules(5.0) * Length::meters(1.0); + assert_eq!( + serde_yaml::to_string(&unnamed_dimension).unwrap().trim(), + "5 m^3 s^-2 kg" + ); + } + } + }; +} + #[cfg(any(feature = "glam-vec2", feature = "glam-dvec2"))] macro_rules! gen_tests_for_vector_2 { ($float_name: ident, $mod_name: ident, $vec_name: ty, $assert_is_close: path) => { @@ -89,6 +140,12 @@ macro_rules! gen_tests_for_vector_3 { }; } +#[cfg(feature = "f32")] +gen_tests_for_float!(f32, crate::utils::assert_is_close_f32); + +#[cfg(feature = "f64")] +gen_tests_for_float!(f64, crate::utils::assert_is_close_f64); + #[cfg(all(feature = "f32", feature = "glam-vec2"))] gen_tests_for_vector_2!(f32, vec2, glam::Vec2, crate::utils::assert_is_close_f32); From 6131729edaea7458d154f58cb763384fd2300c66 Mon Sep 17 00:00:00 2001 From: tehforsch Date: Sat, 13 Jan 2024 13:50:56 +0100 Subject: [PATCH 02/10] add runtime unit storage --- crates/diman_lib/src/lib.rs | 1 + crates/diman_lib/src/runtime_unit_storage.rs | 33 +++++++++++++++ .../src/codegen/debug_trait.rs | 42 +++++++++++-------- src/lib.rs | 1 + 4 files changed, 60 insertions(+), 17 deletions(-) create mode 100644 crates/diman_lib/src/runtime_unit_storage.rs diff --git a/crates/diman_lib/src/lib.rs b/crates/diman_lib/src/lib.rs index 1a77b12..3d0345e 100644 --- a/crates/diman_lib/src/lib.rs +++ b/crates/diman_lib/src/lib.rs @@ -2,3 +2,4 @@ #![feature(generic_const_exprs, adt_const_params)] pub mod ratio; +pub mod runtime_unit_storage; diff --git a/crates/diman_lib/src/runtime_unit_storage.rs b/crates/diman_lib/src/runtime_unit_storage.rs new file mode 100644 index 0000000..ed93a60 --- /dev/null +++ b/crates/diman_lib/src/runtime_unit_storage.rs @@ -0,0 +1,33 @@ +pub struct RuntimeUnit<'a, D> { + pub symbol: &'a str, + pub dimension: D, + pub magnitude: f64, +} + +impl<'a, D> RuntimeUnit<'a, D> { + pub fn new(symbol: &'a str, dimension: D, magnitude: f64) -> Self { + Self { + symbol, + dimension, + magnitude, + } + } +} + +pub struct RuntimeUnitStorage<'a, D> { + units: &'a [RuntimeUnit<'a, D>], +} + +impl<'a, D: PartialEq> RuntimeUnitStorage<'a, D> { + pub fn new(units: &'a [RuntimeUnit<'a, D>]) -> Self { + Self { units } + } + + pub fn get_first_symbol(&self, dim: D) -> Option<&'a str> { + self.units + .iter() + .filter(|unit| unit.dimension == dim) + .map(|unit| unit.symbol) + .next() + } +} diff --git a/crates/diman_unit_system/src/codegen/debug_trait.rs b/crates/diman_unit_system/src/codegen/debug_trait.rs index aee73a3..fff2746 100644 --- a/crates/diman_unit_system/src/codegen/debug_trait.rs +++ b/crates/diman_unit_system/src/codegen/debug_trait.rs @@ -2,6 +2,7 @@ use proc_macro2::TokenStream; use quote::quote; use crate::{ + codegen::CallerType, dimension_math::BaseDimensions, types::{base_dimension::BaseDimension, Unit}, }; @@ -9,24 +10,40 @@ use crate::{ use super::Codegen; impl Codegen { - pub fn units_array<'a>(&self, units: impl Iterator) -> TokenStream { + pub fn runtime_unit_storage<'a>(&self, units: impl Iterator) -> TokenStream { + let runtime_unit_storage = match self.caller_type { + CallerType::Internal => quote! { diman_lib::runtime_unit_storage::RuntimeUnitStorage }, + CallerType::External => quote! { ::diman::runtime_unit_storage::RuntimeUnitStorage }, + }; + let runtime_unit = match self.caller_type { + CallerType::Internal => quote! { diman_lib::runtime_unit_storage::RuntimeUnit }, + CallerType::External => quote! { ::diman::runtime_unit_storage::RuntimeUnit }, + }; let units: TokenStream = units .filter_map(|unit| { let dim = self.get_dimension_expr(&unit.dimensions); let magnitude = unit.magnitude; let symbol = &unit.symbol.as_ref()?.0.to_string(); Some(quote! { - (#dim, #symbol, #magnitude), + #runtime_unit::new( + #symbol, + #dim, + #magnitude, + ), }) }) .collect(); - quote! { [ #units ] } + quote! { + let units_array = &[#units]; + let units = #runtime_unit_storage::new(units_array); + } } pub fn gen_debug_trait_impl(&self) -> TokenStream { 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 units_storage = + self.runtime_unit_storage(self.defs.units.iter().filter(|unit| unit.magnitude == 1.0)); let get_base_dimension_symbols = self .defs .base_dimensions @@ -34,20 +51,11 @@ impl Codegen { .map(|base_dim| self.get_base_dimension_symbol(base_dim)) .collect::(); quote! { - fn get_symbol() -> Option<&'static str> { - let units: &[(#dimension_type, &str, f64)] = &#units; - units - .iter() - .filter(|(d, name, _)| d == &D ) - .map(|(_, name, _)| name) - .next() - .copied() - } - impl core::fmt::Debug for #quantity_type { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + #units_storage self.0.fmt(f)?; - if let Some(symbol) = get_symbol::() { + if let Some(symbol) = units.get_first_symbol(D) { write!(f, " {}", symbol) } else { @@ -67,10 +75,10 @@ impl Codegen { let base_dim = &base_dim.0; quote! { if D.#base_dim == #base_dimension_type_one { - write!(f, " {}", get_symbol::< { #dim }>().unwrap())?; + write!(f, " {}", units.get_first_symbol(#dim).unwrap())?; } else if D.#base_dim != #base_dimension_type_zero { - write!(f, " {}^{}", get_symbol::< { #dim }>().unwrap(), D.#base_dim)?; + write!(f, " {}^{}", units.get_first_symbol(#dim).unwrap(), D.#base_dim)?; } } } diff --git a/src/lib.rs b/src/lib.rs index 2f811b5..4d28349 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -135,3 +135,4 @@ pub type Product = >::Output; pub type Quotient = >::Output; pub use diman_lib::ratio::Ratio; +pub use diman_lib::runtime_unit_storage; From e3f54fce0e2f0f7578f1ad6090db994deb611688 Mon Sep 17 00:00:00 2001 From: tehforsch Date: Sun, 14 Jan 2024 17:17:11 +0100 Subject: [PATCH 03/10] turn base_dimension_exponent into trait in diman_lib, make BaseDimensionExponent(i64) just i64 --- .../diman_lib/src/base_dimension_exponent.rs | 21 ++++++++ crates/diman_lib/src/lib.rs | 1 + crates/diman_lib/src/ratio.rs | 22 ++++---- .../src/codegen/base_dimension_type.rs | 15 ++---- .../diman_unit_system/src/dimension_math.rs | 17 +++--- crates/diman_unit_system/src/parse/mod.rs | 14 ++--- crates/diman_unit_system/src/resolve/error.rs | 5 +- .../src/resolve/ident_storage.rs | 6 +-- .../src/types/base_dimension_exponent.rs | 53 ------------------- .../diman_unit_system/src/types/expression.rs | 18 +++---- crates/diman_unit_system/src/types/mod.rs | 11 ++-- 11 files changed, 77 insertions(+), 106 deletions(-) create mode 100644 crates/diman_lib/src/base_dimension_exponent.rs delete mode 100644 crates/diman_unit_system/src/types/base_dimension_exponent.rs diff --git a/crates/diman_lib/src/base_dimension_exponent.rs b/crates/diman_lib/src/base_dimension_exponent.rs new file mode 100644 index 0000000..ae79c4c --- /dev/null +++ b/crates/diman_lib/src/base_dimension_exponent.rs @@ -0,0 +1,21 @@ +use std::ops::{AddAssign, Mul, Neg}; + +pub trait BaseDimensionExponent: Clone + PartialEq + Copy + Mul + AddAssign + Neg { + fn float_pow(num: f64, exponent: Self) -> f64; + fn one() -> Self; + fn zero() -> Self; +} + +impl BaseDimensionExponent for i64 { + fn one() -> Self { + 1 + } + + fn zero() -> Self { + 0 + } + + fn float_pow(num: f64, exponent: Self) -> f64 { + num.powi(exponent as i32) + } +} diff --git a/crates/diman_lib/src/lib.rs b/crates/diman_lib/src/lib.rs index 3d0345e..ac5a170 100644 --- a/crates/diman_lib/src/lib.rs +++ b/crates/diman_lib/src/lib.rs @@ -1,5 +1,6 @@ #![allow(incomplete_features)] #![feature(generic_const_exprs, adt_const_params)] +pub mod base_dimension_exponent; pub mod ratio; pub mod runtime_unit_storage; diff --git a/crates/diman_lib/src/ratio.rs b/crates/diman_lib/src/ratio.rs index cbcf4f4..bc0bab5 100644 --- a/crates/diman_lib/src/ratio.rs +++ b/crates/diman_lib/src/ratio.rs @@ -1,3 +1,5 @@ +use crate::base_dimension_exponent::BaseDimensionExponent; + #[derive( ::core::cmp::PartialEq, ::core::cmp::Eq, @@ -21,14 +23,6 @@ const fn gcd(mut a: i64, mut b: i64) -> i64 { } 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 } } @@ -88,8 +82,18 @@ impl Ratio { denom: self.num, } } +} + +impl BaseDimensionExponent for Ratio { + fn one() -> Self { + Self { num: 1, denom: 1 } + } + + fn zero() -> Self { + Self { num: 0, denom: 1 } + } - pub fn float_pow(num: f64, exponent: Self) -> f64 { + fn float_pow(num: f64, exponent: Self) -> f64 { num.powf(exponent.num as f64 / exponent.denom as f64) } } 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 d12b072..c1c7ece 100644 --- a/crates/diman_unit_system/src/codegen/base_dimension_type.rs +++ b/crates/diman_unit_system/src/codegen/base_dimension_type.rs @@ -2,15 +2,11 @@ use proc_macro2::{Ident, TokenStream}; use quote::quote; use super::Codegen; -use crate::types::BaseDimensionExponent; +use crate::types::Exponent; #[cfg(feature = "rational-dimensions")] impl Codegen { - pub fn get_base_dimension_entry( - &self, - field: &Ident, - value: &BaseDimensionExponent, - ) -> TokenStream { + pub fn get_base_dimension_entry(&self, field: &Ident, value: &Exponent) -> TokenStream { let num = value.num(); let denom = value.denom(); quote! { #field: Ratio::new(#num, #denom), } @@ -80,12 +76,7 @@ impl Codegen { #[cfg(not(feature = "rational-dimensions"))] impl Codegen { - pub fn get_base_dimension_entry( - &self, - field: &Ident, - value: &BaseDimensionExponent, - ) -> TokenStream { - let value = value.0; + pub fn get_base_dimension_entry(&self, field: &Ident, value: &Exponent) -> TokenStream { quote! { #field: #value, } } diff --git a/crates/diman_unit_system/src/dimension_math.rs b/crates/diman_unit_system/src/dimension_math.rs index 7a22e78..46f132f 100644 --- a/crates/diman_unit_system/src/dimension_math.rs +++ b/crates/diman_unit_system/src/dimension_math.rs @@ -1,15 +1,16 @@ use std::collections::HashMap; +use diman_lib::base_dimension_exponent::BaseDimensionExponent; use proc_macro2::Ident; use crate::{ types::expression::MulDiv, - types::{base_dimension::BaseDimension, BaseDimensionExponent}, + types::{base_dimension::BaseDimension, Exponent}, }; #[derive(Clone)] pub struct BaseDimensions { - fields: HashMap, + fields: HashMap, } #[derive(Clone)] @@ -38,11 +39,11 @@ impl BaseDimensions { pub fn for_base_dimension(base_dim: BaseDimension) -> Self { let mut fields = HashMap::new(); - fields.insert(base_dim, BaseDimensionExponent::one()); + fields.insert(base_dim, Exponent::one()); Self { fields } } - pub(crate) fn fields(&self) -> impl Iterator { + pub(crate) fn fields(&self) -> impl Iterator { self.fields.iter().map(|(dim, exp)| (&dim.0, exp)) } @@ -54,7 +55,7 @@ impl BaseDimensions { self.fields.len() } - pub(crate) fn get(&self, dim: &BaseDimension) -> Option<&BaseDimensionExponent> { + pub(crate) fn get(&self, dim: &BaseDimension) -> Option<&Exponent> { self.fields.get(dim) } } @@ -96,7 +97,7 @@ impl core::ops::Div for BaseDimensions { } impl MulDiv for BaseDimensions { - fn pow(self, pow: BaseDimensionExponent) -> Self { + fn pow(self, pow: Exponent) -> Self { BaseDimensions { fields: self .fields @@ -146,9 +147,9 @@ impl core::ops::Div for DimensionsAndMagnitude { } impl MulDiv for DimensionsAndMagnitude { - fn pow(self, pow: BaseDimensionExponent) -> Self { + fn pow(self, pow: Exponent) -> Self { Self { - magnitude: BaseDimensionExponent::float_pow(self.magnitude, pow), + magnitude: Exponent::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 890cb9b..c3a2c37 100644 --- a/crates/diman_unit_system/src/parse/mod.rs +++ b/crates/diman_unit_system/src/parse/mod.rs @@ -11,7 +11,7 @@ use crate::{ parse::attributes::Attributes, types::expression::{BinaryOperator, Expr, Factor, Operator}, types::prefixes::{ExplicitPrefixes, MetricPrefixes}, - types::{Alias, BaseAttribute, BaseDimensionExponent, Definition, One, UnresolvedTemplates}, + types::{Alias, BaseAttribute, Definition, One, UnresolvedTemplates}, }; use self::{ @@ -175,16 +175,18 @@ impl Parse for DimensionFactor { } #[cfg(feature = "rational-dimensions")] -fn read_exponent(e: Exponent) -> BaseDimensionExponent { - BaseDimensionExponent::new(e.num.int, e.denom.map(|denom| denom.int).unwrap_or(1)) +fn read_exponent(e: Exponent) -> crate::types::Exponent { + crate::types::Exponent::new(e.num.int, e.denom.map(|denom| denom.int).unwrap_or(1)) } #[cfg(not(feature = "rational-dimensions"))] -fn read_exponent(e: Exponent) -> BaseDimensionExponent { - BaseDimensionExponent(e.0) +fn read_exponent(e: Exponent) -> crate::types::Exponent { + e.0 } -fn parse_int_exponent_expr(input: ParseStream) -> Result> { +fn parse_int_exponent_expr( + input: ParseStream, +) -> Result> { let expr: Expr = input.parse()?; Ok(expr.map_exp(read_exponent)) } diff --git a/crates/diman_unit_system/src/resolve/error.rs b/crates/diman_unit_system/src/resolve/error.rs index 3ed280f..a2c6b5b 100644 --- a/crates/diman_unit_system/src/resolve/error.rs +++ b/crates/diman_unit_system/src/resolve/error.rs @@ -1,12 +1,13 @@ use std::collections::HashSet; +use diman_lib::base_dimension_exponent::BaseDimensionExponent; use proc_macro::{Diagnostic, Level}; use proc_macro2::Span; use syn::Ident; use crate::{ dimension_math::BaseDimensions, - types::{BaseDimensionExponent, Unit}, + types::{Exponent, Unit}, }; use super::ident_storage::Kind; @@ -113,7 +114,7 @@ fn format_lhs_rhs_dimensions(lhs: &BaseDimensions, rhs: &BaseDimensions) -> (Str available_dims .iter() .map(|dim| { - let value = *dims.get(dim).unwrap_or(&BaseDimensionExponent::zero()); + let value = *dims.get(dim).unwrap_or(&Exponent::zero()); format!("{}^{}", dim.0, value) }) .collect::>() diff --git a/crates/diman_unit_system/src/resolve/ident_storage.rs b/crates/diman_unit_system/src/resolve/ident_storage.rs index 2d92d95..5d7cdd3 100644 --- a/crates/diman_unit_system/src/resolve/ident_storage.rs +++ b/crates/diman_unit_system/src/resolve/ident_storage.rs @@ -9,8 +9,8 @@ use crate::{ expression::{self, Expr}, }, types::{ - BaseDimensionExponent, Constant, ConstantEntry, Definition, Dimension, DimensionEntry, - Factor, Unit, UnitEntry, + Constant, ConstantEntry, Definition, Dimension, DimensionEntry, Exponent, Factor, Unit, + UnitEntry, }, }; @@ -43,7 +43,7 @@ impl Kind { #[derive(Clone)] pub struct Item { - expr: Expr, BaseDimensionExponent>, + expr: Expr, Exponent>, type_: ItemType, } diff --git a/crates/diman_unit_system/src/types/base_dimension_exponent.rs b/crates/diman_unit_system/src/types/base_dimension_exponent.rs deleted file mode 100644 index cba25e8..0000000 --- a/crates/diman_unit_system/src/types/base_dimension_exponent.rs +++ /dev/null @@ -1,53 +0,0 @@ -#[cfg(feature = "rational-dimensions")] -pub use diman_lib::ratio::Ratio as BaseDimensionExponent; - -#[cfg(not(feature = "rational-dimensions"))] -pub use reexport::BaseDimensionExponent; - -#[cfg(not(feature = "rational-dimensions"))] -mod reexport { - #[derive(Clone, PartialEq, Copy)] - pub struct BaseDimensionExponent(pub i64); - - impl BaseDimensionExponent { - pub fn one() -> BaseDimensionExponent { - Self(1) - } - - pub fn zero() -> BaseDimensionExponent { - Self(0) - } - - pub fn float_pow(num: f64, exponent: Self) -> f64 { - num.powi(exponent.0 as i32) - } - } - - impl core::fmt::Display for BaseDimensionExponent { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{}", self.0) - } - } - - impl core::ops::Mul for BaseDimensionExponent { - type Output = Self; - - fn mul(self, rhs: Self) -> Self::Output { - Self(self.0 * rhs.0) - } - } - - impl core::ops::AddAssign for BaseDimensionExponent { - fn add_assign(&mut self, rhs: Self) { - self.0 += rhs.0 - } - } - - impl core::ops::Neg for BaseDimensionExponent { - type Output = Self; - - fn neg(self) -> Self::Output { - Self(-self.0) - } - } -} diff --git a/crates/diman_unit_system/src/types/expression.rs b/crates/diman_unit_system/src/types/expression.rs index f1391c2..dc2c817 100644 --- a/crates/diman_unit_system/src/types/expression.rs +++ b/crates/diman_unit_system/src/types/expression.rs @@ -1,4 +1,4 @@ -use super::BaseDimensionExponent; +use super::Exponent; #[derive(Clone)] #[cfg_attr(test, derive(PartialEq, Debug))] @@ -44,7 +44,7 @@ pub enum Factor { pub trait MulDiv: core::ops::Mul + core::ops::Div + Sized + Clone { - fn pow(self, pow: BaseDimensionExponent) -> Self; + fn pow(self, pow: Exponent) -> Self; } impl Expr { @@ -122,7 +122,7 @@ impl Factor { } } -impl + Clone> Expr { +impl + Clone> Expr { pub fn eval(&self) -> T { match self { Expr::Value(val) => val.eval(), @@ -138,7 +138,7 @@ impl + Clone> Expr { } } -impl + Clone> Factor { +impl + Clone> Factor { pub fn eval(&self) -> T { match self { Factor::Value(val) => val.clone(), @@ -154,7 +154,7 @@ mod tests { use crate::parse::tests::parse_expr; use crate::parse::tests::MyInt; use crate::types::expression::MulDiv; - use crate::types::BaseDimensionExponent; + use crate::types::Exponent; use quote::quote; @@ -175,14 +175,14 @@ mod tests { } impl MulDiv for MyInt { - fn pow(self, pow: BaseDimensionExponent) -> Self { - Self(self.0.pow(pow.0 as u32)) + fn pow(self, pow: Exponent) -> Self { + Self(self.0.pow(pow as u32)) } } - impl From for BaseDimensionExponent { + impl From for Exponent { fn from(value: MyInt) -> Self { - BaseDimensionExponent(value.0.into()) + value.0.into() } } diff --git a/crates/diman_unit_system/src/types/mod.rs b/crates/diman_unit_system/src/types/mod.rs index 42fb9e3..45e694b 100644 --- a/crates/diman_unit_system/src/types/mod.rs +++ b/crates/diman_unit_system/src/types/mod.rs @@ -1,5 +1,4 @@ pub mod base_dimension; -mod base_dimension_exponent; pub mod expression; pub mod prefixes; @@ -13,7 +12,11 @@ use self::{ }; use crate::dimension_math::BaseDimensions; -pub use base_dimension_exponent::BaseDimensionExponent; +#[cfg(feature = "rational-dimensions")] +pub use diman_lib::ratio::Ratio as Exponent; + +#[cfg(not(feature = "rational-dimensions"))] +pub use i64 as Exponent; #[derive(Clone)] pub enum Factor { @@ -33,7 +36,7 @@ impl Factor { #[derive(Clone)] pub enum Definition { Base(Base), - Expression(Expr, BaseDimensionExponent>), + Expression(Expr, Exponent>), } pub type DimensionFactor = Factor; @@ -69,7 +72,7 @@ pub struct Symbol(pub Ident); #[derive(Clone)] pub struct ConstantEntry { pub name: Ident, - pub rhs: Expr, BaseDimensionExponent>, + pub rhs: Expr, Exponent>, pub dimension_annotation: Option, } From 93077181e357e020f75a1661ca70a6823082fc77 Mon Sep 17 00:00:00 2001 From: tehforsch Date: Sun, 14 Jan 2024 17:41:30 +0100 Subject: [PATCH 04/10] move items that are only for internal use (Ratio, BaseDimensionExponent, ...) into internal module in diman --- .../src/codegen/base_dimension_type.rs | 36 +++--------------- .../src/codegen/debug_trait.rs | 12 +++--- .../src/codegen/dimension_type.rs | 37 ++++++++++++++++--- .../src/codegen/dimensions.rs | 2 +- src/lib.rs | 7 +++- 5 files changed, 48 insertions(+), 46 deletions(-) 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 c1c7ece..35d5025 100644 --- a/crates/diman_unit_system/src/codegen/base_dimension_type.rs +++ b/crates/diman_unit_system/src/codegen/base_dimension_type.rs @@ -9,24 +9,11 @@ impl Codegen { pub fn get_base_dimension_entry(&self, field: &Ident, value: &Exponent) -> TokenStream { let num = value.num(); let denom = value.denom(); - quote! { #field: Ratio::new(#num, #denom), } + quote! { #field: Exponent::new(#num, #denom), } } pub fn base_dimension_type(&self) -> TokenStream { - quote! { Ratio } - } - - pub fn base_dimension_type_zero(&self) -> TokenStream { - quote! { Ratio::int(0i64) } - } - - pub fn base_dimension_type_one(&self) -> TokenStream { - quote! { Ratio::int(1i64) } - } - - pub fn zero_entry(&self, ident: &Ident) -> TokenStream { - let zero = self.base_dimension_type_zero(); - quote! { #ident: #zero, } + quote! { Exponent } } pub fn add_entry(&self, ident: &Ident) -> TokenStream { @@ -49,19 +36,19 @@ impl Codegen { pub fn mul_entry(&self, ident: &Ident) -> TokenStream { quote! { - #ident: self.#ident.mul(Ratio::int(other as i64)), + #ident: self.#ident.mul(Exponent::int(other as i64)), } } pub fn sqrt_entry(&self, ident: &Ident) -> TokenStream { quote! { - #ident: self.#ident.div(Ratio::int(2)), + #ident: self.#ident.div(Exponent::int(2)), } } pub fn cbrt_entry(&self, ident: &Ident) -> TokenStream { quote! { - #ident: self.#ident.div(Ratio::int(3)), + #ident: self.#ident.div(Exponent::int(3)), } } @@ -84,19 +71,6 @@ impl Codegen { quote! { i64 } } - pub fn base_dimension_type_zero(&self) -> TokenStream { - quote! { 0i64 } - } - - pub fn base_dimension_type_one(&self) -> TokenStream { - quote! { 1i64 } - } - - pub fn zero_entry(&self, ident: &Ident) -> TokenStream { - let zero = self.base_dimension_type_zero(); - quote! { #ident: #zero, } - } - pub fn add_entry(&self, ident: &Ident) -> TokenStream { quote! { #ident: self.#ident + other.#ident, diff --git a/crates/diman_unit_system/src/codegen/debug_trait.rs b/crates/diman_unit_system/src/codegen/debug_trait.rs index fff2746..a0201b7 100644 --- a/crates/diman_unit_system/src/codegen/debug_trait.rs +++ b/crates/diman_unit_system/src/codegen/debug_trait.rs @@ -13,11 +13,13 @@ impl Codegen { pub fn runtime_unit_storage<'a>(&self, units: impl Iterator) -> TokenStream { let runtime_unit_storage = match self.caller_type { CallerType::Internal => quote! { diman_lib::runtime_unit_storage::RuntimeUnitStorage }, - CallerType::External => quote! { ::diman::runtime_unit_storage::RuntimeUnitStorage }, + CallerType::External => { + quote! { ::diman::internal::runtime_unit_storage::RuntimeUnitStorage } + } }; let runtime_unit = match self.caller_type { CallerType::Internal => quote! { diman_lib::runtime_unit_storage::RuntimeUnit }, - CallerType::External => quote! { ::diman::runtime_unit_storage::RuntimeUnit }, + CallerType::External => quote! { ::diman::internal::runtime_unit_storage::RuntimeUnit }, }; let units: TokenStream = units .filter_map(|unit| { @@ -70,14 +72,12 @@ impl Codegen { fn get_base_dimension_symbol(&self, base_dim: &BaseDimension) -> TokenStream { let dim = self.get_dimension_expr(&BaseDimensions::for_base_dimension(base_dim.clone())); // We know that symbols exist for base dimensions, so we can unwrap here. - let base_dimension_type_zero = self.base_dimension_type_zero(); - let base_dimension_type_one = self.base_dimension_type_one(); let base_dim = &base_dim.0; quote! { - if D.#base_dim == #base_dimension_type_one { + if D.#base_dim == Exponent::one() { write!(f, " {}", units.get_first_symbol(#dim).unwrap())?; } - else if D.#base_dim != #base_dimension_type_zero { + else if D.#base_dim != Exponent::zero() { write!(f, " {}^{}", units.get_first_symbol(#dim).unwrap(), D.#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 a86ef6b..e5bc37d 100644 --- a/crates/diman_unit_system/src/codegen/dimension_type.rs +++ b/crates/diman_unit_system/src/codegen/dimension_type.rs @@ -20,9 +20,9 @@ impl Codegen { }) .collect(); let methods_impl: proc_macro2::TokenStream = self.dimension_methods_impl(); - let use_ratio = self.use_ratio(); + let use_exponent = self.use_exponent_and_base_dimension_exponent_trait(); quote! { - #use_ratio + #use_exponent #[derive(::core::cmp::PartialEq, ::core::cmp::Eq, ::core::clone::Clone, ::core::fmt::Debug, ::core::marker::ConstParamTy)] pub struct #name { @@ -33,17 +33,42 @@ impl Codegen { } } - fn use_ratio(&self) -> TokenStream { - match self.caller_type { + fn use_exponent_and_base_dimension_exponent_trait(&self) -> TokenStream { + let use_exponent = match self.caller_type { CallerType::External => { - quote! { use ::diman::Ratio; } + #[cfg(feature = "rational-dimensions")] + quote! { use ::diman::internal::Ratio as Exponent; } + #[cfg(not(feature = "rational-dimensions"))] + quote! { use i64 as Exponent; } } CallerType::Internal => { - quote! { use ::diman_lib::ratio::Ratio; } + #[cfg(feature = "rational-dimensions")] + quote! { use ::diman_lib::ratio::Ratio as Exponent; } + #[cfg(not(feature = "rational-dimensions"))] + quote! { use i64 as Exponent; } } + }; + let use_base_dimension_exponent_trait = match self.caller_type { + CallerType::External => { + quote! { use ::diman::internal::BaseDimensionExponent; } + } + CallerType::Internal => { + quote! { use ::diman_lib::base_dimension_exponent::BaseDimensionExponent; } + } + }; + quote! { + #use_exponent + #use_base_dimension_exponent_trait } } + fn zero_entry(&self, ident: &Ident) -> TokenStream { + #[cfg(feature = "rational-dimensions")] + quote! { #ident: Exponent::int(0), } + #[cfg(not(feature = "rational-dimensions"))] + quote! { #ident: 0, } + } + fn dimension_methods_impl(&self) -> TokenStream { let type_name = &self.defs.dimension_type; let gen = |f: &dyn Fn(&Codegen, &Ident) -> TokenStream| { diff --git a/crates/diman_unit_system/src/codegen/dimensions.rs b/crates/diman_unit_system/src/codegen/dimensions.rs index e63a6b8..0589d08 100644 --- a/crates/diman_unit_system/src/codegen/dimensions.rs +++ b/crates/diman_unit_system/src/codegen/dimensions.rs @@ -110,7 +110,7 @@ impl Codegen { pub mod #module_name { use super::#dimension_type; use super::#quantity_type; - use super::Ratio; + use super::Exponent; #quantities #constants } diff --git a/src/lib.rs b/src/lib.rs index 4d28349..0bc7888 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -134,5 +134,8 @@ pub type Product = >::Output; /// ``` pub type Quotient = >::Output; -pub use diman_lib::ratio::Ratio; -pub use diman_lib::runtime_unit_storage; +pub mod internal { + pub use diman_lib::base_dimension_exponent::BaseDimensionExponent; + pub use diman_lib::ratio::Ratio; + pub use diman_lib::runtime_unit_storage; +} From 9383e3fe3c8f0180edb35e953c95577882540f04 Mon Sep 17 00:00:00 2001 From: tehforsch Date: Sun, 14 Jan 2024 17:50:53 +0100 Subject: [PATCH 05/10] get rid of the extra file base_dimension_type and move that to dimension_type --- .../src/codegen/base_dimension_type.rs | 125 ----------------- .../src/codegen/dimension_type.rs | 128 ++++++++++++++++++ crates/diman_unit_system/src/codegen/mod.rs | 1 - 3 files changed, 128 insertions(+), 126 deletions(-) delete mode 100644 crates/diman_unit_system/src/codegen/base_dimension_type.rs diff --git a/crates/diman_unit_system/src/codegen/base_dimension_type.rs b/crates/diman_unit_system/src/codegen/base_dimension_type.rs deleted file mode 100644 index 35d5025..0000000 --- a/crates/diman_unit_system/src/codegen/base_dimension_type.rs +++ /dev/null @@ -1,125 +0,0 @@ -use proc_macro2::{Ident, TokenStream}; -use quote::quote; - -use super::Codegen; -use crate::types::Exponent; - -#[cfg(feature = "rational-dimensions")] -impl Codegen { - pub fn get_base_dimension_entry(&self, field: &Ident, value: &Exponent) -> TokenStream { - let num = value.num(); - let denom = value.denom(); - quote! { #field: Exponent::new(#num, #denom), } - } - - pub fn base_dimension_type(&self) -> TokenStream { - quote! { Exponent } - } - - pub fn add_entry(&self, ident: &Ident) -> TokenStream { - quote! { - #ident: self.#ident.add(other.#ident), - } - } - - pub fn sub_entry(&self, ident: &Ident) -> TokenStream { - quote! { - #ident: self.#ident.sub(other.#ident), - } - } - - pub fn neg_entry(&self, ident: &Ident) -> TokenStream { - quote! { - #ident: self.#ident.neg(), - } - } - - pub fn mul_entry(&self, ident: &Ident) -> TokenStream { - quote! { - #ident: self.#ident.mul(Exponent::int(other as i64)), - } - } - - pub fn sqrt_entry(&self, ident: &Ident) -> TokenStream { - quote! { - #ident: self.#ident.div(Exponent::int(2)), - } - } - - pub fn cbrt_entry(&self, ident: &Ident) -> TokenStream { - quote! { - #ident: self.#ident.div(Exponent::int(3)), - } - } - - pub fn sqrt_safety(&self, _ident: &Ident) -> TokenStream { - quote! {} - } - - pub fn cbrt_safety(&self, _ident: &Ident) -> TokenStream { - quote! {} - } -} - -#[cfg(not(feature = "rational-dimensions"))] -impl Codegen { - pub fn get_base_dimension_entry(&self, field: &Ident, value: &Exponent) -> TokenStream { - quote! { #field: #value, } - } - - pub fn base_dimension_type(&self) -> TokenStream { - quote! { i64 } - } - - pub fn add_entry(&self, ident: &Ident) -> TokenStream { - quote! { - #ident: self.#ident + other.#ident, - } - } - - pub fn sub_entry(&self, ident: &Ident) -> TokenStream { - quote! { - #ident: self.#ident - other.#ident, - } - } - - pub fn neg_entry(&self, ident: &Ident) -> TokenStream { - quote! { - #ident: -self.#ident, - } - } - - pub fn mul_entry(&self, ident: &Ident) -> TokenStream { - quote! { - #ident: self.#ident * other as i64, - } - } - - pub fn sqrt_entry(&self, ident: &Ident) -> TokenStream { - quote! { - #ident: self.#ident / 2, - } - } - - pub fn cbrt_entry(&self, ident: &Ident) -> TokenStream { - quote! { - #ident: self.#ident / 3, - } - } - - pub fn sqrt_safety(&self, ident: &Ident) -> TokenStream { - quote! { - if self.#ident % 2 != 0 { - panic!("Cannot take square root of quantity with a dimension that is not divisible by 2 in all components."); - } - } - } - - pub fn cbrt_safety(&self, ident: &Ident) -> TokenStream { - quote! { - if self.#ident % 3 != 0 { - panic!("Cannot take cubic root of quantity with a dimension that is not divisible by 3 in all components."); - } - } - } -} diff --git a/crates/diman_unit_system/src/codegen/dimension_type.rs b/crates/diman_unit_system/src/codegen/dimension_type.rs index e5bc37d..28620a1 100644 --- a/crates/diman_unit_system/src/codegen/dimension_type.rs +++ b/crates/diman_unit_system/src/codegen/dimension_type.rs @@ -2,7 +2,135 @@ use proc_macro2::{Ident, TokenStream}; use quote::quote; use super::{CallerType, Codegen}; +use crate::types::Exponent; +// The following impls are all really ugly, and I'd prefer +// if they were just part of a trait. However they need to be +// const, so we'd need a const trait - this certainly isn't worth +// adding an unstable feature for. +// There is also an option of using a custom type instead of i64 +// for the integer exponents, but this still doesn't solve all problems +// and also requires all the methods to "magically" exist. + +#[cfg(feature = "rational-dimensions")] +impl Codegen { + pub fn get_base_dimension_entry(&self, field: &Ident, value: &Exponent) -> TokenStream { + let num = value.num(); + let denom = value.denom(); + quote! { #field: Exponent::new(#num, #denom), } + } + + fn base_dimension_type(&self) -> TokenStream { + quote! { Exponent } + } + + fn add_entry(&self, ident: &Ident) -> TokenStream { + quote! { + #ident: self.#ident.add(other.#ident), + } + } + + fn sub_entry(&self, ident: &Ident) -> TokenStream { + quote! { + #ident: self.#ident.sub(other.#ident), + } + } + + fn neg_entry(&self, ident: &Ident) -> TokenStream { + quote! { + #ident: self.#ident.neg(), + } + } + + fn mul_entry(&self, ident: &Ident) -> TokenStream { + quote! { + #ident: self.#ident.mul(Exponent::int(other as i64)), + } + } + + fn sqrt_entry(&self, ident: &Ident) -> TokenStream { + quote! { + #ident: self.#ident.div(Exponent::int(2)), + } + } + + fn cbrt_entry(&self, ident: &Ident) -> TokenStream { + quote! { + #ident: self.#ident.div(Exponent::int(3)), + } + } + + fn sqrt_safety(&self, _ident: &Ident) -> TokenStream { + quote! {} + } + + fn cbrt_safety(&self, _ident: &Ident) -> TokenStream { + quote! {} + } +} + +#[cfg(not(feature = "rational-dimensions"))] +impl Codegen { + pub fn get_base_dimension_entry(&self, field: &Ident, value: &Exponent) -> TokenStream { + quote! { #field: #value, } + } + + fn base_dimension_type(&self) -> TokenStream { + quote! { i64 } + } + + fn add_entry(&self, ident: &Ident) -> TokenStream { + quote! { + #ident: self.#ident + other.#ident, + } + } + + fn sub_entry(&self, ident: &Ident) -> TokenStream { + quote! { + #ident: self.#ident - other.#ident, + } + } + + fn neg_entry(&self, ident: &Ident) -> TokenStream { + quote! { + #ident: -self.#ident, + } + } + + fn mul_entry(&self, ident: &Ident) -> TokenStream { + quote! { + #ident: self.#ident * other as i64, + } + } + + fn sqrt_entry(&self, ident: &Ident) -> TokenStream { + quote! { + #ident: self.#ident / 2, + } + } + + fn cbrt_entry(&self, ident: &Ident) -> TokenStream { + quote! { + #ident: self.#ident / 3, + } + } + + fn sqrt_safety(&self, ident: &Ident) -> TokenStream { + quote! { + if self.#ident % 2 != 0 { + panic!("Cannot take square root of quantity with a dimension that is not divisible by 2 in all components."); + } + } + } + + fn cbrt_safety(&self, ident: &Ident) -> TokenStream { + quote! { + if self.#ident % 3 != 0 { + panic!("Cannot take cubic root of quantity with a dimension that is not divisible by 3 in all components."); + } + } + } +} impl Codegen { pub(crate) fn gen_dimension(&self) -> TokenStream { let name = &self.defs.dimension_type; diff --git a/crates/diman_unit_system/src/codegen/mod.rs b/crates/diman_unit_system/src/codegen/mod.rs index fe3b486..0580826 100644 --- a/crates/diman_unit_system/src/codegen/mod.rs +++ b/crates/diman_unit_system/src/codegen/mod.rs @@ -1,4 +1,3 @@ -mod base_dimension_type; mod debug_trait; mod dimension_type; mod dimensions; From 5eb09ccd58ab38fdeef36c366873e98f9643921e Mon Sep 17 00:00:00 2001 From: tehforsch Date: Sun, 14 Jan 2024 17:54:04 +0100 Subject: [PATCH 06/10] rename BaseDimensionExponent -> DimensionExponent --- ...e_dimension_exponent.rs => dimension_exponent.rs} | 4 ++-- crates/diman_lib/src/lib.rs | 2 +- crates/diman_lib/src/ratio.rs | 4 ++-- .../diman_unit_system/src/codegen/dimension_type.rs | 12 ++++++------ crates/diman_unit_system/src/dimension_math.rs | 2 +- crates/diman_unit_system/src/resolve/error.rs | 2 +- src/lib.rs | 2 +- 7 files changed, 14 insertions(+), 14 deletions(-) rename crates/diman_lib/src/{base_dimension_exponent.rs => dimension_exponent.rs} (72%) diff --git a/crates/diman_lib/src/base_dimension_exponent.rs b/crates/diman_lib/src/dimension_exponent.rs similarity index 72% rename from crates/diman_lib/src/base_dimension_exponent.rs rename to crates/diman_lib/src/dimension_exponent.rs index ae79c4c..8aca2bf 100644 --- a/crates/diman_lib/src/base_dimension_exponent.rs +++ b/crates/diman_lib/src/dimension_exponent.rs @@ -1,12 +1,12 @@ use std::ops::{AddAssign, Mul, Neg}; -pub trait BaseDimensionExponent: Clone + PartialEq + Copy + Mul + AddAssign + Neg { +pub trait DimensionExponent: Clone + PartialEq + Copy + Mul + AddAssign + Neg { fn float_pow(num: f64, exponent: Self) -> f64; fn one() -> Self; fn zero() -> Self; } -impl BaseDimensionExponent for i64 { +impl DimensionExponent for i64 { fn one() -> Self { 1 } diff --git a/crates/diman_lib/src/lib.rs b/crates/diman_lib/src/lib.rs index ac5a170..032b56f 100644 --- a/crates/diman_lib/src/lib.rs +++ b/crates/diman_lib/src/lib.rs @@ -1,6 +1,6 @@ #![allow(incomplete_features)] #![feature(generic_const_exprs, adt_const_params)] -pub mod base_dimension_exponent; +pub mod dimension_exponent; pub mod ratio; pub mod runtime_unit_storage; diff --git a/crates/diman_lib/src/ratio.rs b/crates/diman_lib/src/ratio.rs index bc0bab5..47a67bc 100644 --- a/crates/diman_lib/src/ratio.rs +++ b/crates/diman_lib/src/ratio.rs @@ -1,4 +1,4 @@ -use crate::base_dimension_exponent::BaseDimensionExponent; +use crate::dimension_exponent::DimensionExponent; #[derive( ::core::cmp::PartialEq, @@ -84,7 +84,7 @@ impl Ratio { } } -impl BaseDimensionExponent for Ratio { +impl DimensionExponent for Ratio { fn one() -> Self { Self { num: 1, denom: 1 } } diff --git a/crates/diman_unit_system/src/codegen/dimension_type.rs b/crates/diman_unit_system/src/codegen/dimension_type.rs index 28620a1..3c27806 100644 --- a/crates/diman_unit_system/src/codegen/dimension_type.rs +++ b/crates/diman_unit_system/src/codegen/dimension_type.rs @@ -148,7 +148,7 @@ impl Codegen { }) .collect(); let methods_impl: proc_macro2::TokenStream = self.dimension_methods_impl(); - let use_exponent = self.use_exponent_and_base_dimension_exponent_trait(); + let use_exponent = self.use_exponent_and_dimension_exponent_trait(); quote! { #use_exponent @@ -161,7 +161,7 @@ impl Codegen { } } - fn use_exponent_and_base_dimension_exponent_trait(&self) -> TokenStream { + fn use_exponent_and_dimension_exponent_trait(&self) -> TokenStream { let use_exponent = match self.caller_type { CallerType::External => { #[cfg(feature = "rational-dimensions")] @@ -176,17 +176,17 @@ impl Codegen { quote! { use i64 as Exponent; } } }; - let use_base_dimension_exponent_trait = match self.caller_type { + let use_dimension_exponent_trait = match self.caller_type { CallerType::External => { - quote! { use ::diman::internal::BaseDimensionExponent; } + quote! { use ::diman::internal::DimensionExponent; } } CallerType::Internal => { - quote! { use ::diman_lib::base_dimension_exponent::BaseDimensionExponent; } + quote! { use ::diman_lib::dimension_exponent::DimensionExponent; } } }; quote! { #use_exponent - #use_base_dimension_exponent_trait + #use_dimension_exponent_trait } } diff --git a/crates/diman_unit_system/src/dimension_math.rs b/crates/diman_unit_system/src/dimension_math.rs index 46f132f..6aed613 100644 --- a/crates/diman_unit_system/src/dimension_math.rs +++ b/crates/diman_unit_system/src/dimension_math.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use diman_lib::base_dimension_exponent::BaseDimensionExponent; +use diman_lib::dimension_exponent::DimensionExponent; use proc_macro2::Ident; use crate::{ diff --git a/crates/diman_unit_system/src/resolve/error.rs b/crates/diman_unit_system/src/resolve/error.rs index a2c6b5b..0f2f229 100644 --- a/crates/diman_unit_system/src/resolve/error.rs +++ b/crates/diman_unit_system/src/resolve/error.rs @@ -1,6 +1,6 @@ use std::collections::HashSet; -use diman_lib::base_dimension_exponent::BaseDimensionExponent; +use diman_lib::dimension_exponent::DimensionExponent; use proc_macro::{Diagnostic, Level}; use proc_macro2::Span; use syn::Ident; diff --git a/src/lib.rs b/src/lib.rs index 0bc7888..0ae528a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -135,7 +135,7 @@ pub type Product = >::Output; pub type Quotient = >::Output; pub mod internal { - pub use diman_lib::base_dimension_exponent::BaseDimensionExponent; + pub use diman_lib::dimension_exponent::DimensionExponent; pub use diman_lib::ratio::Ratio; pub use diman_lib::runtime_unit_storage; } From 678f452d74b745dc04787195896cbbe64548cb75 Mon Sep 17 00:00:00 2001 From: tehforsch Date: Sun, 14 Jan 2024 19:07:34 +0100 Subject: [PATCH 07/10] fix serialize and deserialize impl --- crates/diman_lib/src/dimension_exponent.rs | 5 ++ crates/diman_lib/src/ratio.rs | 4 ++ crates/diman_lib/src/runtime_unit_storage.rs | 10 +++- .../src/codegen/debug_trait.rs | 8 +-- crates/diman_unit_system/src/codegen/serde.rs | 54 ++++--------------- 5 files changed, 32 insertions(+), 49 deletions(-) diff --git a/crates/diman_lib/src/dimension_exponent.rs b/crates/diman_lib/src/dimension_exponent.rs index 8aca2bf..78bd6ca 100644 --- a/crates/diman_lib/src/dimension_exponent.rs +++ b/crates/diman_lib/src/dimension_exponent.rs @@ -4,6 +4,7 @@ pub trait DimensionExponent: Clone + PartialEq + Copy + Mul + AddAssign + Neg { fn float_pow(num: f64, exponent: Self) -> f64; fn one() -> Self; fn zero() -> Self; + fn from_int(i: i32) -> Self; } impl DimensionExponent for i64 { @@ -18,4 +19,8 @@ impl DimensionExponent for i64 { fn float_pow(num: f64, exponent: Self) -> f64 { num.powi(exponent as i32) } + + fn from_int(i: i32) -> Self { + i as i64 + } } diff --git a/crates/diman_lib/src/ratio.rs b/crates/diman_lib/src/ratio.rs index 47a67bc..9d73f59 100644 --- a/crates/diman_lib/src/ratio.rs +++ b/crates/diman_lib/src/ratio.rs @@ -96,6 +96,10 @@ impl DimensionExponent for Ratio { fn float_pow(num: f64, exponent: Self) -> f64 { num.powf(exponent.num as f64 / exponent.denom as f64) } + + fn from_int(i: i32) -> Self { + Ratio::int(i as i64) + } } impl core::fmt::Display for Ratio { diff --git a/crates/diman_lib/src/runtime_unit_storage.rs b/crates/diman_lib/src/runtime_unit_storage.rs index ed93a60..85c4a1c 100644 --- a/crates/diman_lib/src/runtime_unit_storage.rs +++ b/crates/diman_lib/src/runtime_unit_storage.rs @@ -23,11 +23,17 @@ impl<'a, D: PartialEq> RuntimeUnitStorage<'a, D> { Self { units } } - pub fn get_first_symbol(&self, dim: D) -> Option<&'a str> { + pub fn get_first_unit_for_dimension(&self, dim: D) -> Option<&'a RuntimeUnit<'a, D>> { self.units .iter() .filter(|unit| unit.dimension == dim) - .map(|unit| unit.symbol) + .next() + } + + pub fn get_unit_by_symbol(&self, symbol: &str) -> Option<&'a RuntimeUnit<'a, D>> { + self.units + .iter() + .filter(|unit| unit.symbol == symbol) .next() } } diff --git a/crates/diman_unit_system/src/codegen/debug_trait.rs b/crates/diman_unit_system/src/codegen/debug_trait.rs index a0201b7..0a66091 100644 --- a/crates/diman_unit_system/src/codegen/debug_trait.rs +++ b/crates/diman_unit_system/src/codegen/debug_trait.rs @@ -57,8 +57,8 @@ impl Codegen { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { #units_storage self.0.fmt(f)?; - if let Some(symbol) = units.get_first_symbol(D) { - write!(f, " {}", symbol) + if let Some(unit) = units.get_first_unit_for_dimension(D) { + write!(f, " {}", unit.symbol) } else { #get_base_dimension_symbols @@ -75,10 +75,10 @@ impl Codegen { let base_dim = &base_dim.0; quote! { if D.#base_dim == Exponent::one() { - write!(f, " {}", units.get_first_symbol(#dim).unwrap())?; + write!(f, " {}", units.get_first_unit_for_dimension(#dim).unwrap().symbol)?; } else if D.#base_dim != Exponent::zero() { - write!(f, " {}^{}", units.get_first_symbol(#dim).unwrap(), D.#base_dim)?; + write!(f, " {}^{}", units.get_first_unit_for_dimension(#dim).unwrap().symbol, D.#base_dim)?; } } } diff --git a/crates/diman_unit_system/src/codegen/serde.rs b/crates/diman_unit_system/src/codegen/serde.rs index 7cde276..67645b9 100644 --- a/crates/diman_unit_system/src/codegen/serde.rs +++ b/crates/diman_unit_system/src/codegen/serde.rs @@ -19,7 +19,7 @@ impl Codegen { fn serde_helpers_impl(&self) -> TokenStream { let dimension_type = &self.defs.dimension_type; let quantity_type = &self.defs.quantity_type; - let units = self.units_array(self.defs.units.iter()); + let all_units_storage = self.runtime_unit_storage(self.defs.units.iter()); quote! { use std::marker::PhantomData; @@ -74,14 +74,13 @@ impl Codegen { } else { (unit_str, 1) }; - let units: &[(#dimension_type, &str, f64)] = &#units; - let (dimension, _, factor) = units - .iter() - .find(|(_, known_unit_name, _)| &unit == known_unit_name) + #all_units_storage + let unit = units + .get_unit_by_symbol(unit) .ok_or_else(|| E::custom(format!("unknown unit: {}", &unit)))?; Ok(( - dimension.clone().mul(exponent), - factor.powi(exponent), + unit.dimension.clone().mul(exponent), + Exponent::float_pow(unit.magnitude, Exponent::from_int(exponent)), )) } } @@ -97,8 +96,6 @@ impl Codegen { fn serde_float_impl(&self, float_type: &FloatType) -> TokenStream { 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! { impl<'de, const D: #dimension_type> serde::Deserialize<'de> for #quantity_type<#float_type, D> { @@ -187,21 +184,7 @@ impl Codegen { where S: serde::Serializer, { - let units: &[(#dimension_type, &str, f64)] = &#units; - if D == #dimension_type::none() { - serializer.#serialize_method(self.0) - } else { - let unit_name = units - .iter() - .filter(|(d, _, _)| d == &D) - .filter(|(_, _, val)| *val == 1.0) - .map(|(_, name, _)| name) - .next() - .unwrap_or_else(|| { - panic!("Attempt to serialize quantity with dimension: {D:?}. Make sure that the unit with conversion factor 1 for this dimension is named.") - }); - serializer.serialize_str(&format!("{} {}", self.0.to_string(), unit_name)) - } + serializer.serialize_str(&format!("{:?}", self)) } } } @@ -220,7 +203,6 @@ impl Codegen { let vector_type = &vector_type.name; 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> @@ -283,24 +265,10 @@ impl Codegen { where S: serde::Serializer, { - let vec_to_string = |vec: #vector_type| { - vec.to_string().replace("[", "(").replace("]", ")").replace(",", "") - }; - if D == #dimension_type::none() { - serializer.serialize_str(&vec_to_string(self.0)) - } else { - let units: &[(#dimension_type, &str, f64)] = &#units; - let unit_name = units - .iter() - .filter(|(d, _, _)| d == &D) - .filter(|(_, _, val)| *val == 1.0) - .map(|(_, name, _)| name) - .next() - .unwrap_or_else(|| { - panic!("Attempt to serialize quantity with dimension: {D:?}. Make sure that the unit with conversion factor 1 for this dimension is named.") - }); - serializer.serialize_str(&format!("{} {}", vec_to_string(self.0), unit_name)) - } + // yaml syntax struggles with comma delimited [] entries because + // they look like lists, so do this ugly stuff + let vec_str = format!("{:?}", self); + serializer.serialize_str(&vec_str.replace("[", "(").replace("]", ")").replace(",", "")) } } } From 524b174506687ce6e7c7fb041f9640fbc8e5ccfa Mon Sep 17 00:00:00 2001 From: tehforsch Date: Tue, 16 Jan 2024 10:01:22 +0100 Subject: [PATCH 08/10] allow unconditional_recursion to prevent CI failing due to clippy bug --- src/lib.rs | 2 ++ tests/mod.rs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 0ae528a..0bfaecc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,8 @@ #![allow(incomplete_features)] #![feature(generic_const_exprs, adt_const_params)] #![doc = include_str!("../README.md")] +// clippy bug: https://github.com/rust-lang/rust-clippy/issues/12133 +#![allow(clippy::unconditional_recursion)] // This ensures we don't have to differentiate between // imports via `crate::` and `diman::` in the proc macro. diff --git a/tests/mod.rs b/tests/mod.rs index 603527d..a9442e7 100644 --- a/tests/mod.rs +++ b/tests/mod.rs @@ -1,6 +1,8 @@ #![allow(incomplete_features)] #![feature(generic_const_exprs, adt_const_params)] #![feature(const_fn_floating_point_arithmetic)] +// clippy bug: https://github.com/rust-lang/rust-clippy/issues/12133 +#![allow(clippy::unconditional_recursion)] pub mod example_system; pub mod utils; From aae178f699a064f275dc985853c05c81b23cb4ef Mon Sep 17 00:00:00 2001 From: tehforsch Date: Tue, 16 Jan 2024 10:01:40 +0100 Subject: [PATCH 09/10] fix clippy lint --- crates/diman_lib/src/runtime_unit_storage.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/crates/diman_lib/src/runtime_unit_storage.rs b/crates/diman_lib/src/runtime_unit_storage.rs index 85c4a1c..1300df5 100644 --- a/crates/diman_lib/src/runtime_unit_storage.rs +++ b/crates/diman_lib/src/runtime_unit_storage.rs @@ -24,16 +24,10 @@ impl<'a, D: PartialEq> RuntimeUnitStorage<'a, D> { } pub fn get_first_unit_for_dimension(&self, dim: D) -> Option<&'a RuntimeUnit<'a, D>> { - self.units - .iter() - .filter(|unit| unit.dimension == dim) - .next() + self.units.iter().find(|unit| unit.dimension == dim) } pub fn get_unit_by_symbol(&self, symbol: &str) -> Option<&'a RuntimeUnit<'a, D>> { - self.units - .iter() - .filter(|unit| unit.symbol == symbol) - .next() + self.units.iter().find(|unit| unit.symbol == symbol) } } From 397b5d3e824c83862e92462094fc8cf3775fb300 Mon Sep 17 00:00:00 2001 From: tehforsch Date: Tue, 16 Jan 2024 10:16:19 +0100 Subject: [PATCH 10/10] fix clippy ci --- .github/workflows/rust.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 8aa35c7..9db4ff2 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -59,8 +59,6 @@ jobs: run: | sudo apt-get update sudo apt-get install mpich - - name: Run clippy on all targets - run: cargo clippy --version - name: Run clippy on all targets run: cargo clippy --all-targets --all-features -- -D warnings