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, 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
25impl<T: ZeroablePrimitive> NonZero<T> {
26    #[doc = r" Creates a non-zero if the given value is not zero."]
27    #[must_use]
28    #[inline(always)]
29    pub const fn new(value: T) -> Option<Self> {
30        <std::num::NonZero<T>>::new(value).map(Self::from_std)
31    }
32
33    #[doc = r" Creates a non-zero without checking whether the value is non-zero."]
34    #[doc = r" This results in undefined behaviour if the value is zero."]
35    #[doc = r""]
36    #[doc = r" # Safety"]
37    #[doc = r""]
38    #[doc = r" The value must not be zero."]
39    #[must_use]
40    #[inline(always)]
41    pub const unsafe fn new_unchecked(value: T) -> Self {
42        Self::from_std(unsafe { std::num::NonZero::new_unchecked(value) })
43    }
44
45    #[must_use]
46    #[inline(always)]
47    pub const fn get(self) -> T {
48        self.into_std().get()
49    }
50
51    #[must_use]
52    #[inline(always)]
53    pub const fn into_std(self) -> std::num::NonZero<T> {
54        unsafe { <std::num::NonZero<T>>::new_unchecked(self.0) }
55    }
56
57    #[must_use]
58    #[inline(always)]
59    pub const fn from_std(value: std::num::NonZero<T>) -> Self {
60        Self(value.get())
61    }
62}
63
64impl<T: ZeroablePrimitive + fmt::Display> fmt::Display for NonZero<T> {
65    #[inline]
66    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
67        <T as fmt::Display>::fmt(&self.0, f)
68    }
69}
70
71#[cfg(feature = "serde")]
72impl<'de, T: ZeroablePrimitive + serde::Deserialize<'de>> serde::Deserialize<'de> for NonZero<T> {
73    #[inline]
74    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
75    where
76        D: serde::Deserializer<'de>,
77    {
78        let v = <T as serde::Deserialize<'de>>::deserialize(deserializer)?;
79        Self::new(v).ok_or_else(|| serde::de::Error::custom("expected nonzero integer"))
80    }
81}
82
83#[cfg(test)]
84mod tests {
85    use super::*;
86
87    #[test]
88    fn test() {
89        struct A<const NZ: NonZero<u8>>;
90
91        impl<const NZ: NonZero<u8>> A<NZ> {
92            fn get(self) -> u8 {
93                NZ.get()
94            }
95
96            fn get_static() -> u8 {
97                NZ.get()
98            }
99        }
100
101        assert_eq!(A::<{ NonZero::new(1).unwrap() }>.get(), 1);
102        assert_eq!(A::<{ NonZero::new(1).unwrap() }>::get_static(), 1);
103    }
104}