use std::io;
use super::Inspect;
#[derive(Debug, Copy, Clone)]
enum IndentState<'a> {
MidLine,
NeedIndent,
WritingIndent(&'a [u8]),
}
use IndentState::*;
#[derive(Debug, Clone)]
pub struct IndentWriter<'i, W> {
writer: W,
indent: &'i str,
state: IndentState<'i>,
}
impl<'i, W: io::Write> IndentWriter<'i, W> {
pub fn new(indent: &'i str, writer: W) -> Self {
Self {
writer,
indent,
state: NeedIndent,
}
}
#[inline]
pub fn new_skip_initial(indent: &'i str, writer: W) -> Self {
Self {
writer,
indent,
state: MidLine,
}
}
#[inline]
pub fn into_inner(self) -> W {
self.writer
}
#[inline]
pub fn get_ref(&self) -> &W {
&self.writer
}
#[inline]
pub fn indent(&self) -> &'i str {
self.indent
}
}
impl<'i, W: io::Write> io::Write for IndentWriter<'i, W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
loop {
match self.state {
IndentState::MidLine => match buf.iter().position(|&b| b == b'\n') {
None => break self.writer.write(buf),
Some(0) => self.state = NeedIndent,
Some(len) => {
break self.writer.write(&buf[..len + 1]).inspect(|&n| {
if n >= len {
self.state = NeedIndent;
}
})
}
},
IndentState::NeedIndent => match buf.iter().position(|&b| b != b'\n') {
None => break self.writer.write(buf),
Some(0) => self.state = WritingIndent(self.indent.as_bytes()),
Some(len) => {
break self.writer.write(&buf[..len]).inspect(|&n| {
if n >= len {
self.state = IndentState::WritingIndent(self.indent.as_bytes())
}
})
}
},
IndentState::WritingIndent(indent) => match self.writer.write(indent)? {
n if n >= indent.len() => self.state = MidLine,
0 => break Ok(0),
n => self.state = WritingIndent(&indent[n..]),
},
}
}
}
fn flush(&mut self) -> io::Result<()> {
while let WritingIndent(ref mut indent) = self.state {
match self.writer.write(*indent)? {
len if len >= indent.len() => self.state = MidLine,
0 => return Err(io::ErrorKind::WriteZero.into()),
len => *indent = &indent[len..],
}
}
self.writer.flush()
}
}