typenum_consts/lib.rs
1#![doc = include_str!("../README.md")]
2#![cfg_attr(docsrs, feature(doc_auto_cfg))]
3
4use crate::ast::{
5 LitIntegerOrExprs, NegativeLitIntegerOrExprs, PositiveLitIntegerOrExprs,
6 UnsignedLitIntegerOrExprs,
7};
8use crate::macros::debug_eprintln;
9use proc_macro::{self, TokenStream};
10use tnconst_impl::{
11 nconst_impl_lit_integer, nconst_impl_math_exprs, pconst_impl_lit_integer,
12 pconst_impl_math_exprs, tnconst_impl_lit_integer, tnconst_impl_math_exprs,
13 uconst_impl_lit_integer, uconst_impl_math_exprs,
14};
15
16mod ast;
17mod ast_macro;
18mod exprs_impl;
19mod macros;
20mod tnconst_impl;
21mod uconst_impl;
22
23/// [`uconst!`] is a procedural macro that converts a literal integer or an expression into a [`typenum`]'s type-level unsigned integer (i.e. the type that implements the [`typenum::Unsigned`] trait).
24///
25/// There are three ways you can invoke this macro.
26///
27/// ## 1. Invoke it with a literal integer
28///
29/// ```rust
30/// use typenum::{U123, assert_type_eq};
31/// use typenum_consts::uconst;
32///
33/// type A = uconst![123];
34/// assert_type_eq!(A, U123);
35/// ```
36///
37/// Compilation fails if the literal integer is prefixed with either a `-` or a `+`.
38///
39/// ```compile_fail
40/// # use typenum::{U123, assert_type_eq};
41/// # use typenum_consts::uconst;
42/// type B = uconst![+123]; // Fail to compile
43/// ```
44///
45/// ```compile_fail
46/// # use typenum::{U123, assert_type_eq};
47/// # use typenum_consts::uconst;
48/// type C = uconst![-123]; // Fail to compile
49/// ```
50///
51/// ## 2. Invoke using an expression or many simple mathematical expressions
52///
53/// ```rust
54/// use typenum::{U15, assert_type_eq};
55/// use typenum_consts::uconst;
56/// type D = uconst![{
57/// a = 10;
58/// b = 5;
59/// a + b; // Last statement is always the final returned value to be casted into `typenum` type-level integer, U15
60/// }];
61/// assert_type_eq!(D, U15);
62/// ```
63///
64/// It is a compilation error if the mathematical expressions evaluate to a negative literal integer.
65///
66/// ```compile_fail
67/// use typenum::{U15, assert_type_eq};
68/// use typenum_consts::uconst;
69/// type D = uconst![{
70/// a = 10;
71/// b = 5;
72/// b - a; // 5 - 10 = -5, cannot be made into a `U15`
73/// }];
74/// assert_type_eq!(D, U15);
75/// ```
76///
77/// ## 3. Invoke by reading from an environment variable
78///
79/// Note: `env!(...)` is a macro-like invocation. The first parameter is mandatory and is the key of the environment variable that `uconst` will read. The second parameter is optional and is the file path of the `.env.*` file to read the environment variable from, e.g. `env!("ENV_VAR", "./.env.prod")`, `"ENV_VAR"` is the key to read the value from and `"./.env.prod"` is the file path relative to [`CARGO_MANIFEST_DIR`].
80///
81/// ```rust
82/// use typenum::{U69, assert_type_eq};
83/// use typenum_consts::uconst;
84/// // ``` .env
85/// // ENV_VAR=69
86/// // ```
87/// type E = uconst![env!("ENV_VAR");];
88/// assert_type_eq!(E, U69);
89/// ```
90///
91/// It is a compilation error if the environment variable evaluate to a negative literal integer.
92///
93/// ```compile_fail
94/// use typenum::{U69, assert_type_eq};
95/// use typenum_consts::uconst;
96/// // ``` .env
97/// // NENV_VAR=-69
98/// // ```
99/// type F = uconst![env!("NENV_VAR");];
100/// assert_type_eq!(F, U69);
101/// ```
102///
103/// [`CARGO_MANIFEST_DIR`]: https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-crates
104/// [`typenum::Unsigned`]: https://docs.rs/typenum/latest/typenum/marker_traits/trait.Unsigned.html
105/// [`typenum`]: https://github.com/paholg/typenum/tree/main/src
106#[proc_macro]
107pub fn uconst(items: TokenStream) -> TokenStream {
108 match syn::parse::<UnsignedLitIntegerOrExprs>(items) {
109 Ok(litint_exprs) => match litint_exprs.0 {
110 LitIntegerOrExprs::Exprs(math_exprs) => uconst_impl_math_exprs(math_exprs)
111 .unwrap_or_else(syn::Error::into_compile_error)
112 .into(),
113 LitIntegerOrExprs::LitInteger(lit_integer) => uconst_impl_lit_integer(lit_integer)
114 .unwrap_or_else(syn::Error::into_compile_error)
115 .into(),
116 },
117 Err(err) => err.into_compile_error().into(),
118 }
119}
120
121/// [`tnconst!`] is a procedural macro that converts a literal integer or an expression into a [`typenum`]'s type-level unsigned/positive/negative (depending on what is the prefix-sign) integer (i.e. the type that implements the [`typenum::Unsigned`]/[`typenum::Integer`] trait).
122///
123/// Because [`tnconst!`] can be evaluated into [`typenum::UInt`], [`typenum::PInt`] and [`typenum::NInt`], to disambiguate them, one is required to invoke the macro with either `+`, `-` to get [`tnconst!`] to evaluate the macro input as [`typenum::PInt`] or [`typenum::NInt`], respectively. [`typenum::UInt`] is the default and does not require any sign to be prefixed.
124///
125/// Examples:
126///
127/// If you invoke e.g. `tnconst![123]`, i.e. there is no sign prefixing the literal integer `123`, then this will be evaluated as a [`typenum::UInt`], specifically, [`typenum::U123`].
128///
129/// If you invoke e.g. `tnconst![-123]`, i.e. there is a negative sign prefixing the literal integer `123`, then this will be evaluated as a [`typenum::NInt`], specifically, [`typenum::N123`].
130///
131/// There are three ways you can invoke this macro.
132///
133/// ## 1. Invoke it with a literal integer
134///
135/// ```rust
136/// use typenum::{N123, assert_type_eq};
137/// use typenum_consts::tnconst;
138///
139/// type A = tnconst![-123];
140/// assert_type_eq!(A, N123);
141/// ```
142///
143/// ## 2. Invoke using an expression or many simple mathematical expressions
144///
145/// ```rust
146/// use typenum::{P15, assert_type_eq};
147/// use typenum_consts::tnconst;
148/// type D = tnconst![+ {
149/// a = 10;
150/// b = 5;
151/// a + b; // Last statement is always the final returned value to be casted into `typenum` type-level integer, P15
152/// }];
153/// assert_type_eq!(D, P15);
154/// ```
155///
156/// It is a compilation error if the mathematical expressions evaluate to a negative (positive) literal integer and you had specify a `+` (`-`) prefix to ask [`tnconst!`] to evaluate the input as a [`typenum::PInt`] ([`typenum::NInt`]).
157///
158/// ```compile_fail
159/// use typenum::{P15, assert_type_eq};
160/// use typenum_consts::tnconst;
161/// type D = tnconst![+ {
162/// a = 10;
163/// b = 5;
164/// b - a; // 5 - 10 = -5, cannot be made into a `P15`
165/// }];
166/// assert_type_eq!(D, P15);
167/// ```
168///
169/// ## 3. Invoke by reading from an environment variable
170///
171/// Note: `env!(...)` is a macro-like invocation. The first parameter is mandatory and is the key of the environment variable that `tnconst` will read. The second parameter is optional and is the file path of the `.env.*` file to read the environment variable from, e.g. `env!("ENV_VAR", "./.env.prod")`, `"ENV_VAR"` is the key to read the value from and `"./.env.prod"` is the file path relative to [`CARGO_MANIFEST_DIR`].
172///
173/// ```rust
174/// use typenum::{U69, assert_type_eq};
175/// use typenum_consts::tnconst;
176/// // ``` .env
177/// // ENV_VAR=69
178/// // ```
179/// type E = tnconst![env!("ENV_VAR");];
180/// assert_type_eq!(E, U69);
181/// ```
182///
183/// It is a compilation error if the environment variable evaluate to a negative (positive) literal integer and you had specify a `+` (`-`) prefix to ask [`tnconst!`] to evaluate the input as a [`typenum::PInt`] ([`typenum::NInt`]).
184///
185/// ```compile_fail
186/// use typenum::{P69, assert_type_eq};
187/// use typenum_consts::tnconst;
188/// // ``` .env
189/// // NENV_VAR=-69
190/// // ```
191/// type F = tnconst![+ env!("NENV_VAR");];
192/// assert_type_eq!(F, P69);
193/// ```
194///
195/// [`CARGO_MANIFEST_DIR`]: https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-crates
196/// [`typenum::Unsigned`]: https://docs.rs/typenum/latest/typenum/marker_traits/trait.Unsigned.html
197/// [`typenum::Integer`]: https://docs.rs/typenum/latest/typenum/marker_traits/trait.Integer.html
198/// [`typenum::PInt`]: https://docs.rs/typenum/latest/typenum/int/struct.PInt.html
199/// [`typenum::UInt`]: https://docs.rs/typenum/latest/typenum/uint/struct.UInt.html
200/// [`typenum::NInt`]: https://docs.rs/typenum/latest/typenum/int/struct.NInt.html
201/// [`typenum`]: https://github.com/paholg/typenum/tree/main/src
202#[proc_macro]
203pub fn tnconst(items: TokenStream) -> TokenStream {
204 match syn::parse::<LitIntegerOrExprs>(items) {
205 Ok(litint_exprs) => match litint_exprs {
206 LitIntegerOrExprs::Exprs(math_exprs) => tnconst_impl_math_exprs(math_exprs)
207 .unwrap_or_else(syn::Error::into_compile_error)
208 .into(),
209 LitIntegerOrExprs::LitInteger(lit_integer) => tnconst_impl_lit_integer(lit_integer)
210 .unwrap_or_else(syn::Error::into_compile_error)
211 .into(),
212 },
213 Err(err) => err.into_compile_error().into(),
214 }
215}
216
217/// [`pconst!`] is a procedural macro that converts a literal integer or an expression into a [`typenum`]'s type-level positive integer (i.e. the type that implements the [`typenum::Integer`] trait).
218///
219/// There are three ways you can invoke this macro.
220///
221/// ## 1. Invoke it with a literal integer
222///
223/// ```rust
224/// use typenum::{P123, assert_type_eq};
225/// use typenum_consts::pconst;
226///
227/// type A = pconst![123];
228/// assert_type_eq!(A, P123);
229/// ```
230///
231/// Compilation fails if the literal integer is prefixed with either a `-` or a `+`.
232///
233/// ```compile_fail
234/// # use typenum::{P123, assert_type_eq};
235/// # use typenum_consts::pconst;
236/// type B = pconst![+123]; // Fail to compile
237/// ```
238///
239/// ```compile_fail
240/// # use typenum::{P123, assert_type_eq};
241/// # use typenum_consts::pconst;
242/// type C = pconst![-123]; // Fail to compile
243/// ```
244///
245/// ## 2. Invoke using an expression or many simple mathematical expressions
246///
247/// ```rust
248/// use typenum::{P15, assert_type_eq};
249/// use typenum_consts::pconst;
250/// type D = pconst![{
251/// a = 10;
252/// b = 5;
253/// a + b; // Last statement is always the final returned value to be casted into `typenum` type-level integer, P15
254/// }];
255/// assert_type_eq!(D, P15);
256/// ```
257///
258/// It is a compilation error if the mathematical expressions evaluate to a negative literal integer.
259///
260/// ```compile_fail
261/// use typenum::{P15, assert_type_eq};
262/// use typenum_consts::pconst;
263/// type D = pconst![{
264/// a = 10;
265/// b = 5;
266/// b - a; // 5 - 10 = -5, cannot be made into a `PInt<U15>`
267/// }];
268/// assert_type_eq!(D, P15);
269/// ```
270///
271/// ## 3. Invoke by reading from an environment variable
272///
273/// Note: `env!(...)` is a macro-like invocation. The first parameter is mandatory and is the key of the environment variable that `pconst` will read. The second parameter is optional and is the file path of the `.env.*` file to read the environment variable from, e.g. `env!("ENV_VAR", "./.env.prod")`, `"ENV_VAR"` is the key to read the value from and `"./.env.prod"` is the file path relative to [`CARGO_MANIFEST_DIR`].
274///
275/// ```rust
276/// use typenum::{P69, assert_type_eq};
277/// use typenum_consts::pconst;
278/// // ``` .env
279/// // ENV_VAR=69
280/// // ```
281/// type E = pconst![env!("ENV_VAR");];
282/// assert_type_eq!(E, P69);
283/// ```
284///
285/// It is a compilation error if the environment variable evaluate to a negative literal integer.
286///
287/// ```compile_fail
288/// use typenum::{P69, assert_type_eq};
289/// use typenum_consts::pconst;
290/// // ``` .env
291/// // NENV_VAR=-69
292/// // ```
293/// type F = pconst![env!("NENV_VAR");];
294/// assert_type_eq!(F, P69);
295/// ```
296///
297/// [`CARGO_MANIFEST_DIR`]: https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-crates
298/// [`typenum::Integer`]: https://docs.rs/typenum/latest/typenum/marker_traits/trait.Integer.html
299/// [`typenum`]: https://github.com/paholg/typenum/tree/main/src
300#[proc_macro]
301pub fn pconst(items: TokenStream) -> TokenStream {
302 match syn::parse::<PositiveLitIntegerOrExprs>(items) {
303 Ok(litint_exprs) => match litint_exprs.0 {
304 LitIntegerOrExprs::Exprs(math_exprs) => pconst_impl_math_exprs(math_exprs)
305 .unwrap_or_else(syn::Error::into_compile_error)
306 .into(),
307 LitIntegerOrExprs::LitInteger(lit_integer) => pconst_impl_lit_integer(lit_integer)
308 .unwrap_or_else(syn::Error::into_compile_error)
309 .into(),
310 },
311 Err(err) => err.into_compile_error().into(),
312 }
313}
314
315/// [`nconst!`] is a procedural macro that converts a literal integer or an expression into a [`typenum`]'s type-level negative integer (i.e. the type that implements the [`typenum::Integer`] trait).
316///
317/// There are three ways you can invoke this macro.
318///
319/// ## 1. Invoke it with a literal integer
320///
321/// ```rust
322/// use typenum::{N123, assert_type_eq};
323/// use typenum_consts::nconst;
324///
325/// type A = nconst![123];
326/// assert_type_eq!(A, N123);
327/// ```
328///
329/// Compilation fails if the literal integer is prefixed with either a `-` or a `+`.
330///
331/// ```compile_fail
332/// # use typenum::{N123, assert_type_eq};
333/// # use typenum_consts::nconst;
334/// type B = nconst![+123]; // Fail to compile
335/// ```
336///
337/// ```compile_fail
338/// # use typenum::{N123, assert_type_eq};
339/// # use typenum_consts::nconst;
340/// type C = nconst![-123]; // Fail to compile
341/// ```
342///
343/// ## 2. Invoke using an expression or many simple mathematical expressions
344///
345/// ```rust
346/// use typenum::{N15, assert_type_eq};
347/// use typenum_consts::nconst;
348/// type D = nconst![{
349/// a = 10;
350/// b = 5;
351/// 0 - a - b; // Last statement is always the final returned value to be casted into `typenum` type-level integer, N15
352/// }];
353/// assert_type_eq!(D, N15);
354/// ```
355///
356/// It is a compilation error if the mathematical expressions evaluate to a positive literal integer.
357///
358/// ```compile_fail
359/// use typenum::{N15, assert_type_eq};
360/// use typenum_consts::nconst;
361/// type D = nconst![{
362/// a = 10;
363/// b = 5;
364/// b + a; // 5 + 10 = 15, cannot be made into a `N15`
365/// }];
366/// assert_type_eq!(D, N15);
367/// ```
368///
369/// ## 3. Invoke by reading from an environment variable
370///
371/// Note: `env!(...)` is a macro-like invocation. The first parameter is mandatory and is the key of the environment variable that `nconst` will read. The second parameter is optional and is the file path of the `.env.*` file to read the environment variable from, e.g. `env!("ENV_VAR", "./.env.prod")`, `"ENV_VAR"` is the key to read the value from and `"./.env.prod"` is the file path relative to [`CARGO_MANIFEST_DIR`].
372///
373/// ```rust
374/// use typenum::{N69, assert_type_eq};
375/// use typenum_consts::nconst;
376/// // ``` .env
377/// // NENV_VAR=-69
378/// // ```
379/// type E = nconst![env!("NENV_VAR");];
380/// assert_type_eq!(E, N69);
381/// ```
382///
383/// It is a compilation error if the environment variable evaluate to a positive literal integer.
384///
385/// ```compile_fail
386/// use typenum::{N69, assert_type_eq};
387/// use typenum_consts::nconst;
388/// // ``` .env
389/// // ENV_VAR=69
390/// // ```
391/// type F = nconst![env!("ENV_VAR");];
392/// assert_type_eq!(F, N69);
393/// ```
394///
395/// [`CARGO_MANIFEST_DIR`]: https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-crates
396/// [`typenum::Integer`]: https://docs.rs/typenum/latest/typenum/marker_traits/trait.Integer.html
397/// [`typenum`]: https://github.com/paholg/typenum/tree/main/src
398#[proc_macro]
399pub fn nconst(items: TokenStream) -> TokenStream {
400 match syn::parse::<NegativeLitIntegerOrExprs>(items) {
401 Ok(litint_exprs) => match litint_exprs.0 {
402 LitIntegerOrExprs::Exprs(math_exprs) => nconst_impl_math_exprs(math_exprs)
403 .unwrap_or_else(syn::Error::into_compile_error)
404 .into(),
405 LitIntegerOrExprs::LitInteger(lit_integer) => nconst_impl_lit_integer(lit_integer)
406 .unwrap_or_else(syn::Error::into_compile_error)
407 .into(),
408 },
409 Err(err) => err.into_compile_error().into(),
410 }
411}