1use crate::Result;
2use crate::error::DdError;
3
4pub fn hex_encode(bytes: &[u8]) -> String {
5 const HEX: &[u8] = b"0123456789abcdef";
6 let mut out = String::with_capacity(bytes.len() * 2);
7 for b in bytes {
8 out.push(HEX[(b >> 4) as usize] as char);
9 out.push(HEX[(b & 0x0f) as usize] as char);
10 }
11 out
12}
13
14pub fn hex_decode(s: &str) -> Result<Vec<u8>> {
15 if !s.len().is_multiple_of(2) {
16 return Err(DdError::protocol(
17 crate::error::ErrorCode::Ddp1005BadIdentifier,
18 "odd hex length",
19 ));
20 }
21 let mut out = Vec::with_capacity(s.len() / 2);
22 let bytes = s.as_bytes();
23 for i in (0..bytes.len()).step_by(2) {
24 let hi = hex_val(bytes[i])?;
25 let lo = hex_val(bytes[i + 1])?;
26 out.push((hi << 4) | lo);
27 }
28 Ok(out)
29}
30
31fn hex_val(c: u8) -> Result<u8> {
32 match c {
33 b'0'..=b'9' => Ok(c - b'0'),
34 b'a'..=b'f' => Ok(c - b'a' + 10),
35 b'A'..=b'F' => Ok(c - b'A' + 10),
36 _ => Err(DdError::protocol(
37 crate::error::ErrorCode::Ddp1005BadIdentifier,
38 "invalid hex",
39 )),
40 }
41}
42
43#[cfg(test)]
44mod tests {
45 use super::*;
46
47 #[test]
48 fn hex_roundtrip() {
49 let b = [0x7f, 0x4a, 0x91];
50 assert_eq!(hex_decode(&hex_encode(&b)).unwrap(), b);
51 }
52}