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;