diff --git a/src/hex.rs b/src/hex.rs index f772fe2..c27aa71 100644 --- a/src/hex.rs +++ b/src/hex.rs @@ -111,16 +111,126 @@ impl<'a> AsHexBytes<'a> for &'a str { fn hex_bytes(&self) -> HexBytes<'a> { HexBytes::new(self) } } +//pub trait HexDecodable { +// fn hex_decoded(self) -> Option>; +//} +// +//impl<'a> HexDecodable for &'a str { +// fn hex_decoded(self) -> Option> { +// fn valid(ch: &&str) -> bool { ch.chars().all(|c| c.is_digit(16)) } +// fn decode(ch: &str) -> u8 { ch.chars().fold(0u8, |acc, c| (acc << 4) + c.to_digit(16).unwrap() as u8) } +// self.splitn(2, "") +// .take_while(valid) +// .map(decode) +// .collect::>() +// } +//} + +pub trait HexDecodable { + fn hex_decoded(self) -> HexDecoder; +} + +pub struct HexDecoder { + input: T, +} + +impl HexDecoder { + pub fn new(input: T) -> HexDecoder { + HexDecoder { input: input } + } +} + +impl<'a, T> Iterator for HexDecoder where T: Iterator + 'a { + type Item = u8; + + fn next(&mut self) -> Option { + let c0 = match self.input.next() { + Some(ch) => match ch.to_digit(16) { + Some(digit) => digit as u8, + None => return None + }, + None => return None + }; + + let c1 = match self.input.next() { + Some(ch) => match ch.to_digit(16) { + Some(digit) => Some(digit as u8), + None => return None + }, + None => None + }; + + let out_char = if let Some(c1) = c1 { + (c0 << 4) + (c1 & 0x0F) + } else { + c0 & 0x0F + }; + + Some(out_char) + } +} + +impl<'a, T> HexDecodable for T where T: Iterator + 'a { + fn hex_decoded(self) -> HexDecoder { HexDecoder::new(self) } +} + +pub trait HexEncodable { + fn hex_encoded(self) -> HexEncoder; +} + +pub struct HexEncoder { + input: T, + current_byte: u8, +} + +impl HexEncoder { + pub fn new(input: T) -> HexEncoder { + HexEncoder { input: input, current_byte: 0 } + } +} + +impl<'a, T> Iterator for HexEncoder where T: Iterator + 'a { + type Item = char; + + fn next(&mut self) -> Option { + if self.current_byte == 0 { + // Get a new byte. + match self.input.next() { + Some(byte) => { + // Swap the order of the nibbles to make the code below nicer. + self.current_byte = (byte << 4) + (byte >> 4); + } + None => return None + } + } + // Convert the lowest order nibble to a hex digit. + match char::from_digit((self.current_byte & 0xF) as u32, 16) { + Some(ch) => { + self.current_byte = self.current_byte >> 4; + return Some(ch); + }, + None => panic!("This will never happen???") + } + } +} + +impl<'a, T> HexEncodable for T where T: Iterator + 'a { + fn hex_encoded(self) -> HexEncoder { HexEncoder::new(self) } +} + #[cfg(test)] mod tests { use super::*; #[test] - fn simple() { - let collected: Vec = "123".hex_bytes().map(|c| match c { - HexResult::Byte(c) => c, - _ => panic!(), - }).collect(); - assert_eq!(collected, vec![1, 2, 3]); + fn simple_encode() { + let collected: String = "123".bytes().hex_encoded().collect(); + assert_eq!(collected, "313233"); + } + + #[test] + fn simple_decode() { + let decoded: Vec = "313233".chars().hex_decoded().collect(); + assert_eq!(decoded, vec![0x31u8, 0x32u8, 0x33u8]); } }