use std::any::type_name;
use std::io::{self, Write};
use std::mem;
use std::ptr;
#[inline]
#[doc(hidden)]
pub unsafe fn as_bytes_with_len<T: ?Sized>(t: &T, len: usize) -> &[u8] {
let p = t as *const _ as *const u8;
&*ptr::slice_from_raw_parts(p, len)
}
#[inline]
#[doc(hidden)]
pub fn as_bytes<T: ?Sized>(t: &T) -> &[u8] {
unsafe { as_bytes_with_len(t, mem::size_of_val::<T>(t)) }
}
#[doc(hidden)]
pub struct Record<'a, T: ?Sized> {
pub reference: &'a T,
pub bytes: &'a [u8],
pub sized: bool,
pub source: &'a str,
pub label: Option<&'a str>,
pub file: &'a str,
pub line: u32,
pub column: u32,
}
#[doc(hidden)]
pub fn write_internal<W: Write, T: ?Sized>(
mut w: W,
record: &Record<T>,
absolute: bool,
) -> Result<(), io::Error> {
let width = 16;
let center = width / 2;
if absolute {
writeln!(
w,
"{:p} : {} = {}",
record.reference,
type_name::<T>(),
record.source
)?;
} else {
writeln!(
w,
"-----+ {:p}: {} = {}",
record.reference,
type_name::<T>(),
record.source
)?;
}
for (i, x) in record.bytes.iter().enumerate() {
if i % width == 0 {
if i != 0 {
writeln!(w)?;
}
if absolute {
write!(w, "{:p} |", unsafe {
(record.reference as *const _ as *const u8).add(i)
})?;
} else {
write!(w, "{:04x} |", i)?;
}
} else if i % center == 0 {
write!(w, " :")?;
}
write!(w, " {:02x}", x)?;
}
if !record.bytes.is_empty() {
writeln!(w)?;
}
Ok(())
}
#[inline]
#[doc(hidden)]
pub fn print_internal<T: ?Sized>(record: &Record<T>, absolute: bool) {
write_internal(io::stdout().lock(), record, absolute).unwrap()
}
#[inline]
#[doc(hidden)]
pub fn eprint_internal<T: ?Sized>(record: &Record<T>, absolute: bool) {
write_internal(io::stderr().lock(), record, absolute).unwrap()
}
#[macro_export]
#[doc(hidden)]
macro_rules! record {
($t: expr, $v: expr, $bs: expr, $sized: expr) => {{
let bytes = $bs;
$crate::Record {
reference: $t,
bytes,
sized: $sized,
source: stringify!($v),
label: None,
file: file!(),
line: line!(),
column: column!(),
}
}};
}
#[macro_export]
macro_rules! binspect {
($v: expr) => {{
let t = &$v;
let bs = $crate::as_bytes(t);
$crate::print_internal(&$crate::record!(t, $v, bs, true), false);
}};
($v: expr, $len: expr) => {{
let t = &$v;
let bs = $crate::as_bytes_with_len(t, $len);
$crate::print_internal(&$crate::record!(t, $v, bs, false), false);
}};
}
#[macro_export]
macro_rules! ebinspect {
($v: expr) => {{
let t = &$v;
let bs = $crate::as_bytes(t);
$crate::eprint_internal(&$crate::record!(t, $v, bs, true), false);
}};
($v: expr, $len: expr) => {{
let t = &$v;
let bs = $crate::as_bytes_with_len(t, $len);
$crate::eprint_internal(&$crate::record!(t, $v, bs, false), false);
}};
}
#[macro_export]
macro_rules! write_binspect {
($w: expr, $v: expr) => {{
let t = &$v;
let bs = $crate::as_bytes(t);
$crate::write_internal($w, &$crate::record!(t, $v, bs, true), false)
}};
($w: expr, $v: expr, $len: expr) => {{
let t = &$v;
let bs = $crate::as_bytes_with_len(t, $len);
$crate::write_internal($w, &$crate::record!(t, $v, bs, false), false)
}};
}