use core::{option, str::Chars};
use super::actionmap::{ActionMap, CharMapAction};
pub struct CharMapper<'a, M>
where
M: ActionMap,
{
actionmap: &'a M,
default: CharMapAction<'a>,
}
impl<'a, M> CharMapper<'a, M>
where
M: ActionMap,
{
#[inline]
pub fn new(actionmap: &'a M, default: CharMapAction<'a>) -> Self {
CharMapper { actionmap, default }
}
#[inline]
pub fn get_action(&'a self, c: char) -> &'a CharMapAction<'a> {
match self.actionmap.map_char(c) {
None => &self.default,
Some(action) => action,
}
}
#[inline]
pub fn map_chars_iter<I>(&'a self, text_chars: I) -> MappedChars<'a, M, I>
where
I: Iterator<Item = char>,
{
MappedChars::new(self, text_chars)
}
}
#[derive(Clone)]
pub struct MappedChars<'a, M, I>
where
M: ActionMap,
I: Iterator<Item = char>,
{
charmapper: &'a CharMapper<'a, M>,
text_chars: I,
sub_chars: Chars<'a>,
in_sub: bool,
}
impl<'a, M, I> MappedChars<'a, M, I>
where
M: ActionMap,
I: Iterator<Item = char>,
{
#[inline]
pub(self) fn new(charmapper: &'a CharMapper<'a, M>, text_chars: I) -> Self
where
I: Iterator<Item = char>,
{
MappedChars {
charmapper,
text_chars,
sub_chars: "".chars(),
in_sub: false,
}
}
}
impl<'a, M, I> Iterator for MappedChars<'a, M, I>
where
M: ActionMap,
I: Iterator<Item = char>,
{
type Item = char;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.in_sub {
match self.sub_chars.next() {
Some(c) => return Some(c),
None => self.in_sub = false,
}
}
loop {
let next_char = self.text_chars.next();
match next_char {
Some(c) => {
match self.charmapper.get_action(c) {
CharMapAction::Pass => return Some(c),
CharMapAction::Delete => continue,
CharMapAction::SubChar(d) => return Some(*d),
CharMapAction::SubStr(sub_str) => {
self.in_sub = true;
self.sub_chars = sub_str.chars();
match self.sub_chars.next() {
Some(c) => return Some(c),
None => {
self.in_sub = false;
continue;
}
}
}
}
}
None => return None,
}
}
}
}
pub trait MapCharsIter<'a, M, I: Iterator<Item = char>>
where
M: ActionMap,
{
fn map_chars(self, mapper: &'a CharMapper<'a, M>)
-> MappedChars<'a, M, I>;
}
impl<'a, M> MapCharsIter<'a, M, Chars<'a>> for &'a str
where
M: ActionMap,
{
#[inline]
fn map_chars(
self,
mapper: &'a CharMapper<'a, M>,
) -> MappedChars<'a, M, Chars<'a>>
where
Self: Sized,
{
MappedChars::new(mapper, self.chars())
}
}
impl<'a, M> MapCharsIter<'a, M, option::IntoIter<char>> for char
where
M: ActionMap,
{
#[inline]
fn map_chars(
self,
mapper: &'a CharMapper<'a, M>,
) -> MappedChars<'a, M, option::IntoIter<char>>
where
Self: Sized,
{
MappedChars::new(mapper, Some(self).into_iter())
}
}
impl<'a, M, I: Iterator<Item = char>> MapCharsIter<'a, M, I> for I
where
M: ActionMap,
{
#[inline]
fn map_chars(
self,
mapper: &'a CharMapper<'a, M>,
) -> MappedChars<'a, M, Self>
where
Self: Sized,
{
MappedChars::new(mapper, self)
}
}