midenc_session/
emitter.rs1#[cfg(feature = "std")]
2use alloc::string::String;
3#[cfg(not(feature = "std"))]
4use alloc::vec;
5use alloc::vec::Vec;
6use core::ops::Deref;
7
8#[cfg(not(feature = "std"))]
9use midenc_hir_symbol::sync::RwLock;
10
11#[cfg(feature = "std")]
12use crate::diagnostics::IntoDiagnostic;
13use crate::{diagnostics::Report, ColorChoice};
14
15pub trait Emitter: Send + Sync {
24 fn buffer(&self) -> Buffer;
26 fn print(&self, buffer: Buffer) -> Result<(), Report>;
28}
29
30pub struct DefaultEmitter(DefaultEmitterImpl);
33impl DefaultEmitter {
34 pub fn new(color: ColorChoice) -> Self {
36 Self(DefaultEmitterImpl::new(color))
37 }
38}
39impl Emitter for DefaultEmitter {
40 #[inline(always)]
41 fn buffer(&self) -> Buffer {
42 self.0.buffer()
43 }
44
45 #[inline(always)]
46 fn print(&self, buffer: Buffer) -> Result<(), Report> {
47 self.0.print(buffer)
48 }
49}
50impl Deref for DefaultEmitter {
51 type Target = DefaultEmitterImpl;
52
53 #[inline(always)]
54 fn deref(&self) -> &Self::Target {
55 &self.0
56 }
57}
58
59#[cfg(feature = "std")]
60#[doc(hidden)]
61pub struct DefaultEmitterImpl {
62 writer: termcolor::BufferWriter,
63}
64
65#[cfg(not(feature = "std"))]
66#[doc(hidden)]
67pub struct DefaultEmitterImpl {
68 writer: RwLock<Vec<u8>>,
69 ansi: bool,
70}
71
72#[cfg(feature = "std")]
73impl DefaultEmitterImpl {
74 fn new(color: ColorChoice) -> Self {
75 Self {
76 writer: termcolor::BufferWriter::stderr(color.into()),
77 }
78 }
79}
80
81#[cfg(feature = "std")]
82impl Emitter for DefaultEmitterImpl {
83 #[inline(always)]
84 fn buffer(&self) -> Buffer {
85 Buffer(self.writer.buffer())
86 }
87
88 #[inline(always)]
89 fn print(&self, buffer: Buffer) -> Result<(), Report> {
90 self.writer.print(&buffer.0).into_diagnostic()
91 }
92}
93
94#[cfg(not(feature = "std"))]
95impl DefaultEmitterImpl {
96 fn new(color: ColorChoice) -> Self {
97 Self {
98 ansi: color.should_ansi(),
99 writer: Default::default(),
100 }
101 }
102}
103
104#[cfg(not(feature = "std"))]
105impl Emitter for DefaultEmitterImpl {
106 #[inline(always)]
107 fn buffer(&self) -> Buffer {
108 if self.ansi {
109 Buffer::ansi()
110 } else {
111 Buffer::no_color()
112 }
113 }
114
115 #[inline(always)]
116 fn print(&self, buffer: Buffer) -> Result<(), Report> {
117 let mut writer = self.writer.write();
118 writer.push(b'\n');
119 writer.extend(buffer.into_inner());
120 Ok(())
121 }
122}
123
124#[derive(Default)]
129#[cfg(feature = "std")]
130pub struct CaptureEmitter {
131 buffer: parking_lot::Mutex<Vec<u8>>,
132}
133#[cfg(feature = "std")]
134impl CaptureEmitter {
135 #[inline]
137 pub fn new() -> Self {
138 Self::default()
139 }
140
141 pub fn captured(&self) -> String {
142 let buf = self.buffer.lock();
143 String::from_utf8_lossy(buf.as_slice()).into_owned()
144 }
145}
146#[cfg(feature = "std")]
147impl Emitter for CaptureEmitter {
148 #[inline]
149 fn buffer(&self) -> Buffer {
150 Buffer::no_color()
151 }
152
153 #[inline]
154 fn print(&self, buffer: Buffer) -> Result<(), Report> {
155 let mut bytes = buffer.into_inner();
156 let mut buf = self.buffer.lock();
157 buf.append(&mut bytes);
158 Ok(())
159 }
160}
161
162#[derive(Clone, Copy, Default)]
167pub struct NullEmitter {
168 ansi: bool,
169}
170impl NullEmitter {
171 #[cfg(feature = "std")]
172 pub fn new(color: ColorChoice) -> Self {
173 use std::io::IsTerminal;
174
175 let ansi = match color {
176 ColorChoice::Never => false,
177 ColorChoice::Always | ColorChoice::AlwaysAnsi => true,
178 ColorChoice::Auto => std::io::stdout().is_terminal(),
179 };
180 Self { ansi }
181 }
182
183 #[cfg(not(feature = "std"))]
184 pub fn new(color: ColorChoice) -> Self {
185 let ansi = match color {
186 ColorChoice::Never => false,
187 ColorChoice::Always | ColorChoice::AlwaysAnsi => true,
188 ColorChoice::Auto => false,
189 };
190 Self { ansi }
191 }
192}
193impl Emitter for NullEmitter {
194 #[inline(always)]
195 fn buffer(&self) -> Buffer {
196 if self.ansi {
197 Buffer::ansi()
198 } else {
199 Buffer::no_color()
200 }
201 }
202
203 #[inline(always)]
204 fn print(&self, _buffer: Buffer) -> Result<(), Report> {
205 Ok(())
206 }
207}
208
209#[doc(hidden)]
210#[cfg(not(feature = "std"))]
211#[derive(Clone, Debug)]
212pub struct Buffer(Vec<u8>);
213
214#[doc(hidden)]
215#[cfg(feature = "std")]
216#[derive(Clone, Debug)]
217pub struct Buffer(termcolor::Buffer);
218
219impl Buffer {
220 #[cfg(not(feature = "std"))]
222 pub fn new(_choice: ColorChoice) -> Buffer {
223 Self::no_color()
224 }
225
226 #[cfg(feature = "std")]
227 pub fn new(choice: ColorChoice) -> Buffer {
228 match choice {
229 ColorChoice::Never => Self::no_color(),
230 ColorChoice::Auto => {
231 if choice.should_attempt_color() {
232 Self::ansi()
233 } else {
234 Self::no_color()
235 }
236 }
237 ColorChoice::Always | ColorChoice::AlwaysAnsi => Self::ansi(),
238 }
239 }
240
241 #[cfg(not(feature = "std"))]
243 pub fn no_color() -> Buffer {
244 Self(vec![])
245 }
246
247 #[cfg(feature = "std")]
249 pub fn no_color() -> Buffer {
250 Self(termcolor::Buffer::no_color())
251 }
252
253 #[cfg(not(feature = "std"))]
255 pub fn ansi() -> Buffer {
256 Buffer(vec![])
257 }
258
259 #[cfg(feature = "std")]
261 pub fn ansi() -> Buffer {
262 Self(termcolor::Buffer::ansi())
263 }
264
265 pub fn is_empty(&self) -> bool {
267 self.len() == 0
268 }
269
270 #[inline]
272 pub fn len(&self) -> usize {
273 self.0.len()
274 }
275
276 #[inline]
278 pub fn clear(&mut self) {
279 self.0.clear()
280 }
281
282 #[inline(always)]
287 #[cfg(not(feature = "std"))]
288 pub fn into_inner(self) -> Vec<u8> {
289 self.0
290 }
291
292 #[cfg(feature = "std")]
293 pub fn into_inner(self) -> Vec<u8> {
294 self.0.into_inner()
295 }
296
297 #[inline(always)]
299 pub fn as_slice(&self) -> &[u8] {
300 self.0.as_slice()
301 }
302
303 #[inline(always)]
305 pub fn as_mut_slice(&mut self) -> &mut [u8] {
306 self.0.as_mut_slice()
307 }
308}
309
310#[cfg(not(feature = "std"))]
311impl core::fmt::Write for Buffer {
312 fn write_str(&mut self, s: &str) -> core::fmt::Result {
313 use miden_assembly::utils::ByteWriter;
314 self.0.write_bytes(s.as_bytes());
315 Ok(())
316 }
317}
318
319#[cfg(feature = "std")]
320impl std::io::Write for Buffer {
321 #[inline]
322 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
323 self.0.write(buf)
324 }
325
326 #[inline]
327 fn flush(&mut self) -> std::io::Result<()> {
328 self.0.flush()
329 }
330}