use common::prelude::*;
pub fn from_hex(input: &str) -> Result<Vec<u8>> {
let mut result = Vec::with_capacity(input.len() / 2);
let mut pending: u8 = 0;
let mut buffer: u8 = 0;
let mut current: u8;
for (i, byte) in input.bytes().enumerate() {
pending += 1;
current = match byte {
b'0'...b'9' => byte - b'0',
b'a'...b'f' => byte - b'a' + 10,
b'A'...b'F' => byte - b'A' + 10,
_ => {
return Err(ErrorKind::HexInvalidChar(
input[i..].chars().next().unwrap()
).into());
}
};
if pending == 1 {
buffer = current;
} else {
result.push(buffer * 16 + current);
pending = 0;
}
}
if pending != 0 {
Err(ErrorKind::HexInvalidLength.into())
} else {
Ok(result)
}
}
#[cfg(test)]
mod tests {
use common::prelude::*;
use super::from_hex;
#[test]
fn test_from_hex() {
assert_eq!(from_hex("68656c6c6f").unwrap(), b"hello");
assert_eq!(from_hex("68656C6C6F").unwrap(), b"hello");
assert_err!(from_hex("0"), ErrorKind::HexInvalidLength);
assert_err!(from_hex("fg"), ErrorKind::HexInvalidChar('g'));
}
}