sn_bindgen 0.13.18

A library to automatically generate C, Java, and C# files from Rust source files.
use std::fmt::{self, Write};
use std::ops::Deref;

pub struct IndentedWriter {
    inner: String,
    indent: bool,
    indent_level: usize,
    indent_width: usize,
}

impl IndentedWriter {
    pub fn new(width: usize) -> Self {
        IndentedWriter {
            inner: String::new(),
            indent: true,
            indent_level: 0,
            indent_width: width,
        }
    }

    pub fn into_inner(self) -> String {
        self.inner
    }

    pub fn indent(&mut self) {
        self.indent_level += 1;
    }

    pub fn unindent(&mut self) {
        self.indent_level -= 1;
    }

    fn write_indent(&mut self) -> Result<(), fmt::Error> {
        for _ in 0..(self.indent_level * self.indent_width) {
            self.inner.write_char(' ')?;
        }

        Ok(())
    }
}

impl Write for IndentedWriter {
    fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
        if s.is_empty() {
            return Ok(());
        }

        let mut lines = s.lines().peekable();
        let mut indent = self.indent;

        while let Some(line) = lines.next() {
            if !line.is_empty() && indent {
                self.write_indent()?;
            }

            self.inner.write_str(line)?;

            if lines.peek().is_some() {
                self.inner.write_char('\n')?;
            }

            indent = true;
        }

        if s.ends_with('\n') {
            self.inner.write_char('\n')?;
            self.indent = true;
        } else {
            self.indent = false;
        }

        Ok(())
    }
}

impl Deref for IndentedWriter {
    type Target = String;

    fn deref(&self) -> &Self::Target {
        &self.inner
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use unwrap::unwrap;

    #[test]
    fn smoke() {
        let mut output = IndentedWriter::new(4);

        unwrap!(writeln!(output, "pub struct Foo {{"));
        output.indent();
        unwrap!(writeln!(output, "bar: Bar,"));
        unwrap!(write!(output, "baz"));
        unwrap!(writeln!(output, ": Baz,"));
        output.unindent();
        unwrap!(writeln!(output, "}}"));

        let expected = "pub struct Foo {\n    bar: Bar,\n    baz: Baz,\n}\n";
        assert_eq!(&*output, expected);
    }

    #[test]
    fn does_not_indent_empty_lines() {
        let mut output = IndentedWriter::new(4);
        output.indent();

        unwrap!(write!(output, "foo\n\n\nbar"));

        let expected = "    foo\n\n\n    bar";
        assert_eq!(&*output, expected);
    }
}