cargo-checkmate 0.1.18

checkmate checks all the things - comprehensive out-of-the-box safety & hygiene checks.
Documentation
use std::io::{Result, Write};

pub struct Indenter<W> {
    f: W,
    linestart: bool,
}

impl<W> From<W> for Indenter<W> {
    fn from(f: W) -> Indenter<W> {
        Indenter { f, linestart: true }
    }
}

impl<W: Write> Write for Indenter<W> {
    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        let mut written = 0;
        let mut chunks = buf.split(|&c| c == b'\n').fuse();
        let mut ochunk = chunks.next();

        for nextchunk in chunks {
            let chunk = ochunk.expect("Indenter::write internal loop invariant failed");
            written += self.write_eol_chunk(chunk)?;
            ochunk = Some(nextchunk);
        }

        if let Some(chunk) = ochunk {
            written += self.write_trailing_chunk(chunk)?;
        }

        Ok(written)
    }

    fn flush(&mut self) -> Result<()> {
        self.f.flush()
    }
}

impl<W: Write> Indenter<W> {
    fn write_eol_chunk(&mut self, chunk: &[u8]) -> Result<usize> {
        self._write_chunk(chunk, true)
    }

    fn write_trailing_chunk(&mut self, chunk: &[u8]) -> Result<usize> {
        if !chunk.is_empty() {
            self._write_chunk(chunk, false)
        } else {
            Ok(0)
        }
    }

    fn _write_chunk(&mut self, chunk: &[u8], newline: bool) -> Result<usize> {
        if self.linestart {
            self.f.write_all("| ".as_bytes())?;
        }
        self.linestart = newline;

        self.f.write_all(chunk)?;
        if newline {
            self.f.write_all(&[b'\n'])?;
        }

        Ok(chunk.len() + if newline { 1 } else { 0 })
    }
}

#[cfg(test)]
mod tests {
    use super::Indenter;
    use std::io::Write;

    use test_case::test_case;

    impl<W> Indenter<W> {
        fn unwrap(self) -> W {
            self.f
        }
    }

    #[test_case(&String::new(), &String::new())]
    #[test_case("blah", "| blah")]
    #[test_case("foo\nbar", "| foo\n| bar")]
    #[test_case("foo\nbar\n", "| foo\n| bar\n")]
    #[test_case("foo\n\nbar", "| foo\n| \n| bar")]
    fn transformation_tests(input: &str, expected: &str) {
        for stride in 1..input.len() + 2 {
            let mut id = Indenter::from(Vec::new());

            for inchunk in input.as_bytes().chunks(stride) {
                id.write_all(inchunk).unwrap();
            }
            let outvec = id.unwrap();
            let actual = std::str::from_utf8(&outvec).unwrap();
            assert_eq!(actual, expected, "stride {}", stride);
        }
    }
}