//! Extensions use super::*; use std::{ collections::HashMap, hash::Hash, borrow::{ Borrow, ToOwned, }, num::NonZeroU8, }; pub use dedup::DedupIterExt; /// Iterator that maps `T` -> `U` pub struct ReplacingIter<'a, I,T, U=T> { iter: I, table: &'a HashMap, } impl<'a, I,T,U> Iterator for ReplacingIter<'a, I,T,U> where I: Iterator, T: Hash+ Eq + ToOwned, U: Borrow + Clone, { type Item = U; fn next(&mut self) -> Option { if let Some(item) = self.iter.next() { Some(self.table.get(&item) .map(Clone::clone) .unwrap_or(item.to_owned())) } else { None } } #[inline] fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } } impl<'a, I,T,U> ExactSizeIterator for ReplacingIter<'a, I,T,U> where I: Iterator + ExactSizeIterator, T: Hash+ Eq + ToOwned, U: Borrow + Clone{} impl<'a, I,T,U> std::iter::FusedIterator for ReplacingIter<'a, I,T,U> where I: Iterator + std::iter::FusedIterator, T: Hash+ Eq + ToOwned, U: Borrow + Clone{} impl<'a, I,T,U> std::iter::DoubleEndedIterator for ReplacingIter<'a, I,T,U> where I: Iterator + std::iter::DoubleEndedIterator, T: Hash+ Eq + ToOwned, U: Borrow + Clone { fn next_back(&mut self) -> Option { if let Some(item) = self.iter.next_back() { Some(self.table.get(&item) .map(Clone::clone) .unwrap_or(item.to_owned())) } else { None } } } impl<'a ,I,T,U> ReplacingIter<'a, I,T,U> { pub fn into_inner(self) -> I { self.iter } pub fn table(&self) -> &'a HashMap { self.table } } pub trait ReplacingIterExt: Sized { fn replace_with<'a>(self, table: &'a HashMap) -> ReplacingIter<'a, Self, T, U>; } impl ReplacingIterExt for I where I: Iterator, T: Hash+ Eq + ToOwned, U: Borrow + Clone, { fn replace_with<'a>(self, table: &'a HashMap) -> ReplacingIter<'a, Self, T, U> { ReplacingIter { iter: self, table, } } } 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 HexStrIterator { iter: I, buf: Option, //we don't need full `char` here, since we can only have 0-9a-f anyway } impl Iterator for HexStrIterator where I: Iterator { type Item = char; fn next(&mut self) -> Option { if let Some(buf) = self.buf.take() { return Some(u8::from(buf) as char); } if let Some(next) = self.iter.next() { let buf = HEX_MAP[next as usize]; debug_assert_ne!(buf.1, 0); //SAFETY: We know `HEX_MAP` contains only non-zero bytes. unsafe { self.buf = Some(NonZeroU8::new_unchecked(buf.1)); } Some(buf.0 as char) } else { None } } fn size_hint(&self) -> (usize, Option) { let (min, max) = self.iter.size_hint(); (min * 2, max.map(|x| x * 2)) } } impl ExactSizeIterator for HexStrIterator where I: Iterator + ExactSizeIterator{} impl std::iter::FusedIterator for HexStrIterator where I: Iterator + std::iter::FusedIterator{} pub trait HexStrIterExt: Sized { fn hex(self) -> HexStrIterator; } impl HexStrIterExt for I where I: Iterator { fn hex(self) -> HexStrIterator { HexStrIterator{ iter: self, buf: None, } } }