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