kbvm/
from_bytes.rs

1#[cfg(test)]
2mod tests;
3
4pub(crate) trait FromBytes: Sized {
5    fn from_bytes_dec(b: &[u8]) -> Option<Self>;
6
7    fn from_bytes_hex(b: &[u8]) -> Option<Self>;
8
9    fn from_bytes(b: &[u8], hex: bool) -> Option<Self> {
10        match hex {
11            true => Self::from_bytes_hex(b),
12            false => Self::from_bytes_dec(b),
13        }
14    }
15}
16
17macro_rules! from_bytes {
18    ($ty:ty, $signed:expr) => {
19        impl FromBytes for $ty {
20            fn from_bytes_dec(b: &[u8]) -> Option<Self> {
21                if b.len() == 0 {
22                    return None;
23                }
24                let mut res = 0 as $ty;
25                for &c in b {
26                    match c {
27                        b'0'..=b'9' => res = res.checked_mul(10)?.checked_add((c - b'0') as $ty)?,
28                        _ => return None,
29                    }
30                }
31                Some(res)
32            }
33
34            fn from_bytes_hex(mut b: &[u8]) -> Option<Self> {
35                if b.len() == 0 {
36                    return None;
37                }
38                const MAX_BYTES: usize = <$ty>::BITS as usize / 8;
39                const MAX_CHARS: usize = MAX_BYTES * 2;
40                if b.len() > MAX_CHARS || ($signed && b.len() == MAX_CHARS) {
41                    while b.len() > 0 && b[0] == b'0' {
42                        b = &b[1..];
43                    }
44                    if b.len() > MAX_CHARS {
45                        return None;
46                    }
47                    if $signed && b.len() == MAX_CHARS {
48                        if matches!(b[0], b'8'..=b'9' | b'A'..=b'F' | b'a'..=b'f') {
49                            return None;
50                        }
51                    }
52                }
53                let mut res = 0;
54                for &c in b {
55                    res = res << 4
56                        | match c {
57                        b'0'..=b'9' => c - b'0',
58                        b'A'..=b'F' => c - b'A' + 10,
59                        b'a'..=b'f' => c - b'a' + 10,
60                        _ => return None,
61                    } as $ty;
62                }
63                Some(res)
64            }
65        }
66    };
67}
68
69from_bytes!(u32, false);
70from_bytes!(i64, true);