beer-protocols/codex: add hex -> numerical value helper

Co-authored-by: faukah <fau@faukah.com>
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I55a55d89e886a1c4f8c0a415089607b16a6a6964
This commit is contained in:
raf 2026-06-27 01:05:57 +03:00
commit aea1e9cd92
No known key found for this signature in database
GPG key ID: 29D95B64378DB4BF

View file

@ -75,22 +75,27 @@ pub fn decode_hex(s: &[u8]) -> Option<Vec<u8>> {
if s.is_empty() || !s.len().is_multiple_of(2) { if s.is_empty() || !s.len().is_multiple_of(2) {
return None; return None;
} }
let nibble = |b: u8| (b as char).to_digit(16).map(|d| d as u8);
s.chunks_exact(2) s.chunks_exact(2)
.map(|pair| Some((nibble(pair[0])? << 4) | nibble(pair[1])?)) .map(|pair| Some((hex_nibble(pair[0])? << 4) | hex_nibble(pair[1])?))
.collect() .collect()
} }
/// Turn a hexadecimal character into its numerical value.
fn hex_nibble(b: u8) -> Option<u8> {
(b as char).to_digit(16).map(|d| d as u8)
}
/// Percent-decode `%XX` byte escapes in a URI path, passing other bytes through. /// Percent-decode `%XX` byte escapes in a URI path, passing other bytes through.
pub fn percent_decode(s: &[u8]) -> Vec<u8> { pub fn percent_decode(s: &[u8]) -> Vec<u8> {
let mut out = Vec::with_capacity(s.len()); let mut out = Vec::with_capacity(s.len());
let mut i = 0; let mut i = 0;
while i < s.len() { while i < s.len() {
if s[i] == b'%' && i + 2 < s.len() { if s[i] == b'%' && i + 2 < s.len() {
let hi = (s[i + 1] as char).to_digit(16); let hi = hex_nibble(s[i + 1]);
let lo = (s[i + 2] as char).to_digit(16); let lo = hex_nibble(s[i + 2]);
if let (Some(hi), Some(lo)) = (hi, lo) { if let (Some(hi), Some(lo)) = (hi, lo) {
out.push((hi * 16 + lo) as u8); out.push(hi << 4 | lo);
i += 3; i += 3;
continue; continue;
} }