niche_types.rs - source
Description: Source of the Rust file `library/core/src/num/niche_types.rs`.

#
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` 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
    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
    115#[rustc_const_unstable(feature = "const_default", issue = "143894")]
    116impl const Default for Nanoseconds {
    117    #[inline]
    118    fn default() -> Self {
    119        Self::ZERO
    120    }
    121}
    122
    123define_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")]
    140define_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")]
    146define_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")]
    152define_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
    158define_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
    166pub trait NotAllOnesHelper {
    167    type Type;
    168}
    169pub type NotAllOnes<T> = <T as NotAllOnesHelper>::Type;
    170impl NotAllOnesHelper for u32 {
    171    type Type = U32NotAllOnes;
    172}
    173impl NotAllOnesHelper for i32 {
    174    type Type = I32NotAllOnes;
    175}
    176impl NotAllOnesHelper for u64 {
    177    type Type = U64NotAllOnes;
    178}
    179impl NotAllOnesHelper for i64 {
    180    type Type = I64NotAllOnes;
    181}
    182
    183define_valid_range_type! {
    184    pub struct CodePointInner(u32 as u32 in 0..=0x10ffff);
    185}
    186
    187impl CodePointInner {
    188    pub const ZERO: Self = CodePointInner::new(0).unwrap();
    189}
    190
    191impl Default for CodePointInner {
    192    #[inline]
    193    fn default() -> Self {
    194        Self::ZERO
    195    }
    196}