use std::borrow::Cow;
use std::iter::Fuse;
use std::ops::RangeInclusive;
use std::str::CharIndices;
pub trait CharSource<'s> {
fn next(&mut self) -> Option<(usize, char)>;
fn get_slice(&mut self, range: RangeInclusive<usize>) -> Cow<'s, str>;
fn get_len(&self) -> usize;
}
pub struct StrSource<'s> {
input: &'s str,
char_indices: Fuse<CharIndices<'s>>,
}
impl<'s> CharSource<'s> for StrSource<'s> {
fn next(&mut self) -> Option<(usize, char)> {
self.char_indices.next()
}
fn get_slice(&mut self, range: RangeInclusive<usize>) -> Cow<'s, str> {
Cow::Borrowed(self.input.get(range).unwrap())
}
fn get_len(&self) -> usize {
self.input.len()
}
}
pub struct StringSource {
input: Vec<(usize, char)>,
cur_char_idx: usize,
}
impl CharSource<'static> for StringSource {
fn next(&mut self) -> Option<(usize, char)> {
if self.cur_char_idx < self.input.len() {
let out = self.input[self.cur_char_idx];
self.cur_char_idx += 1;
Some(out)
} else {
None
}
}
fn get_slice(&mut self, range: RangeInclusive<usize>) -> Cow<'static, str> {
let start_idx = self
.input
.binary_search_by_key(range.start(), |x| x.0)
.unwrap();
let end_idx = self
.input
.binary_search_by_key(range.end(), |x| x.0)
.unwrap();
let out: String = self.input[start_idx..=end_idx]
.iter()
.map(|x| x.1)
.collect();
Cow::Owned(out)
}
fn get_len(&self) -> usize {
self.input.len()
}
}
impl Into<StringSource> for String {
fn into(self) -> StringSource {
StringSource {
input: self.char_indices().collect(),
cur_char_idx: 0,
}
}
}
impl<'s> Into<StrSource<'s>> for &'s str {
fn into(self) -> StrSource<'s> {
StrSource {
char_indices: self.char_indices().fuse(),
input: self,
}
}
}