core/num/
niche_types.rs

1#![unstable(
2    feature = "temporary_niche_types",
3    issue = "none",
4    reason = "for core, alloc, and std internals until pattern types are further along"
5)]
6
7use crate::cmp::Ordering;
8use crate::fmt;
9use crate::hash::{Hash, Hasher};
10use crate::marker::StructuralPartialEq;
11
12macro_rules! define_valid_range_type {
13    ($(
14        $(#[$m:meta])*
15        $vis:vis struct $name:ident($int:ident as $uint:ident in $low:literal..=$high:literal);
16    )+) => {$(
17        #[derive(Clone, Copy, Eq)]
18        #[repr(transparent)]
19        #[rustc_layout_scalar_valid_range_start($low)]
20        #[rustc_layout_scalar_valid_range_end($high)]
21        $(#[$m])*
22        $vis struct $name($int);
23
24        const _: () = {
25            // With the `valid_range` attributes, it's always specified as unsigned
26            assert!(<$uint>::MIN == 0);
27            let ulow: $uint = $low;
28            let uhigh: $uint = $high;
29            assert!(ulow <= uhigh);
30
31            assert!(size_of::<$int>() == size_of::<$uint>());
32        };
33
34        impl $name {
35            #[inline]
36            pub const fn new(val: $int) -> Option<Self> {
37                if (val as $uint) >= ($low as $uint) && (val as $uint) <= ($high as $uint) {
38                    // SAFETY: just checked the inclusive range
39                    Some(unsafe { $name(val) })
40                } else {
41                    None
42                }
43            }
44
45            /// Constructs an instance of this type from the underlying integer
46            /// primitive without checking whether its zero.
47            ///
48            /// # Safety
49            /// Immediate language UB if `val == 0`, as it violates the validity
50            /// invariant of this type.
51            #[inline]
52            pub const unsafe fn new_unchecked(val: $int) -> Self {
53                // SAFETY: Caller promised that `val` is non-zero.
54                unsafe { $name(val) }
55            }
56
57            #[inline]
58            pub const fn as_inner(self) -> $int {
59                // SAFETY: This is a transparent wrapper, so unwrapping it is sound
60                // (Not using `.0` due to MCP#807.)
61                unsafe { crate::mem::transmute(self) }
62            }
63        }
64
65        // This is required to allow matching a constant.  We don't get it from a derive
66        // because the derived `PartialEq` would do a field projection, which is banned
67        // by <https://github.com/rust-lang/compiler-team/issues/807>.
68        impl StructuralPartialEq for $name {}
69
70        impl PartialEq for $name {
71            #[inline]
72            fn eq(&self, other: &Self) -> bool {
73                self.as_inner() == other.as_inner()
74            }
75        }
76
77        impl Ord for $name {
78            #[inline]
79            fn cmp(&self, other: &Self) -> Ordering {
80                Ord::cmp(&self.as_inner(), &other.as_inner())
81            }
82        }
83
84        impl PartialOrd for $name {
85            #[inline]
86            fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
87                Some(Ord::cmp(self, other))
88            }
89        }
90
91        impl Hash for $name {
92            // Required method
93            fn hash<H: Hasher>(&self, state: &mut H) {
94                Hash::hash(&self.as_inner(), state);
95            }
96        }
97
98        impl fmt::Debug for $name {
99            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
100                <$int as fmt::Debug>::fmt(&self.as_inner(), f)
101            }
102        }
103    )+};
104}
105
106define_valid_range_type! {
107    pub struct Nanoseconds(u32 as u32 in 0..=999_999_999);
108}
109
110impl Nanoseconds {
111    // SAFETY: 0 is within the valid range
112    pub const ZERO: Self = unsafe { Nanoseconds::new_unchecked(0) };
113}
114
115impl Default for Nanoseconds {
116    #[inline]
117    fn default() -> Self {
118        Self::ZERO
119    }
120}
121
122define_valid_range_type! {
123    pub struct NonZeroU8Inner(u8 as u8 in 1..=0xff);
124    pub struct NonZeroU16Inner(u16 as u16 in 1..=0xff_ff);
125    pub struct NonZeroU32Inner(u32 as u32 in 1..=0xffff_ffff);
126    pub struct NonZeroU64Inner(u64 as u64 in 1..=0xffffffff_ffffffff);
127    pub struct NonZeroU128Inner(u128 as u128 in 1..=0xffffffffffffffff_ffffffffffffffff);
128
129    pub struct NonZeroI8Inner(i8 as u8 in 1..=0xff);
130    pub struct NonZeroI16Inner(i16 as u16 in 1..=0xff_ff);
131    pub struct NonZeroI32Inner(i32 as u32 in 1..=0xffff_ffff);
132    pub struct NonZeroI64Inner(i64 as u64 in 1..=0xffffffff_ffffffff);
133    pub struct NonZeroI128Inner(i128 as u128 in 1..=0xffffffffffffffff_ffffffffffffffff);
134}
135
136#[cfg(target_pointer_width = "16")]
137define_valid_range_type! {
138    pub struct UsizeNoHighBit(usize as usize in 0..=0x7fff);
139    pub struct NonZeroUsizeInner(usize as usize in 1..=0xffff);
140    pub struct NonZeroIsizeInner(isize as usize in 1..=0xffff);
141}
142#[cfg(target_pointer_width = "32")]
143define_valid_range_type! {
144    pub struct UsizeNoHighBit(usize as usize in 0..=0x7fff_ffff);
145    pub struct NonZeroUsizeInner(usize as usize in 1..=0xffff_ffff);
146    pub struct NonZeroIsizeInner(isize as usize in 1..=0xffff_ffff);
147}
148#[cfg(target_pointer_width = "64")]
149define_valid_range_type! {
150    pub struct UsizeNoHighBit(usize as usize in 0..=0x7fff_ffff_ffff_ffff);
151    pub struct NonZeroUsizeInner(usize as usize in 1..=0xffff_ffff_ffff_ffff);
152    pub struct NonZeroIsizeInner(isize as usize in 1..=0xffff_ffff_ffff_ffff);
153}
154
155define_valid_range_type! {
156    pub struct U32NotAllOnes(u32 as u32 in 0..=0xffff_fffe);
157    pub struct I32NotAllOnes(i32 as u32 in 0..=0xffff_fffe);
158
159    pub struct U64NotAllOnes(u64 as u64 in 0..=0xffff_ffff_ffff_fffe);
160    pub struct I64NotAllOnes(i64 as u64 in 0..=0xffff_ffff_ffff_fffe);
161}
162
163pub trait NotAllOnesHelper {
164    type Type;
165}
166pub type NotAllOnes<T> = <T as NotAllOnesHelper>::Type;
167impl NotAllOnesHelper for u32 {
168    type Type = U32NotAllOnes;
169}
170impl NotAllOnesHelper for i32 {
171    type Type = I32NotAllOnes;
172}
173impl NotAllOnesHelper for u64 {
174    type Type = U64NotAllOnes;
175}
176impl NotAllOnesHelper for i64 {
177    type Type = I64NotAllOnes;
178}