#[derive(Debug)] pub enum HexDecodeError { InvalidByteCount, InvalidHexCharacter, } fn hex_char_byte_to_value(c : u8) -> Result { if !c.is_ascii_hexdigit() { return Err(HexDecodeError::InvalidHexCharacter); } Ok( (c as char).to_digit(16).unwrap() as u8) } fn byte_to_hex_char(b : u8) -> char { assert!(b <= 15); match b { digit if digit < 10 => ('0' as u8 + digit) as char, letter => ('a' as u8 + letter - 10) as char } } fn append_byte_hex_to_string(byte : u8, string : &mut String) { let high = (byte & 0xF0) >> 4; let low = byte & 0x0F; string.push(byte_to_hex_char(high)); string.push(byte_to_hex_char(low)); } pub fn decode_hex>(string : T) -> Result, HexDecodeError> { let chars = string.as_ref(); if chars.len() % 2 != 0 { return Err(HexDecodeError::InvalidByteCount); } let mut data = Vec::new(); let mut index = 0; let mut first_digit : u8 = 0; for c in chars.iter() { if index % 2 != 0 { let second_digit = hex_char_byte_to_value(*c)?; let value = first_digit * 16 + second_digit; data.push(value); }else { first_digit = hex_char_byte_to_value(*c)?; } index += 1; } Ok(data) } pub fn encode_hex>(data : T) -> String { let mut string = String::new(); let data_ref = data.as_ref(); for b in data_ref.iter() { append_byte_hex_to_string(*b, &mut string); } string } #[cfg(test)] mod tests { use super::*; #[test] fn decode_zero_bytes_test() { let string = ""; let data = decode_hex(string).unwrap(); assert_eq!(0, data.len()); } #[test] fn decode_one_byte_test() { let string = "ff"; let data = decode_hex(string).unwrap(); assert_eq!(1, data.len()); assert_eq!(0xff, data[0]); } #[test] fn decode_multiple_bytes_test() { let string = "ffaabbccdd1122"; let data = decode_hex(string).unwrap(); assert_eq!(7, data.len()); assert_eq!(&[0xff, 0xaa, 0xbb, 0xcc, 0xdd, 0x11, 0x22], data.as_slice()); } #[test] fn decode_invalid_character_test() { let string = "ffaabz"; match decode_hex(string) { Err(HexDecodeError::InvalidHexCharacter) => {} _ => panic!("Invalid result returned"), } } #[test] fn decode_invalid_character_length() { let string = "ffaab"; match decode_hex(string) { Err(HexDecodeError::InvalidByteCount) => {} _ => panic!("Invalid result returned"), } } #[test] fn encode_zero_bytes() { let data: &[u8; 0] = &[]; let string = encode_hex(&data); assert_eq!(string, ""); } #[test] fn encode_one_byte() { let data: &[u8; 1] = &[0xa1]; let string = encode_hex(&data); assert_eq!(string, "a1"); } #[test] fn encode_multiple_bytes() { let data: &[u8; 5] = &[0xaa, 0xbb, 0xcc, 0xdd, 0xee]; let string = encode_hex(&data); assert_eq!(string, "aabbccddee"); } }