1#![no_std]
2#![doc = include_str!("../README.md")]
3#![doc(
4 html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg",
5 html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg"
6)]
7
8const fn next_hex_char(string: &[u8], mut pos: usize) -> Option<(u8, usize)> {
9 while pos < string.len() {
10 let raw_val = string[pos];
11 pos += 1;
12 let val = match raw_val {
13 b'0'..=b'9' => raw_val - 48,
14 b'A'..=b'F' => raw_val - 55,
15 b'a'..=b'f' => raw_val - 87,
16 b' ' | b'\r' | b'\n' | b'\t' => continue,
17 0..=127 => panic!("Encountered invalid ASCII character"),
18 _ => panic!("Encountered non-ASCII character"),
19 };
20 return Some((val, pos));
21 }
22 None
23}
24
25const fn next_byte(string: &[u8], pos: usize) -> Option<(u8, usize)> {
26 let (half1, pos) = match next_hex_char(string, pos) {
27 Some(v) => v,
28 None => return None,
29 };
30 let (half2, pos) = match next_hex_char(string, pos) {
31 Some(v) => v,
32 None => panic!("Odd number of hex characters"),
33 };
34 Some(((half1 << 4) + half2, pos))
35}
36
37#[doc(hidden)]
41pub const fn len(strings: &[&[u8]]) -> usize {
42 let mut i = 0;
43 let mut len = 0;
44 while i < strings.len() {
45 let mut pos = 0;
46 while let Some((_, new_pos)) = next_byte(strings[i], pos) {
47 len += 1;
48 pos = new_pos;
49 }
50 i += 1;
51 }
52 len
53}
54
55#[doc(hidden)]
59pub const fn decode<const LEN: usize>(strings: &[&[u8]]) -> Option<[u8; LEN]> {
60 let mut string_pos = 0;
61 let mut buf = [0u8; LEN];
62 let mut buf_pos = 0;
63 while string_pos < strings.len() {
64 let mut pos = 0;
65 let string = &strings[string_pos];
66 string_pos += 1;
67
68 while let Some((byte, new_pos)) = next_byte(string, pos) {
69 buf[buf_pos] = byte;
70 buf_pos += 1;
71 pos = new_pos;
72 }
73 }
74 if LEN == buf_pos { Some(buf) } else { None }
75}
76
77#[macro_export]
80macro_rules! hex {
81 ($($s:literal)*) => {{
82 const STRINGS: &[&'static [u8]] = &[$($s.as_bytes(),)*];
83 const {
84 $crate::decode::<{ $crate::len(STRINGS) }>(STRINGS)
85 .expect("Output array length should be correct")
86 }
87 }};
88}