use std::borrow::Borrow;
use std::io;
use types::{Error, ParseHexError};
#[inline]
pub fn intoval(c: u8) -> Result<u8, ParseHexError> {
match c {
b'A'...b'F' => Ok(c - b'A' + 10),
b'a'...b'f' => Ok(c - b'a' + 10),
b'0'...b'9' => Ok(c - b'0'),
_ => {
let val = c as char;
Err(ParseHexError::Char { val })
}
}
}
#[inline]
pub fn fromval(val: u8) -> u8 {
match val {
0xa...0xf => val - 0xa + b'a',
0x0...0x9 => val + b'0',
_ => panic!("value outside range 0x0...0xf"),
}
}
#[inline]
pub fn fromvalcaps(val: u8) -> u8 {
match val {
0xA...0xF => val - 0xa + b'A',
0x0...0x9 => val + b'0',
_ => panic!("value outside range 0x0...0xf"),
}
}
#[inline]
pub fn intobyte(a: u8, b: u8) -> Result<u8, ParseHexError> {
Ok(intoval(a)? << 4 | intoval(b)?)
}
#[inline]
fn frombyte(val: u8) -> (u8, u8) {
(fromval(val >> 4), fromval(val & 0x0f))
}
#[inline]
pub fn frombytecaps(val: u8) -> (u8, u8) {
(fromvalcaps(val >> 4), fromvalcaps(val & 0x0f))
}
pub fn fromhex(buf: &mut [u8], src: &[u8]) -> Result<(), ParseHexError> {
let expect = buf.len() * 2;
let actual = src.len();
if expect == actual {
for (idx, pair) in src.chunks(2).enumerate() {
buf[idx] = intobyte(pair[0], pair[1])?;
}
Ok(())
} else {
Err(ParseHexError::Size { expect, actual })
}
}
pub fn intohex(buf: &mut [u8], src: &[u8]) {
if buf.len() == src.len() * 2 {
for (i, byte) in src.iter().enumerate() {
let (a, b) = frombyte(*byte);
let idx = i * 2;
buf[idx] = a;
buf[idx + 1] = b;
}
} else {
panic!("invalid buffer sizes");
}
}
pub fn intohexcaps(buf: &mut [u8], src: &[u8]) {
if buf.len() == src.len() * 2 {
for (i, byte) in src.iter().enumerate() {
let (a, b) = frombytecaps(*byte);
let idx = i * 2;
buf[idx] = a;
buf[idx + 1] = b;
}
} else {
panic!("invalid buffer sizes");
}
}
pub fn writehex<S, B, D>(src: S, mut dst: D) -> Result<(), Error>
where
S: IntoIterator<Item = B>,
B: Borrow<u8>,
D: io::Write,
{
for byte in src.into_iter() {
let (a, b) = frombyte(*byte.borrow());
dst.write_all(&[a, b])?;
}
Ok(())
}
pub fn writehexcaps<S, B, D>(src: S, mut dst: D) -> Result<(), Error>
where
S: IntoIterator<Item = B>,
B: Borrow<u8>,
D: io::Write,
{
for byte in src.into_iter() {
let (a, b) = frombytecaps(*byte.borrow());
dst.write_all(&[a, b])?;
}
Ok(())
}
#[cfg(test)]
mod tests {
#[test]
fn hex_bytes() {
use utils::{frombyte, intobyte};
for i in 0..255u8 {
let h = frombyte(i);
let b = intobyte(h.0, h.1).unwrap();
assert_eq!(i, b);
}
let hex = ["ff", "aa", "f0", "a0", "0f", "0a", "00", "99", "90", "09"];
for s in hex.iter() {
let s: &[u8] = s.as_ref();
let v = intobyte(s[0], s[1]).unwrap();
let (a, b) = frombyte(v);
assert_eq!(s, &[a, b]);
}
}
#[test]
fn hex_strings() {
use utils::{fromhex, intohex};
let hv = [
"ff",
"aa",
"f0f0",
"a0a0",
"1234",
"5678",
"0000",
"0123456789abfdef",
];
for hs in hv.iter() {
let src: &[u8] = hs.as_ref();
let mut buff = vec![0u8; src.len() / 2];
let mut rslt = vec![0u8; buff.len() * 2];
fromhex(&mut buff, src).unwrap();
intohex(&mut rslt, &buff);
assert_eq!(src, AsRef::<[u8]>::as_ref(&rslt));
}
}
}