]>
Commit | Line | Data |
---|---|---|
29967ef6 XL |
1 | use rustc_apfloat::ieee::{Double, Single}; |
2 | use rustc_apfloat::Float; | |
3 | use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; | |
136023e0 | 4 | use rustc_target::abi::Size; |
29967ef6 XL |
5 | use std::convert::{TryFrom, TryInto}; |
6 | use std::fmt; | |
064997fb | 7 | use std::num::NonZeroU8; |
3dfed10e | 8 | |
6a06907d XL |
9 | use crate::ty::TyCtxt; |
10 | ||
3dfed10e XL |
11 | #[derive(Copy, Clone)] |
12 | /// A type for representing any integer. Only used for printing. | |
3dfed10e | 13 | pub struct ConstInt { |
29967ef6 XL |
14 | /// The "untyped" variant of `ConstInt`. |
15 | int: ScalarInt, | |
3dfed10e XL |
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, | |
3dfed10e XL |
20 | } |
21 | ||
22 | impl ConstInt { | |
29967ef6 XL |
23 | pub fn new(int: ScalarInt, signed: bool, is_ptr_sized_integral: bool) -> Self { |
24 | Self { int, signed, is_ptr_sized_integral } | |
3dfed10e XL |
25 | } |
26 | } | |
27 | ||
28 | impl std::fmt::Debug for ConstInt { | |
29 | fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | |
29967ef6 XL |
30 | let Self { int, signed, is_ptr_sized_integral } = *self; |
31 | let size = int.size().bytes(); | |
32 | let raw = int.data; | |
3dfed10e XL |
33 | if signed { |
34 | let bit_size = size * 8; | |
35 | let min = 1u128 << (bit_size - 1); | |
36 | let max = min - 1; | |
37 | if raw == min { | |
38 | match (size, is_ptr_sized_integral) { | |
39 | (_, true) => write!(fmt, "isize::MIN"), | |
40 | (1, _) => write!(fmt, "i8::MIN"), | |
41 | (2, _) => write!(fmt, "i16::MIN"), | |
42 | (4, _) => write!(fmt, "i32::MIN"), | |
43 | (8, _) => write!(fmt, "i64::MIN"), | |
44 | (16, _) => write!(fmt, "i128::MIN"), | |
45 | _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed), | |
46 | } | |
47 | } else if raw == max { | |
48 | match (size, is_ptr_sized_integral) { | |
49 | (_, true) => write!(fmt, "isize::MAX"), | |
50 | (1, _) => write!(fmt, "i8::MAX"), | |
51 | (2, _) => write!(fmt, "i16::MAX"), | |
52 | (4, _) => write!(fmt, "i32::MAX"), | |
53 | (8, _) => write!(fmt, "i64::MAX"), | |
54 | (16, _) => write!(fmt, "i128::MAX"), | |
55 | _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed), | |
56 | } | |
57 | } else { | |
58 | match size { | |
59 | 1 => write!(fmt, "{}", raw as i8)?, | |
60 | 2 => write!(fmt, "{}", raw as i16)?, | |
61 | 4 => write!(fmt, "{}", raw as i32)?, | |
62 | 8 => write!(fmt, "{}", raw as i64)?, | |
63 | 16 => write!(fmt, "{}", raw as i128)?, | |
64 | _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed), | |
65 | } | |
66 | if fmt.alternate() { | |
67 | match (size, is_ptr_sized_integral) { | |
68 | (_, true) => write!(fmt, "_isize")?, | |
69 | (1, _) => write!(fmt, "_i8")?, | |
70 | (2, _) => write!(fmt, "_i16")?, | |
71 | (4, _) => write!(fmt, "_i32")?, | |
72 | (8, _) => write!(fmt, "_i64")?, | |
73 | (16, _) => write!(fmt, "_i128")?, | |
74 | _ => bug!(), | |
75 | } | |
76 | } | |
77 | Ok(()) | |
78 | } | |
79 | } else { | |
29967ef6 | 80 | let max = Size::from_bytes(size).truncate(u128::MAX); |
3dfed10e XL |
81 | if raw == max { |
82 | match (size, is_ptr_sized_integral) { | |
83 | (_, true) => write!(fmt, "usize::MAX"), | |
84 | (1, _) => write!(fmt, "u8::MAX"), | |
85 | (2, _) => write!(fmt, "u16::MAX"), | |
86 | (4, _) => write!(fmt, "u32::MAX"), | |
87 | (8, _) => write!(fmt, "u64::MAX"), | |
88 | (16, _) => write!(fmt, "u128::MAX"), | |
89 | _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed), | |
90 | } | |
91 | } else { | |
92 | match size { | |
93 | 1 => write!(fmt, "{}", raw as u8)?, | |
94 | 2 => write!(fmt, "{}", raw as u16)?, | |
95 | 4 => write!(fmt, "{}", raw as u32)?, | |
96 | 8 => write!(fmt, "{}", raw as u64)?, | |
97 | 16 => write!(fmt, "{}", raw as u128)?, | |
98 | _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed), | |
99 | } | |
100 | if fmt.alternate() { | |
101 | match (size, is_ptr_sized_integral) { | |
102 | (_, true) => write!(fmt, "_usize")?, | |
103 | (1, _) => write!(fmt, "_u8")?, | |
104 | (2, _) => write!(fmt, "_u16")?, | |
105 | (4, _) => write!(fmt, "_u32")?, | |
106 | (8, _) => write!(fmt, "_u64")?, | |
107 | (16, _) => write!(fmt, "_u128")?, | |
108 | _ => bug!(), | |
109 | } | |
110 | } | |
111 | Ok(()) | |
112 | } | |
113 | } | |
114 | } | |
115 | } | |
29967ef6 XL |
116 | |
117 | /// The raw bytes of a simple value. | |
118 | /// | |
119 | /// This is a packed struct in order to allow this type to be optimally embedded in enums | |
120 | /// (like Scalar). | |
121 | #[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] | |
122 | #[repr(packed)] | |
123 | pub struct ScalarInt { | |
124 | /// The first `size` bytes of `data` are the value. | |
125 | /// Do not try to read less or more bytes than that. The remaining bytes must be 0. | |
126 | data: u128, | |
064997fb | 127 | size: NonZeroU8, |
29967ef6 XL |
128 | } |
129 | ||
130 | // Cannot derive these, as the derives take references to the fields, and we | |
131 | // can't take references to fields of packed structs. | |
132 | impl<CTX> crate::ty::HashStable<CTX> for ScalarInt { | |
133 | fn hash_stable(&self, hcx: &mut CTX, hasher: &mut crate::ty::StableHasher) { | |
134 | // Using a block `{self.data}` here to force a copy instead of using `self.data` | |
135 | // directly, because `hash_stable` takes `&self` and would thus borrow `self.data`. | |
136 | // Since `Self` is a packed struct, that would create a possibly unaligned reference, | |
137 | // which is UB. | |
138 | { self.data }.hash_stable(hcx, hasher); | |
064997fb | 139 | self.size.get().hash_stable(hcx, hasher); |
29967ef6 XL |
140 | } |
141 | } | |
142 | ||
143 | impl<S: Encoder> Encodable<S> for ScalarInt { | |
923072b8 FG |
144 | fn encode(&self, s: &mut S) { |
145 | s.emit_u128(self.data); | |
064997fb | 146 | s.emit_u8(self.size.get()); |
29967ef6 XL |
147 | } |
148 | } | |
149 | ||
150 | impl<D: Decoder> Decodable<D> for ScalarInt { | |
5099ac24 | 151 | fn decode(d: &mut D) -> ScalarInt { |
064997fb | 152 | ScalarInt { data: d.read_u128(), size: NonZeroU8::new(d.read_u8()).unwrap() } |
29967ef6 XL |
153 | } |
154 | } | |
155 | ||
156 | impl ScalarInt { | |
064997fb | 157 | pub const TRUE: ScalarInt = ScalarInt { data: 1_u128, size: NonZeroU8::new(1).unwrap() }; |
29967ef6 | 158 | |
064997fb | 159 | pub const FALSE: ScalarInt = ScalarInt { data: 0_u128, size: NonZeroU8::new(1).unwrap() }; |
29967ef6 XL |
160 | |
161 | #[inline] | |
162 | pub fn size(self) -> Size { | |
064997fb | 163 | Size::from_bytes(self.size.get()) |
29967ef6 XL |
164 | } |
165 | ||
166 | /// Make sure the `data` fits in `size`. | |
167 | /// This is guaranteed by all constructors here, but having had this check saved us from | |
168 | /// bugs many times in the past, so keeping it around is definitely worth it. | |
169 | #[inline(always)] | |
170 | fn check_data(self) { | |
171 | // Using a block `{self.data}` here to force a copy instead of using `self.data` | |
172 | // directly, because `debug_assert_eq` takes references to its arguments and formatting | |
173 | // arguments and would thus borrow `self.data`. Since `Self` | |
174 | // is a packed struct, that would create a possibly unaligned reference, which | |
175 | // is UB. | |
176 | debug_assert_eq!( | |
177 | self.size().truncate(self.data), | |
178 | { self.data }, | |
179 | "Scalar value {:#x} exceeds size of {} bytes", | |
180 | { self.data }, | |
181 | self.size | |
182 | ); | |
183 | } | |
184 | ||
185 | #[inline] | |
186 | pub fn null(size: Size) -> Self { | |
064997fb | 187 | Self { data: 0, size: NonZeroU8::new(size.bytes() as u8).unwrap() } |
29967ef6 XL |
188 | } |
189 | ||
190 | #[inline] | |
191 | pub fn is_null(self) -> bool { | |
192 | self.data == 0 | |
193 | } | |
194 | ||
29967ef6 XL |
195 | #[inline] |
196 | pub fn try_from_uint(i: impl Into<u128>, size: Size) -> Option<Self> { | |
197 | let data = i.into(); | |
198 | if size.truncate(data) == data { | |
064997fb | 199 | Some(Self { data, size: NonZeroU8::new(size.bytes() as u8).unwrap() }) |
29967ef6 XL |
200 | } else { |
201 | None | |
202 | } | |
203 | } | |
204 | ||
205 | #[inline] | |
206 | pub fn try_from_int(i: impl Into<i128>, size: Size) -> Option<Self> { | |
207 | let i = i.into(); | |
208 | // `into` performed sign extension, we have to truncate | |
209 | let truncated = size.truncate(i as u128); | |
210 | if size.sign_extend(truncated) as i128 == i { | |
064997fb | 211 | Some(Self { data: truncated, size: NonZeroU8::new(size.bytes() as u8).unwrap() }) |
29967ef6 XL |
212 | } else { |
213 | None | |
214 | } | |
215 | } | |
216 | ||
217 | #[inline] | |
218 | pub fn assert_bits(self, target_size: Size) -> u128 { | |
219 | self.to_bits(target_size).unwrap_or_else(|size| { | |
220 | bug!("expected int of size {}, but got size {}", target_size.bytes(), size.bytes()) | |
221 | }) | |
222 | } | |
223 | ||
224 | #[inline] | |
225 | pub fn to_bits(self, target_size: Size) -> Result<u128, Size> { | |
226 | assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST"); | |
064997fb | 227 | if target_size.bytes() == u64::from(self.size.get()) { |
29967ef6 XL |
228 | self.check_data(); |
229 | Ok(self.data) | |
230 | } else { | |
231 | Err(self.size()) | |
232 | } | |
233 | } | |
6a06907d XL |
234 | |
235 | #[inline] | |
a2a8927a | 236 | pub fn try_to_machine_usize<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Result<u64, Size> { |
6a06907d XL |
237 | Ok(self.to_bits(tcx.data_layout.pointer_size)? as u64) |
238 | } | |
04454e1e FG |
239 | |
240 | /// Tries to convert the `ScalarInt` to an unsigned integer of the given size. | |
241 | /// Fails if the size of the `ScalarInt` is unequal to `size` and returns the | |
242 | /// `ScalarInt`s size in that case. | |
243 | #[inline] | |
244 | pub fn try_to_uint(self, size: Size) -> Result<u128, Size> { | |
245 | self.to_bits(size) | |
246 | } | |
247 | ||
487cf647 FG |
248 | // Tries to convert the `ScalarInt` to `bool`. Fails if the `size` of the `ScalarInt` |
249 | // in not equal to `Size { raw: 1 }` or if the value is not 0 or 1 and returns the `size` | |
250 | // value of the `ScalarInt` in that case. | |
251 | #[inline] | |
252 | pub fn try_to_bool(self) -> Result<bool, Size> { | |
253 | match self.try_to_u8()? { | |
254 | 0 => Ok(false), | |
255 | 1 => Ok(true), | |
256 | _ => Err(self.size()), | |
257 | } | |
258 | } | |
259 | ||
04454e1e FG |
260 | // Tries to convert the `ScalarInt` to `u8`. Fails if the `size` of the `ScalarInt` |
261 | // in not equal to `Size { raw: 1 }` and returns the `size` value of the `ScalarInt` in | |
262 | // that case. | |
263 | #[inline] | |
264 | pub fn try_to_u8(self) -> Result<u8, Size> { | |
265 | self.to_bits(Size::from_bits(8)).map(|v| u8::try_from(v).unwrap()) | |
266 | } | |
267 | ||
268 | /// Tries to convert the `ScalarInt` to `u16`. Fails if the size of the `ScalarInt` | |
269 | /// in not equal to `Size { raw: 2 }` and returns the `size` value of the `ScalarInt` in | |
270 | /// that case. | |
271 | #[inline] | |
272 | pub fn try_to_u16(self) -> Result<u16, Size> { | |
273 | self.to_bits(Size::from_bits(16)).map(|v| u16::try_from(v).unwrap()) | |
274 | } | |
275 | ||
276 | /// Tries to convert the `ScalarInt` to `u32`. Fails if the `size` of the `ScalarInt` | |
277 | /// in not equal to `Size { raw: 4 }` and returns the `size` value of the `ScalarInt` in | |
278 | /// that case. | |
279 | #[inline] | |
280 | pub fn try_to_u32(self) -> Result<u32, Size> { | |
281 | self.to_bits(Size::from_bits(32)).map(|v| u32::try_from(v).unwrap()) | |
282 | } | |
283 | ||
284 | /// Tries to convert the `ScalarInt` to `u64`. Fails if the `size` of the `ScalarInt` | |
285 | /// in not equal to `Size { raw: 8 }` and returns the `size` value of the `ScalarInt` in | |
286 | /// that case. | |
287 | #[inline] | |
288 | pub fn try_to_u64(self) -> Result<u64, Size> { | |
289 | self.to_bits(Size::from_bits(64)).map(|v| u64::try_from(v).unwrap()) | |
290 | } | |
291 | ||
292 | /// Tries to convert the `ScalarInt` to `u128`. Fails if the `size` of the `ScalarInt` | |
293 | /// in not equal to `Size { raw: 16 }` and returns the `size` value of the `ScalarInt` in | |
294 | /// that case. | |
295 | #[inline] | |
296 | pub fn try_to_u128(self) -> Result<u128, Size> { | |
297 | self.to_bits(Size::from_bits(128)) | |
298 | } | |
299 | ||
300 | /// Tries to convert the `ScalarInt` to a signed integer of the given size. | |
301 | /// Fails if the size of the `ScalarInt` is unequal to `size` and returns the | |
302 | /// `ScalarInt`s size in that case. | |
303 | #[inline] | |
304 | pub fn try_to_int(self, size: Size) -> Result<i128, Size> { | |
305 | let b = self.to_bits(size)?; | |
306 | Ok(size.sign_extend(b) as i128) | |
307 | } | |
308 | ||
309 | /// Tries to convert the `ScalarInt` to i8. | |
310 | /// Fails if the size of the `ScalarInt` is unequal to `Size { raw: 1 }` | |
311 | /// and returns the `ScalarInt`s size in that case. | |
312 | pub fn try_to_i8(self) -> Result<i8, Size> { | |
313 | self.try_to_int(Size::from_bits(8)).map(|v| i8::try_from(v).unwrap()) | |
314 | } | |
315 | ||
316 | /// Tries to convert the `ScalarInt` to i16. | |
317 | /// Fails if the size of the `ScalarInt` is unequal to `Size { raw: 2 }` | |
318 | /// and returns the `ScalarInt`s size in that case. | |
319 | pub fn try_to_i16(self) -> Result<i16, Size> { | |
320 | self.try_to_int(Size::from_bits(16)).map(|v| i16::try_from(v).unwrap()) | |
321 | } | |
322 | ||
323 | /// Tries to convert the `ScalarInt` to i32. | |
324 | /// Fails if the size of the `ScalarInt` is unequal to `Size { raw: 4 }` | |
325 | /// and returns the `ScalarInt`s size in that case. | |
326 | pub fn try_to_i32(self) -> Result<i32, Size> { | |
327 | self.try_to_int(Size::from_bits(32)).map(|v| i32::try_from(v).unwrap()) | |
328 | } | |
329 | ||
330 | /// Tries to convert the `ScalarInt` to i64. | |
331 | /// Fails if the size of the `ScalarInt` is unequal to `Size { raw: 8 }` | |
332 | /// and returns the `ScalarInt`s size in that case. | |
333 | pub fn try_to_i64(self) -> Result<i64, Size> { | |
334 | self.try_to_int(Size::from_bits(64)).map(|v| i64::try_from(v).unwrap()) | |
335 | } | |
336 | ||
337 | /// Tries to convert the `ScalarInt` to i128. | |
338 | /// Fails if the size of the `ScalarInt` is unequal to `Size { raw: 16 }` | |
339 | /// and returns the `ScalarInt`s size in that case. | |
340 | pub fn try_to_i128(self) -> Result<i128, Size> { | |
341 | self.try_to_int(Size::from_bits(128)).map(|v| i128::try_from(v).unwrap()) | |
342 | } | |
29967ef6 XL |
343 | } |
344 | ||
345 | macro_rules! from { | |
346 | ($($ty:ty),*) => { | |
347 | $( | |
348 | impl From<$ty> for ScalarInt { | |
349 | #[inline] | |
350 | fn from(u: $ty) -> Self { | |
351 | Self { | |
352 | data: u128::from(u), | |
064997fb | 353 | size: NonZeroU8::new(std::mem::size_of::<$ty>() as u8).unwrap(), |
29967ef6 XL |
354 | } |
355 | } | |
356 | } | |
357 | )* | |
358 | } | |
359 | } | |
360 | ||
361 | macro_rules! try_from { | |
362 | ($($ty:ty),*) => { | |
363 | $( | |
364 | impl TryFrom<ScalarInt> for $ty { | |
365 | type Error = Size; | |
366 | #[inline] | |
367 | fn try_from(int: ScalarInt) -> Result<Self, Size> { | |
368 | // The `unwrap` cannot fail because to_bits (if it succeeds) | |
369 | // is guaranteed to return a value that fits into the size. | |
370 | int.to_bits(Size::from_bytes(std::mem::size_of::<$ty>())) | |
371 | .map(|u| u.try_into().unwrap()) | |
372 | } | |
373 | } | |
374 | )* | |
375 | } | |
376 | } | |
377 | ||
378 | from!(u8, u16, u32, u64, u128, bool); | |
379 | try_from!(u8, u16, u32, u64, u128); | |
380 | ||
6a06907d XL |
381 | impl TryFrom<ScalarInt> for bool { |
382 | type Error = Size; | |
383 | #[inline] | |
384 | fn try_from(int: ScalarInt) -> Result<Self, Size> { | |
385 | int.to_bits(Size::from_bytes(1)).and_then(|u| match u { | |
386 | 0 => Ok(false), | |
387 | 1 => Ok(true), | |
388 | _ => Err(Size::from_bytes(1)), | |
389 | }) | |
390 | } | |
391 | } | |
392 | ||
29967ef6 XL |
393 | impl From<char> for ScalarInt { |
394 | #[inline] | |
395 | fn from(c: char) -> Self { | |
064997fb | 396 | Self { data: c as u128, size: NonZeroU8::new(std::mem::size_of::<char>() as u8).unwrap() } |
29967ef6 XL |
397 | } |
398 | } | |
399 | ||
5099ac24 FG |
400 | /// Error returned when a conversion from ScalarInt to char fails. |
401 | #[derive(Debug)] | |
402 | pub struct CharTryFromScalarInt; | |
403 | ||
29967ef6 | 404 | impl TryFrom<ScalarInt> for char { |
5099ac24 FG |
405 | type Error = CharTryFromScalarInt; |
406 | ||
29967ef6 | 407 | #[inline] |
5099ac24 FG |
408 | fn try_from(int: ScalarInt) -> Result<Self, Self::Error> { |
409 | let Ok(bits) = int.to_bits(Size::from_bytes(std::mem::size_of::<char>())) else { | |
410 | return Err(CharTryFromScalarInt); | |
411 | }; | |
412 | match char::from_u32(bits.try_into().unwrap()) { | |
413 | Some(c) => Ok(c), | |
414 | None => Err(CharTryFromScalarInt), | |
415 | } | |
29967ef6 XL |
416 | } |
417 | } | |
418 | ||
419 | impl From<Single> for ScalarInt { | |
420 | #[inline] | |
421 | fn from(f: Single) -> Self { | |
422 | // We trust apfloat to give us properly truncated data. | |
064997fb | 423 | Self { data: f.to_bits(), size: NonZeroU8::new((Single::BITS / 8) as u8).unwrap() } |
29967ef6 XL |
424 | } |
425 | } | |
426 | ||
427 | impl TryFrom<ScalarInt> for Single { | |
428 | type Error = Size; | |
429 | #[inline] | |
430 | fn try_from(int: ScalarInt) -> Result<Self, Size> { | |
431 | int.to_bits(Size::from_bytes(4)).map(Self::from_bits) | |
432 | } | |
433 | } | |
434 | ||
435 | impl From<Double> for ScalarInt { | |
436 | #[inline] | |
437 | fn from(f: Double) -> Self { | |
438 | // We trust apfloat to give us properly truncated data. | |
064997fb | 439 | Self { data: f.to_bits(), size: NonZeroU8::new((Double::BITS / 8) as u8).unwrap() } |
29967ef6 XL |
440 | } |
441 | } | |
442 | ||
443 | impl TryFrom<ScalarInt> for Double { | |
444 | type Error = Size; | |
445 | #[inline] | |
446 | fn try_from(int: ScalarInt) -> Result<Self, Size> { | |
447 | int.to_bits(Size::from_bytes(8)).map(Self::from_bits) | |
448 | } | |
449 | } | |
450 | ||
451 | impl fmt::Debug for ScalarInt { | |
452 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
064997fb FG |
453 | // Dispatch to LowerHex below. |
454 | write!(f, "0x{:x}", self) | |
29967ef6 XL |
455 | } |
456 | } | |
457 | ||
458 | impl fmt::LowerHex for ScalarInt { | |
459 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
460 | self.check_data(); | |
064997fb FG |
461 | if f.alternate() { |
462 | // Like regular ints, alternate flag adds leading `0x`. | |
463 | write!(f, "0x")?; | |
464 | } | |
29967ef6 XL |
465 | // Format as hex number wide enough to fit any value of the given `size`. |
466 | // So data=20, size=1 will be "0x14", but with size=4 it'll be "0x00000014". | |
467 | // Using a block `{self.data}` here to force a copy instead of using `self.data` | |
468 | // directly, because `write!` takes references to its formatting arguments and | |
469 | // would thus borrow `self.data`. Since `Self` | |
470 | // is a packed struct, that would create a possibly unaligned reference, which | |
471 | // is UB. | |
064997fb | 472 | write!(f, "{:01$x}", { self.data }, self.size.get() as usize * 2) |
29967ef6 XL |
473 | } |
474 | } | |
475 | ||
476 | impl fmt::UpperHex for ScalarInt { | |
477 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
478 | self.check_data(); | |
479 | // Format as hex number wide enough to fit any value of the given `size`. | |
480 | // So data=20, size=1 will be "0x14", but with size=4 it'll be "0x00000014". | |
481 | // Using a block `{self.data}` here to force a copy instead of using `self.data` | |
482 | // directly, because `write!` takes references to its formatting arguments and | |
483 | // would thus borrow `self.data`. Since `Self` | |
484 | // is a packed struct, that would create a possibly unaligned reference, which | |
485 | // is UB. | |
064997fb | 486 | write!(f, "{:01$X}", { self.data }, self.size.get() as usize * 2) |
29967ef6 XL |
487 | } |
488 | } | |
5e7ed085 FG |
489 | |
490 | impl fmt::Display for ScalarInt { | |
491 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
492 | self.check_data(); | |
493 | write!(f, "{}", { self.data }) | |
494 | } | |
495 | } |