Skip to main content

rustc_middle/ty/consts/
int.rs

1use std::fmt;
2use std::num::NonZero;
3
4use rustc_abi::Size;
5use rustc_apfloat::Float;
6use rustc_apfloat::ieee::{Double, Half, Quad, Single};
7use rustc_data_structures::stable_hash::{StableHash, StableHashCtxt};
8use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
9use rustc_span::bug;
10
11use crate::ty::TyCtxt;
12
13#[derive(#[automatically_derived]
impl ::core::marker::Copy for ConstInt { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for ConstInt { }
#[automatically_derived]
impl ::core::clone::Clone for ConstInt {
    #[inline]
    fn clone(&self) -> Self {
        let _: ::core::clone::AssertParamIsClone<ScalarInt>;
        let _: ::core::clone::AssertParamIsClone<bool>;
        *self
    }
}Clone)]
14/// A type for representing any integer. Only used for printing.
15pub struct ConstInt {
16    /// The "untyped" variant of `ConstInt`.
17    int: ScalarInt,
18    /// Whether the value is of a signed integer type.
19    signed: bool,
20    /// Whether the value is a `usize` or `isize` type.
21    is_ptr_sized_integral: bool,
22}
23
24impl ConstInt {
25    pub fn new(int: ScalarInt, signed: bool, is_ptr_sized_integral: bool) -> Self {
26        Self { int, signed, is_ptr_sized_integral }
27    }
28}
29
30/// An enum to represent the compiler-side view of `intrinsics::AtomicOrdering`.
31/// This lives here because there's a method in this file that needs it and it is entirely unclear
32/// where else to put this...
33#[derive(#[automatically_derived]
impl ::core::fmt::Debug for AtomicOrdering {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f,
            match self {
                AtomicOrdering::Relaxed => "Relaxed",
                AtomicOrdering::Release => "Release",
                AtomicOrdering::Acquire => "Acquire",
                AtomicOrdering::AcqRel => "AcqRel",
                AtomicOrdering::SeqCst => "SeqCst",
            })
    }
}Debug, #[automatically_derived]
impl ::core::marker::Copy for AtomicOrdering { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for AtomicOrdering { }
#[automatically_derived]
impl ::core::clone::Clone for AtomicOrdering {
    #[inline]
    fn clone(&self) -> Self { *self }
}Clone)]
34pub enum AtomicOrdering {
35    // These values must match `intrinsics::AtomicOrdering`!
36    Relaxed = 0,
37    Release = 1,
38    Acquire = 2,
39    AcqRel = 3,
40    SeqCst = 4,
41}
42
43/// An enum to represent the compiler-side view of `intrinsics::simd::SimdAlign`.
44#[derive(#[automatically_derived]
impl ::core::fmt::Debug for SimdAlign {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f,
            match self {
                SimdAlign::Unaligned => "Unaligned",
                SimdAlign::Element => "Element",
                SimdAlign::Vector => "Vector",
            })
    }
}Debug, #[automatically_derived]
impl ::core::marker::Copy for SimdAlign { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for SimdAlign { }
#[automatically_derived]
impl ::core::clone::Clone for SimdAlign {
    #[inline]
    fn clone(&self) -> Self { *self }
}Clone)]
45pub enum SimdAlign {
46    // These values must match `intrinsics::simd::SimdAlign`!
47    Unaligned = 0,
48    Element = 1,
49    Vector = 2,
50}
51
52impl std::fmt::Debug for ConstInt {
53    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
54        let Self { int, signed, is_ptr_sized_integral } = *self;
55        let size = int.size().bytes();
56        let raw = int.data;
57        if signed {
58            let bit_size = size * 8;
59            let min = 1u128 << (bit_size - 1);
60            let max = min - 1;
61            if raw == min {
62                match (size, is_ptr_sized_integral) {
63                    (_, true) => fmt.write_fmt(format_args!("isize::MIN"))write!(fmt, "isize::MIN"),
64                    (1, _) => fmt.write_fmt(format_args!("i8::MIN"))write!(fmt, "i8::MIN"),
65                    (2, _) => fmt.write_fmt(format_args!("i16::MIN"))write!(fmt, "i16::MIN"),
66                    (4, _) => fmt.write_fmt(format_args!("i32::MIN"))write!(fmt, "i32::MIN"),
67                    (8, _) => fmt.write_fmt(format_args!("i64::MIN"))write!(fmt, "i64::MIN"),
68                    (16, _) => fmt.write_fmt(format_args!("i128::MIN"))write!(fmt, "i128::MIN"),
69                    _ => ::rustc_span::macros::bug_impl(None,
    format_args!("ConstInt 0x{0:x} with size = {1} and signed = {2}", raw,
        size, signed), Location::caller())bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
70                }
71            } else if raw == max {
72                match (size, is_ptr_sized_integral) {
73                    (_, true) => fmt.write_fmt(format_args!("isize::MAX"))write!(fmt, "isize::MAX"),
74                    (1, _) => fmt.write_fmt(format_args!("i8::MAX"))write!(fmt, "i8::MAX"),
75                    (2, _) => fmt.write_fmt(format_args!("i16::MAX"))write!(fmt, "i16::MAX"),
76                    (4, _) => fmt.write_fmt(format_args!("i32::MAX"))write!(fmt, "i32::MAX"),
77                    (8, _) => fmt.write_fmt(format_args!("i64::MAX"))write!(fmt, "i64::MAX"),
78                    (16, _) => fmt.write_fmt(format_args!("i128::MAX"))write!(fmt, "i128::MAX"),
79                    _ => ::rustc_span::macros::bug_impl(None,
    format_args!("ConstInt 0x{0:x} with size = {1} and signed = {2}", raw,
        size, signed), Location::caller())bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
80                }
81            } else {
82                match size {
83                    1 => fmt.write_fmt(format_args!("{0}", raw as i8))write!(fmt, "{}", raw as i8)?,
84                    2 => fmt.write_fmt(format_args!("{0}", raw as i16))write!(fmt, "{}", raw as i16)?,
85                    4 => fmt.write_fmt(format_args!("{0}", raw as i32))write!(fmt, "{}", raw as i32)?,
86                    8 => fmt.write_fmt(format_args!("{0}", raw as i64))write!(fmt, "{}", raw as i64)?,
87                    16 => fmt.write_fmt(format_args!("{0}", raw as i128))write!(fmt, "{}", raw as i128)?,
88                    _ => ::rustc_span::macros::bug_impl(None,
    format_args!("ConstInt 0x{0:x} with size = {1} and signed = {2}", raw,
        size, signed), Location::caller())bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
89                }
90                if fmt.alternate() {
91                    match (size, is_ptr_sized_integral) {
92                        (_, true) => fmt.write_fmt(format_args!("_isize"))write!(fmt, "_isize")?,
93                        (1, _) => fmt.write_fmt(format_args!("_i8"))write!(fmt, "_i8")?,
94                        (2, _) => fmt.write_fmt(format_args!("_i16"))write!(fmt, "_i16")?,
95                        (4, _) => fmt.write_fmt(format_args!("_i32"))write!(fmt, "_i32")?,
96                        (8, _) => fmt.write_fmt(format_args!("_i64"))write!(fmt, "_i64")?,
97                        (16, _) => fmt.write_fmt(format_args!("_i128"))write!(fmt, "_i128")?,
98                        (sz, _) => ::rustc_span::macros::bug_impl(None,
    format_args!("unexpected int size i{0}", sz), Location::caller())bug!("unexpected int size i{sz}"),
99                    }
100                }
101                Ok(())
102            }
103        } else {
104            let max = Size::from_bytes(size).truncate(u128::MAX);
105            if raw == max {
106                match (size, is_ptr_sized_integral) {
107                    (_, true) => fmt.write_fmt(format_args!("usize::MAX"))write!(fmt, "usize::MAX"),
108                    (1, _) => fmt.write_fmt(format_args!("u8::MAX"))write!(fmt, "u8::MAX"),
109                    (2, _) => fmt.write_fmt(format_args!("u16::MAX"))write!(fmt, "u16::MAX"),
110                    (4, _) => fmt.write_fmt(format_args!("u32::MAX"))write!(fmt, "u32::MAX"),
111                    (8, _) => fmt.write_fmt(format_args!("u64::MAX"))write!(fmt, "u64::MAX"),
112                    (16, _) => fmt.write_fmt(format_args!("u128::MAX"))write!(fmt, "u128::MAX"),
113                    _ => ::rustc_span::macros::bug_impl(None,
    format_args!("ConstInt 0x{0:x} with size = {1} and signed = {2}", raw,
        size, signed), Location::caller())bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
114                }
115            } else {
116                match size {
117                    1 => fmt.write_fmt(format_args!("{0}", raw as u8))write!(fmt, "{}", raw as u8)?,
118                    2 => fmt.write_fmt(format_args!("{0}", raw as u16))write!(fmt, "{}", raw as u16)?,
119                    4 => fmt.write_fmt(format_args!("{0}", raw as u32))write!(fmt, "{}", raw as u32)?,
120                    8 => fmt.write_fmt(format_args!("{0}", raw as u64))write!(fmt, "{}", raw as u64)?,
121                    16 => fmt.write_fmt(format_args!("{0}", raw as u128))write!(fmt, "{}", raw as u128)?,
122                    _ => ::rustc_span::macros::bug_impl(None,
    format_args!("ConstInt 0x{0:x} with size = {1} and signed = {2}", raw,
        size, signed), Location::caller())bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
123                }
124                if fmt.alternate() {
125                    match (size, is_ptr_sized_integral) {
126                        (_, true) => fmt.write_fmt(format_args!("_usize"))write!(fmt, "_usize")?,
127                        (1, _) => fmt.write_fmt(format_args!("_u8"))write!(fmt, "_u8")?,
128                        (2, _) => fmt.write_fmt(format_args!("_u16"))write!(fmt, "_u16")?,
129                        (4, _) => fmt.write_fmt(format_args!("_u32"))write!(fmt, "_u32")?,
130                        (8, _) => fmt.write_fmt(format_args!("_u64"))write!(fmt, "_u64")?,
131                        (16, _) => fmt.write_fmt(format_args!("_u128"))write!(fmt, "_u128")?,
132                        (sz, _) => ::rustc_span::macros::bug_impl(None,
    format_args!("unexpected unsigned int size u{0}", sz), Location::caller())bug!("unexpected unsigned int size u{sz}"),
133                    }
134                }
135                Ok(())
136            }
137        }
138    }
139}
140
141/// The raw bytes of a simple value.
142///
143/// This is a packed struct in order to allow this type to be optimally embedded in enums
144/// (like Scalar).
145#[derive(#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for ScalarInt { }
#[automatically_derived]
impl ::core::clone::Clone for ScalarInt {
    #[inline]
    fn clone(&self) -> Self {
        let _: ::core::clone::AssertParamIsClone<u128>;
        let _: ::core::clone::AssertParamIsClone<NonZero<u8>>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for ScalarInt { }Copy, #[automatically_derived]
impl ::core::cmp::Eq for ScalarInt {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<u128>;
        let _: ::core::cmp::AssertParamIsEq<NonZero<u8>>;
    }
}Eq, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for ScalarInt { }
#[automatically_derived]
impl ::core::cmp::PartialEq for ScalarInt {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        ({ self.data }) == ({ other.data }) &&
            ({ self.size }) == ({ other.size })
    }
}PartialEq, #[automatically_derived]
impl ::core::hash::Hash for ScalarInt {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        ::core::hash::Hash::hash(&{ self.data }, state);
        ::core::hash::Hash::hash(&{ self.size }, state)
    }
}Hash)]
146#[repr(packed)]
147pub struct ScalarInt {
148    /// The first `size` bytes of `data` are the value.
149    /// Do not try to read less or more bytes than that. The remaining bytes must be 0.
150    data: u128,
151    size: NonZero<u8>,
152}
153
154// Cannot derive these, as the derives take references to the fields, and we
155// can't take references to fields of packed structs.
156impl StableHash for ScalarInt {
157    fn stable_hash<Hcx: StableHashCtxt>(
158        &self,
159        hcx: &mut Hcx,
160        hasher: &mut crate::ty::StableHasher,
161    ) {
162        // Using a block `{self.data}` here to force a copy instead of using `self.data`
163        // directly, because `stable_hash` takes `&self` and would thus borrow `self.data`.
164        // Since `Self` is a packed struct, that would create a possibly unaligned reference,
165        // which is UB.
166        { self.data }.stable_hash(hcx, hasher);
167        self.size.get().stable_hash(hcx, hasher);
168    }
169}
170
171impl<S: Encoder> Encodable<S> for ScalarInt {
172    fn encode(&self, s: &mut S) {
173        let size = self.size.get();
174        s.emit_u8(size);
175        s.emit_raw_bytes(&self.data.to_le_bytes()[..size as usize]);
176    }
177}
178
179impl<D: Decoder> Decodable<D> for ScalarInt {
180    fn decode(d: &mut D) -> ScalarInt {
181        let mut data = [0u8; 16];
182        let size = d.read_u8();
183        data[..size as usize].copy_from_slice(d.read_raw_bytes(size as usize));
184        ScalarInt { data: u128::from_le_bytes(data), size: NonZero::new(size).unwrap() }
185    }
186}
187
188impl ScalarInt {
189    pub const TRUE: ScalarInt = ScalarInt { data: 1_u128, size: NonZero::new(1).unwrap() };
190    pub const FALSE: ScalarInt = ScalarInt { data: 0_u128, size: NonZero::new(1).unwrap() };
191
192    fn raw(data: u128, size: Size) -> Self {
193        Self { data, size: NonZero::new(size.bytes() as u8).unwrap() }
194    }
195
196    #[inline]
197    pub fn size(self) -> Size {
198        Size::from_bytes(self.size.get())
199    }
200
201    /// Make sure the `data` fits in `size`.
202    /// This is guaranteed by all constructors here, but having had this check saved us from
203    /// bugs many times in the past, so keeping it around is definitely worth it.
204    #[inline(always)]
205    fn check_data(self) {
206        // Using a block `{self.data}` here to force a copy instead of using `self.data`
207        // directly, because `debug_assert_eq` takes references to its arguments and formatting
208        // arguments and would thus borrow `self.data`. Since `Self`
209        // is a packed struct, that would create a possibly unaligned reference, which
210        // is UB.
211        if true {
    {
        match (&self.size().truncate(self.data), &{ self.data }) {
            (left_val, right_val) => {
                if !(*left_val == *right_val) {
                    let kind = ::core::panicking::AssertKind::Eq;
                    ::core::panicking::assert_failed(kind, &*left_val,
                        &*right_val,
                        ::core::option::Option::Some(format_args!("Scalar value {0:#x} exceeds size of {1} bytes",
                                { self.data }, self.size)));
                }
            }
        }
    };
};debug_assert_eq!(
212            self.size().truncate(self.data),
213            { self.data },
214            "Scalar value {:#x} exceeds size of {} bytes",
215            { self.data },
216            self.size
217        );
218    }
219
220    #[inline]
221    pub fn null(size: Size) -> Self {
222        Self::raw(0, size)
223    }
224
225    #[inline]
226    pub fn is_null(self) -> bool {
227        self.data == 0
228    }
229
230    #[inline]
231    pub fn try_from_uint(i: impl Into<u128>, size: Size) -> Option<Self> {
232        let (r, overflow) = Self::truncate_from_uint(i, size);
233        if overflow { None } else { Some(r) }
234    }
235
236    /// Returns the truncated result, and whether truncation changed the value.
237    #[inline]
238    pub fn truncate_from_uint(i: impl Into<u128>, size: Size) -> (Self, bool) {
239        let data = i.into();
240        let r = Self::raw(size.truncate(data), size);
241        (r, r.data != data)
242    }
243
244    #[inline]
245    pub fn try_from_int(i: impl Into<i128>, size: Size) -> Option<Self> {
246        let (r, overflow) = Self::truncate_from_int(i, size);
247        if overflow { None } else { Some(r) }
248    }
249
250    /// Returns the truncated result, and whether truncation changed the value.
251    #[inline]
252    pub fn truncate_from_int(i: impl Into<i128>, size: Size) -> (Self, bool) {
253        let data = i.into();
254        // `into` performed sign extension, we have to truncate
255        let r = Self::raw(size.truncate(data as u128), size);
256        (r, size.sign_extend(r.data) != data)
257    }
258
259    #[inline]
260    pub fn try_from_target_usize(i: impl Into<u128>, tcx: TyCtxt<'_>) -> Option<Self> {
261        Self::try_from_uint(i, tcx.data_layout.pointer_size())
262    }
263
264    /// Convert this ScalarInt to the underlying bits.
265    #[inline]
266    pub fn to_bits(self, expected_size: Size) -> u128 {
267        let self_size = u64::from(self.size.get());
268        if expected_size.bytes() != self_size {
269            #[cold]
270            fn invalid(expected_size: u64, self_size: u64) -> ! {
271                {
    ::core::panicking::panic_fmt(format_args!("ScalarInt has size {0} but expected {1}",
            self_size, expected_size));
}panic!("ScalarInt has size {self_size} but expected {expected_size}")
272            }
273
274            invalid(expected_size.bytes(), self_size);
275        }
276
277        self.check_data();
278        self.data
279    }
280
281    /// Extracts the bits from the scalar without checking the size.
282    #[inline]
283    pub fn to_bits_unchecked(self) -> u128 {
284        self.check_data();
285        self.data
286    }
287
288    /// Converts the `ScalarInt` to an unsigned integer of the given size.
289    /// Panics if the size of the `ScalarInt` is not equal to `size`.
290    #[inline]
291    pub fn to_uint(self, size: Size) -> u128 {
292        self.to_bits(size)
293    }
294
295    /// Converts the `ScalarInt` to `u8`.
296    /// Panics if the `size` of the `ScalarInt`in not equal to 1 byte.
297    #[inline]
298    pub fn to_u8(self) -> u8 {
299        self.to_uint(Size::from_bits(8)).try_into().unwrap()
300    }
301
302    /// Converts the `ScalarInt` to `u16`.
303    /// Panics if the size of the `ScalarInt` in not equal to 2 bytes.
304    #[inline]
305    pub fn to_u16(self) -> u16 {
306        self.to_uint(Size::from_bits(16)).try_into().unwrap()
307    }
308
309    /// Converts the `ScalarInt` to `u32`.
310    /// Panics if the `size` of the `ScalarInt` in not equal to 4 bytes.
311    #[inline]
312    pub fn to_u32(self) -> u32 {
313        self.to_uint(Size::from_bits(32)).try_into().unwrap()
314    }
315
316    /// Converts the `ScalarInt` to `u64`.
317    /// Panics if the `size` of the `ScalarInt` in not equal to 8 bytes.
318    #[inline]
319    pub fn to_u64(self) -> u64 {
320        self.to_uint(Size::from_bits(64)).try_into().unwrap()
321    }
322
323    /// Converts the `ScalarInt` to `u128`.
324    /// Panics if the `size` of the `ScalarInt` in not equal to 16 bytes.
325    #[inline]
326    pub fn to_u128(self) -> u128 {
327        self.to_uint(Size::from_bits(128))
328    }
329
330    #[inline]
331    pub fn to_target_usize(&self, tcx: TyCtxt<'_>) -> u64 {
332        self.to_uint(tcx.data_layout.pointer_size()).try_into().unwrap()
333    }
334
335    #[inline]
336    pub fn to_atomic_ordering(self) -> AtomicOrdering {
337        use AtomicOrdering::*;
338        let val = self.to_u32();
339        if val == Relaxed as u32 {
340            Relaxed
341        } else if val == Release as u32 {
342            Release
343        } else if val == Acquire as u32 {
344            Acquire
345        } else if val == AcqRel as u32 {
346            AcqRel
347        } else if val == SeqCst as u32 {
348            SeqCst
349        } else {
350            { ::core::panicking::panic_fmt(format_args!("not a valid atomic ordering")); }panic!("not a valid atomic ordering")
351        }
352    }
353
354    #[inline]
355    pub fn to_simd_alignment(self) -> SimdAlign {
356        use SimdAlign::*;
357        let val = self.to_u32();
358        if val == Unaligned as u32 {
359            Unaligned
360        } else if val == Element as u32 {
361            Element
362        } else if val == Vector as u32 {
363            Vector
364        } else {
365            { ::core::panicking::panic_fmt(format_args!("not a valid simd alignment")); }panic!("not a valid simd alignment")
366        }
367    }
368
369    /// Converts the `ScalarInt` to `bool`.
370    /// Panics if the `size` of the `ScalarInt` is not equal to 1 byte.
371    /// Errors if it is not a valid `bool`.
372    #[inline]
373    pub fn try_to_bool(self) -> Result<bool, ()> {
374        match self.to_u8() {
375            0 => Ok(false),
376            1 => Ok(true),
377            _ => Err(()),
378        }
379    }
380
381    /// Converts the `ScalarInt` to a signed integer of the given size.
382    /// Panics if the size of the `ScalarInt` is not equal to `size`.
383    #[inline]
384    pub fn to_int(self, size: Size) -> i128 {
385        let b = self.to_bits(size);
386        size.sign_extend(b)
387    }
388
389    /// Converts the `ScalarInt` to i8.
390    /// Panics if the size of the `ScalarInt` is not equal to 1 byte.
391    pub fn to_i8(self) -> i8 {
392        self.to_int(Size::from_bits(8)).try_into().unwrap()
393    }
394
395    /// Converts the `ScalarInt` to i16.
396    /// Panics if the size of the `ScalarInt` is not equal to 2 bytes.
397    pub fn to_i16(self) -> i16 {
398        self.to_int(Size::from_bits(16)).try_into().unwrap()
399    }
400
401    /// Converts the `ScalarInt` to i32.
402    /// Panics if the size of the `ScalarInt` is not equal to 4 bytes.
403    pub fn to_i32(self) -> i32 {
404        self.to_int(Size::from_bits(32)).try_into().unwrap()
405    }
406
407    /// Converts the `ScalarInt` to i64.
408    /// Panics if the size of the `ScalarInt` is not equal to 8 bytes.
409    pub fn to_i64(self) -> i64 {
410        self.to_int(Size::from_bits(64)).try_into().unwrap()
411    }
412
413    /// Converts the `ScalarInt` to i128.
414    /// Panics if the size of the `ScalarInt` is not equal to 16 bytes.
415    pub fn to_i128(self) -> i128 {
416        self.to_int(Size::from_bits(128))
417    }
418
419    #[inline]
420    pub fn to_target_isize(&self, tcx: TyCtxt<'_>) -> i64 {
421        self.to_int(tcx.data_layout.pointer_size()).try_into().unwrap()
422    }
423
424    #[inline]
425    pub fn to_float<F: Float>(self) -> F {
426        // Going through `to_uint` to check size and truncation.
427        F::from_bits(self.to_bits(Size::from_bits(F::BITS)))
428    }
429
430    #[inline]
431    pub fn to_f16(self) -> Half {
432        self.to_float()
433    }
434
435    #[inline]
436    pub fn to_f32(self) -> Single {
437        self.to_float()
438    }
439
440    #[inline]
441    pub fn to_f64(self) -> Double {
442        self.to_float()
443    }
444
445    #[inline]
446    pub fn to_f128(self) -> Quad {
447        self.to_float()
448    }
449}
450
451macro_rules! from_x_for_scalar_int {
452    ($($ty:ty),*) => {
453        $(
454            impl From<$ty> for ScalarInt {
455                #[inline]
456                fn from(u: $ty) -> Self {
457                    Self {
458                        data: u128::from(u),
459                        size: NonZero::new(size_of::<$ty>() as u8).unwrap(),
460                    }
461                }
462            }
463        )*
464    }
465}
466
467macro_rules! from_scalar_int_for_x {
468    ($($ty:ty),*) => {
469        $(
470            impl From<ScalarInt> for $ty {
471                #[inline]
472                fn from(int: ScalarInt) -> Self {
473                    // The `unwrap` cannot fail because to_uint (if it succeeds)
474                    // is guaranteed to return a value that fits into the size.
475                    int.to_uint(Size::from_bytes(size_of::<$ty>()))
476                       .try_into().unwrap()
477                }
478            }
479        )*
480    }
481}
482
483impl From<u8> for ScalarInt {
    #[inline]
    fn from(u: u8) -> Self {
        Self {
            data: u128::from(u),
            size: NonZero::new(size_of::<u8>() as u8).unwrap(),
        }
    }
}
impl From<u16> for ScalarInt {
    #[inline]
    fn from(u: u16) -> Self {
        Self {
            data: u128::from(u),
            size: NonZero::new(size_of::<u16>() as u8).unwrap(),
        }
    }
}
impl From<u32> for ScalarInt {
    #[inline]
    fn from(u: u32) -> Self {
        Self {
            data: u128::from(u),
            size: NonZero::new(size_of::<u32>() as u8).unwrap(),
        }
    }
}
impl From<u64> for ScalarInt {
    #[inline]
    fn from(u: u64) -> Self {
        Self {
            data: u128::from(u),
            size: NonZero::new(size_of::<u64>() as u8).unwrap(),
        }
    }
}
impl From<u128> for ScalarInt {
    #[inline]
    fn from(u: u128) -> Self {
        Self {
            data: u128::from(u),
            size: NonZero::new(size_of::<u128>() as u8).unwrap(),
        }
    }
}
impl From<bool> for ScalarInt {
    #[inline]
    fn from(u: bool) -> Self {
        Self {
            data: u128::from(u),
            size: NonZero::new(size_of::<bool>() as u8).unwrap(),
        }
    }
}from_x_for_scalar_int!(u8, u16, u32, u64, u128, bool);
484impl From<ScalarInt> for u8 {
    #[inline]
    fn from(int: ScalarInt) -> Self {
        int.to_uint(Size::from_bytes(size_of::<u8>())).try_into().unwrap()
    }
}
impl From<ScalarInt> for u16 {
    #[inline]
    fn from(int: ScalarInt) -> Self {
        int.to_uint(Size::from_bytes(size_of::<u16>())).try_into().unwrap()
    }
}
impl From<ScalarInt> for u32 {
    #[inline]
    fn from(int: ScalarInt) -> Self {
        int.to_uint(Size::from_bytes(size_of::<u32>())).try_into().unwrap()
    }
}
impl From<ScalarInt> for u64 {
    #[inline]
    fn from(int: ScalarInt) -> Self {
        int.to_uint(Size::from_bytes(size_of::<u64>())).try_into().unwrap()
    }
}
impl From<ScalarInt> for u128 {
    #[inline]
    fn from(int: ScalarInt) -> Self {
        int.to_uint(Size::from_bytes(size_of::<u128>())).try_into().unwrap()
    }
}from_scalar_int_for_x!(u8, u16, u32, u64, u128);
485
486impl TryFrom<ScalarInt> for bool {
487    type Error = ();
488    #[inline]
489    fn try_from(int: ScalarInt) -> Result<Self, ()> {
490        int.try_to_bool()
491    }
492}
493
494impl From<char> for ScalarInt {
495    #[inline]
496    fn from(c: char) -> Self {
497        (c as u32).into()
498    }
499}
500
501macro_rules! from_x_for_scalar_int_signed {
502    ($($ty:ty),*) => {
503        $(
504            impl From<$ty> for ScalarInt {
505                #[inline]
506                fn from(u: $ty) -> Self {
507                    Self {
508                        data: u128::from(u.cast_unsigned()), // go via the unsigned type of the same size
509                        size: NonZero::new(size_of::<$ty>() as u8).unwrap(),
510                    }
511                }
512            }
513        )*
514    }
515}
516
517macro_rules! from_scalar_int_for_x_signed {
518    ($($ty:ty),*) => {
519        $(
520            impl From<ScalarInt> for $ty {
521                #[inline]
522                fn from(int: ScalarInt) -> Self {
523                    // The `unwrap` cannot fail because to_int (if it succeeds)
524                    // is guaranteed to return a value that fits into the size.
525                    int.to_int(Size::from_bytes(size_of::<$ty>()))
526                       .try_into().unwrap()
527                }
528            }
529        )*
530    }
531}
532
533impl From<i8> for ScalarInt {
    #[inline]
    fn from(u: i8) -> Self {
        Self {
            data: u128::from(u.cast_unsigned()),
            size: NonZero::new(size_of::<i8>() as u8).unwrap(),
        }
    }
}
impl From<i16> for ScalarInt {
    #[inline]
    fn from(u: i16) -> Self {
        Self {
            data: u128::from(u.cast_unsigned()),
            size: NonZero::new(size_of::<i16>() as u8).unwrap(),
        }
    }
}
impl From<i32> for ScalarInt {
    #[inline]
    fn from(u: i32) -> Self {
        Self {
            data: u128::from(u.cast_unsigned()),
            size: NonZero::new(size_of::<i32>() as u8).unwrap(),
        }
    }
}
impl From<i64> for ScalarInt {
    #[inline]
    fn from(u: i64) -> Self {
        Self {
            data: u128::from(u.cast_unsigned()),
            size: NonZero::new(size_of::<i64>() as u8).unwrap(),
        }
    }
}
impl From<i128> for ScalarInt {
    #[inline]
    fn from(u: i128) -> Self {
        Self {
            data: u128::from(u.cast_unsigned()),
            size: NonZero::new(size_of::<i128>() as u8).unwrap(),
        }
    }
}from_x_for_scalar_int_signed!(i8, i16, i32, i64, i128);
534impl From<ScalarInt> for i8 {
    #[inline]
    fn from(int: ScalarInt) -> Self {
        int.to_int(Size::from_bytes(size_of::<i8>())).try_into().unwrap()
    }
}
impl From<ScalarInt> for i16 {
    #[inline]
    fn from(int: ScalarInt) -> Self {
        int.to_int(Size::from_bytes(size_of::<i16>())).try_into().unwrap()
    }
}
impl From<ScalarInt> for i32 {
    #[inline]
    fn from(int: ScalarInt) -> Self {
        int.to_int(Size::from_bytes(size_of::<i32>())).try_into().unwrap()
    }
}
impl From<ScalarInt> for i64 {
    #[inline]
    fn from(int: ScalarInt) -> Self {
        int.to_int(Size::from_bytes(size_of::<i64>())).try_into().unwrap()
    }
}
impl From<ScalarInt> for i128 {
    #[inline]
    fn from(int: ScalarInt) -> Self {
        int.to_int(Size::from_bytes(size_of::<i128>())).try_into().unwrap()
    }
}from_scalar_int_for_x_signed!(i8, i16, i32, i64, i128);
535
536impl From<std::cmp::Ordering> for ScalarInt {
537    #[inline]
538    fn from(c: std::cmp::Ordering) -> Self {
539        // Here we rely on `cmp::Ordering` having the same values in host and target!
540        ScalarInt::from(c as i8)
541    }
542}
543
544/// Error returned when a conversion from ScalarInt to char fails.
545#[derive(#[automatically_derived]
impl ::core::fmt::Debug for CharTryFromScalarInt {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f, "CharTryFromScalarInt")
    }
}Debug)]
546pub struct CharTryFromScalarInt;
547
548impl TryFrom<ScalarInt> for char {
549    type Error = CharTryFromScalarInt;
550
551    #[inline]
552    fn try_from(int: ScalarInt) -> Result<Self, Self::Error> {
553        match char::from_u32(int.to_u32()) {
554            Some(c) => Ok(c),
555            None => Err(CharTryFromScalarInt),
556        }
557    }
558}
559
560impl From<Half> for ScalarInt {
561    #[inline]
562    fn from(f: Half) -> Self {
563        // We trust apfloat to give us properly truncated data.
564        Self { data: f.to_bits(), size: NonZero::new((Half::BITS / 8) as u8).unwrap() }
565    }
566}
567
568impl From<ScalarInt> for Half {
569    #[inline]
570    fn from(int: ScalarInt) -> Self {
571        Self::from_bits(int.to_bits(Size::from_bytes(2)))
572    }
573}
574
575impl From<Single> for ScalarInt {
576    #[inline]
577    fn from(f: Single) -> Self {
578        // We trust apfloat to give us properly truncated data.
579        Self { data: f.to_bits(), size: NonZero::new((Single::BITS / 8) as u8).unwrap() }
580    }
581}
582
583impl From<ScalarInt> for Single {
584    #[inline]
585    fn from(int: ScalarInt) -> Self {
586        Self::from_bits(int.to_bits(Size::from_bytes(4)))
587    }
588}
589
590impl From<Double> for ScalarInt {
591    #[inline]
592    fn from(f: Double) -> Self {
593        // We trust apfloat to give us properly truncated data.
594        Self { data: f.to_bits(), size: NonZero::new((Double::BITS / 8) as u8).unwrap() }
595    }
596}
597
598impl From<ScalarInt> for Double {
599    #[inline]
600    fn from(int: ScalarInt) -> Self {
601        Self::from_bits(int.to_bits(Size::from_bytes(8)))
602    }
603}
604
605impl From<Quad> for ScalarInt {
606    #[inline]
607    fn from(f: Quad) -> Self {
608        // We trust apfloat to give us properly truncated data.
609        Self { data: f.to_bits(), size: NonZero::new((Quad::BITS / 8) as u8).unwrap() }
610    }
611}
612
613impl From<ScalarInt> for Quad {
614    #[inline]
615    fn from(int: ScalarInt) -> Self {
616        Self::from_bits(int.to_bits(Size::from_bytes(16)))
617    }
618}
619
620impl fmt::Debug for ScalarInt {
621    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
622        // Dispatch to LowerHex below.
623        f.write_fmt(format_args!("0x{0:x}", self))write!(f, "0x{self:x}")
624    }
625}
626
627impl fmt::LowerHex for ScalarInt {
628    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
629        self.check_data();
630        if f.alternate() {
631            // Like regular ints, alternate flag adds leading `0x`.
632            f.write_fmt(format_args!("0x"))write!(f, "0x")?;
633        }
634        // Format as hex number wide enough to fit any value of the given `size`.
635        // So data=20, size=1 will be "0x14", but with size=4 it'll be "0x00000014".
636        // Using a block `{self.data}` here to force a copy instead of using `self.data`
637        // directly, because `write!` takes references to its formatting arguments and
638        // would thus borrow `self.data`. Since `Self`
639        // is a packed struct, that would create a possibly unaligned reference, which
640        // is UB.
641        f.write_fmt(format_args!("{0:01$x}", { self.data },
        self.size.get() as usize * 2))write!(f, "{:01$x}", { self.data }, self.size.get() as usize * 2)
642    }
643}
644
645impl fmt::UpperHex for ScalarInt {
646    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
647        self.check_data();
648        // Format as hex number wide enough to fit any value of the given `size`.
649        // So data=20, size=1 will be "0x14", but with size=4 it'll be "0x00000014".
650        // Using a block `{self.data}` here to force a copy instead of using `self.data`
651        // directly, because `write!` takes references to its formatting arguments and
652        // would thus borrow `self.data`. Since `Self`
653        // is a packed struct, that would create a possibly unaligned reference, which
654        // is UB.
655        f.write_fmt(format_args!("{0:01$X}", { self.data },
        self.size.get() as usize * 2))write!(f, "{:01$X}", { self.data }, self.size.get() as usize * 2)
656    }
657}
658
659impl fmt::Display for ScalarInt {
660    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
661        self.check_data();
662        f.write_fmt(format_args!("{0}", { self.data }))write!(f, "{}", { self.data })
663    }
664}