use super::{
Encoding,
Error::{self, EncodingInvalid, LengthInvalid},
};
#[cfg(feature = "alloc")]
use prelude::*;
#[cfg(feature = "alloc")]
pub fn encode<B: AsRef<[u8]>>(bytes: B) -> Vec<u8> {
Hex::lower_case().encode(bytes)
}
#[cfg(feature = "alloc")]
pub fn decode<B: AsRef<[u8]>>(encoded_bytes: B) -> Result<Vec<u8>, Error> {
Hex::lower_case().decode(encoded_bytes)
}
#[cfg(feature = "alloc")]
pub fn encode_upper<B: AsRef<[u8]>>(bytes: B) -> Vec<u8> {
Hex::upper_case().encode(bytes)
}
#[cfg(feature = "alloc")]
pub fn decode_upper<B: AsRef<[u8]>>(encoded_bytes: B) -> Result<Vec<u8>, Error> {
Hex::upper_case().decode(encoded_bytes)
}
#[derive(Copy, Clone, Debug, Default, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub struct Hex {
case: Case,
}
impl Hex {
pub fn lower_case() -> Hex {
Hex { case: Case::Lower }
}
pub fn upper_case() -> Hex {
Hex { case: Case::Upper }
}
}
impl Encoding for Hex {
fn encode_to_slice(&self, src: &[u8], dst: &mut [u8]) -> Result<usize, Error> {
for (i, src_byte) in src.iter().enumerate() {
let offset = mul!(i, 2);
dst[offset] = self.case.encode_nibble(shr!(src_byte, 4));
dst[add!(offset, 1)] = self.case.encode_nibble(src_byte & 0x0f);
}
Ok(mul!(src.len(), 2))
}
fn encoded_len(&self, bytes: &[u8]) -> usize {
mul!(bytes.len(), 2)
}
fn decode_to_slice(&self, src: &[u8], dst: &mut [u8]) -> Result<usize, Error> {
let dst_length = self.decoded_len(src)?;
ensure!(dst_length <= dst.len(), LengthInvalid);
let mut err: usize = 0;
for (i, dst_byte) in dst.iter_mut().enumerate().take(dst_length) {
let src_offset = mul!(i, 2);
let byte = shl!(self.case.decode_nibble(src[src_offset]), 4)
| self.case.decode_nibble(src[add!(src_offset, 1)]);
err |= shr!(byte, 8);
*dst_byte = byte as u8;
}
if err == 0 {
Ok(dst_length)
} else {
Err(EncodingInvalid)
}
}
fn decoded_len(&self, bytes: &[u8]) -> Result<usize, Error> {
let encoded_length = bytes.len();
if encoded_length == 0 {
return Ok(0);
} else {
ensure!(encoded_length & 1 == 0, LengthInvalid);
}
Ok(shr!(encoded_length, 1))
}
}
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
enum Case {
Lower,
Upper,
}
impl Case {
#[inline]
fn decode_nibble(self, src: u8) -> usize {
let byte = src as isize;
let mut ret: isize = -1;
ret = add!(
ret,
shr!((sub!(0x2fisize, byte) & sub!(byte, 0x3a)), 8) & sub!(byte, 47)
);
ret = match self {
Case::Lower => {
add!(
ret,
shr!(sub!(0x60isize, byte) & sub!(byte, 0x67), 8) & sub!(byte, 86)
)
}
Case::Upper => {
add!(
ret,
shr!(sub!(0x40isize, byte) & sub!(byte, 0x47), 8) & sub!(byte, 54)
)
}
};
ret as usize
}
#[inline]
fn encode_nibble(self, src: u8) -> u8 {
let mut ret: isize = src as isize;
ret = match self {
Case::Lower => {
ret = add!(ret, 0x30);
add!(ret, shr!(sub!(0x39isize, ret), 8) & sub!(0x61isize, 0x3a))
}
Case::Upper => {
ret = add!(ret, 0x30);
add!(ret, shr!(sub!(0x39isize, ret), 8) & sub!(0x41isize, 0x3a))
}
};
ret as u8
}
}
impl Default for Case {
fn default() -> Case {
Case::Lower
}
}
#[cfg(test)]
mod tests {
use super::*;
use error::Error::*;
struct HexVector {
raw: &'static [u8],
hex: &'static [u8],
}
const HEX_TEST_VECTORS: &[HexVector] = &[
HexVector { raw: b"", hex: b"" },
HexVector {
raw: b"\0",
hex: b"00",
},
HexVector {
raw: b"***",
hex: b"2a2a2a",
},
HexVector {
raw: b"\x01\x02\x03\x04",
hex: b"01020304",
},
HexVector {
raw: b"\xAD\xAD\xAD\xAD\xAD",
hex: b"adadadadad",
},
HexVector {
raw: b"\xFF\xFF\xFF\xFF\xFF",
hex: b"ffffffffff",
},
];
#[test]
fn encode_test_vectors() {
for vector in HEX_TEST_VECTORS {
let mut out = [0u8; 10];
let out_len = Hex::lower_case()
.encode_to_slice(vector.raw, &mut out)
.unwrap();
assert_eq!(vector.hex, &out[..out_len]);
}
}
#[test]
fn decode_test_vectors() {
for vector in HEX_TEST_VECTORS {
let mut out = [0u8; 5];
let out_len = Hex::lower_case()
.decode_to_slice(vector.hex, &mut out)
.unwrap();
assert_eq!(vector.raw, &out[..out_len]);
}
}
#[test]
fn reject_odd_size_input() {
let mut out = [0u8; 3];
assert_eq!(
LengthInvalid,
Hex::lower_case()
.decode_to_slice(b"12345", &mut out)
.err()
.unwrap(),
)
}
#[test]
fn encode_and_decode_various_lengths() {
let data = [b'X'; 64];
for i in 0..data.len() {
let encoded = Hex::lower_case().encode(&data[..i]);
let decoded = Hex::lower_case().decode(encoded).unwrap();
assert_eq!(decoded.as_slice(), &data[..i]);
}
}
}