nordisk/heimdall
crates/heimdall-core/src/hex.rs
// SPDX-License-Identifier: AGPL-3.0-only
// Copyright (C) 2026 Ignalina ApS and Vetra Automation AB
//! Lower-case hex, strict on input (even length, `0-9a-fA-F` only).
const DIGITS: &[u8; 16] = b"0123456789abcdef";
/// Lower-case hex of `bytes`.
pub fn encode(bytes: &[u8]) -> String {
let mut s = String::with_capacity(bytes.len() * 2);
for b in bytes {
s.push(DIGITS[(b >> 4) as usize] as char);
s.push(DIGITS[(b & 0x0f) as usize] as char);
}
s
}
fn nibble(c: u8) -> Option<u8> {
match c {
b'0'..=b'9' => Some(c - b'0'),
b'a'..=b'f' => Some(c - b'a' + 10),
b'A'..=b'F' => Some(c - b'A' + 10),
_ => None,
}
}
/// Decode hex; `None` on odd length or a non-hex character.
pub fn decode(s: &str) -> Option<Vec<u8>> {
let b = s.as_bytes();
if b.len() % 2 != 0 {
return None;
}
b.chunks_exact(2)
.map(|p| Some((nibble(p[0])? << 4) | nibble(p[1])?))
.collect()
}