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