Skip to main content

nonzero_const_param/
lib.rs

1//! `NonZero*` types that derive [`ConstParamTy`] and can be used as constant generic params.
2
3#![expect(internal_features)]
4#![feature(
5    adt_const_params,
6    const_option_ops,
7    const_param_ty_unchecked,
8    const_trait_impl,
9    nonzero_internals
10)]
11
12use std::fmt;
13use std::marker::ConstParamTy;
14use std::num::ZeroablePrimitive;
15
16#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, ConstParamTy)]
17#[cfg_attr(feature = "serde", derive(serde::Serialize))]
18#[cfg_attr(
19    feature = "zerocopy",
20    derive(zerocopy::AsBytes, zerocopy::FromBytes, zerocopy::FromZeroes)
21)]
22#[repr(transparent)]
23pub struct NonZero<T: ZeroablePrimitive>(T);
24
25pub type NonZeroU8 = NonZero<u8>;
26pub type NonZeroU16 = NonZero<u16>;
27pub type NonZeroU32 = NonZero<u32>;
28pub type NonZeroU64 = NonZero<u64>;
29pub type NonZeroU128 = NonZero<u128>;
30pub type NonZeroUsize = NonZero<usize>;
31pub type NonZeroI8 = NonZero<i8>;
32pub type NonZeroI16 = NonZero<i16>;
33pub type NonZeroI32 = NonZero<i32>;
34pub type NonZeroI64 = NonZero<i64>;
35pub type NonZeroI128 = NonZero<i128>;
36pub type NonZeroIsize = NonZero<isize>;
37
38impl<T: ZeroablePrimitive> NonZero<T> {
39    #[doc = r" Creates a non-zero if the given value is not zero."]
40    #[must_use]
41    #[inline(always)]
42    pub const fn new(value: T) -> Option<Self> {
43        <std::num::NonZero<T>>::new(value).map(Self::from_std)
44    }
45
46    #[doc = r" Creates a non-zero without checking whether the value is non-zero."]
47    #[doc = r" This results in undefined behaviour if the value is zero."]
48    #[doc = r""]
49    #[doc = r" # Safety"]
50    #[doc = r""]
51    #[doc = r" The value must not be zero."]
52    #[must_use]
53    #[inline(always)]
54    pub const unsafe fn new_unchecked(value: T) -> Self {
55        Self::from_std(unsafe { std::num::NonZero::new_unchecked(value) })
56    }
57
58    #[must_use]
59    #[inline(always)]
60    pub const fn get(self) -> T {
61        self.into_std().get()
62    }
63
64    #[must_use]
65    #[inline(always)]
66    pub const fn into_std(self) -> std::num::NonZero<T> {
67        unsafe { <std::num::NonZero<T>>::new_unchecked(self.0) }
68    }
69
70    #[must_use]
71    #[inline(always)]
72    pub const fn from_std(value: std::num::NonZero<T>) -> Self {
73        Self(value.get())
74    }
75}
76
77impl<T: ZeroablePrimitive + fmt::Display> fmt::Display for NonZero<T> {
78    #[inline]
79    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
80        <T as fmt::Display>::fmt(&self.0, f)
81    }
82}
83
84#[cfg(feature = "serde")]
85impl<'de, T: ZeroablePrimitive + serde::Deserialize<'de>> serde::Deserialize<'de> for NonZero<T> {
86    #[inline]
87    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
88    where
89        D: serde::Deserializer<'de>,
90    {
91        let v = <T as serde::Deserialize<'de>>::deserialize(deserializer)?;
92        Self::new(v).ok_or_else(|| serde::de::Error::custom("expected nonzero integer"))
93    }
94}
95
96#[cfg(test)]
97mod tests {
98    use super::*;
99
100    #[test]
101    fn test() {
102        struct A<const NZ: NonZero<u8>>;
103
104        impl<const NZ: NonZero<u8>> A<NZ> {
105            fn get(self) -> u8 {
106                NZ.get()
107            }
108
109            fn get_static() -> u8 {
110                NZ.get()
111            }
112        }
113
114        assert_eq!(A::<{ NonZero::new(1).unwrap() }>.get(), 1);
115        assert_eq!(A::<{ NonZero::new(1).unwrap() }>::get_static(), 1);
116    }
117}