use std::{ mem, iter::{ self, ExactSizeIterator, FusedIterator, }, slice, fmt, }; #[derive(Debug, Clone)] pub struct HexStringIter(I, [u8; 2]); impl> HexStringIter { /// Write this hex string iterator to a formattable buffer pub fn consume(self, f: &mut F) -> fmt::Result where F: std::fmt::Write { if self.1[0] != 0 { write!(f, "{}", self.1[0] as char)?; } if self.1[1] != 0 { write!(f, "{}", self.1[1] as char)?; } for x in self.0 { write!(f, "{:02x}", x)?; } Ok(()) } /// Consume into a string pub fn into_string(self) -> String { let mut output = match self.size_hint() { (0, None) => String::new(), (_, Some(x)) | (x, None) => String::with_capacity(x), }; self.consume(&mut output).unwrap(); output } } pub trait HexStringIterExt: Sized { fn into_hex(self) -> HexStringIter; } pub type HexStringSliceIter<'a> = HexStringIter>>; pub trait HexStringSliceIterExt { fn hex(&self) -> HexStringSliceIter<'_>; } impl HexStringSliceIterExt for S where S: AsRef<[u8]> { fn hex(&self) -> HexStringSliceIter<'_> { self.as_ref().iter().copied().into_hex() } } impl> HexStringIterExt for I { #[inline] fn into_hex(self) -> HexStringIter { HexStringIter(self.into_iter(), [0u8; 2]) } } impl> Iterator for HexStringIter { type Item = char; fn next(&mut self) -> Option { match self.1 { [_, 0] => { use std::io::Write; write!(&mut self.1[..], "{:02x}", self.0.next()?).unwrap(); Some(mem::replace(&mut self.1[0], 0) as char) }, [0, _] => Some(mem::replace(&mut self.1[1], 0) as char), _ => unreachable!(), } } fn size_hint(&self) -> (usize, Option) { let (l, h) = self.0.size_hint(); (l * 2, h.map(|x| x*2)) } } impl + ExactSizeIterator> ExactSizeIterator for HexStringIter{} impl + FusedIterator> FusedIterator for HexStringIter{} impl> From> for String { fn from(from: HexStringIter) -> Self { from.into_string() } } impl + Clone> fmt::Display for HexStringIter { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.clone().consume(f) } } /* #[macro_export] macro_rules! prog1 { ($first:expr, $($rest:expr);+ $(;)?) => { ($first, $( $rest ),+).0 } } */