use core::fmt::*;
pub struct Hexdump<'a> {
data: &'a [u8],
show_index: bool,
items_per_row: usize,
}
impl<'a> Hexdump<'a> {
pub fn new(data: &'a [u8]) -> Self {
Hexdump {
data,
show_index: true,
items_per_row: 16,
}
}
pub fn show_index(&mut self, value: bool) -> &mut Self {
self.show_index = value;
self
}
pub fn items_per_row(&mut self, value: usize) -> &mut Self {
self.items_per_row = value;
self
}
}
impl<'a> Display for Hexdump<'a> {
fn fmt(&self, f: &mut Formatter) -> Result {
for i in 0..self.data.len() {
if self.show_index && i % self.items_per_row == 0 {
write!(f, "{:08x}\t", i)?;
}
write!(f, "{:02x}", self.data[i])?;
if i != self.data.len() - 1 {
if i % self.items_per_row == self.items_per_row - 1 {
f.write_char('\n')?;
} else {
f.write_char(' ')?;
}
}
}
Ok(())
}
}
pub trait AsHexdump {
fn as_hexdump(&self) -> Hexdump<'_>;
}
impl<T: AsRef<[u8]>> AsHexdump for T {
fn as_hexdump(&self) -> Hexdump<'_> {
Hexdump::new(self.as_ref())
}
}
#[macro_export]
macro_rules! hexdump {
($value:expr) => (
$value.as_hexdump()
);
($value:expr, $($setting:ident: $setting_value: expr)*) => (
$value.as_hexdump() $(
.$setting($setting_value)
)*
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn readme() {
assert_eq!(
format!("{}", hexdump!(&[1u8, 2, 255, 64])),
"00000000 01 02 ff 40"
);
assert_eq!(
format!("{}", hexdump!(64i32.to_le_bytes())),
"00000000 40 00 00 00"
);
assert_eq!(
format!("{}", hexdump!(64i32.to_le_bytes(), show_index: false)),
"40 00 00 00"
);
}
}