use crate::buffer::{Buffer, StringBuffer};
use crate::error::InvalidInput;
use crate::{decode, encode};
trait HexPriv {}
#[allow(private_bounds, reason = "Sealed trait.")]
pub trait Hex: HexPriv {
#[doc(alias = "encode")]
fn hex<O: StringBuffer, const UPPER: bool>(&self) -> Result<O, InvalidInput>;
#[doc(alias = "decode")]
fn unhex<O: Buffer>(&self) -> Result<O, InvalidInput>;
}
impl<T: AsRef<[u8]>> HexPriv for T {}
impl<T: AsRef<[u8]>> Hex for T {
fn hex<O: StringBuffer, const UPPER: bool>(&self) -> Result<O, InvalidInput> {
let this = self.as_ref();
let mut buf = O::Bytes::uninit(this.len() * 2)?;
let written = encode::<UPPER>(this, &mut buf)?;
#[allow(unsafe_code, reason = "XXX")]
let buf = unsafe {
debug_assert!(written.len() == this.len() * 2);
O::Bytes::assume_init(buf)
};
#[allow(
unsafe_code,
reason = "Hexadecimal output contains only ASCII bytes, which are valid UTF-8."
)]
let buf = unsafe { O::from_utf8_unchecked(buf) };
Ok(buf)
}
fn unhex<O: Buffer>(&self) -> Result<O, InvalidInput> {
let this = self.as_ref();
if this.len() % 2 != 0 {
return Err(InvalidInput);
}
let mut buf = O::uninit(this.len() / 2)?;
let written = decode(this, &mut buf)?;
#[allow(unsafe_code, reason = "XXX")]
let buf = unsafe {
debug_assert!(written.len() == this.len() / 2);
O::assume_init(buf)
};
Ok(buf)
}
}
#[cfg(test)]
mod smoking {
use alloc::boxed::Box;
use alloc::rc::Rc;
use alloc::string::String;
use alloc::sync::Arc;
use alloc::vec::Vec;
use super::*;
#[test]
fn test_encode() {
let bytes = &[0xde, 0xad, 0xbe, 0xef];
macro_rules! test {
($ty:ty, $expected:expr) => {
assert!(
bytes
.hex::<$ty, false>()
.unwrap()
.eq_ignore_ascii_case($expected)
);
};
}
test!([u8; 8], b"deadbeef");
test!(Vec<u8>, b"deadbeef");
test!(Box<[u8]>, b"deadbeef");
test!(Arc<[u8]>, b"deadbeef");
test!(Rc<[u8]>, b"deadbeef");
test!(String, "deadbeef");
test!(Box<str>, "deadbeef");
test!(Arc<str>, "deadbeef");
test!(Rc<str>, "deadbeef");
}
#[test]
fn test_decode() {
let hex = b"deadbeef";
macro_rules! test {
($ty:ty, $expected:expr) => {
assert_eq!(&hex.unhex::<$ty>().unwrap()[..], $expected);
};
}
test!([u8; 4], b"\xde\xad\xbe\xef");
test!(Vec<u8>, b"\xde\xad\xbe\xef");
test!(Box<[u8]>, b"\xde\xad\xbe\xef");
test!(Arc<[u8]>, b"\xde\xad\xbe\xef");
test!(Rc<[u8]>, b"\xde\xad\xbe\xef");
}
}