witx_codegen/
pretty_writer.rs

1use std::cell::RefCell;
2use std::convert::Into;
3use std::io::prelude::*;
4use std::rc::Rc;
5
6use super::Error;
7
8pub struct PrettyWriter<W: Write> {
9    writer: Rc<RefCell<W>>,
10    indent: u32,
11    indent_bytes: &'static str,
12    continuation_bytes: &'static str,
13}
14
15impl<W: Write> Clone for PrettyWriter<W> {
16    fn clone(&self) -> Self {
17        PrettyWriter {
18            writer: self.writer.clone(),
19            indent: self.indent,
20            indent_bytes: self.indent_bytes,
21            continuation_bytes: DEFAULT_CONTINUATION_BYTES,
22        }
23    }
24}
25
26const DEFAULT_CONTINUATION_BYTES: &str = "    ";
27
28impl<W: Write> PrettyWriter<W> {
29    /// Create a new `PrettyWriter` with `indent` initial units of indentation
30    pub fn new_with_indent(writer: W, indent: u32, indent_bytes: &'static str) -> Self {
31        PrettyWriter {
32            writer: Rc::new(RefCell::new(writer)),
33            indent,
34            indent_bytes,
35            continuation_bytes: DEFAULT_CONTINUATION_BYTES,
36        }
37    }
38
39    /// Create a new `PrettyWriter` with no initial indentation
40    pub fn new(writer: W, indent_bytes: &'static str) -> Self {
41        PrettyWriter::new_with_indent(writer, 0, indent_bytes)
42    }
43
44    /// Create a writer based on a existing writer, but with no indentation`
45    #[allow(dead_code)]
46    pub fn new_from_writer(&mut self) -> Self {
47        PrettyWriter {
48            writer: self.writer.clone(),
49            indent: 0,
50            indent_bytes: self.indent_bytes,
51            continuation_bytes: DEFAULT_CONTINUATION_BYTES,
52        }
53    }
54
55    /// Create an indented block within the current `PrettyWriter`
56    pub fn new_block(&mut self) -> Self {
57        PrettyWriter {
58            writer: self.writer.clone(),
59            indent: self.indent + 1,
60            indent_bytes: self.indent_bytes,
61            continuation_bytes: DEFAULT_CONTINUATION_BYTES,
62        }
63    }
64
65    fn _write_all<T: AsRef<[u8]>>(writer: &mut W, buf: T) -> Result<(), Error> {
66        let buf = buf.as_ref();
67        writer.write_all(buf).map_err(Into::into)
68    }
69
70    /// Return the current indentation level
71    #[allow(dead_code)]
72    pub fn indent_level(&self) -> u32 {
73        self.indent
74    }
75
76    /// Output an indentation string
77    pub fn indent(&mut self) -> Result<&mut Self, Error> {
78        let indent_bytes = &self.indent_bytes;
79        {
80            let mut writer = self.writer.borrow_mut();
81            for _ in 0..self.indent {
82                Self::_write_all(&mut writer, indent_bytes)?
83            }
84        }
85        Ok(self)
86    }
87
88    /// Output a space
89    #[allow(dead_code)]
90    pub fn space(&mut self) -> Result<&mut Self, Error> {
91        Self::_write_all(&mut self.writer.borrow_mut(), b" ")?;
92        Ok(self)
93    }
94
95    /// Output an end of line
96    pub fn eol(&mut self) -> Result<&mut Self, Error> {
97        Self::_write_all(&mut self.writer.borrow_mut(), b"\n")?;
98        Ok(self)
99    }
100
101    /// Output a block separator
102    pub fn eob(&mut self) -> Result<&mut Self, Error> {
103        self.eol()
104    }
105
106    /// Continuation
107    pub fn continuation(&mut self) -> Result<&mut Self, Error> {
108        self.indent()?;
109        let continuation_bytes = &self.continuation_bytes;
110        Self::_write_all(&mut self.writer.borrow_mut(), continuation_bytes)?;
111        Ok(self)
112    }
113
114    /// Write raw data
115    pub fn write<T: AsRef<[u8]>>(&mut self, buf: T) -> Result<&mut Self, Error> {
116        let buf = buf.as_ref();
117        Self::_write_all(&mut self.writer.borrow_mut(), buf)?;
118        Ok(self)
119    }
120
121    /// Indent, write raw data and terminate with an end of line
122    pub fn write_line<T: AsRef<[u8]>>(&mut self, buf: T) -> Result<&mut Self, Error> {
123        let buf = buf.as_ref();
124        self.indent()?.write(buf)?.eol()
125    }
126
127    /// Write multiple indented lines
128    pub fn write_lines<T: AsRef<[u8]>>(&mut self, buf: T) -> Result<&mut Self, Error> {
129        let buf = buf.as_ref();
130        for line in buf.lines().flatten() {
131            self.write_line(line)?;
132        }
133        Ok(self)
134    }
135
136    /// Indent, write raw data after a continuation and terminate with an end of
137    /// line
138    pub fn write_line_continued<T: AsRef<[u8]>>(&mut self, buf: T) -> Result<&mut Self, Error> {
139        let buf = buf.as_ref();
140        self.continuation()?.write(buf)?.eol()
141    }
142}