nz
The nz crate provides a collection of macros that simplify the creation of
new instances of non-zero numeric types implemented in core::num. With these macros, you can easily generate constants of such numeric types using
literals, constant values or expressions, all at compile time.
Features
- No unsafe code
- No dependencies
no_stdcompatible- Supports all
core::num::NonZero{Integer}types - Compile time evaluation
- Zero detection at compile time
Macros
Basic usage
use NonZeroU8;
// A NonZero type can be constructed by different
// types of arguments when using the matching macro
//
// such argument can be a numeric literal
const NZ_MIN: NonZeroU8 = u8!;
let nz_two = u8!;
// or a constant value
const NZ_MAX: NonZeroU8 = u8!;
let five = u8!;
// or even a constant expression
const RES: NonZeroU8 = u8!;
// non-constant expression leads to compile-time error
// const OUTPUT: NonZeroU8 = nz::u8!({ 3 + 7 } - nz_two.get()); // casued by `mz_two.get()`
let result_as_nz = u8!;
Limitations
const fn
Declarative macros (such as all the nz macros) cannot be used with
constant function arguments since they are not currently recognized
as constant values, as demonstrated in the code below.
use NonZeroU64;
const
let nz = wrapping_add_nz;
const hygiene
When constants are used in a declarative macro, specifically in the most outer scope where a constant can be declared, there is a possibility of cyclic reference when an expression is expected as an argument and an outer constant is used within that expression. This "collision" can occur if any of the inner constants share the same identifier as the outer constant after the macro is expanded compile-time. The code snippet below demonstrates this scenario.
use NonZeroU16;
const NZ: NonZeroU16 = u16!;
const CHECK_ZERO: NonZeroU16 = u16!;
// although `CHECK_ZERO` is used in `nz::u16!` macro, it will not result in
// an error when a constant with the same name is passed as part
// of a constant expression, because this inner macro constant is not
// declared in the most outer scope
const OK: NonZeroU16 = u16!;
// using `NZ` is fine for the same reason
const ___NZ___INTERNAL___NUM___1___: u16
= u16!.get;
// using `___NZ___INTERNAL___NUM___1___` constant as the argument
// causes compile-time error in the code line below, because the
// internal macro constant has the same identifier
const FAILS: NonZeroU16 = u16!;
This "collision" between the outer and inner constants leads to a compile-time
error, specifically error [E0391],
because the inner macro constant tries to use itself, creating a cyclic dependency
during the evaluation of the macro at compile-time. Essentially, the code above has
the same error as this single line:
const X: u8 = X;
License
This library is distributed under the terms of either of the following licenses at your option: