use core::{fmt, str};
use Hash;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Error {
InvalidChar(u8),
OddLengthString(usize),
InvalidLength(usize, usize),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Error::InvalidChar(ch) => write!(f, "invalid hex character {}", ch),
Error::OddLengthString(ell) => write!(f, "odd hex string length {}", ell),
Error::InvalidLength(ell, ell2) => write!(f, "bad hex string length {} (expected {})", ell2, ell),
}
}
}
#[cfg(any(test, feature = "std"))]
pub trait ToHex {
fn to_hex(&self) -> String;
}
pub trait FromHex: Sized {
fn from_byte_iter<I>(iter: I) -> Result<Self, Error>
where I: Iterator<Item=Result<u8, Error>> +
ExactSizeIterator +
DoubleEndedIterator;
fn from_hex(s: &str) -> Result<Self, Error> {
Self::from_byte_iter(HexIterator::new(s)?)
}
}
#[cfg(any(test, feature = "std"))]
impl<T: fmt::LowerHex> ToHex for T {
fn to_hex(&self) -> String {
format!("{:x}", self)
}
}
impl<T: Hash> FromHex for T {
fn from_byte_iter<I>(iter: I) -> Result<Self, Error>
where I: Iterator<Item=Result<u8, Error>> +
ExactSizeIterator +
DoubleEndedIterator,
{
let inner;
if Self::DISPLAY_BACKWARD {
inner = T::Inner::from_byte_iter(iter.rev())?;
} else {
inner = T::Inner::from_byte_iter(iter)?;
}
Ok(Hash::from_inner(inner))
}
}
pub struct HexIterator<'a> {
iter: str::Bytes<'a>,
}
impl<'a> HexIterator<'a> {
pub fn new(s: &'a str) -> Result<HexIterator<'a>, Error> {
if s.len() % 2 != 0 {
Err(Error::OddLengthString(s.len()))
} else {
Ok(HexIterator { iter: s.bytes() })
}
}
}
fn chars_to_hex(hi: u8, lo: u8) -> Result<u8, Error> {
let hih = (hi as char)
.to_digit(16)
.ok_or(Error::InvalidChar(hi))?;
let loh = (lo as char)
.to_digit(16)
.ok_or(Error::InvalidChar(lo))?;
let ret = (hih << 4) + loh;
Ok(ret as u8)
}
impl<'a> Iterator for HexIterator<'a> {
type Item = Result<u8, Error>;
fn next(&mut self) -> Option<Result<u8, Error>> {
let hi = self.iter.next()?;
let lo = self.iter.next().unwrap();
Some(chars_to_hex(hi, lo))
}
fn size_hint(&self) -> (usize, Option<usize>) {
let (min, max) = self.iter.size_hint();
(min / 2, max.map(|x| x /2))
}
}
impl<'a> DoubleEndedIterator for HexIterator<'a> {
fn next_back(&mut self) -> Option<Result<u8, Error>> {
let lo = self.iter.next_back()?;
let hi = self.iter.next_back().unwrap();
Some(chars_to_hex(hi, lo))
}
}
impl<'a> ExactSizeIterator for HexIterator<'a> {}
pub fn format_hex(data: &[u8], f: &mut fmt::Formatter) -> fmt::Result {
let prec = f.precision().unwrap_or(2 * data.len());
let width = f.width().unwrap_or(2 * data.len());
for _ in (2 * data.len())..width {
f.write_str("0")?;
}
for ch in data.iter().take(prec / 2) {
write!(f, "{:02x}", *ch)?;
}
if prec < 2 * data.len() && prec % 2 == 1 {
write!(f, "{:x}", data[prec / 2] / 16)?;
}
Ok(())
}
pub fn format_hex_reverse(data: &[u8], f: &mut fmt::Formatter) -> fmt::Result {
let prec = f.precision().unwrap_or(2 * data.len());
let width = f.width().unwrap_or(2 * data.len());
for _ in (2 * data.len())..width {
f.write_str("0")?;
}
for ch in data.iter().rev().take(prec / 2) {
write!(f, "{:02x}", *ch)?;
}
if prec < 2 * data.len() && prec % 2 == 1 {
write!(f, "{:x}", data[data.len() - 1 - prec / 2] / 16)?;
}
Ok(())
}
#[cfg(any(test, feature = "std"))]
impl ToHex for [u8] {
fn to_hex(&self) -> String {
use core::fmt::Write;
let mut ret = String::with_capacity(2 * self.len());
for ch in self {
write!(ret, "{:02x}", ch).expect("writing to string");
}
ret
}
}
#[cfg(any(test, feature = "std"))]
impl FromHex for Vec<u8> {
fn from_byte_iter<I>(iter: I) -> Result<Self, Error>
where I: Iterator<Item=Result<u8, Error>> +
ExactSizeIterator +
DoubleEndedIterator,
{
iter.collect()
}
}
macro_rules! impl_fromhex_array {
($len:expr) => {
impl FromHex for [u8; $len] {
fn from_byte_iter<I>(iter: I) -> Result<Self, Error>
where I: Iterator<Item=Result<u8, Error>> +
ExactSizeIterator +
DoubleEndedIterator,
{
if iter.len() == $len {
let mut ret = [0; $len];
for (n, byte) in iter.enumerate() {
ret[n] = byte?;
}
Ok(ret)
} else {
Err(Error::InvalidLength(2 * $len, 2 * iter.len()))
}
}
}
}
}
impl_fromhex_array!(2);
impl_fromhex_array!(4);
impl_fromhex_array!(6);
impl_fromhex_array!(8);
impl_fromhex_array!(10);
impl_fromhex_array!(12);
impl_fromhex_array!(14);
impl_fromhex_array!(16);
impl_fromhex_array!(20);
impl_fromhex_array!(24);
impl_fromhex_array!(28);
impl_fromhex_array!(32);
impl_fromhex_array!(33);
impl_fromhex_array!(64);
impl_fromhex_array!(65);
impl_fromhex_array!(128);
impl_fromhex_array!(256);
impl_fromhex_array!(384);
impl_fromhex_array!(512);
#[cfg(test)]
mod tests {
use super::*;
use core::fmt;
#[test]
fn hex_roundtrip() {
let expected = "0123456789abcdef";
let expected_up = "0123456789ABCDEF";
let parse: Vec<u8> = FromHex::from_hex(expected).expect("parse lowercase string");
assert_eq!(parse, vec![0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]);
let ser = parse.to_hex();
assert_eq!(ser, expected);
let parse: Vec<u8> = FromHex::from_hex(expected_up).expect("parse uppercase string");
assert_eq!(parse, vec![0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]);
let ser = parse.to_hex();
assert_eq!(ser, expected);
let parse: [u8; 8] = FromHex::from_hex(expected_up).expect("parse uppercase string");
assert_eq!(parse, [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]);
let ser = parse.to_hex();
assert_eq!(ser, expected);
}
#[test]
fn hex_truncate() {
struct HexBytes(Vec<u8>);
impl fmt::LowerHex for HexBytes {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
format_hex(&self.0, f)
}
}
let bytes = HexBytes(vec![1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
assert_eq!(
format!("{:x}", bytes),
"0102030405060708090a"
);
for i in 0..20 {
assert_eq!(
format!("{:.prec$x}", bytes, prec = i),
&"0102030405060708090a"[0..i]
);
}
assert_eq!(
format!("{:25x}", bytes),
"000000102030405060708090a"
);
assert_eq!(
format!("{:26x}", bytes),
"0000000102030405060708090a"
);
}
#[test]
fn hex_truncate_rev() {
struct HexBytes(Vec<u8>);
impl fmt::LowerHex for HexBytes {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
format_hex_reverse(&self.0, f)
}
}
let bytes = HexBytes(vec![1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
assert_eq!(
format!("{:x}", bytes),
"0a090807060504030201"
);
for i in 0..20 {
assert_eq!(
format!("{:.prec$x}", bytes, prec = i),
&"0a090807060504030201"[0..i]
);
}
assert_eq!(
format!("{:25x}", bytes),
"000000a090807060504030201"
);
assert_eq!(
format!("{:26x}", bytes),
"0000000a090807060504030201"
);
}
#[test]
fn hex_error() {
let oddlen = "0123456789abcdef0";
let badchar1 = "Z123456789abcdef";
let badchar2 = "012Y456789abcdeb";
let badchar3 = "«23456789abcdef";
assert_eq!(
Vec::<u8>::from_hex(oddlen),
Err(Error::OddLengthString(17))
);
assert_eq!(
<[u8; 4]>::from_hex(oddlen),
Err(Error::OddLengthString(17))
);
assert_eq!(
<[u8; 8]>::from_hex(oddlen),
Err(Error::OddLengthString(17))
);
assert_eq!(
Vec::<u8>::from_hex(badchar1),
Err(Error::InvalidChar(b'Z'))
);
assert_eq!(
Vec::<u8>::from_hex(badchar2),
Err(Error::InvalidChar(b'Y'))
);
assert_eq!(
Vec::<u8>::from_hex(badchar3),
Err(Error::InvalidChar(194))
);
}
}