#[must_use]
pub fn lower(bytes: &[u8]) -> String {
use std::fmt::Write as _;
let mut s = String::with_capacity(bytes.len() * 2);
for b in bytes {
let _ = write!(&mut s, "{b:02x}");
}
s
}
#[must_use]
pub fn decode(s: &str) -> Option<Vec<u8>> {
if !s.len().is_multiple_of(2) {
return None;
}
(0..s.len())
.step_by(2)
.map(|i| u8::from_str_radix(&s[i..i + 2], 16).ok())
.collect()
}
#[cfg(test)]
mod tests {
#![allow(clippy::pedantic, clippy::nursery, missing_docs)]
use super::*;
#[test]
fn round_trips_and_fails_closed() {
assert_eq!(lower(&[0x00, 0xab, 0xff]), "00abff");
assert_eq!(decode("00abff"), Some(vec![0x00, 0xab, 0xff]));
assert_eq!(decode(""), Some(Vec::new()));
assert_eq!(decode("abc"), None, "odd length fails closed");
assert_eq!(decode("zz"), None, "non-hex fails closed");
}
}