diff --git a/parsers/src/util/helpers.rs b/parsers/src/util/helpers.rs index ff309933..752dcfe2 100644 --- a/parsers/src/util/helpers.rs +++ b/parsers/src/util/helpers.rs @@ -84,6 +84,27 @@ impl WhitespaceAwareBase64 { } } +/// Codec for bytes of lowercase hexadecimal. +pub struct Hex; + +impl Hex { + pub fn decode(s: &str) -> Result, Error> { + let mut bytes = Vec::with_capacity(s.len() / 2); + for i in 0..s.len() / 2 { + bytes.push(u8::from_str_radix(&s[2 * i..2 * i + 2], 16)?); + } + Ok(bytes) + } + + pub fn encode(b: &[u8]) -> Option { + let mut bytes = String::with_capacity(b.len() * 2); + for byte in b { + bytes.extend(format!("{:02x}", byte).chars()); + } + Some(bytes) + } +} + /// Codec for colon-separated bytes of uppercase hexadecimal. pub struct ColonSeparatedHex; @@ -121,3 +142,30 @@ impl JidCodec { Some(jid.to_string()) } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn hex() { + let value = [0x01, 0xfe, 0xef]; + + // Test that we support both lowercase and uppercase as input. + let hex = Hex::decode("01feEF").unwrap(); + assert_eq!(hex, &value); + + // Test that we do output lowercase. + let hex = Hex::encode(&value).unwrap(); + assert_eq!(hex, "01feef"); + } + + #[test] + fn bad_hex() { + // No colon supported. + Hex::decode("01:fe:EF").unwrap_err(); + + // No non-hex character allowed. + Hex::decode("01defg").unwrap_err(); + } +}