You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
videl/src/ext.rs

226 lines
4.4 KiB

//! 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
}
}