89 lines
2.9 KiB
Rust
89 lines
2.9 KiB
Rust
use crate::scannable::{ChunkIter, Scannable};
|
|
use core::ops::{Bound, Range, RangeBounds, RangeFull};
|
|
use core::fmt::{Display, Formatter};
|
|
|
|
const SEP: &str = " | ";
|
|
|
|
pub struct HexDump<'s, T: Scannable + ?Sized, R: RangeBounds<usize>>(pub &'s T, pub R);
|
|
|
|
pub fn hex<
|
|
T: Scannable + ?Sized,
|
|
R: RangeBounds<usize>
|
|
>(
|
|
data: &T,
|
|
range:R
|
|
) -> HexDump<T, R> {
|
|
HexDump(data, range)
|
|
}
|
|
|
|
|
|
impl<'s, T: Scannable> HexDump<'s, T, RangeFull> {
|
|
pub fn new(scannable: &'s T) -> Self {
|
|
Self(scannable, ..)
|
|
}
|
|
}
|
|
|
|
|
|
impl<'s, T: Scannable + ?Sized, R: RangeBounds<usize>> Display for HexDump<'s, T, R> {
|
|
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
|
|
|
// calculate the end and the start addresses
|
|
let (start, end) = {
|
|
let r = self.0.range();
|
|
let start = match self.1.start_bound() {
|
|
Bound::Included(i) => *i,
|
|
Bound::Excluded(i) => i.saturating_add(1),
|
|
Bound::Unbounded => 0,
|
|
}.max(r.start);
|
|
let end = match self.1.end_bound() {
|
|
Bound::Included(i) => *i,
|
|
Bound::Excluded(i) => i.saturating_sub(1),
|
|
Bound::Unbounded => usize::MAX,
|
|
}.min(r.end);
|
|
(start, end)
|
|
};
|
|
|
|
// the number of digits the address column should have
|
|
let digits = if end == 0 { 4 } else {
|
|
(end.ilog(16) as usize + 1).max(4)
|
|
};
|
|
|
|
for (mut addr, chunk) in ChunkIter::new(self.0, start) {
|
|
for chunk in chunk.chunks(16) {
|
|
if addr > end { return Ok(()) }
|
|
let chunk = &chunk[..(1 + end - addr).min(chunk.len())];
|
|
|
|
|
|
//╶───╴Column╶────────────────────────────────╴
|
|
write!(f, "{:0digits$X}{SEP}", addr, digits = digits)?;
|
|
|
|
//╶───╴Bytes╶─────────────────────────────────╴
|
|
for (i, byte) in chunk.iter().enumerate() {
|
|
if i != 0 { write!(f, " ")?; }
|
|
write!(f, "{byte:02X}")?;
|
|
}
|
|
for i in (chunk.len()..16) {
|
|
match i {
|
|
0 => write!(f, " ")?,
|
|
_ => write!(f, " ")?,
|
|
}
|
|
}
|
|
|
|
//╶───╴Text╶──────────────────────────────────╴
|
|
write!(f, "{SEP}")?;
|
|
for &byte in chunk {
|
|
match byte {
|
|
0x20..0x7e => write!(f, "{}", char::from(byte))?,
|
|
_ => write!(f, ".")?,
|
|
}
|
|
}
|
|
writeln!(f)?;
|
|
addr += chunk.len()
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
}
|