#[derive(Debug)]
pub struct Quoted<I, S>(I)
where I: Iterator<Item = S>,
S: AsRef<str>;
impl<I, J, S> From<I> for Quoted<J, S>
where I: IntoIterator<Item = S, IntoIter = J>,
J: Iterator<Item = S>,
S: AsRef<str>
{
fn from(lines: I) -> Self {
Quoted(lines.into_iter())
}
}
impl<I, S> Iterator for Quoted<I, S>
where I: Iterator<Item = S>,
S: AsRef<str>
{
type Item = String;
fn next(&mut self) -> Option<Self::Item> {
self.0.next().map(|l| {
let line = l.as_ref();
match line.is_empty() {
true => String::from(">"),
false => format!("> {}", line),
}
})
}
}
pub struct StripWhiteSpaceLeftIter<I, S>(I)
where I: Iterator<Item = S> + Sized,
S: AsRef<str>;
impl<I, J, S> From<I> for StripWhiteSpaceLeftIter<J, S>
where I: IntoIterator<Item = S, IntoIter = J>,
J: Iterator<Item = S>,
S: AsRef<str>
{
fn from(lines: I) -> Self {
StripWhiteSpaceLeftIter(lines.into_iter())
}
}
impl<'a, I, S> Iterator for StripWhiteSpaceLeftIter<I, S>
where I: Iterator<Item = S> + Sized,
S: AsRef<str>
{
type Item = String;
fn next(&mut self) -> Option<Self::Item> {
self.0.next().map(|s| String::from(s.as_ref().trim_start()))
}
}
pub struct StripWhiteSpaceRightIter<I, S>(I)
where I: Iterator<Item = S> + Sized,
S: AsRef<str>;
impl<I, J, S> From<I> for StripWhiteSpaceRightIter<J, S>
where I: IntoIterator<Item = S, IntoIter = J>,
J: Iterator<Item = S>,
S: AsRef<str>
{
fn from(lines: I) -> Self {
StripWhiteSpaceRightIter(lines.into_iter())
}
}
impl<'a, I, S> Iterator for StripWhiteSpaceRightIter<I, S>
where I: Iterator<Item = S> + Sized,
S: AsRef<str>
{
type Item = String;
fn next(&mut self) -> Option<Self::Item> {
self.0.next().map(|s| String::from(s.as_ref().trim_end()))
}
}
pub struct WithoutCommentsIter<I, S>(I)
where I: Iterator<Item = S> + Sized,
S: AsRef<str>;
impl<I, J, S> From<I> for WithoutCommentsIter<J, S>
where I: IntoIterator<Item = S, IntoIter = J>,
J: Iterator<Item = S>,
S: AsRef<str>
{
fn from(lines: I) -> Self {
WithoutCommentsIter(lines.into_iter())
}
}
impl<I, S> Iterator for WithoutCommentsIter<I, S>
where I: Iterator<Item = S> + Sized,
S: AsRef<str>
{
type Item = S;
fn next(&mut self) -> Option<Self::Item> {
while let Some(next) = self.0.next() {
if !next.as_ref().starts_with("#") {
return Some(next)
}
}
None
}
}
pub struct TrailingBlankTrimmer<I, S>
where I: Iterator<Item = S> + Sized,
S: AsRef<str> + Default
{
inner: ::std::iter::Peekable<I>,
blanks: usize,
}
impl<I, J, S> From<I> for TrailingBlankTrimmer<J, S>
where I: IntoIterator<Item = S, IntoIter = J>,
J: Iterator<Item = S>,
S: AsRef<str> + Default
{
fn from(lines: I) -> Self {
TrailingBlankTrimmer { inner: lines.into_iter().peekable(), blanks: 0 }
}
}
impl<I, S> Iterator for TrailingBlankTrimmer<I, S>
where I: Iterator<Item = S>,
S: AsRef<str> + Default
{
type Item = S;
fn next(&mut self) -> Option<Self::Item> {
if self.blanks > 0 {
self.blanks = self.blanks - 1;
return Some(S::default());
}
while self
.inner
.peek()
.map(AsRef::as_ref)
.map(str::is_empty)
.unwrap_or_else(|| {
self.blanks = 0;
false
})
{
self.blanks = self.blanks + 1;
self.inner.next();
}
if self.blanks > 0 {
self.blanks = self.blanks - 1;
Some(S::default())
} else {
self.inner.next()
}
}
}
pub type StrippingIter<I, S> = TrailingBlankTrimmer<
StripWhiteSpaceRightIter<
WithoutCommentsIter<I, S>,
S>,
String>;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn quoted_lines() {
let mut lines = Quoted::from(vec!["foo", "bar", "", "baz"]);
assert_eq!(lines.next().expect("Premature end of input"), "> foo");
assert_eq!(lines.next().expect("Premature end of input"), "> bar");
assert_eq!(lines.next().expect("Premature end of input"), ">");
assert_eq!(lines.next().expect("Premature end of input"), "> baz");
assert!(!lines.next().is_some());
}
#[test]
fn left_stripped_lines() {
let mut lines = StripWhiteSpaceLeftIter::from(vec!["foo ", " bar", " ", ""]);
assert_eq!(lines.next().expect("Premature end of input"), "foo ");
assert_eq!(lines.next().expect("Premature end of input"), "bar");
assert_eq!(lines.next().expect("Premature end of input"), "");
assert_eq!(lines.next().expect("Premature end of input"), "");
assert!(!lines.next().is_some());
}
#[test]
fn right_stripped_lines() {
let mut lines = StripWhiteSpaceRightIter::from(vec!["foo ", " bar", " ", ""]);
assert_eq!(lines.next().expect("Premature end of input"), "foo");
assert_eq!(lines.next().expect("Premature end of input"), " bar");
assert_eq!(lines.next().expect("Premature end of input"), "");
assert_eq!(lines.next().expect("Premature end of input"), "");
assert!(!lines.next().is_some());
}
#[test]
fn lines_without_comments() {
let mut lines = WithoutCommentsIter::from(vec!["foo", "# bar", "#", ""]);
assert_eq!(lines.next().expect("Premature end of input"), "foo");
assert_eq!(lines.next().expect("Premature end of input"), "");
assert!(!lines.next().is_some());
}
#[test]
fn trailing_blank_trimmer() {
let mut lines = TrailingBlankTrimmer::from(vec!["", "foo", "bar", "", "baz", "", ""]);
assert_eq!(lines.next().expect("Premature end of input"), "");
assert_eq!(lines.next().expect("Premature end of input"), "foo");
assert_eq!(lines.next().expect("Premature end of input"), "bar");
assert_eq!(lines.next().expect("Premature end of input"), "");
assert_eq!(lines.next().expect("Premature end of input"), "baz");
assert!(!lines.next().is_some());
}
}