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}