nz
The nz crate provides a collection of macros that simplify the creation
of non-zero numerics implemented in core::num.
With these macros, you can easily generate constants of all the NonZero
types using literals, constant values or expressions at compile time.
Features
- No unsafe code
- No dependencies
no_stdcompatible- Supports all
core::num::NonZero{Integer}types - Compile-time evaluation and zero detection
NonZero macros
Basic usage
use NonZeroU8;
// A `NonZeroU8` 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!;
const SIX: u8 = 6;
let six = u8!;
// or even a constant expression
const RES: NonZeroU8 = u8!;
// non-constant expression results in a compile-time error
// which is caused by `nz_two` in this case
// const OUTPUT: NonZeroU8 = nz::u8!({ 3 + 7 } - nz_two.get());
let res = u8!;
let five = u8!;
# assert_eq!;
# assert_eq!;
# assert_eq!;
# assert_eq!;
# assert_eq!;
# assert_eq!;
Limitations
const fn
Declarative macros, such as all the nz macros, cannot be used with
constant function arguments since they are not considered 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 dependency 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 at 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 as the constant
// specified in the macro argument
const _: NonZeroU16 = u16!;
More concisely, the problem is:
const X: u8 = X;
This collision between the outer and inner constants results in a compile-time error^cd_error, because the inner macro constant depends on itself, creating a cyclic dependency.
License
This library is distributed under the terms of either of the following licenses at your option: