Skip to main content

speck_core/util/
hex.rs

1//! Hex encoding utilities
2
3/// Extension trait for hex operations
4pub trait HexExt {
5    /// Encode as hex string
6    fn to_hex(&self) -> String;
7    /// Decode from hex string
8    fn from_hex(s: &str) -> Result<Self, HexError> where Self: Sized;
9}
10
11impl HexExt for [u8] {
12    fn to_hex(&self) -> String {
13        self.iter().map(|b| format!("{:02x}", b)).collect()
14    }
15}
16
17impl HexExt for Vec<u8> {
18    fn to_hex(&self) -> String {
19        self.as_slice().to_hex()
20    }
21    
22    fn from_hex(s: &str) -> Result<Self, HexError> {
23        let cleaned: String = s.chars().filter(|c| c.is_ascii_hexdigit()).collect();
24        if cleaned.len() % 2 != 0 {
25            return Err(HexError::OddLength);
26        }
27        
28        cleaned.as_bytes()
29            .chunks(2)
30            .map(|chunk| {
31                u8::from_str_radix(std::str::from_utf8(chunk).unwrap(), 16)
32                    .map_err(|_| HexError::InvalidCharacter)
33            })
34            .collect::<Result<Vec<_>, _>>()
35    }
36}
37
38/// Hex decoding errors
39#[derive(Debug, Clone, Copy, PartialEq, Eq)]
40pub enum HexError {
41    /// Odd number of hex digits
42    OddLength,
43    /// Invalid character in input
44    InvalidCharacter,
45}
46
47impl core::fmt::Display for HexError {
48    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
49        match self {
50            HexError::OddLength => write!(f, "odd number of hex digits"),
51            HexError::InvalidCharacter => write!(f, "invalid hex character"),
52        }
53    }
54}
55
56impl core::error::Error for HexError {}