wasmprinter/
print.rs

1use std::fmt;
2use std::io;
3use termcolor::{Color, ColorSpec};
4
5/// Trait used to print WebAssembly modules in this crate.
6///
7/// Instances of this trait are passed to
8/// [`Config::print`](super::Config::print). Instances of this trait are where
9/// the output of a WebAssembly binary goes.
10///
11/// Note that this trait has built-in adapters in the `wasmprinter` crate:
12///
13/// * For users of [`std::io::Write`] use [`PrintIoWrite`].
14/// * For users of [`std::fmt::Write`] use [`PrintFmtWrite`].
15pub trait Print {
16    /// Writes the given string `s` in its entirety.
17    ///
18    /// Returns an error for any I/O error.
19    fn write_str(&mut self, s: &str) -> io::Result<()>;
20
21    /// Indicates that a newline is being printed.
22    ///
23    /// This can be overridden to hook into the offset at which lines are
24    /// printed.
25    fn newline(&mut self) -> io::Result<()> {
26        self.write_str("\n")
27    }
28
29    /// Indicates that a new line in the output is starting at the
30    /// `binary_offset` provided.
31    ///
32    /// Not all new lines have a binary offset associated with them but this
33    /// method should be called for new lines in the output. This enables
34    /// correlating binary offsets to lines in the output.
35    fn start_line(&mut self, binary_offset: Option<usize>) {
36        let _ = binary_offset;
37    }
38
39    /// Enables usage of `write!` with this trait.
40    fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> {
41        struct Adapter<'a, T: ?Sized + 'a> {
42            inner: &'a mut T,
43            error: io::Result<()>,
44        }
45
46        impl<T: Print + ?Sized> fmt::Write for Adapter<'_, T> {
47            fn write_str(&mut self, s: &str) -> fmt::Result {
48                match self.inner.write_str(s) {
49                    Ok(()) => Ok(()),
50                    Err(e) => {
51                        self.error = Err(e);
52                        Err(fmt::Error)
53                    }
54                }
55            }
56        }
57
58        let mut output = Adapter {
59            inner: self,
60            error: Ok(()),
61        };
62        match fmt::write(&mut output, args) {
63            Ok(()) => Ok(()),
64            Err(..) => output.error,
65        }
66    }
67
68    /// Helper to print a custom section, if needed.
69    ///
70    /// If this output has a custom means of printing a custom section then this
71    /// can be used to override the default. If `Ok(true)` is returned then the
72    /// section will be considered to be printed. Otherwise an `Ok(false)`
73    /// return value indicates that the default printing should happen.
74    fn print_custom_section(
75        &mut self,
76        name: &str,
77        binary_offset: usize,
78        data: &[u8],
79    ) -> io::Result<bool> {
80        let _ = (name, binary_offset, data);
81        Ok(false)
82    }
83
84    /// Sets the colors settings for literals (`"foo"`) to be printed.
85    fn start_literal(&mut self) -> io::Result<()> {
86        Ok(())
87    }
88
89    /// Sets the colors settings for a name (`$foo`) to be printed.
90    fn start_name(&mut self) -> io::Result<()> {
91        Ok(())
92    }
93
94    /// Sets the colors settings for a keyword (`(module ...)`) to be printed.
95    fn start_keyword(&mut self) -> io::Result<()> {
96        Ok(())
97    }
98
99    /// Sets the colors settings for a type (`(param i32)`) to be printed.
100    fn start_type(&mut self) -> io::Result<()> {
101        Ok(())
102    }
103
104    /// Sets the colors settings for a comment (`;; ...`) to be printed.
105    fn start_comment(&mut self) -> io::Result<()> {
106        Ok(())
107    }
108
109    /// Resets colors settings to the default.
110    fn reset_color(&mut self) -> io::Result<()> {
111        Ok(())
112    }
113
114    /// Returns `true` if the device uses colors without interacting synchronously with a terminal (e.g. ANSI)
115    fn supports_async_color(&self) -> bool {
116        false
117    }
118}
119
120/// An adapter between the [`std::io::Write`] trait and [`Print`].
121pub struct PrintIoWrite<T>(pub T);
122
123impl<T> Print for PrintIoWrite<T>
124where
125    T: io::Write,
126{
127    fn write_str(&mut self, s: &str) -> io::Result<()> {
128        self.0.write_all(s.as_bytes())
129    }
130}
131
132/// An adapter between the [`std::fmt::Write`] trait and [`Print`].
133pub struct PrintFmtWrite<T>(pub T);
134
135impl<T> Print for PrintFmtWrite<T>
136where
137    T: fmt::Write,
138{
139    fn write_str(&mut self, s: &str) -> io::Result<()> {
140        match self.0.write_str(s) {
141            Ok(()) => Ok(()),
142            Err(fmt::Error) => Err(io::Error::new(
143                io::ErrorKind::Other,
144                "failed to write string",
145            )),
146        }
147    }
148}
149
150/// An adapter between the [`termcolor::WriteColor`] trait and [`Print`].
151pub struct PrintTermcolor<T>(pub T);
152
153impl<T> Print for PrintTermcolor<T>
154where
155    T: termcolor::WriteColor,
156{
157    fn write_str(&mut self, s: &str) -> io::Result<()> {
158        self.0.write_all(s.as_bytes())
159    }
160
161    fn start_name(&mut self) -> io::Result<()> {
162        self.0
163            .set_color(ColorSpec::new().set_fg(Some(Color::Magenta)))
164    }
165
166    fn start_literal(&mut self) -> io::Result<()> {
167        self.0.set_color(ColorSpec::new().set_fg(Some(Color::Red)))
168    }
169
170    fn start_keyword(&mut self) -> io::Result<()> {
171        self.0.set_color(
172            ColorSpec::new()
173                .set_fg(Some(Color::Yellow))
174                .set_bold(true)
175                .set_intense(true),
176        )
177    }
178
179    fn start_type(&mut self) -> io::Result<()> {
180        self.0.set_color(
181            ColorSpec::new()
182                .set_fg(Some(Color::Green))
183                .set_bold(true)
184                .set_intense(true),
185        )
186    }
187
188    fn start_comment(&mut self) -> io::Result<()> {
189        self.0.set_color(ColorSpec::new().set_fg(Some(Color::Cyan)))
190    }
191
192    fn reset_color(&mut self) -> io::Result<()> {
193        self.0.reset()
194    }
195
196    fn supports_async_color(&self) -> bool {
197        self.0.supports_color() && !self.0.is_synchronous()
198    }
199}