Skip to main content

multiversx_sc/formatter/
formatter_impl_num.rs

1use super::{SCBinary, SCDisplay, SCLowerHex, hex_util::byte_to_hex_digits};
2
3const MINUS_SYMBOL: &[u8] = b"-";
4
5/// u64::MAX is 18446744073709551615 in base 10, which is 20 digits. so 20 digits is enough
6const MAX_BASE_10_LEN: usize = 64;
7
8fn format_unsigned_to_buffer(
9    mut num: u64,
10    buffer: &mut [u8; MAX_BASE_10_LEN],
11    base_no: u64,
12) -> &[u8] {
13    let mut buf_index = MAX_BASE_10_LEN;
14    if num == 0 {
15        buf_index -= 1;
16        buffer[buf_index] = b'0';
17    } else {
18        while num > 0 {
19            buf_index -= 1;
20            let last_digit = (num % base_no) as u8;
21            let ascii_last_digit = byte_to_hex_digits(last_digit)[1];
22            buffer[buf_index] = ascii_last_digit;
23            num /= base_no;
24        }
25    }
26    &buffer[buf_index..]
27}
28
29fn format_unsigned<F: super::FormatByteReceiver>(num: u64, f: &mut F, base_no: u64) {
30    let mut buffer = [0u8; MAX_BASE_10_LEN];
31    let formatted = format_unsigned_to_buffer(num, &mut buffer, base_no);
32    f.append_bytes(formatted);
33}
34
35macro_rules! formatter_unsigned {
36    ($num_ty:ty) => {
37        impl SCDisplay for $num_ty {
38            #[inline]
39            fn fmt<F: super::FormatByteReceiver>(&self, f: &mut F) {
40                format_unsigned(*self as u64, f, 10);
41            }
42        }
43        impl SCLowerHex for $num_ty {
44            #[inline]
45            fn fmt<F: super::FormatByteReceiver>(&self, f: &mut F) {
46                format_unsigned(*self as u64, f, 16);
47            }
48        }
49        impl SCBinary for $num_ty {
50            #[inline]
51            fn fmt<F: super::FormatByteReceiver>(&self, f: &mut F) {
52                format_unsigned(*self as u64, f, 2);
53            }
54        }
55    };
56}
57
58formatter_unsigned! {u64}
59formatter_unsigned! {u32}
60formatter_unsigned! {usize}
61formatter_unsigned! {u16}
62formatter_unsigned! {u8}
63
64fn format_signed<F: super::FormatByteReceiver>(num: i64, f: &mut F) {
65    let abs = if num >= 0 {
66        num as u64
67    } else {
68        f.append_bytes(MINUS_SYMBOL);
69        if num == i64::MIN {
70            // overflow edge case
71            (i64::MAX as u64) + 1
72        } else {
73            (-num) as u64
74        }
75    };
76    format_unsigned(abs, f, 10);
77}
78
79fn format_signed_hex<F: super::FormatByteReceiver>(num: i64, f: &mut F, size_in_bits: u8) {
80    let abs = if num >= 0 {
81        num as u64
82    } else if size_in_bits == 64 {
83        // overflow for 64 bits edge case
84        (num | i64::MIN) as u64
85    } else {
86        ((1 << size_in_bits) - 1) & (num & i64::MAX) as u64
87    };
88    format_unsigned(abs, f, 16);
89}
90
91macro_rules! formatter_signed {
92    ($num_ty:ty) => {
93        impl SCDisplay for $num_ty {
94            #[inline]
95            fn fmt<F: super::FormatByteReceiver>(&self, f: &mut F) {
96                format_signed(*self as i64, f);
97            }
98        }
99    };
100}
101
102macro_rules! formatter_signed_hex {
103    ($num_ty:ty, $size_in_bits:expr) => {
104        impl SCLowerHex for $num_ty {
105            #[inline]
106            fn fmt<F: super::FormatByteReceiver>(&self, f: &mut F) {
107                format_signed_hex(*self as i64, f, $size_in_bits);
108            }
109        }
110    };
111}
112
113formatter_signed! {i64}
114formatter_signed! {i32}
115formatter_signed! {isize}
116formatter_signed! {i16}
117formatter_signed! {i8}
118
119formatter_signed_hex! {i64, 64}
120formatter_signed_hex! {i32, 32}
121formatter_signed_hex! {isize, 32}
122formatter_signed_hex! {i16, 16}
123formatter_signed_hex! {i8, 8}