nonzero_const_param/
lib.rs

1//! `NonZero*` types that derive [`ConstParamTy`] and can be used as constant generic params.
2
3#![allow(incomplete_features, internal_features)]
4#![feature(adt_const_params, rustc_attrs)]
5
6use std::fmt;
7use std::marker::ConstParamTy;
8
9macro_rules! impl_nonzero {
10    ($ty:ident, $int:ty, $std:ty) => {
11        #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, ConstParamTy)]
12        #[cfg_attr(feature = "serde", derive(serde::Serialize))]
13        #[cfg_attr(
14            feature = "zerocopy",
15            derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes)
16        )]
17        #[repr(transparent)]
18        #[rustc_layout_scalar_valid_range_start(1)]
19        #[rustc_nonnull_optimization_guaranteed]
20        pub struct $ty($int);
21
22        impl $ty {
23            /// Creates a non-zero if the given value is not zero.
24            #[must_use]
25            #[inline]
26            pub const fn new(value: $int) -> Option<Self> {
27                if let Some(value) = <$std>::new(value) {
28                    Some(Self::from_std(value))
29                } else {
30                    None
31                }
32            }
33
34            /// Creates a non-zero without checking whether the value is non-zero.
35            /// This results in undefined behaviour if the value is zero.
36            ///
37            /// # Safety
38            ///
39            /// The value must not be zero.
40            #[must_use]
41            #[inline]
42            pub const unsafe fn new_unchecked(value: $int) -> Self {
43                Self(value)
44            }
45
46            #[must_use]
47            #[inline]
48            pub const fn get(self) -> $int {
49                self.0
50            }
51
52            #[must_use]
53            #[inline]
54            pub const fn into_std(self) -> $std {
55                // Safety: $std has the same range validity constraints as Self
56                unsafe { <$std>::new_unchecked(self.0) }
57            }
58
59            #[must_use]
60            #[inline]
61            pub const fn from_std(value: $std) -> Self {
62                // Safety: $std has the same range validity constraints as Self
63                unsafe { Self(value.get()) }
64            }
65        }
66
67        impl fmt::Display for $ty {
68            #[inline]
69            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
70                <$int as fmt::Display>::fmt(&self.0, f)
71            }
72        }
73
74        #[cfg(feature = "serde")]
75        impl<'de> serde::Deserialize<'de> for $ty {
76            #[inline]
77            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
78            where
79                D: serde::Deserializer<'de>,
80            {
81                <$std as serde::Deserialize<'de>>::deserialize(deserializer).map(Self::from_std)
82            }
83        }
84    };
85}
86
87impl_nonzero!(NonZeroU8, u8, std::num::NonZeroU8);
88impl_nonzero!(NonZeroU16, u16, std::num::NonZeroU16);
89impl_nonzero!(NonZeroU32, u32, std::num::NonZeroU32);
90impl_nonzero!(NonZeroU64, u64, std::num::NonZeroU64);
91impl_nonzero!(NonZeroU128, u128, std::num::NonZeroU128);
92impl_nonzero!(NonZeroUsize, usize, std::num::NonZeroUsize);
93impl_nonzero!(NonZeroI8, i8, std::num::NonZeroI8);
94impl_nonzero!(NonZeroI16, i16, std::num::NonZeroI16);
95impl_nonzero!(NonZeroI32, i32, std::num::NonZeroI32);
96impl_nonzero!(NonZeroI64, i64, std::num::NonZeroI64);
97impl_nonzero!(NonZeroI128, i128, std::num::NonZeroI128);
98impl_nonzero!(NonZeroIsize, isize, std::num::NonZeroIsize);