|
|
|
@ -7,6 +7,9 @@ use std::{
|
|
|
|
|
ops::{
|
|
|
|
|
Range,
|
|
|
|
|
},
|
|
|
|
|
marker::{
|
|
|
|
|
PhantomData,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
use tokio::{
|
|
|
|
|
io::AsyncRead,
|
|
|
|
@ -131,12 +134,105 @@ const ASCII_MAP: [char; 256] = [
|
|
|
|
|
'.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.',
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
pub struct HexStringIter<'a, I>(&'a I, bool);
|
|
|
|
|
pub struct HexView<'a, I>(&'a I);
|
|
|
|
|
const fn create_hex_map() -> [(u8, u8); 256]
|
|
|
|
|
{
|
|
|
|
|
let mut out = [(0, 0); 256];
|
|
|
|
|
const HEX: &[u8; 16] = b"0123456789abcdef";
|
|
|
|
|
let mut i = 0usize;
|
|
|
|
|
while i <= 255
|
|
|
|
|
{
|
|
|
|
|
out[i] = (
|
|
|
|
|
HEX[i >> 4],
|
|
|
|
|
HEX[i & 0xf]
|
|
|
|
|
);
|
|
|
|
|
i+=1;
|
|
|
|
|
}
|
|
|
|
|
out
|
|
|
|
|
}
|
|
|
|
|
const HEX_MAP: [(u8, u8); 256] = create_hex_map();
|
|
|
|
|
|
|
|
|
|
pub struct HexStringView<'a, I:?Sized>(&'a I, bool);
|
|
|
|
|
pub struct HexStringIter<'a, I:?Sized>(std::slice::Iter<'a, u8>, (u8, u8), PhantomData<&'a I>);
|
|
|
|
|
|
|
|
|
|
pub struct HexView<'a, I:?Sized>(&'a I);
|
|
|
|
|
|
|
|
|
|
pub struct AsciiView<'a, I:?Sized>(&'a I);
|
|
|
|
|
pub struct AsciiIter<'a, I:?Sized>(&'a [u8], PhantomData<&'a I>);
|
|
|
|
|
|
|
|
|
|
const SPLIT_EVERY: usize = 16;
|
|
|
|
|
|
|
|
|
|
impl<'a, I: AsRef<[u8]>> fmt::Display for HexView<'a, I>
|
|
|
|
|
impl<'a, I: ?Sized+AsRef<[u8]>> Iterator for AsciiIter<'a, I>
|
|
|
|
|
{
|
|
|
|
|
type Item = char;
|
|
|
|
|
fn next(&mut self) -> Option<Self::Item>
|
|
|
|
|
{
|
|
|
|
|
match match self.0 {
|
|
|
|
|
[] => None,
|
|
|
|
|
[chr, ..] => Some(ASCII_MAP[*chr as usize]),
|
|
|
|
|
} {
|
|
|
|
|
x @ Some(_) => {
|
|
|
|
|
self.0 = &self.0[1..];
|
|
|
|
|
x
|
|
|
|
|
},
|
|
|
|
|
_ => None,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
|
|
|
|
(self.0.len(), Some(self.0.len()))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
impl<'a, I: ?Sized+AsRef<[u8]>> ExactSizeIterator for AsciiIter<'a, I>{}
|
|
|
|
|
impl<'a, I: ?Sized+AsRef<[u8]>> std::iter::FusedIterator for AsciiIter<'a, I>{}
|
|
|
|
|
|
|
|
|
|
impl<'a, I: ?Sized+AsRef<[u8]>> Iterator for HexStringIter<'a, I>
|
|
|
|
|
{
|
|
|
|
|
type Item = char;
|
|
|
|
|
fn next(&mut self) -> Option<Self::Item>
|
|
|
|
|
{
|
|
|
|
|
match self.1 {
|
|
|
|
|
ref mut buf @ (0, 0) => {
|
|
|
|
|
// both are taken
|
|
|
|
|
if let Some(&byte) = self.0.next() {
|
|
|
|
|
*buf = HEX_MAP[byte as usize];
|
|
|
|
|
} else {
|
|
|
|
|
return None;
|
|
|
|
|
}
|
|
|
|
|
(Some(buf.0 as char),buf.0 = 0).0
|
|
|
|
|
},
|
|
|
|
|
(0, ref mut second) => {
|
|
|
|
|
// first is taken
|
|
|
|
|
(Some(*second as char),*second = 0).0
|
|
|
|
|
},
|
|
|
|
|
#[cold] (ref mut first, _) => {
|
|
|
|
|
// neither are taken, usually shouldn't happen
|
|
|
|
|
(Some(*first as char),*first = 0).0
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
|
|
|
|
let sz = self.0.size_hint();
|
|
|
|
|
(sz.0 * 2, sz.1.map(|x| x*2))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
impl<'a, I: ?Sized+AsRef<[u8]>> ExactSizeIterator for HexStringIter<'a, I>{}
|
|
|
|
|
impl<'a, I: ?Sized+AsRef<[u8]>> std::iter::FusedIterator for HexStringIter<'a, I>{}
|
|
|
|
|
|
|
|
|
|
impl<'a, I: AsRef<[u8]>+?Sized> fmt::Display for AsciiView<'a, I>
|
|
|
|
|
{
|
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
|
|
|
|
{
|
|
|
|
|
for byte in self.0.as_ref().iter().map(|&byte| ASCII_MAP[byte as usize])
|
|
|
|
|
{
|
|
|
|
|
use std::fmt::Write;
|
|
|
|
|
f.write_char(byte)?;
|
|
|
|
|
}
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'a, I: AsRef<[u8]>+?Sized> fmt::Display for HexView<'a, I>
|
|
|
|
|
{
|
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
|
|
|
|
{
|
|
|
|
@ -178,7 +274,7 @@ impl<'a, I: AsRef<[u8]>> fmt::Display for HexView<'a, I>
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'a, I: AsRef<[u8]>> fmt::Display for HexStringIter<'a, I>
|
|
|
|
|
impl<'a, I: AsRef<[u8]>+?Sized> fmt::Display for HexStringView<'a, I>
|
|
|
|
|
{
|
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
|
|
|
|
{
|
|
|
|
@ -202,10 +298,26 @@ impl<'a, I: AsRef<[u8]>> fmt::Display for HexStringIter<'a, I>
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub trait HexStringExt: Sized + AsRef<[u8]>
|
|
|
|
|
/// Extensions on byte slices to print them nicely
|
|
|
|
|
pub trait HexStringExt: AsRef<[u8]>
|
|
|
|
|
{
|
|
|
|
|
/// An iterator that prints readable ascii of each byte
|
|
|
|
|
fn iter_ascii(&self) -> AsciiIter<'_, Self>;
|
|
|
|
|
/// A `Display` implementor that prints ascii of each byte
|
|
|
|
|
fn fmt_ascii(&self) -> AsciiView<'_, Self>;
|
|
|
|
|
|
|
|
|
|
/// A pretty hex view `Display` implementor of the bytes
|
|
|
|
|
fn fmt_view(&self) -> HexView<'_, Self>;
|
|
|
|
|
fn fmt_hex(&self) -> HexStringIter<'_, Self>;
|
|
|
|
|
|
|
|
|
|
/// A `Display` implementor that prints the hex of each byte in lowercase
|
|
|
|
|
fn fmt_hex(&self) -> HexStringView<'_, Self>;
|
|
|
|
|
/// An iterator over `char`s that yields the hex of each byte
|
|
|
|
|
///
|
|
|
|
|
/// # Notes
|
|
|
|
|
/// This yields each character one at a time, to get the hex of each byte, chunk it with a window of 2.
|
|
|
|
|
fn iter_hex(&self) -> HexStringIter<'_, Self>;
|
|
|
|
|
|
|
|
|
|
/// Convenience method for creating a hex string.
|
|
|
|
|
fn to_hex_string(&self) -> String
|
|
|
|
|
{
|
|
|
|
|
let mut string = String::with_capacity(self.as_ref().len()*2);
|
|
|
|
@ -213,9 +325,11 @@ pub trait HexStringExt: Sized + AsRef<[u8]>
|
|
|
|
|
write!(&mut string, "{}", self.fmt_hex()).unwrap();
|
|
|
|
|
string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Convenience method for creating a hex string with each byte broken by a hyphen.
|
|
|
|
|
fn to_broken_hex_string(&self) -> String
|
|
|
|
|
{
|
|
|
|
|
let fmt = HexStringIter(
|
|
|
|
|
let fmt = HexStringView(
|
|
|
|
|
self.fmt_hex().0,
|
|
|
|
|
true
|
|
|
|
|
);
|
|
|
|
@ -224,13 +338,37 @@ pub trait HexStringExt: Sized + AsRef<[u8]>
|
|
|
|
|
write!(&mut string, "{}", fmt).unwrap();
|
|
|
|
|
string
|
|
|
|
|
}
|
|
|
|
|
/// Convenience method for creating a string from `fmt_view()`
|
|
|
|
|
#[inline] fn to_view_string(&self) -> String
|
|
|
|
|
{
|
|
|
|
|
format!("{}", self.fmt_view())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Convenience method for creating a string from `fmt_ascii()`
|
|
|
|
|
|
|
|
|
|
#[inline] fn to_ascii_string(&self) -> String
|
|
|
|
|
{
|
|
|
|
|
self.iter_ascii().collect()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<T: AsRef<[u8]>> HexStringExt for T
|
|
|
|
|
impl<T: AsRef<[u8]>+?Sized> HexStringExt for T
|
|
|
|
|
{
|
|
|
|
|
fn fmt_hex(&self) -> HexStringIter<'_, Self>
|
|
|
|
|
fn iter_hex(&self) -> HexStringIter<'_, Self>
|
|
|
|
|
{
|
|
|
|
|
HexStringIter(self.as_ref().iter(), (0,0), PhantomData)
|
|
|
|
|
}
|
|
|
|
|
fn iter_ascii(&self) -> AsciiIter<'_, Self>
|
|
|
|
|
{
|
|
|
|
|
AsciiIter(self.as_ref(), PhantomData)
|
|
|
|
|
}
|
|
|
|
|
fn fmt_ascii(&self) -> AsciiView<'_, Self>
|
|
|
|
|
{
|
|
|
|
|
AsciiView(&self)
|
|
|
|
|
}
|
|
|
|
|
fn fmt_hex(&self) -> HexStringView<'_, Self>
|
|
|
|
|
{
|
|
|
|
|
HexStringIter(&self, false)
|
|
|
|
|
HexStringView(&self, false)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn fmt_view(&self) -> HexView<'_, Self>
|
|
|
|
|