use crate::Line;
type Inner<'b> = std::iter::Map<
  std::slice::Iter<'b, Line>, for<'a> fn(&'a Line) -> &'a str
>;
type TaggedInner<'b> = std::iter::Map<
  std::slice::Iter<'b, Line>, for<'a> fn(&'a Line) -> (char, &'a str)
>;
pub struct LinesIter<'a> {
  inner: LinesIterInner<'a>,
}
enum LinesIterInner<'a> {
  Real(Inner<'a>),
  #[cfg(any(feature = "testing", fuzzing, test))]
  Test(Box<dyn Iterator<Item = &'a str>>),
}
impl<'a> Iterator for LinesIter<'a> {
  type Item = &'a str;
  fn next(&mut self) -> Option<Self::Item> {
    match &mut self.inner {
      LinesIterInner::Real(x) => x.next(),
      #[cfg(any(feature = "testing", fuzzing, test))]
      LinesIterInner::Test(x) => x.next(),
    }
  }
}
impl<'a> From<Inner<'a>> for LinesIter<'a> {
  fn from(i: Inner<'a>) -> Self {
    Self{ inner: LinesIterInner::Real(i) }
  }
}
#[cfg(any(feature = "testing", fuzzing, test))]
impl<'a, I: Iterator<Item=&'a str> + 'static> From<Box<I>> for LinesIter<'a> {
  fn from(i: Box<I>) -> Self {
    Self{ inner: LinesIterInner::Test(i) }
  }
}
pub struct TaggedLinesIter<'a> {
  inner: TaggedInner<'a>,
}
impl<'a> Iterator for TaggedLinesIter<'a> {
  type Item = (char, &'a str);
  fn next(&mut self) -> Option<Self::Item> {
    self.inner.next()
  }
}
impl<'a> From<TaggedInner<'a>> for TaggedLinesIter<'a> {
  fn from(i: TaggedInner<'a>) -> Self {
    Self{ inner: i }
  }
}