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