From ef4808d389381b16421f57c01ac8bd7db3293579 Mon Sep 17 00:00:00 2001 From: Asa Paparo Date: Tue, 7 Jul 2026 17:29:02 -0500 Subject: [PATCH] Enforce absolute paths in all macro_rules and most proc macros This replaces all call-site instances of e.g. `Result` with `::core::result::Result`, and re-exports whippyunits' dependency crates (`num_traits`, `whippyunits_core`, `whippyunits_proc_macros`) for use within whippyunits macros as e.g. `$crate::__private_num_traits`. It also adds `macro_hygiene_tests` for shadowing issues and a `transitive_dependency` test for ensuring a crate depending on whippyunits can successfully compile without itself depending on `num_traits` or `whippyunits_core`/`whippyunits_proc_macros`. --- .../src/compute_unit_dimensions_macro.rs | 5 +- src/api.rs | 296 +++++++++--------- src/arithmetic.rs | 8 +- src/arithmetic_quantity_types.rs | 211 +++++++++---- src/dimension_traits.rs | 30 +- src/lib.rs | 27 +- src/print/display_traits.rs | 76 +++-- src/print/prettyprint.rs | 14 +- src/quantity.rs | 42 ++- src/scale_conversion.rs | 44 ++- src/serialization.rs | 166 +++++----- .../add_length_to_time.stderr | 4 +- .../compile_fail_cge/assign_wrong_type.stderr | 4 +- .../compare_different_dimensions.stderr | 4 +- .../compare_different_scales.stderr | 4 +- .../add_length_to_time.stderr | 4 +- .../assign_wrong_type.stderr | 4 +- .../compare_different_dimensions.stderr | 4 +- .../compare_different_scales.stderr | 4 +- tests/macro_hygiene_tests.rs | 113 +++++++ tests/transitive_dep_fixture/Cargo.lock | 202 ++++++++++++ tests/transitive_dep_fixture/Cargo.toml | 10 + tests/transitive_dep_fixture/src/lib.rs | 5 + tests/transitive_dependency.rs | 30 ++ 24 files changed, 911 insertions(+), 400 deletions(-) create mode 100644 tests/macro_hygiene_tests.rs create mode 100644 tests/transitive_dep_fixture/Cargo.lock create mode 100644 tests/transitive_dep_fixture/Cargo.toml create mode 100644 tests/transitive_dep_fixture/src/lib.rs create mode 100644 tests/transitive_dependency.rs diff --git a/proc-macros/src/compute_unit_dimensions_macro.rs b/proc-macros/src/compute_unit_dimensions_macro.rs index f5edf6a..52eeb3a 100644 --- a/proc-macros/src/compute_unit_dimensions_macro.rs +++ b/proc-macros/src/compute_unit_dimensions_macro.rs @@ -31,10 +31,7 @@ pub fn compute_unit_dimensions(input: TokenStream) -> TokenStream { ); quote! { - ( - whippyunits_core::dimension_exponents::DynDimensionExponents([#d0, #d1, #d2, #d3, #d4, #d5, #d6, #d7]), - whippyunits_core::scale_exponents::ScaleExponents([#d8, #d9, #d10, #d11]) - ) + (#d0, #d1, #d2, #d3, #d4, #d5, #d6, #d7, #d8, #d9, #d10, #d11) } .into() } diff --git a/src/api.rs b/src/api.rs index 2b7ae30..49fc8f2 100644 --- a/src/api.rs +++ b/src/api.rs @@ -129,16 +129,8 @@ use crate::define_aggregate_scale_factor_float; use crate::define_aggregate_scale_factor_rational; #[cfg(feature = "alloc")] use crate::define_display_traits; -#[cfg(feature = "alloc")] -use crate::print::prettyprint::*; use crate::quantity::*; use crate::scale_conversion::*; -#[cfg(feature = "alloc")] -use core::fmt; -#[cfg(has_generic_const_exprs)] -use crate::IsI16; -#[cfg(not(has_generic_const_exprs))] -use whippyunits_core::num::N; define_aggregate_scale_factor_rational!( // params @@ -338,48 +330,48 @@ macro_rules! define_arithmetic_signed { (), // inversion where clauses ( - (): IsI16<{ -MASS_EXPONENT }>, - (): IsI16<{ -LENGTH_EXPONENT }>, - (): IsI16<{ -TIME_EXPONENT }>, - (): IsI16<{ -CURRENT_EXPONENT }>, - (): IsI16<{ -TEMPERATURE_EXPONENT }>, - (): IsI16<{ -AMOUNT_EXPONENT }>, - (): IsI16<{ -LUMINOSITY_EXPONENT }>, - (): IsI16<{ -ANGLE_EXPONENT }>, - (): IsI16<{ -SCALE_P2 }>, - (): IsI16<{ -SCALE_P3 }>, - (): IsI16<{ -SCALE_P5 }>, - (): IsI16<{ -SCALE_PI }> + (): $crate::IsI16<{ -MASS_EXPONENT }>, + (): $crate::IsI16<{ -LENGTH_EXPONENT }>, + (): $crate::IsI16<{ -TIME_EXPONENT }>, + (): $crate::IsI16<{ -CURRENT_EXPONENT }>, + (): $crate::IsI16<{ -TEMPERATURE_EXPONENT }>, + (): $crate::IsI16<{ -AMOUNT_EXPONENT }>, + (): $crate::IsI16<{ -LUMINOSITY_EXPONENT }>, + (): $crate::IsI16<{ -ANGLE_EXPONENT }>, + (): $crate::IsI16<{ -SCALE_P2 }>, + (): $crate::IsI16<{ -SCALE_P3 }>, + (): $crate::IsI16<{ -SCALE_P5 }>, + (): $crate::IsI16<{ -SCALE_PI }> ), // mul output dimension where clauses ( - (): IsI16<{ MASS_EXPONENT_1 + MASS_EXPONENT_2 }>, - (): IsI16<{ LENGTH_EXPONENT_1 + LENGTH_EXPONENT_2 }>, - (): IsI16<{ TIME_EXPONENT_1 + TIME_EXPONENT_2 }>, - (): IsI16<{ CURRENT_EXPONENT_1 + CURRENT_EXPONENT_2 }>, - (): IsI16<{ TEMPERATURE_EXPONENT_1 + TEMPERATURE_EXPONENT_2 }>, - (): IsI16<{ AMOUNT_EXPONENT_1 + AMOUNT_EXPONENT_2 }>, - (): IsI16<{ LUMINOSITY_EXPONENT_1 + LUMINOSITY_EXPONENT_2 }>, - (): IsI16<{ ANGLE_EXPONENT_1 + ANGLE_EXPONENT_2 }>, - (): IsI16<{ SCALE_P2_1 + SCALE_P2_2 }>, - (): IsI16<{ SCALE_P3_1 + SCALE_P3_2 }>, - (): IsI16<{ SCALE_P5_1 + SCALE_P5_2 }>, - (): IsI16<{ SCALE_PI_1 + SCALE_PI_2 }> + (): $crate::IsI16<{ MASS_EXPONENT_1 + MASS_EXPONENT_2 }>, + (): $crate::IsI16<{ LENGTH_EXPONENT_1 + LENGTH_EXPONENT_2 }>, + (): $crate::IsI16<{ TIME_EXPONENT_1 + TIME_EXPONENT_2 }>, + (): $crate::IsI16<{ CURRENT_EXPONENT_1 + CURRENT_EXPONENT_2 }>, + (): $crate::IsI16<{ TEMPERATURE_EXPONENT_1 + TEMPERATURE_EXPONENT_2 }>, + (): $crate::IsI16<{ AMOUNT_EXPONENT_1 + AMOUNT_EXPONENT_2 }>, + (): $crate::IsI16<{ LUMINOSITY_EXPONENT_1 + LUMINOSITY_EXPONENT_2 }>, + (): $crate::IsI16<{ ANGLE_EXPONENT_1 + ANGLE_EXPONENT_2 }>, + (): $crate::IsI16<{ SCALE_P2_1 + SCALE_P2_2 }>, + (): $crate::IsI16<{ SCALE_P3_1 + SCALE_P3_2 }>, + (): $crate::IsI16<{ SCALE_P5_1 + SCALE_P5_2 }>, + (): $crate::IsI16<{ SCALE_PI_1 + SCALE_PI_2 }> ), // div output dimension where clauses ( - (): IsI16<{ MASS_EXPONENT_1 - MASS_EXPONENT_2 }>, - (): IsI16<{ LENGTH_EXPONENT_1 - LENGTH_EXPONENT_2 }>, - (): IsI16<{ TIME_EXPONENT_1 - TIME_EXPONENT_2 }>, - (): IsI16<{ CURRENT_EXPONENT_1 - CURRENT_EXPONENT_2 }>, - (): IsI16<{ TEMPERATURE_EXPONENT_1 - TEMPERATURE_EXPONENT_2 }>, - (): IsI16<{ AMOUNT_EXPONENT_1 - AMOUNT_EXPONENT_2 }>, - (): IsI16<{ LUMINOSITY_EXPONENT_1 - LUMINOSITY_EXPONENT_2 }>, - (): IsI16<{ ANGLE_EXPONENT_1 - ANGLE_EXPONENT_2 }>, - (): IsI16<{ SCALE_P2_1 - SCALE_P2_2 }>, - (): IsI16<{ SCALE_P3_1 - SCALE_P3_2 }>, - (): IsI16<{ SCALE_P5_1 - SCALE_P5_2 }>, - (): IsI16<{ SCALE_PI_1 - SCALE_PI_2 }> + (): $crate::IsI16<{ MASS_EXPONENT_1 - MASS_EXPONENT_2 }>, + (): $crate::IsI16<{ LENGTH_EXPONENT_1 - LENGTH_EXPONENT_2 }>, + (): $crate::IsI16<{ TIME_EXPONENT_1 - TIME_EXPONENT_2 }>, + (): $crate::IsI16<{ CURRENT_EXPONENT_1 - CURRENT_EXPONENT_2 }>, + (): $crate::IsI16<{ TEMPERATURE_EXPONENT_1 - TEMPERATURE_EXPONENT_2 }>, + (): $crate::IsI16<{ AMOUNT_EXPONENT_1 - AMOUNT_EXPONENT_2 }>, + (): $crate::IsI16<{ LUMINOSITY_EXPONENT_1 - LUMINOSITY_EXPONENT_2 }>, + (): $crate::IsI16<{ ANGLE_EXPONENT_1 - ANGLE_EXPONENT_2 }>, + (): $crate::IsI16<{ SCALE_P2_1 - SCALE_P2_2 }>, + (): $crate::IsI16<{ SCALE_P3_1 - SCALE_P3_2 }>, + (): $crate::IsI16<{ SCALE_P5_1 - SCALE_P5_2 }>, + (): $crate::IsI16<{ SCALE_PI_1 - SCALE_PI_2 }> ), // other parameters $T, rescale_fn @@ -452,48 +444,48 @@ macro_rules! define_arithmetic_signed { ), // inversion where clauses ( - N: core::ops::Neg>, - N: core::ops::Neg>, - N: core::ops::Neg>, - N: core::ops::Neg>, - N: core::ops::Neg>, - N: core::ops::Neg>, - N: core::ops::Neg>, - N: core::ops::Neg>, - N: core::ops::Neg>, - N: core::ops::Neg>, - N: core::ops::Neg>, - N: core::ops::Neg> + $crate::__private_whippyunits_core::num::N: ::core::ops::Neg>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Neg>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Neg>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Neg>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Neg>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Neg>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Neg>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Neg>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Neg>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Neg>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Neg>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Neg> ), // mul output dimension where clauses ( - N: core::ops::Add, Output = N>, - N: core::ops::Add, Output = N>, - N: core::ops::Add, Output = N>, - N: core::ops::Add, Output = N>, - N: core::ops::Add, Output = N>, - N: core::ops::Add, Output = N>, - N: core::ops::Add, Output = N>, - N: core::ops::Add, Output = N>, - N: core::ops::Add, Output = N>, - N: core::ops::Add, Output = N>, - N: core::ops::Add, Output = N>, - N: core::ops::Add, Output = N> + $crate::__private_whippyunits_core::num::N: ::core::ops::Add<$crate::__private_whippyunits_core::num::N, Output = $crate::__private_whippyunits_core::num::N>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Add<$crate::__private_whippyunits_core::num::N, Output = $crate::__private_whippyunits_core::num::N>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Add<$crate::__private_whippyunits_core::num::N, Output = $crate::__private_whippyunits_core::num::N>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Add<$crate::__private_whippyunits_core::num::N, Output = $crate::__private_whippyunits_core::num::N>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Add<$crate::__private_whippyunits_core::num::N, Output = $crate::__private_whippyunits_core::num::N>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Add<$crate::__private_whippyunits_core::num::N, Output = $crate::__private_whippyunits_core::num::N>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Add<$crate::__private_whippyunits_core::num::N, Output = $crate::__private_whippyunits_core::num::N>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Add<$crate::__private_whippyunits_core::num::N, Output = $crate::__private_whippyunits_core::num::N>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Add<$crate::__private_whippyunits_core::num::N, Output = $crate::__private_whippyunits_core::num::N>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Add<$crate::__private_whippyunits_core::num::N, Output = $crate::__private_whippyunits_core::num::N>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Add<$crate::__private_whippyunits_core::num::N, Output = $crate::__private_whippyunits_core::num::N>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Add<$crate::__private_whippyunits_core::num::N, Output = $crate::__private_whippyunits_core::num::N> ), // div output dimension where clauses ( - N: core::ops::Sub, Output = N>, - N: core::ops::Sub, Output = N>, - N: core::ops::Sub, Output = N>, - N: core::ops::Sub, Output = N>, - N: core::ops::Sub, Output = N>, - N: core::ops::Sub, Output = N>, - N: core::ops::Sub, Output = N>, - N: core::ops::Sub, Output = N>, - N: core::ops::Sub, Output = N>, - N: core::ops::Sub, Output = N>, - N: core::ops::Sub, Output = N>, - N: core::ops::Sub, Output = N> + $crate::__private_whippyunits_core::num::N: ::core::ops::Sub<$crate::__private_whippyunits_core::num::N, Output = $crate::__private_whippyunits_core::num::N>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Sub<$crate::__private_whippyunits_core::num::N, Output = $crate::__private_whippyunits_core::num::N>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Sub<$crate::__private_whippyunits_core::num::N, Output = $crate::__private_whippyunits_core::num::N>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Sub<$crate::__private_whippyunits_core::num::N, Output = $crate::__private_whippyunits_core::num::N>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Sub<$crate::__private_whippyunits_core::num::N, Output = $crate::__private_whippyunits_core::num::N>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Sub<$crate::__private_whippyunits_core::num::N, Output = $crate::__private_whippyunits_core::num::N>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Sub<$crate::__private_whippyunits_core::num::N, Output = $crate::__private_whippyunits_core::num::N>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Sub<$crate::__private_whippyunits_core::num::N, Output = $crate::__private_whippyunits_core::num::N>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Sub<$crate::__private_whippyunits_core::num::N, Output = $crate::__private_whippyunits_core::num::N>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Sub<$crate::__private_whippyunits_core::num::N, Output = $crate::__private_whippyunits_core::num::N>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Sub<$crate::__private_whippyunits_core::num::N, Output = $crate::__private_whippyunits_core::num::N>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Sub<$crate::__private_whippyunits_core::num::N, Output = $crate::__private_whippyunits_core::num::N> ), // other parameters $T, rescale_fn @@ -541,48 +533,48 @@ macro_rules! define_arithmetic { (), // inversion where clauses ( - (): IsI16<{ -MASS_EXPONENT }>, - (): IsI16<{ -LENGTH_EXPONENT }>, - (): IsI16<{ -TIME_EXPONENT }>, - (): IsI16<{ -CURRENT_EXPONENT }>, - (): IsI16<{ -TEMPERATURE_EXPONENT }>, - (): IsI16<{ -AMOUNT_EXPONENT }>, - (): IsI16<{ -LUMINOSITY_EXPONENT }>, - (): IsI16<{ -ANGLE_EXPONENT }>, - (): IsI16<{ -SCALE_P2 }>, - (): IsI16<{ -SCALE_P3 }>, - (): IsI16<{ -SCALE_P5 }>, - (): IsI16<{ -SCALE_PI }> + (): $crate::IsI16<{ -MASS_EXPONENT }>, + (): $crate::IsI16<{ -LENGTH_EXPONENT }>, + (): $crate::IsI16<{ -TIME_EXPONENT }>, + (): $crate::IsI16<{ -CURRENT_EXPONENT }>, + (): $crate::IsI16<{ -TEMPERATURE_EXPONENT }>, + (): $crate::IsI16<{ -AMOUNT_EXPONENT }>, + (): $crate::IsI16<{ -LUMINOSITY_EXPONENT }>, + (): $crate::IsI16<{ -ANGLE_EXPONENT }>, + (): $crate::IsI16<{ -SCALE_P2 }>, + (): $crate::IsI16<{ -SCALE_P3 }>, + (): $crate::IsI16<{ -SCALE_P5 }>, + (): $crate::IsI16<{ -SCALE_PI }> ), // mul output dimension where clauses ( - (): IsI16<{ MASS_EXPONENT_1 + MASS_EXPONENT_2 }>, - (): IsI16<{ LENGTH_EXPONENT_1 + LENGTH_EXPONENT_2 }>, - (): IsI16<{ TIME_EXPONENT_1 + TIME_EXPONENT_2 }>, - (): IsI16<{ CURRENT_EXPONENT_1 + CURRENT_EXPONENT_2 }>, - (): IsI16<{ TEMPERATURE_EXPONENT_1 + TEMPERATURE_EXPONENT_2 }>, - (): IsI16<{ AMOUNT_EXPONENT_1 + AMOUNT_EXPONENT_2 }>, - (): IsI16<{ LUMINOSITY_EXPONENT_1 + LUMINOSITY_EXPONENT_2 }>, - (): IsI16<{ ANGLE_EXPONENT_1 + ANGLE_EXPONENT_2 }>, - (): IsI16<{ SCALE_P2_1 + SCALE_P2_2 }>, - (): IsI16<{ SCALE_P3_1 + SCALE_P3_2 }>, - (): IsI16<{ SCALE_P5_1 + SCALE_P5_2 }>, - (): IsI16<{ SCALE_PI_1 + SCALE_PI_2 }> + (): $crate::IsI16<{ MASS_EXPONENT_1 + MASS_EXPONENT_2 }>, + (): $crate::IsI16<{ LENGTH_EXPONENT_1 + LENGTH_EXPONENT_2 }>, + (): $crate::IsI16<{ TIME_EXPONENT_1 + TIME_EXPONENT_2 }>, + (): $crate::IsI16<{ CURRENT_EXPONENT_1 + CURRENT_EXPONENT_2 }>, + (): $crate::IsI16<{ TEMPERATURE_EXPONENT_1 + TEMPERATURE_EXPONENT_2 }>, + (): $crate::IsI16<{ AMOUNT_EXPONENT_1 + AMOUNT_EXPONENT_2 }>, + (): $crate::IsI16<{ LUMINOSITY_EXPONENT_1 + LUMINOSITY_EXPONENT_2 }>, + (): $crate::IsI16<{ ANGLE_EXPONENT_1 + ANGLE_EXPONENT_2 }>, + (): $crate::IsI16<{ SCALE_P2_1 + SCALE_P2_2 }>, + (): $crate::IsI16<{ SCALE_P3_1 + SCALE_P3_2 }>, + (): $crate::IsI16<{ SCALE_P5_1 + SCALE_P5_2 }>, + (): $crate::IsI16<{ SCALE_PI_1 + SCALE_PI_2 }> ), // div output dimension where clauses ( - (): IsI16<{ MASS_EXPONENT_1 - MASS_EXPONENT_2 }>, - (): IsI16<{ LENGTH_EXPONENT_1 - LENGTH_EXPONENT_2 }>, - (): IsI16<{ TIME_EXPONENT_1 - TIME_EXPONENT_2 }>, - (): IsI16<{ CURRENT_EXPONENT_1 - CURRENT_EXPONENT_2 }>, - (): IsI16<{ TEMPERATURE_EXPONENT_1 - TEMPERATURE_EXPONENT_2 }>, - (): IsI16<{ AMOUNT_EXPONENT_1 - AMOUNT_EXPONENT_2 }>, - (): IsI16<{ LUMINOSITY_EXPONENT_1 - LUMINOSITY_EXPONENT_2 }>, - (): IsI16<{ ANGLE_EXPONENT_1 - ANGLE_EXPONENT_2 }>, - (): IsI16<{ SCALE_P2_1 - SCALE_P2_2 }>, - (): IsI16<{ SCALE_P3_1 - SCALE_P3_2 }>, - (): IsI16<{ SCALE_P5_1 - SCALE_P5_2 }>, - (): IsI16<{ SCALE_PI_1 - SCALE_PI_2 }> + (): $crate::IsI16<{ MASS_EXPONENT_1 - MASS_EXPONENT_2 }>, + (): $crate::IsI16<{ LENGTH_EXPONENT_1 - LENGTH_EXPONENT_2 }>, + (): $crate::IsI16<{ TIME_EXPONENT_1 - TIME_EXPONENT_2 }>, + (): $crate::IsI16<{ CURRENT_EXPONENT_1 - CURRENT_EXPONENT_2 }>, + (): $crate::IsI16<{ TEMPERATURE_EXPONENT_1 - TEMPERATURE_EXPONENT_2 }>, + (): $crate::IsI16<{ AMOUNT_EXPONENT_1 - AMOUNT_EXPONENT_2 }>, + (): $crate::IsI16<{ LUMINOSITY_EXPONENT_1 - LUMINOSITY_EXPONENT_2 }>, + (): $crate::IsI16<{ ANGLE_EXPONENT_1 - ANGLE_EXPONENT_2 }>, + (): $crate::IsI16<{ SCALE_P2_1 - SCALE_P2_2 }>, + (): $crate::IsI16<{ SCALE_P3_1 - SCALE_P3_2 }>, + (): $crate::IsI16<{ SCALE_P5_1 - SCALE_P5_2 }>, + (): $crate::IsI16<{ SCALE_PI_1 - SCALE_PI_2 }> ), // other parameters $T, rescale_fn @@ -655,48 +647,48 @@ macro_rules! define_arithmetic { ), // inversion where clauses ( - N: core::ops::Neg>, - N: core::ops::Neg>, - N: core::ops::Neg>, - N: core::ops::Neg>, - N: core::ops::Neg>, - N: core::ops::Neg>, - N: core::ops::Neg>, - N: core::ops::Neg>, - N: core::ops::Neg>, - N: core::ops::Neg>, - N: core::ops::Neg>, - N: core::ops::Neg> + $crate::__private_whippyunits_core::num::N: ::core::ops::Neg>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Neg>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Neg>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Neg>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Neg>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Neg>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Neg>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Neg>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Neg>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Neg>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Neg>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Neg> ), // mul output dimension where clauses ( - N: core::ops::Add, Output = N>, - N: core::ops::Add, Output = N>, - N: core::ops::Add, Output = N>, - N: core::ops::Add, Output = N>, - N: core::ops::Add, Output = N>, - N: core::ops::Add, Output = N>, - N: core::ops::Add, Output = N>, - N: core::ops::Add, Output = N>, - N: core::ops::Add, Output = N>, - N: core::ops::Add, Output = N>, - N: core::ops::Add, Output = N>, - N: core::ops::Add, Output = N> + $crate::__private_whippyunits_core::num::N: ::core::ops::Add<$crate::__private_whippyunits_core::num::N, Output = $crate::__private_whippyunits_core::num::N>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Add<$crate::__private_whippyunits_core::num::N, Output = $crate::__private_whippyunits_core::num::N>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Add<$crate::__private_whippyunits_core::num::N, Output = $crate::__private_whippyunits_core::num::N>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Add<$crate::__private_whippyunits_core::num::N, Output = $crate::__private_whippyunits_core::num::N>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Add<$crate::__private_whippyunits_core::num::N, Output = $crate::__private_whippyunits_core::num::N>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Add<$crate::__private_whippyunits_core::num::N, Output = $crate::__private_whippyunits_core::num::N>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Add<$crate::__private_whippyunits_core::num::N, Output = $crate::__private_whippyunits_core::num::N>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Add<$crate::__private_whippyunits_core::num::N, Output = $crate::__private_whippyunits_core::num::N>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Add<$crate::__private_whippyunits_core::num::N, Output = $crate::__private_whippyunits_core::num::N>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Add<$crate::__private_whippyunits_core::num::N, Output = $crate::__private_whippyunits_core::num::N>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Add<$crate::__private_whippyunits_core::num::N, Output = $crate::__private_whippyunits_core::num::N>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Add<$crate::__private_whippyunits_core::num::N, Output = $crate::__private_whippyunits_core::num::N> ), // div output dimension where clauses ( - N: core::ops::Sub, Output = N>, - N: core::ops::Sub, Output = N>, - N: core::ops::Sub, Output = N>, - N: core::ops::Sub, Output = N>, - N: core::ops::Sub, Output = N>, - N: core::ops::Sub, Output = N>, - N: core::ops::Sub, Output = N>, - N: core::ops::Sub, Output = N>, - N: core::ops::Sub, Output = N>, - N: core::ops::Sub, Output = N>, - N: core::ops::Sub, Output = N>, - N: core::ops::Sub, Output = N> + $crate::__private_whippyunits_core::num::N: ::core::ops::Sub<$crate::__private_whippyunits_core::num::N, Output = $crate::__private_whippyunits_core::num::N>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Sub<$crate::__private_whippyunits_core::num::N, Output = $crate::__private_whippyunits_core::num::N>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Sub<$crate::__private_whippyunits_core::num::N, Output = $crate::__private_whippyunits_core::num::N>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Sub<$crate::__private_whippyunits_core::num::N, Output = $crate::__private_whippyunits_core::num::N>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Sub<$crate::__private_whippyunits_core::num::N, Output = $crate::__private_whippyunits_core::num::N>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Sub<$crate::__private_whippyunits_core::num::N, Output = $crate::__private_whippyunits_core::num::N>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Sub<$crate::__private_whippyunits_core::num::N, Output = $crate::__private_whippyunits_core::num::N>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Sub<$crate::__private_whippyunits_core::num::N, Output = $crate::__private_whippyunits_core::num::N>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Sub<$crate::__private_whippyunits_core::num::N, Output = $crate::__private_whippyunits_core::num::N>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Sub<$crate::__private_whippyunits_core::num::N, Output = $crate::__private_whippyunits_core::num::N>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Sub<$crate::__private_whippyunits_core::num::N, Output = $crate::__private_whippyunits_core::num::N>, + $crate::__private_whippyunits_core::num::N: ::core::ops::Sub<$crate::__private_whippyunits_core::num::N, Output = $crate::__private_whippyunits_core::num::N> ), // other parameters $T, rescale_fn diff --git a/src/arithmetic.rs b/src/arithmetic.rs index 7a1733b..987b189 100644 --- a/src/arithmetic.rs +++ b/src/arithmetic.rs @@ -183,13 +183,13 @@ macro_rules! quantity_quantity_partial_ord_interface { impl< $($single_dimension_single_scale_params)* > - core::cmp::PartialOrd<$crate::quantity_type!($T)> + ::core::cmp::PartialOrd<$crate::quantity_type!($T)> for $crate::quantity_type!($T) where - $T: PartialOrd, - Brand: PartialEq, + $T: ::core::cmp::PartialOrd, + Brand: ::core::cmp::PartialEq, { - fn partial_cmp(&self, other: &$crate::quantity_type!($T)) -> Option<::core::cmp::Ordering> { + fn partial_cmp(&self, other: &$crate::quantity_type!($T)) -> ::core::option::Option<::core::cmp::Ordering> { self.unsafe_value.partial_cmp(&other.unsafe_value) } } diff --git a/src/arithmetic_quantity_types.rs b/src/arithmetic_quantity_types.rs index 3e067ac..d75138b 100644 --- a/src/arithmetic_quantity_types.rs +++ b/src/arithmetic_quantity_types.rs @@ -3,9 +3,23 @@ #[cfg(has_generic_const_exprs)] macro_rules! inverse_quantity_type { ($T:ty) => { - Quantity< - Scale<_2<{ -SCALE_P2 }>, _3<{ -SCALE_P3 }>, _5<{ -SCALE_P5 }>, _Pi<{ -SCALE_PI }>>, - Dimension<_M<{ -MASS_EXPONENT }>, _L<{ -LENGTH_EXPONENT }>, _T<{ -TIME_EXPONENT }>, _I<{ -CURRENT_EXPONENT }>, _Θ<{ -TEMPERATURE_EXPONENT }>, _N<{ -AMOUNT_EXPONENT }>, _J<{ -LUMINOSITY_EXPONENT }>, _A<{ -ANGLE_EXPONENT }>>, + $crate::quantity::Quantity< + $crate::quantity::Scale< + $crate::quantity::_2<{ -SCALE_P2 }>, + $crate::quantity::_3<{ -SCALE_P3 }>, + $crate::quantity::_5<{ -SCALE_P5 }>, + $crate::quantity::_Pi<{ -SCALE_PI }>, + >, + $crate::quantity::Dimension< + $crate::quantity::_M<{ -MASS_EXPONENT }>, + $crate::quantity::_L<{ -LENGTH_EXPONENT }>, + $crate::quantity::_T<{ -TIME_EXPONENT }>, + $crate::quantity::_I<{ -CURRENT_EXPONENT }>, + $crate::quantity::_Θ<{ -TEMPERATURE_EXPONENT }>, + $crate::quantity::_N<{ -AMOUNT_EXPONENT }>, + $crate::quantity::_J<{ -LUMINOSITY_EXPONENT }>, + $crate::quantity::_A<{ -ANGLE_EXPONENT }>, + >, $T, Brand > @@ -17,17 +31,22 @@ macro_rules! inverse_quantity_type { #[cfg(not(has_generic_const_exprs))] macro_rules! inverse_quantity_type { ($T:ty) => { - Quantity< - Scale<_2, _3, _5, _Pi>, - Dimension< - _M, - _L, - _T, - _I, - _Θ, - _N, - _J, - _A + $crate::quantity::Quantity< + $crate::quantity::Scale< + $crate::quantity::_2, + $crate::quantity::_3, + $crate::quantity::_5, + $crate::quantity::_Pi, + >, + $crate::quantity::Dimension< + $crate::quantity::_M, + $crate::quantity::_L, + $crate::quantity::_T, + $crate::quantity::_I, + $crate::quantity::_Θ, + $crate::quantity::_N, + $crate::quantity::_J, + $crate::quantity::_A, >, $T, Brand @@ -39,25 +58,67 @@ macro_rules! inverse_quantity_type { #[doc(hidden)] macro_rules! addition_input { (Strict, $T:ty) => { - Quantity< - Scale<_2, _3, _5, _Pi>, - Dimension<_M, _L, _T, _I, _Θ, _N, _J, _A>, + $crate::quantity::Quantity< + $crate::quantity::Scale< + $crate::quantity::_2, + $crate::quantity::_3, + $crate::quantity::_5, + $crate::quantity::_Pi, + >, + $crate::quantity::Dimension< + $crate::quantity::_M, + $crate::quantity::_L, + $crate::quantity::_T, + $crate::quantity::_I, + $crate::quantity::_Θ, + $crate::quantity::_N, + $crate::quantity::_J, + $crate::quantity::_A, + >, $T, Brand > }; (LeftHand, $T:ty) => { - Quantity< - Scale<_2, _3, _5, _Pi>, - Dimension<_M, _L, _T, _I, _Θ, _N, _J, _A>, + $crate::quantity::Quantity< + $crate::quantity::Scale< + $crate::quantity::_2, + $crate::quantity::_3, + $crate::quantity::_5, + $crate::quantity::_Pi, + >, + $crate::quantity::Dimension< + $crate::quantity::_M, + $crate::quantity::_L, + $crate::quantity::_T, + $crate::quantity::_I, + $crate::quantity::_Θ, + $crate::quantity::_N, + $crate::quantity::_J, + $crate::quantity::_A, + >, $T, Brand > }; (RightHand, $T:ty) => { - Quantity< - Scale<_2, _3, _5, _Pi>, - Dimension<_M, _L, _T, _I, _Θ, _N, _J, _A>, + $crate::quantity::Quantity< + $crate::quantity::Scale< + $crate::quantity::_2, + $crate::quantity::_3, + $crate::quantity::_5, + $crate::quantity::_Pi, + >, + $crate::quantity::Dimension< + $crate::quantity::_M, + $crate::quantity::_L, + $crate::quantity::_T, + $crate::quantity::_I, + $crate::quantity::_Θ, + $crate::quantity::_N, + $crate::quantity::_J, + $crate::quantity::_A, + >, $T, Brand > @@ -68,17 +129,45 @@ macro_rules! addition_input { #[doc(hidden)] macro_rules! multiplication_input { (LeftHand, $T:ty) => { - Quantity< - Scale<_2, _3, _5, _Pi>, - Dimension<_M, _L, _T, _I, _Θ, _N, _J, _A>, + $crate::quantity::Quantity< + $crate::quantity::Scale< + $crate::quantity::_2, + $crate::quantity::_3, + $crate::quantity::_5, + $crate::quantity::_Pi, + >, + $crate::quantity::Dimension< + $crate::quantity::_M, + $crate::quantity::_L, + $crate::quantity::_T, + $crate::quantity::_I, + $crate::quantity::_Θ, + $crate::quantity::_N, + $crate::quantity::_J, + $crate::quantity::_A, + >, $T, Brand > }; (RightHand, $T:ty) => { - Quantity< - Scale<_2, _3, _5, _Pi>, - Dimension<_M, _L, _T, _I, _Θ, _N, _J, _A>, + $crate::quantity::Quantity< + $crate::quantity::Scale< + $crate::quantity::_2, + $crate::quantity::_3, + $crate::quantity::_5, + $crate::quantity::_Pi, + >, + $crate::quantity::Dimension< + $crate::quantity::_M, + $crate::quantity::_L, + $crate::quantity::_T, + $crate::quantity::_I, + $crate::quantity::_Θ, + $crate::quantity::_N, + $crate::quantity::_J, + $crate::quantity::_A, + >, $T, Brand > @@ -90,22 +179,22 @@ macro_rules! multiplication_input { #[cfg(has_generic_const_exprs)] macro_rules! multiplication_output { ($T:ty, $log_op:tt) => { - Quantity< - Scale< - _2<{ SCALE_P2_1 $log_op SCALE_P2_2 }>, - _3<{ SCALE_P3_1 $log_op SCALE_P3_2 }>, - _5<{ SCALE_P5_1 $log_op SCALE_P5_2 }>, - _Pi<{ SCALE_PI_1 $log_op SCALE_PI_2 }> - >, - Dimension< - _M<{ MASS_EXPONENT_1 $log_op MASS_EXPONENT_2 }>, - _L<{ LENGTH_EXPONENT_1 $log_op LENGTH_EXPONENT_2 }>, - _T<{ TIME_EXPONENT_1 $log_op TIME_EXPONENT_2 }>, - _I<{ CURRENT_EXPONENT_1 $log_op CURRENT_EXPONENT_2 }>, - _Θ<{ TEMPERATURE_EXPONENT_1 $log_op TEMPERATURE_EXPONENT_2 }>, - _N<{ AMOUNT_EXPONENT_1 $log_op AMOUNT_EXPONENT_2 }>, - _J<{ LUMINOSITY_EXPONENT_1 $log_op LUMINOSITY_EXPONENT_2 }>, - _A<{ ANGLE_EXPONENT_1 $log_op ANGLE_EXPONENT_2 }> + $crate::quantity::Quantity< + $crate::quantity::Scale< + $crate::quantity::_2<{ SCALE_P2_1 $log_op SCALE_P2_2 }>, + $crate::quantity::_3<{ SCALE_P3_1 $log_op SCALE_P3_2 }>, + $crate::quantity::_5<{ SCALE_P5_1 $log_op SCALE_P5_2 }>, + $crate::quantity::_Pi<{ SCALE_PI_1 $log_op SCALE_PI_2 }>, + >, + $crate::quantity::Dimension< + $crate::quantity::_M<{ MASS_EXPONENT_1 $log_op MASS_EXPONENT_2 }>, + $crate::quantity::_L<{ LENGTH_EXPONENT_1 $log_op LENGTH_EXPONENT_2 }>, + $crate::quantity::_T<{ TIME_EXPONENT_1 $log_op TIME_EXPONENT_2 }>, + $crate::quantity::_I<{ CURRENT_EXPONENT_1 $log_op CURRENT_EXPONENT_2 }>, + $crate::quantity::_Θ<{ TEMPERATURE_EXPONENT_1 $log_op TEMPERATURE_EXPONENT_2 }>, + $crate::quantity::_N<{ AMOUNT_EXPONENT_1 $log_op AMOUNT_EXPONENT_2 }>, + $crate::quantity::_J<{ LUMINOSITY_EXPONENT_1 $log_op LUMINOSITY_EXPONENT_2 }>, + $crate::quantity::_A<{ ANGLE_EXPONENT_1 $log_op ANGLE_EXPONENT_2 }>, >, $T, Brand @@ -118,22 +207,22 @@ macro_rules! multiplication_output { #[cfg(not(has_generic_const_exprs))] macro_rules! multiplication_output { ($T:ty, $log_op:tt) => { - Quantity< - Scale< - _2, - _3, - _5, - _Pi - >, - Dimension< - _M, - _L, - _T, - _I, - _Θ, - _N, - _J, - _A + $crate::quantity::Quantity< + $crate::quantity::Scale< + $crate::quantity::_2, + $crate::quantity::_3, + $crate::quantity::_5, + $crate::quantity::_Pi, + >, + $crate::quantity::Dimension< + $crate::quantity::_M, + $crate::quantity::_L, + $crate::quantity::_T, + $crate::quantity::_I, + $crate::quantity::_Θ, + $crate::quantity::_N, + $crate::quantity::_J, + $crate::quantity::_A, >, $T, Brand diff --git a/src/dimension_traits.rs b/src/dimension_traits.rs index 0f1c794..2416050 100644 --- a/src/dimension_traits.rs +++ b/src/dimension_traits.rs @@ -52,9 +52,6 @@ //! (`D1` and `D2`), and so must be done in the function. There is no way to assert on the trait itself //! that "this type can be added to any other type that also represents a length". -use crate::quantity::Quantity; -use crate::quantity::{_2, _3, _5, _A, _I, _J, _L, _M, _N, _Pi, _T, _Θ, Dimension, Scale}; - /// Expands to a trait and its implementation for a specific atomic dimension. /// It follows the same pattern as the default declarators but focuses only on the /// trait definition and implementation for scale-generic quantities. @@ -73,17 +70,22 @@ macro_rules! define_atomic_dimension_trait { impl $trait_name - for Quantity< - Scale<_2, _3, _5, _Pi>, - Dimension< - _M<$mass_exp>, - _L<$length_exp>, - _T<$time_exp>, - _I<$current_exp>, - _Θ<$temperature_exp>, - _N<$amount_exp>, - _J<$luminosity_exp>, - _A<$angle_exp>, + for $crate::quantity::Quantity< + $crate::quantity::Scale< + $crate::quantity::_2, + $crate::quantity::_3, + $crate::quantity::_5, + $crate::quantity::_Pi, + >, + $crate::quantity::Dimension< + $crate::quantity::_M<$mass_exp>, + $crate::quantity::_L<$length_exp>, + $crate::quantity::_T<$time_exp>, + $crate::quantity::_I<$current_exp>, + $crate::quantity::_Θ<$temperature_exp>, + $crate::quantity::_N<$amount_exp>, + $crate::quantity::_J<$luminosity_exp>, + $crate::quantity::_A<$angle_exp>, >, T, > diff --git a/src/lib.rs b/src/lib.rs index 9a7b736..55fe13b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,16 +1,16 @@ //! WhippyUnits is a zero-cost units-of-measure library for Rust that provides: -//! +//! //! - Dimensional safety (`m + s` is a compile error) //! - Scale safety (`m + mm` requires explicit `rescale`) //! - Ergonomic syntax: macros (`quantity!(1, m)`), methods (`5.0.meters()`), and even literals (`5.0m`) //! - `no-std` and `no-alloc` compatibility -//! +//! //! Works on stable Rust by default, with optional support for nightly `generic_const_exprs` via the `cge` feature flag. -//! +//! //! ## Why WhippyUnits? -//! +//! //! Unlike other Rust units-of-measure libraries, WhippyUnits is: -//! +//! //! - Language-server integrated: pretty-prints complex type signatures in hover info and inlay hints //! - Log-scale-encoded: supports lossless rescaling at the type level, effectively acting as a dimensionally-aware compile-time precision extension //! - Scale-explicit: arithmetic operations are always explicit about the scale of the result @@ -18,7 +18,7 @@ //! - Scale-generic: write functions constrained by dimension - or a disjunctive set of dimensions - that work with any scale, *without* imposing arbitrary rescaling at API boundaries //! - UCUM compliant: supports UCUM-format unit strings (e.g. `"kg.m2/s2"`) for easy interoperability and code generation //! - Fixed-point friendly: integer types are guaranteed to use pure integer math for all operations -//! +//! //! ## Quick Start //! //! ```rust @@ -70,7 +70,7 @@ //! //! For the full categorized example index, see //! [README in crate source](https://docs.rs/crate/whippyunits/latest/source/README.md). -//! +//! //! ## Developer Tooling //! //! The companion [`whippyunits-lsp-proxy`](https://github.com/WhippyUnits/whippyunits-rs/tree/main/lsp-proxy) @@ -85,16 +85,16 @@ //! See the respective READMEs for setup instructions. //! //! ## Experimental Features -//! +//! //! By default, WhippyUnits uses a typenum-based polyfill for compile-time dimensional arithmetic. //! This polyfill is fully functional, but is limited to working with integer exponents in the range -200 to 200. //! To use `generic_const_exprs` (requires nightly toolchain) instead, enable the `cge` feature flag: -//! +//! //! ```toml //! [dependencies] //! whippyunits = { version = "0.1", features = ["cge"] } //! ``` -//! +//! //! With the `cge` flag, exponents can span the full range of i16 integers. //! #![cfg_attr(not(feature = "std"), no_std)] @@ -124,6 +124,13 @@ impl GetSecondGeneric for Helper { #[doc(hidden)] mod alloc; +#[doc(hidden)] +pub use num_traits as __private_num_traits; +#[doc(hidden)] +pub use whippyunits_core as __private_whippyunits_core; +#[doc(hidden)] +pub use whippyunits_proc_macros as __private_whippyunits_proc_macros; + pub mod api; #[doc(hidden)] pub mod arithmetic; diff --git a/src/print/display_traits.rs b/src/print/display_traits.rs index 452615f..7b2b6e0 100644 --- a/src/print/display_traits.rs +++ b/src/print/display_traits.rs @@ -7,31 +7,45 @@ macro_rules! define_display_traits { T, Brand, > - fmt::Display - for Quantity< - Scale<_2, _3, _5, _Pi>, - Dimension<_M, _L, _T, _I, _Θ, _N, _J, _A>, + ::core::fmt::Display + for $crate::quantity::Quantity< + $crate::quantity::Scale< + $crate::quantity::_2, + $crate::quantity::_3, + $crate::quantity::_5, + $crate::quantity::_Pi, + >, + $crate::quantity::Dimension< + $crate::quantity::_M, + $crate::quantity::_L, + $crate::quantity::_T, + $crate::quantity::_I, + $crate::quantity::_Θ, + $crate::quantity::_N, + $crate::quantity::_J, + $crate::quantity::_A, + >, T, Brand, > where - T: Copy + num_traits::NumCast, + T: Copy + $crate::__private_num_traits::NumCast, { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let value_f64 = ::from(self.unsafe_value) + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + let value_f64 = ::from(self.unsafe_value) .expect("unable to convert numeric value to f64 for display"); #[cfg(feature = "std")] - let brand_name = std::any::type_name::(); + let brand_name = ::std::any::type_name::(); #[cfg(not(feature = "std"))] let brand_name = ""; #[cfg(feature = "std")] - let type_name = std::any::type_name::(); + let type_name = ::std::any::type_name::(); #[cfg(not(feature = "std"))] let type_name = ""; - let pretty = pretty_print_quantity_value( + let pretty = $crate::print::prettyprint::pretty_print_quantity_value( value_f64, - whippyunits_core::dimension_exponents::DynDimensionExponents([$($dimension_args)*]), - whippyunits_core::scale_exponents::ScaleExponents([$($scale_args)*]), + $crate::__private_whippyunits_core::dimension_exponents::DynDimensionExponents([$($dimension_args)*]), + $crate::__private_whippyunits_core::scale_exponents::ScaleExponents([$($scale_args)*]), type_name, false, // Non-verbose mode for Display true, // Show type in brackets for Display (now unified) @@ -46,31 +60,45 @@ macro_rules! define_display_traits { T, Brand, > - fmt::Debug - for Quantity< - Scale<_2, _3, _5, _Pi>, - Dimension<_M, _L, _T, _I, _Θ, _N, _J, _A>, + ::core::fmt::Debug + for $crate::quantity::Quantity< + $crate::quantity::Scale< + $crate::quantity::_2, + $crate::quantity::_3, + $crate::quantity::_5, + $crate::quantity::_Pi, + >, + $crate::quantity::Dimension< + $crate::quantity::_M, + $crate::quantity::_L, + $crate::quantity::_T, + $crate::quantity::_I, + $crate::quantity::_Θ, + $crate::quantity::_N, + $crate::quantity::_J, + $crate::quantity::_A, + >, T, Brand, > where - T: Copy + num_traits::NumCast, + T: Copy + $crate::__private_num_traits::NumCast, { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let value_f64 = ::from(self.unsafe_value) + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + let value_f64 = ::from(self.unsafe_value) .expect("unable to convert numeric value to f64 for debug"); #[cfg(feature = "std")] - let brand_name = std::any::type_name::(); + let brand_name = ::std::any::type_name::(); #[cfg(not(feature = "std"))] let brand_name = ""; #[cfg(feature = "std")] - let type_name = std::any::type_name::(); + let type_name = ::std::any::type_name::(); #[cfg(not(feature = "std"))] let type_name = ""; - let pretty = pretty_print_quantity_value( + let pretty = $crate::print::prettyprint::pretty_print_quantity_value( value_f64, - whippyunits_core::dimension_exponents::DynDimensionExponents([$($dimension_args)*]), - whippyunits_core::scale_exponents::ScaleExponents([$($scale_args)*]), + $crate::__private_whippyunits_core::dimension_exponents::DynDimensionExponents([$($dimension_args)*]), + $crate::__private_whippyunits_core::scale_exponents::ScaleExponents([$($scale_args)*]), type_name, true, // Verbose mode for Debug true, // Show type in brackets for Debug (now unified) diff --git a/src/print/prettyprint.rs b/src/print/prettyprint.rs index 3850bd8..42c9dbc 100644 --- a/src/print/prettyprint.rs +++ b/src/print/prettyprint.rs @@ -208,21 +208,21 @@ macro_rules! define_generate_verbose_dimension_names { (($($dimension_names:tt)*)) => { /// Generate verbose dimension names for unresolved types (Length, Time, Mass) pub fn generate_verbose_dimension_names( - exponents: Vec - ) -> String { - let parts: Vec = [ + exponents: $crate::alloc::Vec + ) -> $crate::alloc::String { + let parts: $crate::alloc::Vec<$crate::alloc::String> = [ $($dimension_names)* ].iter() .filter(|(idx, _)| exponents[*idx] != 0) .map(|(idx, name)| if exponents[*idx] == 1 { - name.to_string() + $crate::alloc::ToString::to_string(name) } else { - let superscript = to_unicode_superscript(exponents[*idx], false); - format!("{}{}", name, superscript) + let superscript = $crate::print::utils::to_unicode_superscript(exponents[*idx], false); + $crate::alloc::format!("{}{}", name, superscript) }) .collect(); - if parts.is_empty() { "?".to_string() } else { parts.join("·") } + if parts.is_empty() { $crate::alloc::ToString::to_string("?") } else { parts.join("·") } } }; } diff --git a/src/quantity.rs b/src/quantity.rs index cf1ef5e..8b88a0b 100644 --- a/src/quantity.rs +++ b/src/quantity.rs @@ -139,7 +139,7 @@ pub struct Scale, P3 = _3<0>, P5 = _5<0>, PI = _Pi<0>> { /// - angle: `_A<1>` /// /// Derived dimensions have a mixture of dimension exponents: -/// - velocity: `_L<1>, _T<-1>` +/// - velocity: `_L<1>, _T<-1>` /// - acceleration: `_L<1>, _T<-2>` /// - force: `_M<1>, _L<1>, _T<-2>` /// - energy: `_M<1>, _L<2>, _T<-2>` @@ -1042,17 +1042,45 @@ whippyunits_proc_macros::generate_all_radian_erasures!(9); #[doc(hidden)] macro_rules! quantity_type { () => { - Quantity< - Scale<_2, _3, _5, _Pi>, - Dimension<_M, _L, _T, _I, _Θ, _N, _J, _A>, + $crate::quantity::Quantity< + $crate::quantity::Scale< + $crate::quantity::_2, + $crate::quantity::_3, + $crate::quantity::_5, + $crate::quantity::_Pi + >, + $crate::quantity::Dimension< + $crate::quantity::_M, + $crate::quantity::_L, + $crate::quantity::_T, + $crate::quantity::_I, + $crate::quantity::_Θ, + $crate::quantity::_N, + $crate::quantity::_J, + $crate::quantity::_A, + >, T, Brand > }; ($T:ty) => { - Quantity< - Scale<_2, _3, _5, _Pi>, - Dimension<_M, _L, _T, _I, _Θ, _N, _J, _A>, + $crate::quantity::Quantity< + $crate::quantity::Scale< + $crate::quantity::_2, + $crate::quantity::_3, + $crate::quantity::_5, + $crate::quantity::_Pi, + >, + $crate::quantity::Dimension< + $crate::quantity::_M, + $crate::quantity::_L, + $crate::quantity::_T, + $crate::quantity::_I, + $crate::quantity::_Θ, + $crate::quantity::_N, + $crate::quantity::_J, + $crate::quantity::_A, + >, $T, Brand > diff --git a/src/scale_conversion.rs b/src/scale_conversion.rs index 9f9118c..6dc8f4a 100644 --- a/src/scale_conversion.rs +++ b/src/scale_conversion.rs @@ -157,12 +157,26 @@ macro_rules! _define_float_rescale { > ( quantity: $($float_rescale_input_type)*, ) -> $($float_rescale_output_type)* { - let rescale_factor = aggregate_scale_factor_float( + let rescale_factor = $crate::api::aggregate_scale_factor_float( $($float_rescale_aggregate_args)* ) as $T; - Quantity::< - Scale<_2, _3, _5, _Pi>, - Dimension<_M, _L, _T, _I, _Θ, _N, _J, _A>, + $crate::quantity::Quantity::< + $crate::quantity::Scale< + $crate::quantity::_2, + $crate::quantity::_3, + $crate::quantity::_5, + $crate::quantity::_Pi, + >, + $crate::quantity::Dimension< + $crate::quantity::_M, + $crate::quantity::_L, + $crate::quantity::_T, + $crate::quantity::_I, + $crate::quantity::_Θ, + $crate::quantity::_N, + $crate::quantity::_J, + $crate::quantity::_A, + >, $T, Brand, >::new( @@ -229,7 +243,7 @@ macro_rules! _define_int_rescale { > ( quantity: $($int_rescale_input_type)*, ) -> $($int_rescale_output_type)* { - let (num, den) = aggregate_scale_factor( + let (num, den) = $crate::api::aggregate_scale_factor( $($int_rescale_aggregate_args)* ); let num = num as $T; @@ -245,9 +259,23 @@ macro_rules! _define_int_rescale { (quantity.unsafe_value * num) / den }; - Quantity::< - Scale<_2, _3, _5, _Pi>, - Dimension<_M, _L, _T, _I, _Θ, _N, _J, _A>, + $crate::quantity::Quantity::< + $crate::quantity::Scale< + $crate::quantity::_2, + $crate::quantity::_3, + $crate::quantity::_5, + $crate::quantity::_Pi, + >, + $crate::quantity::Dimension< + $crate::quantity::_M, + $crate::quantity::_L, + $crate::quantity::_T, + $crate::quantity::_I, + $crate::quantity::_Θ, + $crate::quantity::_N, + $crate::quantity::_J, + $crate::quantity::_A, + >, $T, Brand, >::new(result) diff --git a/src/serialization.rs b/src/serialization.rs index eefb8a0..eef9c97 100644 --- a/src/serialization.rs +++ b/src/serialization.rs @@ -33,7 +33,7 @@ //! - All terms trailing the division symbol are considered to be in the denominator //! //! Runtime parsing of unit literal expressions leverages the same parser as the [unit!](crate::unit!) macro; -//! using `from_string` or `from_json` means your binary will include the `syn` crate as a dependency. +//! using `from_string` or `from_json` means your binary will include the `syn` crate as a dependency. //! This is technically no-std, but it is fairly heavyweight for a no-std library, and is not appropriate //! for sufficiently resource-constrained environments. @@ -751,70 +751,60 @@ pub fn calculate_conversion_factor(from_dims: &UnitDimensions, to_dims: &UnitDim macro_rules! from_json { ($json:expr, $unit:expr) => {{ match $crate::serialization::parse_json_input($json) { - Ok((value, unit_str)) => { + ::core::result::Result::Ok((value, unit_str)) => { // Use deserialize_core_quantity to handle dimension checking and rescaling // Returns Quantity directly - no need for quantity! macro - const UNIT_INFO: ( - whippyunits_core::dimension_exponents::DynDimensionExponents, - whippyunits_core::scale_exponents::ScaleExponents, - ) = whippyunits_proc_macros::compute_unit_dimensions!($unit); - const DIMENSIONS: whippyunits_core::dimension_exponents::DynDimensionExponents = - UNIT_INFO.0; - const SCALES: whippyunits_core::scale_exponents::ScaleExponents = UNIT_INFO.1; + const UNIT_INFO: (i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16) = + $crate::__private_whippyunits_proc_macros::compute_unit_dimensions!($unit); $crate::serialization::deserialize_core_quantity::< - { DIMENSIONS.0[0] }, - { DIMENSIONS.0[1] }, - { DIMENSIONS.0[2] }, - { DIMENSIONS.0[3] }, - { DIMENSIONS.0[4] }, - { DIMENSIONS.0[5] }, - { DIMENSIONS.0[6] }, - { DIMENSIONS.0[7] }, - { SCALES.0[0] }, - { SCALES.0[1] }, - { SCALES.0[2] }, - { SCALES.0[3] }, + { UNIT_INFO.0 }, + { UNIT_INFO.1 }, + { UNIT_INFO.2 }, + { UNIT_INFO.3 }, + { UNIT_INFO.4 }, + { UNIT_INFO.5 }, + { UNIT_INFO.6 }, + { UNIT_INFO.7 }, + { UNIT_INFO.8 }, + { UNIT_INFO.9 }, + { UNIT_INFO.10 }, + { UNIT_INFO.11 }, f64, >(value, &unit_str) - as Result< - whippyunits::unit!($unit, f64), + as ::core::result::Result< + $crate::unit!($unit, f64), $crate::serialization::SerializationError, > } - Err(e) => Err(e), + ::core::result::Result::Err(e) => ::core::result::Result::Err(e), } }}; ($json:expr, $unit:expr, $storage_type:ty) => {{ match $crate::serialization::parse_json_input($json) { - Ok((value, unit_str)) => { - const UNIT_INFO: ( - whippyunits_core::dimension_exponents::DynDimensionExponents, - whippyunits_core::scale_exponents::ScaleExponents, - ) = whippyunits_proc_macros::compute_unit_dimensions!($unit); - const DIMENSIONS: whippyunits_core::dimension_exponents::DynDimensionExponents = - UNIT_INFO.0; - const SCALES: whippyunits_core::scale_exponents::ScaleExponents = UNIT_INFO.1; + ::core::result::Result::Ok((value, unit_str)) => { + const UNIT_INFO: (i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16) = + $crate::__private_whippyunits_proc_macros::compute_unit_dimensions!($unit); $crate::serialization::deserialize_core_quantity::< - { DIMENSIONS.0[0] }, - { DIMENSIONS.0[1] }, - { DIMENSIONS.0[2] }, - { DIMENSIONS.0[3] }, - { DIMENSIONS.0[4] }, - { DIMENSIONS.0[5] }, - { DIMENSIONS.0[6] }, - { DIMENSIONS.0[7] }, - { SCALES.0[0] }, - { SCALES.0[1] }, - { SCALES.0[2] }, - { SCALES.0[3] }, + { UNIT_INFO.0 }, + { UNIT_INFO.1 }, + { UNIT_INFO.2 }, + { UNIT_INFO.3 }, + { UNIT_INFO.4 }, + { UNIT_INFO.5 }, + { UNIT_INFO.6 }, + { UNIT_INFO.7 }, + { UNIT_INFO.8 }, + { UNIT_INFO.9 }, + { UNIT_INFO.10 }, + { UNIT_INFO.11 }, $storage_type, >(value, &unit_str) - as Result< - whippyunits::unit!($unit, $storage_type), + as ::core::result::Result< + $crate::unit!($unit, $storage_type), $crate::serialization::SerializationError, > } - Err(e) => Err(e), + ::core::result::Result::Err(e) => ::core::result::Result::Err(e), } }}; } @@ -883,72 +873,62 @@ macro_rules! from_json { macro_rules! from_string { ($string:expr, $unit:expr) => {{ match $crate::serialization::parse_string_input($string) { - Ok((value, unit_str)) => { + ::core::result::Result::Ok((value, unit_str)) => { // Use deserialize_core_quantity to handle dimension checking and rescaling // Returns Quantity directly - no need for quantity! macro - const UNIT_INFO: ( - whippyunits_core::dimension_exponents::DynDimensionExponents, - whippyunits_core::scale_exponents::ScaleExponents, - ) = whippyunits_proc_macros::compute_unit_dimensions!($unit); - const DIMENSIONS: whippyunits_core::dimension_exponents::DynDimensionExponents = - UNIT_INFO.0; - const SCALES: whippyunits_core::scale_exponents::ScaleExponents = UNIT_INFO.1; + const UNIT_INFO: (i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16) = + $crate::__private_whippyunits_proc_macros::compute_unit_dimensions!($unit); $crate::serialization::deserialize_core_quantity::< - { DIMENSIONS.0[0] }, - { DIMENSIONS.0[1] }, - { DIMENSIONS.0[2] }, - { DIMENSIONS.0[3] }, - { DIMENSIONS.0[4] }, - { DIMENSIONS.0[5] }, - { DIMENSIONS.0[6] }, - { DIMENSIONS.0[7] }, - { SCALES.0[0] }, - { SCALES.0[1] }, - { SCALES.0[2] }, - { SCALES.0[3] }, + { UNIT_INFO.0 }, + { UNIT_INFO.1 }, + { UNIT_INFO.2 }, + { UNIT_INFO.3 }, + { UNIT_INFO.4 }, + { UNIT_INFO.5 }, + { UNIT_INFO.6 }, + { UNIT_INFO.7 }, + { UNIT_INFO.8 }, + { UNIT_INFO.9 }, + { UNIT_INFO.10 }, + { UNIT_INFO.11 }, f64, >(value, &unit_str) - as Result< - whippyunits::unit!($unit, f64), + as ::core::result::Result< + $crate::unit!($unit, f64), $crate::serialization::SerializationError, > } - Err(e) => Err(e), + ::core::result::Result::Err(e) => ::core::result::Result::Err(e), } }}; ($string:expr, $unit:expr, $storage_type:ty) => {{ match $crate::serialization::parse_string_input($string) { - Ok((value, unit_str)) => { + ::core::result::Result::Ok((value, unit_str)) => { // Use deserialize_core_quantity to handle dimension checking and rescaling // Returns Quantity directly - no need for quantity! macro - const UNIT_INFO: ( - whippyunits_core::dimension_exponents::DynDimensionExponents, - whippyunits_core::scale_exponents::ScaleExponents, - ) = whippyunits_proc_macros::compute_unit_dimensions!($unit); - const DIMENSIONS: whippyunits_core::dimension_exponents::DynDimensionExponents = - UNIT_INFO.0; - const SCALES: whippyunits_core::scale_exponents::ScaleExponents = UNIT_INFO.1; + const UNIT_INFO: (i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16) = + $crate::__private_whippyunits_proc_macros::compute_unit_dimensions!($unit); $crate::serialization::deserialize_core_quantity::< - { DIMENSIONS.0[0] }, - { DIMENSIONS.0[1] }, - { DIMENSIONS.0[2] }, - { DIMENSIONS.0[3] }, - { DIMENSIONS.0[4] }, - { DIMENSIONS.0[5] }, - { DIMENSIONS.0[6] }, - { DIMENSIONS.0[7] }, - { SCALES.0[0] }, - { SCALES.0[1] }, - { SCALES.0[2] }, - { SCALES.0[3] }, + { UNIT_INFO.0 }, + { UNIT_INFO.1 }, + { UNIT_INFO.2 }, + { UNIT_INFO.3 }, + { UNIT_INFO.4 }, + { UNIT_INFO.5 }, + { UNIT_INFO.6 }, + { UNIT_INFO.7 }, + { UNIT_INFO.8 }, + { UNIT_INFO.9 }, + { UNIT_INFO.10 }, + { UNIT_INFO.11 }, $storage_type, >(value, &unit_str) - as Result< - whippyunits::unit!($unit, $storage_type), + as ::core::result::Result< + $crate::unit!($unit, $storage_type), $crate::serialization::SerializationError, > } - Err(e) => Err(e), + ::core::result::Result::Err(e) => ::core::result::Result::Err(e), } }}; } diff --git a/tests/compile_fail_cge/add_length_to_time.stderr b/tests/compile_fail_cge/add_length_to_time.stderr index 9ad6a76..4972c78 100644 --- a/tests/compile_fail_cge/add_length_to_time.stderr +++ b/tests/compile_fail_cge/add_length_to_time.stderr @@ -4,5 +4,5 @@ error[E0308]: mismatched types 9 | let _result = length + time; | ^^^^ expected `1`, found `0` | - = note: expected struct `Quantity, _T<0>, _I, _Θ, _N, _J, _A>>` - found struct `Quantity, _T<1>, _I, _Θ, _N, _J, _A>>` + = note: expected struct `Quantity>>` + found struct `Quantity>>` diff --git a/tests/compile_fail_cge/assign_wrong_type.stderr b/tests/compile_fail_cge/assign_wrong_type.stderr index b33b9dc..ec8e2fb 100644 --- a/tests/compile_fail_cge/assign_wrong_type.stderr +++ b/tests/compile_fail_cge/assign_wrong_type.stderr @@ -6,5 +6,5 @@ error[E0308]: mismatched types | | | expected due to this | - = note: expected struct `Quantity, _L<0>, _T, _I, _Θ, _N, _J, _A>>` - found struct `Quantity, _L<1>, _T, _I, _Θ, _N, _J, _A>>` + = note: expected struct `Quantity>>` + found struct `Quantity>>` diff --git a/tests/compile_fail_cge/compare_different_dimensions.stderr b/tests/compile_fail_cge/compare_different_dimensions.stderr index 3441de7..1707129 100644 --- a/tests/compile_fail_cge/compare_different_dimensions.stderr +++ b/tests/compile_fail_cge/compare_different_dimensions.stderr @@ -4,5 +4,5 @@ error[E0308]: mismatched types 11 | let _result = distance > time; | ^^^^ expected `1`, found `0` | - = note: expected struct `Quantity, _T<0>, _I, _Θ, _N, _J, _A>>` - found struct `Quantity, _T<1>, _I, _Θ, _N, _J, _A>>` + = note: expected struct `Quantity>>` + found struct `Quantity>>` diff --git a/tests/compile_fail_cge/compare_different_scales.stderr b/tests/compile_fail_cge/compare_different_scales.stderr index fe51857..b8693ba 100644 --- a/tests/compile_fail_cge/compare_different_scales.stderr +++ b/tests/compile_fail_cge/compare_different_scales.stderr @@ -4,5 +4,5 @@ error[E0308]: mismatched types 11 | let _result = meters > millimeters; | ^^^^^^^^^^^ expected `0`, found `-3` | - = note: expected struct `Quantity, _3, _5<0>, _Pi>, Dimension<_M, _L<1>, _T, _I, _Θ, _N, _J, _A>>` - found struct `Quantity, _3, _5<-3>, _Pi>, Dimension<_M, _L<1>, _T, _I, _Θ, _N, _J, _A>>` + = note: expected struct `Quantity>>` + found struct `Quantity, _3, _5<-3>>, whippyunits::quantity::Dimension>>` diff --git a/tests/compile_fail_stable/add_length_to_time.stderr b/tests/compile_fail_stable/add_length_to_time.stderr index 8b92348..2cc7ae9 100644 --- a/tests/compile_fail_stable/add_length_to_time.stderr +++ b/tests/compile_fail_stable/add_length_to_time.stderr @@ -4,5 +4,5 @@ error[E0308]: mismatched types 9 | let _result = length + time; | ^^^^ expected `1`, found `0` | - = note: expected struct `Quantity, _T<0>, _I, _Θ, _N, _J, _A>>` - found struct `Quantity, _T<1>, _I, _Θ, _N, _J, _A>>` + = note: expected struct `Quantity>>` + found struct `Quantity>>` diff --git a/tests/compile_fail_stable/assign_wrong_type.stderr b/tests/compile_fail_stable/assign_wrong_type.stderr index d907d31..081af53 100644 --- a/tests/compile_fail_stable/assign_wrong_type.stderr +++ b/tests/compile_fail_stable/assign_wrong_type.stderr @@ -6,5 +6,5 @@ error[E0308]: mismatched types | | | expected due to this | - = note: expected struct `Quantity, _L<0>, _T, _I, _Θ, _N, _J, _A>>` - found struct `Quantity, _L<1>, _T, _I, _Θ, _N, _J, _A>>` + = note: expected struct `Quantity>>` + found struct `Quantity>>` diff --git a/tests/compile_fail_stable/compare_different_dimensions.stderr b/tests/compile_fail_stable/compare_different_dimensions.stderr index 90578c4..c8a95c2 100644 --- a/tests/compile_fail_stable/compare_different_dimensions.stderr +++ b/tests/compile_fail_stable/compare_different_dimensions.stderr @@ -4,5 +4,5 @@ error[E0308]: mismatched types 11 | let _result = distance > time; | ^^^^ expected `1`, found `0` | - = note: expected struct `Quantity, _T<0>, _I, _Θ, _N, _J, _A>>` - found struct `Quantity, _T<1>, _I, _Θ, _N, _J, _A>>` + = note: expected struct `Quantity>>` + found struct `Quantity>>` diff --git a/tests/compile_fail_stable/compare_different_scales.stderr b/tests/compile_fail_stable/compare_different_scales.stderr index cde6ad8..f0773e3 100644 --- a/tests/compile_fail_stable/compare_different_scales.stderr +++ b/tests/compile_fail_stable/compare_different_scales.stderr @@ -4,5 +4,5 @@ error[E0308]: mismatched types 11 | let _result = meters > millimeters; | ^^^^^^^^^^^ expected `0`, found `-3` | - = note: expected struct `Quantity, _3, _5<0>, _Pi>, Dimension<_M, _L<1>, _T, _I, _Θ, _N, _J, _A>>` - found struct `Quantity, _3, _5<-3>, _Pi>, Dimension<_M, _L<1>, _T, _I, _Θ, _N, _J, _A>>` + = note: expected struct `Quantity>>` + found struct `Quantity, _3, _5<-3>>, whippyunits::quantity::Dimension>>` diff --git a/tests/macro_hygiene_tests.rs b/tests/macro_hygiene_tests.rs new file mode 100644 index 0000000..352de47 --- /dev/null +++ b/tests/macro_hygiene_tests.rs @@ -0,0 +1,113 @@ +#![allow(non_snake_case)] +#![allow(dead_code)] + +// Shadow `Vec`/`Result`/`Option`/etc so bare references emitted by an +// unhygienic macro will resolve to one of these instead of the real prelude +// item, causing a compile error. +struct Vec; +struct Result; +struct Option; +struct Some; +struct None; +struct Ok; +struct Err; +struct String; +struct Box; + +use whippyunits::default_declarators::*; +use whippyunits::dimension_traits::define_generic_dimension; +use whippyunits::quantity; +use whippyunits::unit; +use whippyunits::value; +use whippyunits::{from_json, from_string}; + +#[test] +fn test_quantity_and_default_declarators_under_shadowed_prelude() { + let distance = 5.0.meters(); + let time = 2.0.seconds(); + + assert_eq!(value!(distance, m), 5.0); + assert_eq!(value!(time, s), 2.0); + + let via_macro = quantity!(5.0, m); + let via_unit_annotation: unit!(m) = via_macro; + assert_eq!(value!(via_unit_annotation, m), 5.0); +} + +#[test] +fn test_arithmetic_under_shadowed_prelude() { + let sum = 5.0.meters() + 3.0.meters(); + assert_eq!(value!(sum, m), 8.0); + + let mut accum = 1.0.meters(); + accum += 1.0.meters(); + assert_eq!(value!(accum, m), 2.0); + + let product: unit!(m ^ 2) = 5.0.meters() * 5.0.meters(); + assert_eq!(value!(product, m ^ 2), 25.0); +} + +#[test] +fn test_comparisons_under_shadowed_prelude() { + define_generic_dimension!(Length, L); + fn assert_length(value: T) -> T { + value + } + + let short = assert_length(1.0.meters()); + let long = assert_length(2.0.meters()); + + assert!(short < long); + assert!(long > short); + assert!(short == 1.0.meters()); +} + +#[test] +fn test_rescale_under_shadowed_prelude() { + let distance: unit!(mm) = whippyunits::api::rescale(1.0.meters()); + assert_eq!(value!(distance, mm), 1000.0); +} + +#[test] +fn test_serialization_under_shadowed_prelude() { + let length: unit!(m) = from_json!(r#"{"value": 5.0, "unit": "m"}"#, m).unwrap(); + assert_eq!(value!(length, m), 5.0); + + let error = from_json!(r#"{"value": 5.0, "unit": "m"}"#, kg); + assert!(error.is_err()); + + let length: unit!(m) = from_string!("5.0 m", m).unwrap(); + assert_eq!(value!(length, m), 5.0); + + let error = from_string!("5.0 m", kg); + assert!(error.is_err()); +} + +mod shadowed_crate_name { + #![allow(non_camel_case_types)] + + // Shadow whippyunits' dependency crates so that bare references to them + // by unhygienic macros (e.g. macros using `whippyunits_core` instead of + // `$crate::__private_whippyunits_core`) will cause a compile error. + struct whippyunits_core; + struct whippyunits_proc_macros; + struct num_traits; + + use ::whippyunits::default_declarators::*; + use ::whippyunits::from_json; + use ::whippyunits::quantity; + use ::whippyunits::unit; + use ::whippyunits::value; + + #[test] + fn test_macros_under_shadowed_dependency_crate_names() { + let distance = 5.0.meters(); + assert_eq!(value!(distance, m), 5.0); + + let via_macro: unit!(m) = quantity!(5.0, m); + assert_eq!(value!(via_macro, m), 5.0); + + let length: unit!(m) = from_json!(r#"{"value": 5.0, "unit": "m"}"#, m).unwrap(); + assert_eq!(value!(length, m), 5.0); + } +} diff --git a/tests/transitive_dep_fixture/Cargo.lock b/tests/transitive_dep_fixture/Cargo.lock new file mode 100644 index 0000000..78b81e5 --- /dev/null +++ b/tests/transitive_dep_fixture/Cargo.lock @@ -0,0 +1,202 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "autocfg" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" + +[[package]] +name = "culit" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d610997229592bcea38c012b992e89d32dd73b22eca33696f0ea941261e694d2" +dependencies = [ + "litrs", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + +[[package]] +name = "litrs" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e4cf394bcd88ba72eb3b2862e21ef6458b0e1586654e213b0176e667bb9d19e" + +[[package]] +name = "memchr" +version = "2.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "op_result" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfdf4800632b220b1567fefdc514a47af0bd348d230368ddb0a42903c96e7ad3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.150" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "2.0.118" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "typenum" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "whippyunits" +version = "0.2.2" +dependencies = [ + "culit", + "libm", + "num-traits", + "op_result", + "proc-macro2", + "quote", + "serde", + "serde_json", + "syn", + "whippyunits-core", + "whippyunits-proc-macros", +] + +[[package]] +name = "whippyunits-core" +version = "0.2.1" +dependencies = [ + "proc-macro2", + "syn", + "typenum", +] + +[[package]] +name = "whippyunits-proc-macros" +version = "0.2.1" +dependencies = [ + "proc-macro2", + "quote", + "strsim", + "syn", + "whippyunits-core", +] + +[[package]] +name = "whippyunits-transitive-dep-fixture" +version = "0.0.0" +dependencies = [ + "whippyunits", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/tests/transitive_dep_fixture/Cargo.toml b/tests/transitive_dep_fixture/Cargo.toml new file mode 100644 index 0000000..e80fae7 --- /dev/null +++ b/tests/transitive_dep_fixture/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "whippyunits-transitive-dep-fixture" +version = "0.0.0" +edition = "2024" +publish = false + +[dependencies] +whippyunits = { path = "../.." } + +[workspace] diff --git a/tests/transitive_dep_fixture/src/lib.rs b/tests/transitive_dep_fixture/src/lib.rs new file mode 100644 index 0000000..8f441d9 --- /dev/null +++ b/tests/transitive_dep_fixture/src/lib.rs @@ -0,0 +1,5 @@ +use whippyunits::unit; + +pub fn parse_length(json: &str) -> unit!(m) { + whippyunits::from_json!(json, m).unwrap() +} diff --git a/tests/transitive_dependency.rs b/tests/transitive_dependency.rs new file mode 100644 index 0000000..af81fb8 --- /dev/null +++ b/tests/transitive_dependency.rs @@ -0,0 +1,30 @@ +//! Verifies that macros exported from `whippyunits` are self-contained, i.e. a +//! downstream crate that depends only on `whippyunits` (not `whippyunits-core`, +//! `whippyunits-proc-macros`, or `num-traits`) should still be able to compile +//! code that uses public macros from `whippyunits`. + +use std::path::Path; +use std::process::Command; + +#[test] +fn exported_macros_do_not_leak_internal_dependencies() { + let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR")); + let fixture_manifest = manifest_dir.join("tests/transitive_dep_fixture/Cargo.toml"); + let target_dir = manifest_dir.join("target/transitive-dep-fixture"); + + let output = Command::new(env!("CARGO")) + .args(["build", "--manifest-path"]) + .arg(&fixture_manifest) + .arg("--target-dir") + .arg(&target_dir) + .output() + .expect("failed to invoke `cargo build` on the fixture crate"); + + assert!( + output.status.success(), + "a downstream crate depending only on `whippyunits` (not on its internal \ + dependencies whippyunits-core/whippyunits-proc-macros/num-traits) failed to \ + compile against whippyunits's public macros:\n\n{}", + String::from_utf8_lossy(&output.stderr) + ); +}