quickjs_rusty/
console.rs

1//! Javascript console integration.
2//! See the [ConsoleBackend] trait for more info.
3
4use crate::OwnedJsValue;
5
6/// Log level of a log message sent via the console.
7/// These levels represent the different functions defined in the spec:
8/// <https://s3.amazonaws.com/temp.michaelfbryan.com/callbacks/index.html>
9#[allow(missing_docs)]
10#[derive(PartialEq, Eq, Clone, Copy, Debug)]
11pub enum Level {
12    Trace,
13    Debug,
14    Log,
15    Info,
16    Warn,
17    Error,
18}
19
20impl std::fmt::Display for Level {
21    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
22        use Level::*;
23        let v = match self {
24            Trace => "trace",
25            Debug => "debug",
26            Log => "log",
27            Info => "info",
28            Warn => "warn",
29            Error => "error",
30        };
31        write!(f, "{}", v)
32    }
33}
34
35/// A console backend that handles console messages sent from JS via
36/// console.{log,debug,trace,...} functions.
37///
38/// A backend has to be registered via the `ContextBuilder::console` method.
39///
40/// A backend that forwads to the `log` crate is available with the `log` feature.
41///
42/// Note that any closure of type `Fn(Level, Vec<JsValue>)` implements this trait.
43///
44/// A very simple logger that just prints to stderr could look like this:
45///
46/// ```rust
47/// use quickjs_rusty::{Context, OwnedJsValue, console::Level};
48///
49/// Context::builder()
50///     .console(|level: Level, args: Vec<OwnedJsValue>| {
51///         eprintln!("{}: {:?}", level, args);
52///     })
53///     .build()
54///     # .unwrap();
55/// ```
56///
57pub trait ConsoleBackend: std::panic::RefUnwindSafe + 'static {
58    /// Handle a log message.
59    fn log(&self, level: Level, values: Vec<OwnedJsValue>);
60}
61
62impl<F> ConsoleBackend for F
63where
64    F: Fn(Level, Vec<OwnedJsValue>) + std::panic::RefUnwindSafe + 'static,
65{
66    fn log(&self, level: Level, values: Vec<OwnedJsValue>) {
67        (self)(level, values);
68    }
69}
70
71#[cfg(feature = "log")]
72mod log {
73    use crate::OwnedJsValue;
74
75    use super::Level;
76
77    /// A console implementation that logs messages via the `log` crate.
78    ///
79    /// Only available with the `log` feature.
80    pub struct LogConsole;
81
82    fn print_value(value: OwnedJsValue) -> String {
83        value.to_json_string(0).unwrap()
84    }
85
86    impl super::ConsoleBackend for LogConsole {
87        fn log(&self, level: Level, values: Vec<OwnedJsValue>) {
88            if values.is_empty() {
89                return;
90            }
91            let log_level = match level {
92                Level::Trace => log::Level::Trace,
93                Level::Debug => log::Level::Debug,
94                Level::Log => log::Level::Info,
95                Level::Info => log::Level::Info,
96                Level::Warn => log::Level::Warn,
97                Level::Error => log::Level::Error,
98            };
99
100            let msg = values
101                .into_iter()
102                .map(print_value)
103                .collect::<Vec<_>>()
104                .join(" ");
105
106            log::log!(log_level, "{}", msg);
107        }
108    }
109}
110
111#[cfg(feature = "log")]
112pub use self::log::LogConsole;