1use std::ptr::addr_of_mut;
2use std::{fmt, io};
3
4use crate::error::{Error, ErrorKind};
5use crate::utils::AutoEscape;
6use crate::value::Value;
7
8#[derive(Debug, Clone, Copy, Eq, PartialEq)]
10#[cfg_attr(feature = "unstable_machinery_serde", derive(serde::Serialize))]
11pub enum CaptureMode {
12 Capture,
13 #[allow(unused)]
14 Discard,
15}
16
17pub struct Output<'a> {
23 w: *mut (dyn fmt::Write + 'a),
24 target: *mut (dyn fmt::Write + 'a),
25 capture_stack: Vec<Option<String>>,
26}
27
28impl<'a> Output<'a> {
29 pub(crate) fn new(w: &'a mut (dyn fmt::Write + 'a)) -> Self {
31 Self {
32 w,
33 target: w,
34 capture_stack: Vec::new(),
35 }
36 }
37
38 pub(crate) fn null() -> Self {
40 Self {
44 w: NullWriter::get_mut(),
45 target: NullWriter::get_mut(),
46 capture_stack: vec![None],
47 }
48 }
49
50 pub(crate) fn begin_capture(&mut self, mode: CaptureMode) {
52 self.capture_stack.push(match mode {
53 CaptureMode::Capture => Some(String::new()),
54 CaptureMode::Discard => None,
55 });
56 self.retarget();
57 }
58
59 pub(crate) fn end_capture(&mut self, auto_escape: AutoEscape) -> Value {
61 let rv = if let Some(captured) = self.capture_stack.pop().unwrap() {
62 if !matches!(auto_escape, AutoEscape::None) {
63 Value::from_safe_string(captured)
64 } else {
65 Value::from(captured)
66 }
67 } else {
68 Value::UNDEFINED
69 };
70 self.retarget();
71 rv
72 }
73
74 fn retarget(&mut self) {
75 self.target = match self.capture_stack.last_mut() {
76 Some(Some(stream)) => stream,
77 Some(None) => NullWriter::get_mut(),
78 None => self.w,
79 };
80 }
81
82 #[inline(always)]
83 fn target(&mut self) -> &mut dyn fmt::Write {
84 unsafe { &mut *self.target }
87 }
88
89 #[inline(always)]
91 #[allow(unused)]
92 pub(crate) fn is_discarding(&self) -> bool {
93 matches!(self.capture_stack.last(), Some(None))
94 }
95
96 #[inline]
98 pub fn write_str(&mut self, s: &str) -> fmt::Result {
99 self.target().write_str(s)
100 }
101
102 #[inline]
104 pub fn write_fmt(&mut self, a: fmt::Arguments<'_>) -> fmt::Result {
105 self.target().write_fmt(a)
106 }
107}
108
109impl fmt::Write for Output<'_> {
110 #[inline]
111 fn write_str(&mut self, s: &str) -> fmt::Result {
112 fmt::Write::write_str(self.target(), s)
113 }
114
115 #[inline]
116 fn write_char(&mut self, c: char) -> fmt::Result {
117 fmt::Write::write_char(self.target(), c)
118 }
119
120 #[inline]
121 fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> fmt::Result {
122 fmt::Write::write_fmt(self.target(), args)
123 }
124}
125
126pub struct NullWriter;
127
128impl NullWriter {
129 pub fn get_mut() -> &'static mut NullWriter {
131 static mut NULL_WRITER: NullWriter = NullWriter;
132 unsafe { &mut *addr_of_mut!(NULL_WRITER) }
134 }
135}
136
137impl fmt::Write for NullWriter {
138 #[inline]
139 fn write_str(&mut self, _s: &str) -> fmt::Result {
140 Ok(())
141 }
142
143 #[inline]
144 fn write_char(&mut self, _c: char) -> fmt::Result {
145 Ok(())
146 }
147}
148
149pub struct WriteWrapper<W> {
150 pub w: W,
151 pub err: Option<io::Error>,
152}
153
154impl<W> WriteWrapper<W> {
155 pub fn take_err(&mut self, original: Error) -> Error {
157 self.err
158 .take()
159 .map(|io_err| {
160 Error::new(ErrorKind::WriteFailure, "I/O error during rendering")
161 .with_source(io_err)
162 })
163 .unwrap_or(original)
164 }
165}
166
167impl<W: io::Write> fmt::Write for WriteWrapper<W> {
168 #[inline]
169 fn write_str(&mut self, s: &str) -> fmt::Result {
170 self.w.write_all(s.as_bytes()).map_err(|e| {
171 self.err = Some(e);
172 fmt::Error
173 })
174 }
175
176 #[inline]
177 fn write_char(&mut self, c: char) -> fmt::Result {
178 self.w
179 .write_all(c.encode_utf8(&mut [0; 4]).as_bytes())
180 .map_err(|e| {
181 self.err = Some(e);
182 fmt::Error
183 })
184 }
185}