Skip to main content

num_lazy/
lib.rs

1/*
2 * num-lazy is licensed under The 3-Clause BSD, see LICENSE.
3 * Copyright 2025 Sira Pornsiriprasert <code@psira.me>
4 */
5
6#![no_std]
7
8/*! **num-lazy** helps you write numbers for generic-typed functions.
9
10It is recommended to use `num-lazy` along with [numeric-literals](https://crates.io/crates/numeric_literals).
11Use num-lazy to access macros for constants and special values, while using `numeric_literals` for parsing
12floats or numeric literals.
13```
14use num_lazy::declare_nums;
15use numeric_literals::replace_numeric_literals;
16use num_traits::Float;
17
18declare_nums!{@constant T}
19declare_nums!{@special T}
20// declare_nums!{@literal T} // Recommend using `numeric_literals` instead
21
22// Or use this to declare all macros:
23// declare_nums!{T}
24
25#[replace_numeric_literals(T::from(literal).unwrap())]
26fn circumference<T: Float>(radius: T) -> T {
27    2 * pi!() * radius
28}
29#
30# fn main() {
31#     assert!(circumference(1.0_f64) == 6.283185307179586);
32# }
33```
34
35See what numbers are declared in [declare_nums].
36
37If you `declare_nums!()` in the root of your crate, you don't even need
38to import the macros to submodules. This will not re-export the macros
39to the public crate.
40
41lib.rs or main.rs
42```ignore
43use num_lazy::declare_nums;
44declare_nums!{T}
45
46// My submodules
47pub mod generic_math;
48```
49
50generic_math.rs
51```ignore
52pub fn circle_area<T: Float>(radius: T) -> T {
53    pi!() * radius * radius
54}
55```
56
57If you want to declare the numbers in the root of your crate but keep
58the macro contained in a module, you can simply:
59
60lib.rs or main.rs
61```ignore
62mod generics {
63    use num_lazy::declare_nums;
64    declare_nums!{T}
65}
66```
67
68generic_math.rs
69```ignore
70use crate::generics::*;
71
72pub fn circle_area<T: Float>(radius: T) -> T {
73    pi!() * radius * radius
74}
75```
76*/
77
78/// Declare commonly used num generics.
79///
80/// ```
81/// use num_lazy::declare_nums;
82/// use num_traits::Float;
83/// // Assign to generic type T.
84/// // Important. Use the braces!
85/// declare_nums!{T}
86/// // Or declare as needed
87/// // declare_nums!{@literal T}
88/// // declare_nums!{@constant T}
89/// // declare_nums!{@special T}
90///
91/// fn add_tiny<T: Float>(a: T) -> T {
92///     let tiny = five!() * epsilon!();
93///     a + tiny
94/// }
95///
96/// fn main() {
97///     assert!(add_tiny(1.0_f64) == 1.000000000000001);
98///     assert!(add_tiny(1.0_f32) == 1.0000006);
99/// }
100/// ```
101///
102/// Using `declare_nums!{T}` will populate the module with all available macros:
103/// - `num!($n)`: equivalent to `$t::from($n).unwrap()`, where `$t` is the generic type identifier you
104///   declared, and `$n` is any expression evaluated to a number.
105/// - Literals as in `declare_nums!{@literal T}`.
106/// - Constants as in `declare_nums!{@constant T}`.
107/// - Special as in `declare_nums!{@special T}`.
108///
109/// Each match arm will populate the module with:
110/// - **Literals:** `declare_nums!{@literal T}`
111///     - `zero!()` to `ten!()`
112///     - `hundred!()`, `thousand!()`, and `million!()`
113///     - `half!()`, `third!()`, and `quarter!()`
114///     - `tenth!()`, `hundredth!()`, `thousandth!()`, and `millionth!()`
115/// - **Constants:** `declare_nums!{@constant T}`
116///     - `pi!()`, `pi_2!()`, `pi_3!()`, `frac_1_pi!()`, `frac_2_pi!()`, and `frac_2_sqrt_pi!()`
117///     - `tau!()`
118///     - `e!()`
119///     - `ln_2!()`, `ln_10!()`, `log2_10!()`, `log2_e!()`, `log10_2!()`, and `log10_e!()`
120///     - `sqrt_2!()` and `frac_1_sqrt_2!()`
121///     - The golden ratio: `phi!()`
122/// - **Special Constants:** `declare_nums!{@special T}`
123///     - Infinity: `inf!()` and `neg_inf!()`
124///     - `nan!()`
125///     - Min/max type representation value: `min_val!()`, `max_val!()`, and `min_positive!()`
126///     - Machine epsilon: `epsilon!()`
127///     - Negative zero: `neg_zero!()`
128#[macro_export]
129macro_rules! declare_nums {
130    {$t: ident} => {
131        /// Unwrap the expression into the specified generic type.
132        ///
133        /// Equivalent to `$t::from($n).unwrap()`, where `$t` is the generic type identifier you
134        /// declared, and `$n` is any expression evaluated to a number.
135        #[allow(unused_macros)]
136        macro_rules! num {
137            ($n: expr) => {
138                $t::from($n).unwrap()
139            };
140        }
141
142        declare_nums!{@literal $t}
143        declare_nums!{@constant $t}
144        declare_nums!{@special $t}
145    };
146    {@literal $t:ident} => {
147        macro_rules! _declare_literal {
148            ($name:ident, $n: expr, $doc: expr) => {
149                #[allow(unused_macros)]
150                #[doc=$doc]
151                macro_rules! $name {
152                    () => {
153                        $t::from($n).unwrap()
154                    };
155                }
156            };
157        }
158
159        _declare_literal! { zero, 0.0, "`0`"}
160        _declare_literal! { one, 1.0, "`1`"}
161        _declare_literal! { two, 2.0, "`2`"}
162        _declare_literal! { three, 3.0, "`3`"}
163        _declare_literal! { four, 4.0, "`4`"}
164        _declare_literal! { five, 5.0, "`5`"}
165        _declare_literal! { six, 6.0, "`6`"}
166        _declare_literal! { seven, 7.0, "`7`"}
167        _declare_literal! { eight, 8.0, "`8`"}
168        _declare_literal! { nine, 9.0, "`9`"}
169        _declare_literal! { ten, 10.0, "`10`"}
170        _declare_literal! { hundred, 100.0, "`100`"}
171        _declare_literal! { thousand, 1e3, "`1e3`"}
172        _declare_literal! { million, 1e6, "`1e6`"}
173        _declare_literal! { half, 0.5, "`0.5`"}
174        _declare_literal! { third, 1.0/3.0, "`1/3`"}
175        _declare_literal! { quarter, 0.25, "`0.25`"}
176        _declare_literal! { tenth, 0.1, "`0.1`"}
177        _declare_literal! { hundredth, 0.01, "`0.01`"}
178        _declare_literal! { thousandth, 1e-3, "`1e-3`"}
179        _declare_literal! { millionth, 1e-6, "`1e-6`"}
180    };
181    (@constant $t:ident) => {
182        macro_rules! _declare_constant {
183            ($name:ident, $constant:ident, $doc:expr) => {
184                #[allow(unused_macros)]
185                #[doc=$doc]
186                macro_rules! $name {
187                    () => {
188                        $t::from(core::f64::consts::$constant).unwrap()
189                    };
190                }
191            };
192        }
193        _declare_constant! { pi, PI, "π = `3.141592653589793`"}
194        _declare_constant! { pi_2, FRAC_PI_2, "π/2 = `1.5707963267948966`"}
195        _declare_constant! { pi_3, FRAC_PI_3, "π/3 = `1.0471975511965979`"}
196        _declare_constant! { frac_1_pi, FRAC_1_PI, "1/π = `0.3183098861837907`"}
197        _declare_constant! { frac_2_pi, FRAC_2_PI, "2/π = `0.6366197723675814`"}
198        _declare_constant! { frac_2_sqrt_pi, FRAC_2_SQRT_PI, "2/sqrt(π) = `1.1283791670955126`"}
199        _declare_constant! { tau, TAU, "τ = 2π = `6.283185307179586`"}
200        _declare_constant! { e, E, "Euler's number (e) = `2.718281828459045`"}
201        _declare_constant! { ln_2, LN_2, "ln(2) = `0.6931471805599453`"}
202        _declare_constant! { ln_10, LN_10, "ln(10) = `2.302585092994046`"}
203        _declare_constant! { log2_10, LOG2_10, "log₂(10) = `3.321928094887362`"}
204        _declare_constant! { log2_e, LOG2_E, "log₂(e) = `1.4426950408889634`"}
205        _declare_constant! { log10_2, LOG10_2, "log₁₀(2) = `0.3010299956639812`"}
206        _declare_constant! { log10_e, LOG10_E, "log₁₀(e) = `0.4342944819032518`"}
207        _declare_constant! { sqrt_2, SQRT_2, "sqrt(2) = `1.4142135623730951`"}
208        _declare_constant! { frac_1_sqrt_2, FRAC_1_SQRT_2, "1/sqrt(2) = `0.7071067811865476`"}
209        _declare_constant! { phi, PHI, "The golden ratio (φ) = `1.618033988749895`"}
210    };
211    (@special $t:ident) => {
212        macro_rules! _declare_special {
213            ($name:ident, $const_fn:ident, $doc:expr) => {
214                #[allow(unused_macros)]
215                #[doc=$doc]
216                macro_rules! $name {
217                    () => {
218                        $t::$const_fn()
219                    };
220                }
221            };
222        }
223        _declare_special! { inf, infinity, "Infinity (`∞`)"}
224        _declare_special! { neg_inf, neg_infinity, "Negative infinity (`-∞`)"}
225        _declare_special! { nan, nan, "`NaN`"}
226        _declare_special! { min_val, min_value, "The smallest finite value that this type can represent.\n- f32: `-3.4028235e38`\n- f64: `-1.7976931348623157e308`"}
227        _declare_special! { max_val, max_value, "The largest finite value that this type can represent.\n- f32: `3.4028235e38`\n- f64: `1.7976931348623157e308`"}
228        _declare_special! { min_positive, min_positive_value, "The smallest positive value that this type can represent.\n- f32: `1.1754944e-38`\n- f64: `2.2250738585072014e-308`"}
229        _declare_special! { epsilon, epsilon, "`Machine epsilon` value for this type. This is the difference between `1.0` and the next larger representable number.\n- f32: `1.1920929e-7`\n- f64: `2.220446049250313e-16`"}
230        _declare_special! { neg_zero, neg_zero, "`-0.0`"}
231    };
232}