1use crate::GuidFromStrError;
10
11pub(crate) const fn byte_to_ascii_hex_lower(byte: u8) -> (u8, u8) {
12 let mut l = byte & 0xf;
13 let mut h = byte >> 4;
14 if l <= 9 {
15 l += b'0';
16 } else {
17 l += b'a' - 10;
18 }
19 if h <= 9 {
20 h += b'0';
21 } else {
22 h += b'a' - 10;
23 }
24 (h, l)
25}
26
27const fn parse_byte_from_ascii_char(c: u8) -> Option<u8> {
29 match c {
30 b'0' => Some(0x0),
31 b'1' => Some(0x1),
32 b'2' => Some(0x2),
33 b'3' => Some(0x3),
34 b'4' => Some(0x4),
35 b'5' => Some(0x5),
36 b'6' => Some(0x6),
37 b'7' => Some(0x7),
38 b'8' => Some(0x8),
39 b'9' => Some(0x9),
40 b'a' | b'A' => Some(0xa),
41 b'b' | b'B' => Some(0xb),
42 b'c' | b'C' => Some(0xc),
43 b'd' | b'D' => Some(0xd),
44 b'e' | b'E' => Some(0xe),
45 b'f' | b'F' => Some(0xf),
46 _ => None,
47 }
48}
49
50const fn parse_byte_from_ascii_char_pair(a: u8, b: u8) -> Option<u8> {
53 let Some(a) = parse_byte_from_ascii_char(a) else {
54 return None;
55 };
56
57 let Some(b) = parse_byte_from_ascii_char(b) else {
58 return None;
59 };
60
61 Some(a << 4 | b)
62}
63
64pub(crate) const fn parse_byte_from_ascii_str_at(
67 s: &[u8],
68 start: u8,
69) -> Result<u8, GuidFromStrError> {
70 #![allow(clippy::as_conversions)]
74 let start_usize = start as usize;
75
76 if let Some(byte) =
77 parse_byte_from_ascii_char_pair(s[start_usize], s[start_usize + 1])
78 {
79 Ok(byte)
80 } else {
81 Err(GuidFromStrError::Hex(start))
82 }
83}
84
85#[cfg(test)]
86mod tests {
87 use super::*;
88
89 #[test]
90 fn test_to_ascii() {
91 assert_eq!(byte_to_ascii_hex_lower(0x1f), (b'1', b'f'));
92 assert_eq!(byte_to_ascii_hex_lower(0xf1), (b'f', b'1'));
93 }
94
95 #[test]
96 fn test_parse() {
97 assert_eq!(parse_byte_from_ascii_char_pair(b'1', b'a'), Some(0x1a));
98 assert_eq!(parse_byte_from_ascii_char_pair(b'8', b'f'), Some(0x8f));
99
100 assert_eq!(parse_byte_from_ascii_char_pair(b'g', b'a'), None);
101 assert_eq!(parse_byte_from_ascii_char_pair(b'a', b'g'), None);
102 }
103}