1 | use std::io::{Error as IOError, Write}; |
2 | use std::string::FromUtf8Error; |
3 | |
4 | /// The Output API. |
5 | /// |
6 | /// Handlebars uses this trait to define rendered output. |
7 | pub trait Output { |
8 | fn write(&mut self, seg: &str) -> Result<(), IOError>; |
9 | |
10 | /// Designed to be used with `write!` macro. |
11 | /// for backward compatibility and to avoid breakage the default implementation |
12 | /// uses `format!` this may be not what you want. |
13 | fn write_fmt(&mut self, args: std::fmt::Arguments<'_>) -> Result<(), IOError> { |
14 | // Check if there is nothing to format to avoid allocation on case like |
15 | // write!(out, "hey")?; |
16 | if let Some(content: &str) = args.as_str() { |
17 | self.write(seg:content) |
18 | } else { |
19 | self.write(&std::fmt::format(args)) |
20 | } |
21 | } |
22 | } |
23 | |
24 | pub struct WriteOutput<W: Write> { |
25 | write: W, |
26 | } |
27 | |
28 | impl<W: Write> Output for WriteOutput<W> { |
29 | fn write(&mut self, seg: &str) -> Result<(), IOError> { |
30 | self.write.write_all(buf:seg.as_bytes()) |
31 | } |
32 | |
33 | fn write_fmt(&mut self, args: std::fmt::Arguments<'_>) -> Result<(), IOError> { |
34 | self.write.write_fmt(args) |
35 | } |
36 | } |
37 | |
38 | impl<W: Write> WriteOutput<W> { |
39 | pub fn new(write: W) -> WriteOutput<W> { |
40 | WriteOutput { write } |
41 | } |
42 | } |
43 | |
44 | pub struct StringOutput { |
45 | buf: Vec<u8>, |
46 | } |
47 | |
48 | impl Output for StringOutput { |
49 | fn write(&mut self, seg: &str) -> Result<(), IOError> { |
50 | self.buf.extend_from_slice(seg.as_bytes()); |
51 | Ok(()) |
52 | } |
53 | |
54 | fn write_fmt(&mut self, args: std::fmt::Arguments<'_>) -> Result<(), IOError> { |
55 | self.buf.write_fmt(args) |
56 | } |
57 | } |
58 | |
59 | impl StringOutput { |
60 | pub fn new() -> StringOutput { |
61 | StringOutput { |
62 | buf: Vec::with_capacity(8 * 1024), |
63 | } |
64 | } |
65 | |
66 | pub fn into_string(self) -> Result<String, FromUtf8Error> { |
67 | String::from_utf8(self.buf) |
68 | } |
69 | } |
70 | |
71 | impl Default for StringOutput { |
72 | fn default() -> Self { |
73 | StringOutput::new() |
74 | } |
75 | } |
76 | |