use std::fmt;
#[derive(Debug, Clone)]
pub struct IndentedWrite<'a, W> {
writer: W,
prefix: &'a str,
insert_indent: bool,
}
impl<'a, W> IndentedWrite<'a, W> {
pub fn dedent(self) -> W {
self.writer
}
}
impl<'a, W: fmt::Write> fmt::Write for IndentedWrite<'a, W> {
fn write_str(&mut self, mut buf: &str) -> Result<(), fmt::Error> {
while !buf.is_empty() {
if self.insert_indent {
self.writer.write_str(self.prefix)?;
self.insert_indent = false;
}
match buf.find('\n').map(|idx| idx + 1) {
None => return self.writer.write_str(buf),
Some(newline_boundary) => {
self.writer
.write_str(unsafe { buf.get_unchecked(..newline_boundary) })?;
self.insert_indent = true;
buf = unsafe { buf.get_unchecked(newline_boundary..) };
}
}
}
Ok(())
}
}
#[derive(Debug, Clone)]
pub struct IndentWriter<'i, W> {
writer: W,
indent: &'i str,
need_indent: bool,
}
impl<'i, W: fmt::Write> IndentWriter<'i, W> {
pub fn new(indent: &'i str, writer: W) -> Self {
Self {
writer,
indent,
need_indent: true,
}
}
pub fn into_inner(self) -> W {
self.writer
}
pub fn get_ref(&self) -> &W {
&self.writer
}
pub fn indent(&self) -> &'i str {
self.indent
}
}
impl<'i, W: fmt::Write> fmt::Write for IndentWriter<'i, W> {
fn write_str(&mut self, mut s: &str) -> fmt::Result {
loop {
match self.need_indent {
false => match s.as_bytes().iter().position(|&b| b == b'\n') {
None => break self.writer.write_str(s),
Some(len) => {
let (head, tail) = s.split_at(len + 1);
self.writer.write_str(head)?;
self.need_indent = true;
s = tail;
}
},
true => match s.as_bytes().iter().position(|&b| b != b'\n') {
None => break self.writer.write_str(s),
Some(len) => {
let (head, tail) = s.split_at(len);
self.writer.write_str(head)?;
self.writer.write_str(self.indent)?;
self.need_indent = false;
s = tail;
}
},
}
}
}
fn write_char(&mut self, c: char) -> fmt::Result {
if self.need_indent && c != '\n' {
self.writer.write_str(self.indent)?;
self.need_indent = false;
}
if !self.need_indent && c == '\n' {
self.need_indent = true;
}
self.writer.write_char(c)
}
}