#![no_std]
#![doc = include_str!("../README.md")]
use core::fmt::{Debug, Display, LowerHex, UpperHex};
#[cfg(feature = "std")]
extern crate std;
pub trait HexDisplayExt {
fn hex(&self) -> Hex<'_>;
#[cfg(feature = "std")]
fn upper_hex_string(&self) -> std::string::String {
use std::string::ToString;
format!("{:X}", self.hex())
}
#[cfg(feature = "std")]
fn hex_string(&self) -> std::string::String {
use std::string::ToString;
self.hex().to_string()
}
}
impl HexDisplayExt for [u8] {
fn hex(&self) -> Hex<'_> {
Hex(self)
}
}
impl<const N: usize> HexDisplayExt for [u8; N] {
fn hex(&self) -> Hex<'_> {
Hex(self)
}
}
pub struct Hex<'a>(
pub &'a [u8],
);
impl<'a> UpperHex for Hex<'a> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
for byte in self.0 {
f.write_fmt(format_args!("{:02X}", byte))?;
}
Ok(())
}
}
impl<'a> LowerHex for Hex<'a> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
for byte in self.0 {
f.write_fmt(format_args!("{:02x}", byte))?;
}
Ok(())
}
}
impl<'a> Debug for Hex<'a> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
for byte in self.0 {
f.write_fmt(format_args!("{:02x}", byte))?;
}
Ok(())
}
}
impl<'a> Display for Hex<'a> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
for byte in self.0 {
f.write_fmt(format_args!("{:02x}", byte))?;
}
Ok(())
}
}
#[cfg(test)]
mod tests {
extern crate std;
use std::format;
use super::*;
#[test]
fn test_all_bytes() {
for byte in 0..=0xff {
assert_eq!(format!("{:02x}", byte), format!("{}", Hex(&[byte])));
assert_eq!(format!("{:02X}", byte), format!("{:X}", Hex(&[byte])));
}
}
#[test]
fn test_all_byte_pairs() {
for (a, b) in (0..=0xff).zip(0..=0xff) {
assert_eq!(format!("{:02x}{:02x}", a, b), format!("{}", Hex(&[a, b])));
assert_eq!(format!("{:02X}{:02X}", a, b), format!("{:X}", Hex(&[a, b])));
}
}
}