#[cfg(all(feature = "alloc", not(feature = "std")))]
use alloc::string::String;
#[cfg(all(feature = "alloc", not(feature = "std")))]
use alloc::vec::Vec;
#[cfg(feature = "std")]
use std::string::String;
#[cfg(feature = "std")]
use std::vec::Vec;
use core::fmt;
#[derive(Debug, Clone, PartialEq)]
pub enum HexError {
InvalidHex,
InvalidLength,
InvalidEncoding,
}
impl fmt::Display for HexError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use HexError::*;
match self {
InvalidHex => write!(f, "invalid hex string"),
InvalidLength => write!(f, "hex string had an invalid (odd) length"),
InvalidEncoding => write!(f, "hex value did not encode the expected type"),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for HexError {}
#[doc(hidden)]
pub fn hex_val(c: u8) -> Result<u8, HexError> {
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'),
_ => Err(HexError::InvalidHex),
}
}
#[cfg(feature = "alloc")]
pub fn encode(bytes: &[u8]) -> String {
use core::fmt::Write;
let mut hex = String::new();
for byte in bytes {
write!(hex, "{:02x}", byte).unwrap()
}
hex
}
#[cfg(feature = "alloc")]
pub fn decode(hex: &str) -> Result<Vec<u8>, HexError> {
if (hex.len() % 2) != 0 {
return Err(HexError::InvalidLength);
}
let mut bytes = Vec::with_capacity(hex.len() * 2);
for hex_byte in hex.as_bytes().chunks(2) {
bytes.push(hex_val(hex_byte[0])? << 4 | hex_val(hex_byte[1])?)
}
Ok(bytes)
}