From 922cdd6bf5397f54e083af9e0ca715589567587f Mon Sep 17 00:00:00 2001 From: Lou Garczynski Date: Mon, 24 Aug 2026 02:54:03 +0000 Subject: [PATCH] Give struct and fields the constant's visibility Fields were always private, so `X.f32` failed for any constant used outside its defining module. Switch the visibility capture from tt munching to the `vis` fragment, which drops the three forwarding rules and lets the same `$vis` apply to the struct, its fields and the const. Co-authored-by: Julius Lungys <32368314+voidpumpkin@users.noreply.github.com> Closes #1 --- Cargo.toml | 2 +- README.md | 2 +- src/lib.rs | 45 ++++++++++++++++++--------------------- tests/tests-visibility.rs | 32 ++++++++++++++++++++++++++++ 4 files changed, 55 insertions(+), 26 deletions(-) create mode 100644 tests/tests-visibility.rs diff --git a/Cargo.toml b/Cargo.toml index 8600adc..aa47f20 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polymorphic-constant" -version = "0.2.0" +version = "0.2.1" edition = "2018" authors = ["Louis Garczynski "] diff --git a/README.md b/README.md index edc7075..166da27 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ A few features are supported: /// Doc comment attributes const PI: f32 | f64 = 3.141592653589793; - // Visibility modifiers (for both constant and type) + // Visibility modifiers (constant, type and fields) pub (crate) const E: f32 | f64 = 2.7182818284590452; // Nonzero numeric types (NonZeroI32, NonZeroU8, etc) diff --git a/src/lib.rs b/src/lib.rs index 7836ccb..549b072 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -46,7 +46,7 @@ A few features are supported: /// Doc comment attributes const PI: f32 | f64 = 3.141592653589793; - // Visibility modifiers (for both constant and type) + // Visibility modifiers (constant, type and fields) pub (crate) const E: f32 | f64 = 2.7182818284590452; // Nonzero numeric types (NonZeroI32, NonZeroU8, etc) @@ -110,6 +110,20 @@ Any incompatible type will prevent compilation: # } ``` +* A constant and its fields are never more visible than declared +```compile_fail + # use polymorphic_constant::polymorphic_constant; + + mod inner { + # use polymorphic_constant::polymorphic_constant; + polymorphic_constant! { + const HIDDEN: i32 = 1; + } + } + + let fails = inner::HIDDEN.i32; +``` + * However, floats may lose precision, and a lot of it ```rust # use polymorphic_constant::polymorphic_constant; @@ -193,8 +207,8 @@ let x_i32 = X.i32; #[macro_export(local_inner_macros)] macro_rules! polymorphic_constant { - // Handle the const (pub?) CONST format - ($(#[$attr:meta])* ($($vis:tt)*) const $name:ident : $( $numeric_type:ident )|* = $lit:literal; $($nextLine:tt)*) => { + // Handle the (pub?) const CONST format + ($(#[$attr:meta])* $vis:vis const $name:ident : $( $numeric_type:ident )|* = $lit:literal; $($nextLine:tt)*) => { // Generate the struct to hold the constant @@ -204,12 +218,10 @@ macro_rules! polymorphic_constant { #[cfg_attr(not(no_std), derive(Debug, Clone, Copy))] // Expend the attributes passed by the user $(#[$attr])* - // Add the visibility attributes - $($vis)* // Create the struct - struct $name { - // For each type (f32, ...) create a new property - $($numeric_type: __nz_impl!(@GET_TYPE $numeric_type),)* + $vis struct $name { + // Without $vis, `X.f32` is unreadable outside the defining module + $($vis $numeric_type: __nz_impl!(@GET_TYPE $numeric_type),)* } // Implement `into` for every type @@ -219,29 +231,14 @@ macro_rules! polymorphic_constant { } })* - // Expand the visibility, this time for the constant - $($vis)* // Instantiate the struct and create the constant - const $name: $name = $name { + $vis const $name: $name = $name { $($numeric_type: __nz_impl!(@MAKE_VAL $lit, $numeric_type ),)* }; // Keep munching until the next ; polymorphic_constant!($($nextLine)*); }; - // Handle `const CONST` format - ($(#[$attr:meta])* const $($t:tt)*) => { - // use `()` to explicitly forward the information about private items - polymorphic_constant!($(#[$attr])* () const $($t)*); - }; - // Handle `pub const CONST` format - ($(#[$attr:meta])* pub const $($t:tt)*) => { - polymorphic_constant!($(#[$attr])* (pub) const $($t)*); - }; - // Handle `pub (crate) CONST` format and similar - ($(#[$attr:meta])* pub ($($vis:tt)+) const $($t:tt)*) => { - polymorphic_constant!($(#[$attr])* (pub ($($vis)+)) const $($t)*); - }; () => {}; } diff --git a/tests/tests-visibility.rs b/tests/tests-visibility.rs new file mode 100644 index 0000000..2e63319 --- /dev/null +++ b/tests/tests-visibility.rs @@ -0,0 +1,32 @@ +#![no_std] +#![cfg(test)] + +mod inner { + use polymorphic_constant::polymorphic_constant; + + polymorphic_constant! { + pub const PUBLIC: i16 | i32 = 10; + pub (crate) const CRATE: i16 | i32 = 20; + pub (in crate::inner) const RESTRICTED: i16 | i32 = 30; + const PRIVATE: i16 | i32 = 40; + } + + pub fn private_is_reachable_here() -> i32 { + PRIVATE.i32 + RESTRICTED.i32 + } +} + +use inner::{CRATE, PUBLIC}; + +#[test] +fn fields_follow_constant_visibility() { + assert_eq!(PUBLIC.i16, 10); + assert_eq!(PUBLIC.i32, 10); + assert_eq!(CRATE.i16, 20); + assert_eq!(CRATE.i32, 20); +} + +#[test] +fn private_stays_module_local() { + assert_eq!(inner::private_is_reachable_here(), 70); +}