|
|
|
//! Extensions
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
use std::{
|
|
|
|
collections::HashMap,
|
|
|
|
hash::Hash,
|
|
|
|
borrow::{
|
|
|
|
Borrow,
|
|
|
|
ToOwned,
|
|
|
|
},
|
|
|
|
num::NonZeroU8,
|
|
|
|
};
|
|
|
|
|
|
|
|
pub trait JoinStrsExt: Sized
|
|
|
|
{
|
|
|
|
/// Join an iterator of `str` with a seperator
|
|
|
|
fn join(self, with: &str) -> String;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T,I> JoinStrsExt for I
|
|
|
|
where I: Iterator<Item=T>,
|
|
|
|
T: AsRef<str>
|
|
|
|
{
|
|
|
|
fn join(self, with: &str) -> String
|
|
|
|
{
|
|
|
|
let mut output = String::new();
|
|
|
|
let mut first=true;
|
|
|
|
for string in self
|
|
|
|
{
|
|
|
|
if !first {
|
|
|
|
output.push_str(with);
|
|
|
|
}
|
|
|
|
let string = string.as_ref();
|
|
|
|
output.push_str(string);
|
|
|
|
first=false;
|
|
|
|
}
|
|
|
|
output
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub use dedup::DedupIterExt;
|
|
|
|
|
|
|
|
/// Iterator that maps `T` -> `U`
|
|
|
|
pub struct ReplacingIter<'a, I,T, U=T>
|
|
|
|
{
|
|
|
|
iter: I,
|
|
|
|
table: &'a HashMap<T, U>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a, I,T,U> Iterator for ReplacingIter<'a, I,T,U>
|
|
|
|
where I: Iterator<Item=T>,
|
|
|
|
T: Hash+ Eq + ToOwned<Owned=U>,
|
|
|
|
U: Borrow<T> + Clone,
|
|
|
|
{
|
|
|
|
type Item = U;
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
|
|
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<usize>) {
|
|
|
|
self.iter.size_hint()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a, I,T,U> ExactSizeIterator for ReplacingIter<'a, I,T,U>
|
|
|
|
where I: Iterator<Item=T> + ExactSizeIterator,
|
|
|
|
T: Hash+ Eq + ToOwned<Owned=U>,
|
|
|
|
U: Borrow<T> + Clone{}
|
|
|
|
|
|
|
|
impl<'a, I,T,U> std::iter::FusedIterator for ReplacingIter<'a, I,T,U>
|
|
|
|
where I: Iterator<Item=T> + std::iter::FusedIterator,
|
|
|
|
T: Hash+ Eq + ToOwned<Owned=U>,
|
|
|
|
U: Borrow<T> + Clone{}
|
|
|
|
|
|
|
|
impl<'a, I,T,U> std::iter::DoubleEndedIterator for ReplacingIter<'a, I,T,U>
|
|
|
|
where I: Iterator<Item=T> + std::iter::DoubleEndedIterator,
|
|
|
|
T: Hash+ Eq + ToOwned<Owned=U>,
|
|
|
|
U: Borrow<T> + Clone
|
|
|
|
{
|
|
|
|
fn next_back(&mut self) -> Option<Self::Item> {
|
|
|
|
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<T,U>
|
|
|
|
{
|
|
|
|
self.table
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub trait ReplacingIterExt<T, U>: Sized
|
|
|
|
{
|
|
|
|
fn replace_with<'a>(self, table: &'a HashMap<T,U>) -> ReplacingIter<'a, Self, T, U>;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<I,T,U> ReplacingIterExt<T,U> for I
|
|
|
|
where I: Iterator<Item=T>,
|
|
|
|
T: Hash+ Eq + ToOwned<Owned=U>,
|
|
|
|
U: Borrow<T> + Clone,
|
|
|
|
{
|
|
|
|
fn replace_with<'a>(self, table: &'a HashMap<T,U>) -> 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<I>
|
|
|
|
{
|
|
|
|
iter: I,
|
|
|
|
buf: Option<NonZeroU8>, //we don't need full `char` here, since we can only have 0-9a-f anyway
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<I> Iterator for HexStrIterator<I>
|
|
|
|
where I: Iterator<Item = u8>
|
|
|
|
{
|
|
|
|
type Item = char;
|
|
|
|
fn next(&mut self) -> Option<Self::Item>
|
|
|
|
{
|
|
|
|
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<usize>) {
|
|
|
|
let (min, max) = self.iter.size_hint();
|
|
|
|
|
|
|
|
(min * 2, max.map(|x| x * 2))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<I> ExactSizeIterator for HexStrIterator<I>
|
|
|
|
where I: Iterator<Item = u8> + ExactSizeIterator{}
|
|
|
|
|
|
|
|
impl<I> std::iter::FusedIterator for HexStrIterator<I>
|
|
|
|
where I: Iterator<Item = u8> + std::iter::FusedIterator{}
|
|
|
|
|
|
|
|
pub trait HexStrIterExt: Sized
|
|
|
|
{
|
|
|
|
fn hex(self) -> HexStrIterator<Self>;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<I> HexStrIterExt for I
|
|
|
|
where I: Iterator<Item = u8>
|
|
|
|
{
|
|
|
|
fn hex(self) -> HexStrIterator<Self>
|
|
|
|
{
|
|
|
|
HexStrIterator{
|
|
|
|
iter: self,
|
|
|
|
buf: None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub trait IgnoreResultExt
|
|
|
|
{
|
|
|
|
fn ignore(self);
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T,E> IgnoreResultExt for Result<T,E>
|
|
|
|
{
|
|
|
|
#[inline(always)] fn ignore(self)
|
|
|
|
{
|
|
|
|
//Do nothing
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> IgnoreResultExt for Option<T>
|
|
|
|
{
|
|
|
|
#[inline(always)] fn ignore(self)
|
|
|
|
{
|
|
|
|
//Do nothing
|
|
|
|
}
|
|
|
|
}
|