everscale_types/
util.rs

1//! General stuff.
2
3use std::mem::MaybeUninit;
4
5use crate::error::Error;
6
7/// Brings [unlikely](core::intrinsics::unlikely) to stable rust.
8#[inline(always)]
9pub(crate) const fn unlikely(b: bool) -> bool {
10    #[allow(clippy::needless_bool, clippy::bool_to_int_with_if)]
11    if (1i32).checked_div(if b { 0 } else { 1 }).is_none() {
12        true
13    } else {
14        false
15    }
16}
17
18/// Reads n-byte integer as `u32` from the bytes pointer.
19///
20/// # Safety
21///
22/// The following must be true:
23/// - size must be in range 1..=4.
24/// - data must be at least `size` bytes long.
25pub(crate) unsafe fn read_be_u32_fast(data_ptr: *const u8, size: usize) -> u32 {
26    match size {
27        1 => *data_ptr as u32,
28        2 => u16::from_be_bytes(*(data_ptr as *const [u8; 2])) as u32,
29        3 => {
30            let mut bytes = [0u8; 4];
31            std::ptr::copy_nonoverlapping(data_ptr, bytes.as_mut_ptr().add(1), 3);
32            u32::from_be_bytes(bytes)
33        }
34        4 => u32::from_be_bytes(*(data_ptr as *const [u8; 4])),
35        _ => std::hint::unreachable_unchecked(),
36    }
37}
38
39/// Reads n-byte integer as `u64` from the bytes pointer.
40///
41/// # Safety
42///
43/// The following must be true:
44/// - size must be in range 1..=8.
45/// - data must be at least `size` bytes long.
46pub(crate) unsafe fn read_be_u64_fast(data_ptr: *const u8, size: usize) -> u64 {
47    match size {
48        1..=4 => read_be_u32_fast(data_ptr, size) as u64,
49        5..=8 => {
50            let mut bytes = [0u8; 8];
51            std::ptr::copy_nonoverlapping(data_ptr, bytes.as_mut_ptr().add(8 - size), size);
52            u64::from_be_bytes(bytes)
53        }
54        _ => std::hint::unreachable_unchecked(),
55    }
56}
57
58#[cfg(any(feature = "base64", test))]
59#[inline]
60pub(crate) fn encode_base64<T: AsRef<[u8]>>(data: T) -> String {
61    use base64::Engine;
62    fn encode_base64_impl(data: &[u8]) -> String {
63        base64::engine::general_purpose::STANDARD.encode(data)
64    }
65    encode_base64_impl(data.as_ref())
66}
67
68#[cfg(any(feature = "base64", test))]
69#[inline]
70pub(crate) fn decode_base64<T: AsRef<[u8]>>(data: T) -> Result<Vec<u8>, base64::DecodeError> {
71    use base64::Engine;
72    fn decode_base64_impl(data: &[u8]) -> Result<Vec<u8>, base64::DecodeError> {
73        base64::engine::general_purpose::STANDARD.decode(data)
74    }
75    decode_base64_impl(data.as_ref())
76}
77
78#[cfg(any(feature = "base64", test))]
79#[allow(unused)]
80#[inline]
81pub(crate) fn decode_base64_slice<T: AsRef<[u8]>>(
82    data: T,
83    target: &mut [u8],
84) -> Result<(), base64::DecodeSliceError> {
85    use base64::Engine;
86    fn decode_base64_slice_impl(
87        data: &[u8],
88        target: &mut [u8],
89    ) -> Result<(), base64::DecodeSliceError> {
90        base64::engine::general_purpose::STANDARD
91            .decode_slice(data, target)
92            .map(|_| ())
93    }
94    decode_base64_slice_impl(data.as_ref(), target)
95}
96
97#[cfg(any(feature = "base64", test))]
98#[inline]
99pub(crate) fn crc_16(data: &[u8]) -> u16 {
100    let mut crc: u32 = 0;
101    for c in data {
102        let t = c ^ ((crc >> 8) as u8);
103        crc = (CRC16_TABLE[t as usize] ^ ((crc << 8) as u16)) as u32;
104    }
105    crc as u16
106}
107
108#[cfg(any(feature = "base64", test))]
109static CRC16_TABLE: [u16; 256] = [
110    0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b,
111    0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
112    0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, 0x2462, 0x3443, 0x0420, 0x1401,
113    0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
114    0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738,
115    0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
116    0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, 0x5af5, 0x4ad4, 0x7ab7, 0x6a96,
117    0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
118    0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd,
119    0xad2a, 0xbd0b, 0x8d68, 0x9d49, 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
120    0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, 0x9188, 0x81a9, 0xb1ca, 0xa1eb,
121    0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
122    0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 0x02b1, 0x1290, 0x22f3, 0x32d2,
123    0x4235, 0x5214, 0x6277, 0x7256, 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
124    0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xa7db, 0xb7fa, 0x8799, 0x97b8,
125    0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
126    0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827,
127    0x18c0, 0x08e1, 0x3882, 0x28a3, 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
128    0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d,
129    0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
130    0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74,
131    0x2e93, 0x3eb2, 0x0ed1, 0x1ef0,
132];
133
134/// Small on-stack vector of max length N.
135pub struct ArrayVec<T, const N: usize> {
136    inner: [MaybeUninit<T>; N],
137    len: u8,
138}
139
140impl<T, const N: usize> ArrayVec<T, N> {
141    /// Ensure that provided length is small enough.
142    const _ASSERT_LEN: () = assert!(N <= u8::MAX as usize);
143
144    /// Returns an empty vector.
145    pub const fn new() -> Self {
146        Self {
147            // SAFETY: An uninitialized `[MaybeUninit<_>; LEN]` is valid.
148            inner: unsafe { MaybeUninit::<[MaybeUninit<T>; N]>::uninit().assume_init() },
149            len: 0,
150        }
151    }
152
153    /// Returns the number of elements in the vector, also referred to as its ‘length’.
154    #[inline]
155    pub const fn len(&self) -> usize {
156        self.len as usize
157    }
158
159    /// Returns true if the vector contains no elements.
160    #[inline]
161    pub const fn is_empty(&self) -> bool {
162        self.len == 0
163    }
164
165    /// Appends an element to the back of a collection.
166    ///
167    /// # Safety
168    ///
169    /// The following must be true:
170    /// - The length of this vector is less than `N`.
171    #[inline]
172    pub unsafe fn push(&mut self, item: T) {
173        debug_assert!((self.len as usize) < N);
174
175        *self.inner.get_unchecked_mut(self.len as usize) = MaybeUninit::new(item);
176        self.len += 1;
177    }
178
179    /// Returns a reference to an element.
180    pub const fn get(&self, n: u8) -> Option<&T> {
181        if n < self.len {
182            let references = self.inner.as_ptr() as *const T;
183            // SAFETY: {len} elements were initialized, n < len
184            Some(unsafe { &*references.add(n as usize) })
185        } else {
186            None
187        }
188    }
189
190    /// Returns the inner data without dropping its elements.
191    ///
192    /// # Safety
193    ///
194    /// The caller is responsible for calling the destructor for
195    /// `len` initialized items in the returned array.
196    #[inline]
197    pub unsafe fn into_inner(self) -> [MaybeUninit<T>; N] {
198        let this = std::mem::ManuallyDrop::new(self);
199        std::ptr::read(&this.inner)
200    }
201}
202
203impl<T, const N: usize> Default for ArrayVec<T, N> {
204    #[inline]
205    fn default() -> Self {
206        Self::new()
207    }
208}
209
210impl<R, const N: usize> AsRef<[R]> for ArrayVec<R, N> {
211    #[inline]
212    fn as_ref(&self) -> &[R] {
213        // SAFETY: {len} elements were initialized
214        unsafe { std::slice::from_raw_parts(self.inner.as_ptr() as *const R, self.len as usize) }
215    }
216}
217
218impl<T: Clone, const N: usize> Clone for ArrayVec<T, N> {
219    fn clone(&self) -> Self {
220        let mut res = Self::default();
221        for item in self.as_ref() {
222            // SAFETY: {len} elements were initialized
223            unsafe { res.push(item.clone()) };
224        }
225        res
226    }
227}
228
229impl<T, const N: usize> Drop for ArrayVec<T, N> {
230    fn drop(&mut self) {
231        debug_assert!(self.len as usize <= N);
232
233        let references_ptr = self.inner.as_mut_ptr() as *mut T;
234        for i in 0..self.len {
235            // SAFETY: len items were initialized
236            unsafe { std::ptr::drop_in_place(references_ptr.add(i as usize)) };
237        }
238    }
239}
240
241#[derive(Clone, Copy)]
242pub(crate) enum IterStatus {
243    /// Iterator is still valid.
244    Valid,
245    /// Iterator started with a pruned branch cell.
246    Pruned,
247    /// [`RawDict`] has invalid structure.
248    Broken,
249}
250
251impl IterStatus {
252    #[inline]
253    pub(crate) const fn is_valid(self) -> bool {
254        matches!(self, Self::Valid)
255    }
256
257    #[inline]
258    pub(crate) const fn is_pruned(self) -> bool {
259        matches!(self, Self::Pruned)
260    }
261}
262
263/// Used to get a mutable reference of the inner type if possible.
264pub trait TryAsMut<T: ?Sized> {
265    /// Tries to convert this type into a mutable reference of the (usually inferred) input type.
266    fn try_as_mut(&mut self) -> Option<&mut T>;
267}
268
269/// A wrapper around arbitrary data with the specified bit length.
270pub struct Bitstring<'a> {
271    /// Underlying bytes (with or without termination bit).
272    pub bytes: &'a [u8],
273    /// Length of data in bits.
274    pub bit_len: u16,
275}
276
277impl Bitstring<'_> {
278    /// Parses a bitstring from a hex string.
279    ///
280    /// Returns the parsed data and the bit length.
281    /// Tag bit is removed if present.
282    pub fn from_hex_str(s: &str) -> Result<(Vec<u8>, u16), Error> {
283        fn hex_char(c: u8) -> Result<u8, Error> {
284            match c {
285                b'A'..=b'F' => Ok(c - b'A' + 10),
286                b'a'..=b'f' => Ok(c - b'a' + 10),
287                b'0'..=b'9' => Ok(c - b'0'),
288                _ => Err(Error::InvalidData),
289            }
290        }
291
292        if !s.is_ascii() || s.len() > 128 * 2 {
293            return Err(Error::InvalidData);
294        }
295
296        let s = s.as_bytes();
297        let (mut s, with_tag) = match s.strip_suffix(b"_") {
298            Some(s) => (s, true),
299            None => (s, false),
300        };
301
302        let mut half_byte = None;
303        if s.len() % 2 != 0 {
304            if let Some((last, prefix)) = s.split_last() {
305                half_byte = Some(ok!(hex_char(*last)));
306                s = prefix;
307            }
308        }
309
310        let Ok(mut data) = hex::decode(s) else {
311            return Err(Error::InvalidData);
312        };
313
314        let mut bit_len = data.len() as u16 * 8;
315        if let Some(half_byte) = half_byte {
316            bit_len += 4;
317            data.push(half_byte << 4);
318        }
319
320        if with_tag {
321            bit_len = data.len() as u16 * 8;
322            for byte in data.iter_mut().rev() {
323                if *byte == 0 {
324                    bit_len -= 8;
325                } else {
326                    let trailing = byte.trailing_zeros();
327                    bit_len -= 1 + trailing as u16;
328
329                    // NOTE: `trailing` is in range 0..=7,
330                    // so we must split the shift in two parts.
331                    *byte &= (0xff << trailing) << 1;
332                    break;
333                }
334            }
335
336            data.truncate((bit_len as usize + 7) / 8);
337        }
338
339        Ok((data, bit_len))
340    }
341}
342
343impl std::fmt::Display for Bitstring<'_> {
344    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
345        const CHUNK_LEN: usize = 16;
346
347        let bit_len = std::cmp::min(self.bit_len as usize, self.bytes.len() * 8) as u16;
348        let byte_len = ((bit_len + 7) / 8) as usize;
349        let bytes = &self.bytes[..byte_len];
350
351        let rem = bit_len % 8;
352        let (bytes, last_byte) = match bytes.split_last() {
353            Some((last_byte, bytes)) if rem != 0 => {
354                let tag_mask: u8 = 1 << (7 - rem);
355                let data_mask = !(tag_mask - 1);
356                let last_byte = (*last_byte & data_mask) | tag_mask;
357                (bytes, Some(last_byte))
358            }
359            _ => (bytes, None),
360        };
361
362        let mut chunk = [0u8; CHUNK_LEN * 2];
363        for data in bytes.chunks(CHUNK_LEN) {
364            let chunk = &mut chunk[..data.len() * 2];
365            hex::encode_to_slice(data, chunk).unwrap();
366
367            // SAFETY: result was constructed from valid ascii `HEX_CHARS_LOWER`
368            ok!(f.write_str(unsafe { std::str::from_utf8_unchecked(chunk) }));
369        }
370
371        if let Some(mut last_byte) = last_byte {
372            let tag = if rem != 4 { "_" } else { "" };
373            let rem = 1 + (rem > 4) as usize;
374            if rem == 1 {
375                last_byte >>= 4;
376            }
377            ok!(write!(f, "{last_byte:0rem$x}{tag}"));
378        }
379
380        Ok(())
381    }
382}
383
384impl std::fmt::Binary for Bitstring<'_> {
385    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
386        let bit_len = std::cmp::min(self.bit_len as usize, self.bytes.len() * 8) as u16;
387        let byte_len = ((bit_len + 7) / 8) as usize;
388        let bytes = &self.bytes[..byte_len];
389
390        let rem = (bit_len % 8) as usize;
391        let (bytes, last_byte) = match bytes.split_last() {
392            Some((last_byte, bytes)) if rem != 0 => (bytes, Some(*last_byte)),
393            _ => (bytes, None),
394        };
395
396        for byte in bytes {
397            ok!(write!(f, "{byte:08b}"));
398        }
399
400        if let Some(mut last_byte) = last_byte {
401            last_byte >>= 8 - rem;
402            ok!(write!(f, "{last_byte:0rem$b}"))
403        }
404
405        Ok(())
406    }
407}
408
409#[allow(unused)]
410pub(crate) fn debug_tuple_field1_finish(
411    f: &mut std::fmt::Formatter<'_>,
412    name: &str,
413    value1: &dyn std::fmt::Debug,
414) -> std::fmt::Result {
415    let mut builder = std::fmt::Formatter::debug_tuple(f, name);
416    builder.field(value1);
417    builder.finish()
418}
419
420pub(crate) fn debug_struct_field1_finish(
421    f: &mut std::fmt::Formatter<'_>,
422    name: &str,
423    name1: &str,
424    value1: &dyn std::fmt::Debug,
425) -> std::fmt::Result {
426    let mut builder = std::fmt::Formatter::debug_struct(f, name);
427    builder.field(name1, value1);
428    builder.finish()
429}
430
431pub(crate) fn debug_struct_field2_finish(
432    f: &mut std::fmt::Formatter<'_>,
433    name: &str,
434    name1: &str,
435    value1: &dyn std::fmt::Debug,
436    name2: &str,
437    value2: &dyn std::fmt::Debug,
438) -> std::fmt::Result {
439    let mut builder = std::fmt::Formatter::debug_struct(f, name);
440    builder.field(name1, value1);
441    builder.field(name2, value2);
442    builder.finish()
443}
444
445#[cfg(test)]
446mod tests {
447    use super::*;
448
449    #[test]
450    fn parse_bitstring_from_hex_str() {
451        let (data, bit_len) = Bitstring::from_hex_str("").unwrap();
452        assert_eq!(bit_len, 0);
453        assert!(data.is_empty());
454
455        let (data, bit_len) = Bitstring::from_hex_str("8_").unwrap();
456        assert_eq!(bit_len, 0);
457        assert!(data.is_empty());
458
459        let (data, bit_len) = Bitstring::from_hex_str("ded_").unwrap();
460        assert_eq!(bit_len, 11);
461        assert_eq!(data, vec![0xde, 0xc0]);
462
463        let (data, bit_len) = Bitstring::from_hex_str("b00b1e5").unwrap();
464        assert_eq!(bit_len, 28);
465        assert_eq!(data, vec![0xb0, 0x0b, 0x1e, 0x50]);
466
467        let (data, bit_len) = Bitstring::from_hex_str("b00b1e5_").unwrap();
468        assert_eq!(bit_len, 27);
469        assert_eq!(data, vec![0xb0, 0x0b, 0x1e, 0x40]);
470    }
471
472    #[test]
473    fn bitstring_zero_char_with_completion_tag() {
474        assert_eq!(
475            format!(
476                "{}",
477                Bitstring {
478                    bytes: &[0b_0011_0000],
479                    bit_len: 4
480                }
481            ),
482            format!("{:x}", 0b_0011)
483        );
484        assert_eq!(
485            format!(
486                "{}",
487                Bitstring {
488                    bytes: &[0b_0100_0000],
489                    bit_len: 2
490                }
491            ),
492            format!("{:x}_", 0b_0110)
493        );
494        assert_eq!(
495            format!(
496                "{}",
497                Bitstring {
498                    bytes: &[0b_0000_1000],
499                    bit_len: 5
500                }
501            ),
502            format!("{:x}{:x}_", 0b_0000, 0b_1100)
503        );
504        assert_eq!(
505            format!(
506                "{}",
507                Bitstring {
508                    bytes: &[0b_0000_1000, 0b_0100_0000],
509                    bit_len: 8 + 2
510                }
511            ),
512            format!("{:x}{:x}{:x}_", 0b_0000, 0b_1000, 0b_0110)
513        );
514        assert_eq!(
515            format!(
516                "{}",
517                Bitstring {
518                    bytes: &[0b_0100_0000, 0b_0000_1000],
519                    bit_len: 8 + 5
520                }
521            ),
522            format!("{:x}{:x}{:x}{:x}_", 0b_0100, 0b_0000, 0b_0000, 0b_1100)
523        );
524    }
525}