| 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 | |
| 7 | use crate::cmp::Ordering; |
| 8 | use crate::fmt; |
| 9 | use crate::hash::{Hash, Hasher}; |
| 10 | use crate::marker::StructuralPartialEq; |
| 11 | |
| 12 | macro_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` is not within the valid range for this |
| 50 | /// type, as it violates the validity invariant. |
| 51 | #[inline] |
| 52 | pub const unsafe fn new_unchecked(val: $int) -> Self { |
| 53 | // SAFETY: Caller promised that `val` is within the valid range. |
| 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 | |
| 106 | define_valid_range_type! { |
| 107 | pub struct Nanoseconds(u32 as u32 in 0..=999_999_999); |
| 108 | } |
| 109 | |
| 110 | impl Nanoseconds { |
| 111 | // SAFETY: 0 is within the valid range |
| 112 | pub const ZERO: Self = unsafe { Nanoseconds::new_unchecked(val:0) }; |
| 113 | } |
| 114 | |
| 115 | #[rustc_const_unstable (feature = "const_default" , issue = "143894" )] |
| 116 | impl const Default for Nanoseconds { |
| 117 | #[inline ] |
| 118 | fn default() -> Self { |
| 119 | Self::ZERO |
| 120 | } |
| 121 | } |
| 122 | |
| 123 | define_valid_range_type! { |
| 124 | pub struct NonZeroU8Inner(u8 as u8 in 1..=0xff); |
| 125 | pub struct NonZeroU16Inner(u16 as u16 in 1..=0xff_ff); |
| 126 | pub struct NonZeroU32Inner(u32 as u32 in 1..=0xffff_ffff); |
| 127 | pub struct NonZeroU64Inner(u64 as u64 in 1..=0xffffffff_ffffffff); |
| 128 | pub struct NonZeroU128Inner(u128 as u128 in 1..=0xffffffffffffffff_ffffffffffffffff); |
| 129 | |
| 130 | pub struct NonZeroI8Inner(i8 as u8 in 1..=0xff); |
| 131 | pub struct NonZeroI16Inner(i16 as u16 in 1..=0xff_ff); |
| 132 | pub struct NonZeroI32Inner(i32 as u32 in 1..=0xffff_ffff); |
| 133 | pub struct NonZeroI64Inner(i64 as u64 in 1..=0xffffffff_ffffffff); |
| 134 | pub struct NonZeroI128Inner(i128 as u128 in 1..=0xffffffffffffffff_ffffffffffffffff); |
| 135 | |
| 136 | pub struct NonZeroCharInner(char as u32 in 1..=0x10ffff); |
| 137 | } |
| 138 | |
| 139 | #[cfg (target_pointer_width = "16" )] |
| 140 | define_valid_range_type! { |
| 141 | pub struct UsizeNoHighBit(usize as usize in 0..=0x7fff); |
| 142 | pub struct NonZeroUsizeInner(usize as usize in 1..=0xffff); |
| 143 | pub struct NonZeroIsizeInner(isize as usize in 1..=0xffff); |
| 144 | } |
| 145 | #[cfg (target_pointer_width = "32" )] |
| 146 | define_valid_range_type! { |
| 147 | pub struct UsizeNoHighBit(usize as usize in 0..=0x7fff_ffff); |
| 148 | pub struct NonZeroUsizeInner(usize as usize in 1..=0xffff_ffff); |
| 149 | pub struct NonZeroIsizeInner(isize as usize in 1..=0xffff_ffff); |
| 150 | } |
| 151 | #[cfg (target_pointer_width = "64" )] |
| 152 | define_valid_range_type! { |
| 153 | pub struct UsizeNoHighBit(usize as usize in 0..=0x7fff_ffff_ffff_ffff); |
| 154 | pub struct NonZeroUsizeInner(usize as usize in 1..=0xffff_ffff_ffff_ffff); |
| 155 | pub struct NonZeroIsizeInner(isize as usize in 1..=0xffff_ffff_ffff_ffff); |
| 156 | } |
| 157 | |
| 158 | define_valid_range_type! { |
| 159 | pub struct U32NotAllOnes(u32 as u32 in 0..=0xffff_fffe); |
| 160 | pub struct I32NotAllOnes(i32 as u32 in 0..=0xffff_fffe); |
| 161 | |
| 162 | pub struct U64NotAllOnes(u64 as u64 in 0..=0xffff_ffff_ffff_fffe); |
| 163 | pub struct I64NotAllOnes(i64 as u64 in 0..=0xffff_ffff_ffff_fffe); |
| 164 | } |
| 165 | |
| 166 | pub trait NotAllOnesHelper { |
| 167 | type Type; |
| 168 | } |
| 169 | pub type NotAllOnes<T> = <T as NotAllOnesHelper>::Type; |
| 170 | impl NotAllOnesHelper for u32 { |
| 171 | type Type = U32NotAllOnes; |
| 172 | } |
| 173 | impl NotAllOnesHelper for i32 { |
| 174 | type Type = I32NotAllOnes; |
| 175 | } |
| 176 | impl NotAllOnesHelper for u64 { |
| 177 | type Type = U64NotAllOnes; |
| 178 | } |
| 179 | impl NotAllOnesHelper for i64 { |
| 180 | type Type = I64NotAllOnes; |
| 181 | } |
| 182 | |
| 183 | define_valid_range_type! { |
| 184 | pub struct CodePointInner(u32 as u32 in 0..=0x10ffff); |
| 185 | } |
| 186 | |
| 187 | impl CodePointInner { |
| 188 | pub const ZERO: Self = CodePointInner::new(val:0).unwrap(); |
| 189 | } |
| 190 | |
| 191 | impl Default for CodePointInner { |
| 192 | #[inline ] |
| 193 | fn default() -> Self { |
| 194 | Self::ZERO |
| 195 | } |
| 196 | } |
| 197 | |