From e4d661a6b02d1227a0bed4acebdd6d5626f186f7 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 17 Mar 2026 10:15:31 -0700 Subject: [PATCH 1/2] Add `PrimitiveNumber::CONST` for `0..=127` These are all of the numbers common to every primitive numeric type, available in constant form. Each value corresponds to its `usize` index. This could be seen as a replacement and extension of `ConstZero::ZERO` and `ConstOne::ONE` from `num-traits`, without worrying about the particulars of being additive/multiplicative identities. Here, we're just describing this as a workaround for the lack of generic literals. --- src/number.rs | 24 ++++++++++++++++++++++++ src/tests.rs | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/src/number.rs b/src/number.rs index 84b5a5f..5e54693 100644 --- a/src/number.rs +++ b/src/number.rs @@ -100,6 +100,19 @@ pub trait PrimitiveNumber: + for<'a> core::ops::Sub<&'a Self, Output = Self> + for<'a> core::ops::SubAssign<&'a Self> { + /// Constant values `0..=127` in this type. + /// + /// Since [literal expressions] can't be used for generic types, this constant array provides + /// an alternative way to access particular values. It contains the complete set of numbers + /// that all primitive numeric types have in common, where `CONST[i]` equals the index `i` + /// converted to `Self`. + /// + /// For floating-point types with signed zeros, `-0.0` and `+0.0`, `CONST[0]` is the positive + /// value. + /// + /// [literal expressions]: https://doc.rust-lang.org/reference/expressions/literal-expr.html + const CONST: [Self; 128]; + /// An array of bytes used by methods like [`from_be_bytes`][Self::from_be_bytes] and /// [`to_be_bytes`][Self::to_be_bytes]. It is effectively `[u8; size_of::()]`. type Bytes: PrimitiveBytes; @@ -251,6 +264,17 @@ macro_rules! impl_primitive { impl Sealed for &$Number {} impl PrimitiveNumber for $Number { + const CONST: [Self; 128] = const { + let mut constants = [0 as Self; 128]; + let mut i = 1; + while i < 128 { + constants[i] = i as Self; + assert!(constants[i] as usize == i); + i += 1; + } + constants + }; + type Bytes = [u8; size_of::()]; forward! { diff --git a/src/tests.rs b/src/tests.rs index 99aba34..5f9cfa9 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -111,3 +111,37 @@ fn try_into() { } check(0i32, 0u32); } + +#[test] +fn constants() { + fn check() { + for (i, c) in T::CONST.into_iter().enumerate() { + assert_eq!(T::as_from(i), c); + assert_eq!(i, c.as_to()); + } + // explicitly const context + assert_eq!(T::as_from(0i32), const { T::CONST[0] }); + assert_eq!(T::as_from(1i32), const { T::CONST[1] }); + assert_eq!(T::as_from(42i32), const { T::CONST[42] }); + } + check::(); + check::(); + check::(); + check::(); + check::(); + check::(); + check::(); + check::(); + check::(); + check::(); + check::(); + check::(); + check::(); + check::(); +} + +#[test] +fn constant_float_zero() { + assert!(::CONST[0].is_sign_positive()); + assert!(::CONST[0].is_sign_positive()); +} From d94ba5b979db7586580038e30d84271b307d3fbc Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 17 Mar 2026 13:56:22 -0700 Subject: [PATCH 2/2] Add a `CONST` example --- src/number.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/number.rs b/src/number.rs index 5e54693..79c82e7 100644 --- a/src/number.rs +++ b/src/number.rs @@ -111,6 +111,23 @@ pub trait PrimitiveNumber: /// value. /// /// [literal expressions]: https://doc.rust-lang.org/reference/expressions/literal-expr.html + /// + /// # Examples + /// + /// [Milü](https://en.wikipedia.org/wiki/Mil%C3%BC) is an approximation of π as the ratio + /// `355 / 113`, which can also be written as `3 + 16 / 113`. + /// + /// ``` + /// use num_primitive::{PrimitiveFloat, PrimitiveNumber}; + /// + /// fn milu() -> T { + /// T::CONST[3] + T::CONST[16] / T::CONST[113] + /// } + /// + /// assert!((milu::() - f64::PI).abs() < 1e-6); + /// assert!((milu::() - f32::PI).abs() < 1e-6); + /// assert_eq!(milu::(), 3); + /// ``` const CONST: [Self; 128]; /// An array of bytes used by methods like [`from_be_bytes`][Self::from_be_bytes] and