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_errors::{DiagArgValue, IntoDiagArg};
8use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
9
10use crate::ty::TyCtxt;
11
12#[derive(Copy, Clone)]
13pub struct ConstInt {
15 int: ScalarInt,
17 signed: bool,
19 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
29impl std::fmt::Debug for ConstInt {
30 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31 let Self { int, signed, is_ptr_sized_integral } = *self;
32 let size = int.size().bytes();
33 let raw = int.data;
34 if signed {
35 let bit_size = size * 8;
36 let min = 1u128 << (bit_size - 1);
37 let max = min - 1;
38 if raw == min {
39 match (size, is_ptr_sized_integral) {
40 (_, true) => write!(fmt, "isize::MIN"),
41 (1, _) => write!(fmt, "i8::MIN"),
42 (2, _) => write!(fmt, "i16::MIN"),
43 (4, _) => write!(fmt, "i32::MIN"),
44 (8, _) => write!(fmt, "i64::MIN"),
45 (16, _) => write!(fmt, "i128::MIN"),
46 _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
47 }
48 } else if raw == max {
49 match (size, is_ptr_sized_integral) {
50 (_, true) => write!(fmt, "isize::MAX"),
51 (1, _) => write!(fmt, "i8::MAX"),
52 (2, _) => write!(fmt, "i16::MAX"),
53 (4, _) => write!(fmt, "i32::MAX"),
54 (8, _) => write!(fmt, "i64::MAX"),
55 (16, _) => write!(fmt, "i128::MAX"),
56 _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
57 }
58 } else {
59 match size {
60 1 => write!(fmt, "{}", raw as i8)?,
61 2 => write!(fmt, "{}", raw as i16)?,
62 4 => write!(fmt, "{}", raw as i32)?,
63 8 => write!(fmt, "{}", raw as i64)?,
64 16 => write!(fmt, "{}", raw as i128)?,
65 _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
66 }
67 if fmt.alternate() {
68 match (size, is_ptr_sized_integral) {
69 (_, true) => write!(fmt, "_isize")?,
70 (1, _) => write!(fmt, "_i8")?,
71 (2, _) => write!(fmt, "_i16")?,
72 (4, _) => write!(fmt, "_i32")?,
73 (8, _) => write!(fmt, "_i64")?,
74 (16, _) => write!(fmt, "_i128")?,
75 (sz, _) => bug!("unexpected int size i{sz}"),
76 }
77 }
78 Ok(())
79 }
80 } else {
81 let max = Size::from_bytes(size).truncate(u128::MAX);
82 if raw == max {
83 match (size, is_ptr_sized_integral) {
84 (_, true) => write!(fmt, "usize::MAX"),
85 (1, _) => write!(fmt, "u8::MAX"),
86 (2, _) => write!(fmt, "u16::MAX"),
87 (4, _) => write!(fmt, "u32::MAX"),
88 (8, _) => write!(fmt, "u64::MAX"),
89 (16, _) => write!(fmt, "u128::MAX"),
90 _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
91 }
92 } else {
93 match size {
94 1 => write!(fmt, "{}", raw as u8)?,
95 2 => write!(fmt, "{}", raw as u16)?,
96 4 => write!(fmt, "{}", raw as u32)?,
97 8 => write!(fmt, "{}", raw as u64)?,
98 16 => write!(fmt, "{}", raw as u128)?,
99 _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
100 }
101 if fmt.alternate() {
102 match (size, is_ptr_sized_integral) {
103 (_, true) => write!(fmt, "_usize")?,
104 (1, _) => write!(fmt, "_u8")?,
105 (2, _) => write!(fmt, "_u16")?,
106 (4, _) => write!(fmt, "_u32")?,
107 (8, _) => write!(fmt, "_u64")?,
108 (16, _) => write!(fmt, "_u128")?,
109 (sz, _) => bug!("unexpected unsigned int size u{sz}"),
110 }
111 }
112 Ok(())
113 }
114 }
115 }
116}
117
118impl IntoDiagArg for ConstInt {
119 fn into_diag_arg(self) -> DiagArgValue {
122 DiagArgValue::Str(format!("{self:?}").into())
123 }
124}
125
126#[derive(Clone, Copy, Eq, PartialEq, Hash)]
131#[repr(packed)]
132pub struct ScalarInt {
133 data: u128,
136 size: NonZero<u8>,
137}
138
139impl<CTX> crate::ty::HashStable<CTX> for ScalarInt {
142 fn hash_stable(&self, hcx: &mut CTX, hasher: &mut crate::ty::StableHasher) {
143 { self.data }.hash_stable(hcx, hasher);
148 self.size.get().hash_stable(hcx, hasher);
149 }
150}
151
152impl<S: Encoder> Encodable<S> for ScalarInt {
153 fn encode(&self, s: &mut S) {
154 let size = self.size.get();
155 s.emit_u8(size);
156 s.emit_raw_bytes(&self.data.to_le_bytes()[..size as usize]);
157 }
158}
159
160impl<D: Decoder> Decodable<D> for ScalarInt {
161 fn decode(d: &mut D) -> ScalarInt {
162 let mut data = [0u8; 16];
163 let size = d.read_u8();
164 data[..size as usize].copy_from_slice(d.read_raw_bytes(size as usize));
165 ScalarInt { data: u128::from_le_bytes(data), size: NonZero::new(size).unwrap() }
166 }
167}
168
169impl ScalarInt {
170 pub const TRUE: ScalarInt = ScalarInt { data: 1_u128, size: NonZero::new(1).unwrap() };
171 pub const FALSE: ScalarInt = ScalarInt { data: 0_u128, size: NonZero::new(1).unwrap() };
172
173 fn raw(data: u128, size: Size) -> Self {
174 Self { data, size: NonZero::new(size.bytes() as u8).unwrap() }
175 }
176
177 #[inline]
178 pub fn size(self) -> Size {
179 Size::from_bytes(self.size.get())
180 }
181
182 #[inline(always)]
186 fn check_data(self) {
187 debug_assert_eq!(
193 self.size().truncate(self.data),
194 { self.data },
195 "Scalar value {:#x} exceeds size of {} bytes",
196 { self.data },
197 self.size
198 );
199 }
200
201 #[inline]
202 pub fn null(size: Size) -> Self {
203 Self::raw(0, size)
204 }
205
206 #[inline]
207 pub fn is_null(self) -> bool {
208 self.data == 0
209 }
210
211 #[inline]
212 pub fn try_from_uint(i: impl Into<u128>, size: Size) -> Option<Self> {
213 let (r, overflow) = Self::truncate_from_uint(i, size);
214 if overflow { None } else { Some(r) }
215 }
216
217 #[inline]
219 pub fn truncate_from_uint(i: impl Into<u128>, size: Size) -> (Self, bool) {
220 let data = i.into();
221 let r = Self::raw(size.truncate(data), size);
222 (r, r.data != data)
223 }
224
225 #[inline]
226 pub fn try_from_int(i: impl Into<i128>, size: Size) -> Option<Self> {
227 let (r, overflow) = Self::truncate_from_int(i, size);
228 if overflow { None } else { Some(r) }
229 }
230
231 #[inline]
233 pub fn truncate_from_int(i: impl Into<i128>, size: Size) -> (Self, bool) {
234 let data = i.into();
235 let r = Self::raw(size.truncate(data as u128), size);
237 (r, size.sign_extend(r.data) != data)
238 }
239
240 #[inline]
241 pub fn try_from_target_usize(i: impl Into<u128>, tcx: TyCtxt<'_>) -> Option<Self> {
242 Self::try_from_uint(i, tcx.data_layout.pointer_size)
243 }
244
245 #[inline]
250 pub fn try_to_bits(self, target_size: Size) -> Result<u128, Size> {
251 assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST");
252 if target_size.bytes() == u64::from(self.size.get()) {
253 self.check_data();
254 Ok(self.data)
255 } else {
256 Err(self.size())
257 }
258 }
259
260 #[inline]
261 pub fn to_bits(self, target_size: Size) -> u128 {
262 self.try_to_bits(target_size).unwrap_or_else(|size| {
263 bug!("expected int of size {}, but got size {}", target_size.bytes(), size.bytes())
264 })
265 }
266
267 #[inline]
269 pub fn to_bits_unchecked(self) -> u128 {
270 self.check_data();
271 self.data
272 }
273
274 #[inline]
277 pub fn to_uint(self, size: Size) -> u128 {
278 self.to_bits(size)
279 }
280
281 #[inline]
284 pub fn to_u8(self) -> u8 {
285 self.to_uint(Size::from_bits(8)).try_into().unwrap()
286 }
287
288 #[inline]
291 pub fn to_u16(self) -> u16 {
292 self.to_uint(Size::from_bits(16)).try_into().unwrap()
293 }
294
295 #[inline]
298 pub fn to_u32(self) -> u32 {
299 self.to_uint(Size::from_bits(32)).try_into().unwrap()
300 }
301
302 #[inline]
305 pub fn to_u64(self) -> u64 {
306 self.to_uint(Size::from_bits(64)).try_into().unwrap()
307 }
308
309 #[inline]
312 pub fn to_u128(self) -> u128 {
313 self.to_uint(Size::from_bits(128))
314 }
315
316 #[inline]
317 pub fn to_target_usize(&self, tcx: TyCtxt<'_>) -> u64 {
318 self.to_uint(tcx.data_layout.pointer_size).try_into().unwrap()
319 }
320
321 #[inline]
325 pub fn try_to_bool(self) -> Result<bool, ()> {
326 match self.to_u8() {
327 0 => Ok(false),
328 1 => Ok(true),
329 _ => Err(()),
330 }
331 }
332
333 #[inline]
336 pub fn to_int(self, size: Size) -> i128 {
337 let b = self.to_bits(size);
338 size.sign_extend(b)
339 }
340
341 pub fn to_i8(self) -> i8 {
344 self.to_int(Size::from_bits(8)).try_into().unwrap()
345 }
346
347 pub fn to_i16(self) -> i16 {
350 self.to_int(Size::from_bits(16)).try_into().unwrap()
351 }
352
353 pub fn to_i32(self) -> i32 {
356 self.to_int(Size::from_bits(32)).try_into().unwrap()
357 }
358
359 pub fn to_i64(self) -> i64 {
362 self.to_int(Size::from_bits(64)).try_into().unwrap()
363 }
364
365 pub fn to_i128(self) -> i128 {
368 self.to_int(Size::from_bits(128))
369 }
370
371 #[inline]
372 pub fn to_target_isize(&self, tcx: TyCtxt<'_>) -> i64 {
373 self.to_int(tcx.data_layout.pointer_size).try_into().unwrap()
374 }
375
376 #[inline]
377 pub fn to_float<F: Float>(self) -> F {
378 F::from_bits(self.to_bits(Size::from_bits(F::BITS)))
380 }
381
382 #[inline]
383 pub fn to_f16(self) -> Half {
384 self.to_float()
385 }
386
387 #[inline]
388 pub fn to_f32(self) -> Single {
389 self.to_float()
390 }
391
392 #[inline]
393 pub fn to_f64(self) -> Double {
394 self.to_float()
395 }
396
397 #[inline]
398 pub fn to_f128(self) -> Quad {
399 self.to_float()
400 }
401}
402
403macro_rules! from_x_for_scalar_int {
404 ($($ty:ty),*) => {
405 $(
406 impl From<$ty> for ScalarInt {
407 #[inline]
408 fn from(u: $ty) -> Self {
409 Self {
410 data: u128::from(u),
411 size: NonZero::new(std::mem::size_of::<$ty>() as u8).unwrap(),
412 }
413 }
414 }
415 )*
416 }
417}
418
419macro_rules! from_scalar_int_for_x {
420 ($($ty:ty),*) => {
421 $(
422 impl From<ScalarInt> for $ty {
423 #[inline]
424 fn from(int: ScalarInt) -> Self {
425 int.to_bits(Size::from_bytes(std::mem::size_of::<$ty>()))
428 .try_into().unwrap()
429 }
430 }
431 )*
432 }
433}
434
435from_x_for_scalar_int!(u8, u16, u32, u64, u128, bool);
436from_scalar_int_for_x!(u8, u16, u32, u64, u128);
437
438impl TryFrom<ScalarInt> for bool {
439 type Error = ();
440 #[inline]
441 fn try_from(int: ScalarInt) -> Result<Self, ()> {
442 int.try_to_bool()
443 }
444}
445
446impl From<char> for ScalarInt {
447 #[inline]
448 fn from(c: char) -> Self {
449 (c as u32).into()
450 }
451}
452
453#[derive(Debug)]
455pub struct CharTryFromScalarInt;
456
457impl TryFrom<ScalarInt> for char {
458 type Error = CharTryFromScalarInt;
459
460 #[inline]
461 fn try_from(int: ScalarInt) -> Result<Self, Self::Error> {
462 match char::from_u32(int.to_u32()) {
463 Some(c) => Ok(c),
464 None => Err(CharTryFromScalarInt),
465 }
466 }
467}
468
469impl From<Half> for ScalarInt {
470 #[inline]
471 fn from(f: Half) -> Self {
472 Self { data: f.to_bits(), size: NonZero::new((Half::BITS / 8) as u8).unwrap() }
474 }
475}
476
477impl From<ScalarInt> for Half {
478 #[inline]
479 fn from(int: ScalarInt) -> Self {
480 Self::from_bits(int.to_bits(Size::from_bytes(2)))
481 }
482}
483
484impl From<Single> for ScalarInt {
485 #[inline]
486 fn from(f: Single) -> Self {
487 Self { data: f.to_bits(), size: NonZero::new((Single::BITS / 8) as u8).unwrap() }
489 }
490}
491
492impl From<ScalarInt> for Single {
493 #[inline]
494 fn from(int: ScalarInt) -> Self {
495 Self::from_bits(int.to_bits(Size::from_bytes(4)))
496 }
497}
498
499impl From<Double> for ScalarInt {
500 #[inline]
501 fn from(f: Double) -> Self {
502 Self { data: f.to_bits(), size: NonZero::new((Double::BITS / 8) as u8).unwrap() }
504 }
505}
506
507impl From<ScalarInt> for Double {
508 #[inline]
509 fn from(int: ScalarInt) -> Self {
510 Self::from_bits(int.to_bits(Size::from_bytes(8)))
511 }
512}
513
514impl From<Quad> for ScalarInt {
515 #[inline]
516 fn from(f: Quad) -> Self {
517 Self { data: f.to_bits(), size: NonZero::new((Quad::BITS / 8) as u8).unwrap() }
519 }
520}
521
522impl From<ScalarInt> for Quad {
523 #[inline]
524 fn from(int: ScalarInt) -> Self {
525 Self::from_bits(int.to_bits(Size::from_bytes(16)))
526 }
527}
528
529impl fmt::Debug for ScalarInt {
530 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
531 write!(f, "0x{self:x}")
533 }
534}
535
536impl fmt::LowerHex for ScalarInt {
537 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
538 self.check_data();
539 if f.alternate() {
540 write!(f, "0x")?;
542 }
543 write!(f, "{:01$x}", { self.data }, self.size.get() as usize * 2)
551 }
552}
553
554impl fmt::UpperHex for ScalarInt {
555 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
556 self.check_data();
557 write!(f, "{:01$X}", { self.data }, self.size.get() as usize * 2)
565 }
566}
567
568impl fmt::Display for ScalarInt {
569 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
570 self.check_data();
571 write!(f, "{}", { self.data })
572 }
573}