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