1use super::JsValue;
5
6#[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
35pub trait ConsoleBackend: std::panic::RefUnwindSafe + 'static {
58 fn log(&self, level: Level, values: Vec<JsValue>);
60}
61
62impl<F> ConsoleBackend for F
63where
64 F: Fn(Level, Vec<JsValue>) + std::panic::RefUnwindSafe + 'static,
65{
66 fn log(&self, level: Level, values: Vec<JsValue>) {
67 (self)(level, values);
68 }
69}
70
71#[cfg(feature = "log")]
72mod log {
73 use super::{JsValue, Level};
74
75 pub struct LogConsole;
79
80 fn print_value(value: JsValue) -> String {
81 match value {
82 JsValue::Undefined => "undefined".to_string(),
83 JsValue::Null => "null".to_string(),
84 JsValue::Bool(v) => v.to_string(),
85 JsValue::Int(v) => v.to_string(),
86 JsValue::Float(v) => v.to_string(),
87 JsValue::String(v) => v,
88 JsValue::Array(values) => {
89 let parts = values
90 .into_iter()
91 .map(print_value)
92 .collect::<Vec<_>>()
93 .join(", ");
94 format!("[{}]", parts)
95 }
96 JsValue::Object(map) => {
97 let parts = map
98 .into_iter()
99 .map(|(key, value)| format!("{}: {}", key, print_value(value)))
100 .collect::<Vec<_>>()
101 .join(", ");
102 format!("{{{}}}", parts)
103 }
104 #[cfg(feature = "chrono")]
105 JsValue::Date(v) => v.to_string(),
106 #[cfg(feature = "bigint")]
107 JsValue::BigInt(v) => v.to_string(),
108 JsValue::__NonExhaustive => unreachable!(),
109 }
110 }
111
112 impl super::ConsoleBackend for LogConsole {
113 fn log(&self, level: Level, values: Vec<JsValue>) {
114 if values.is_empty() {
115 return;
116 }
117 let log_level = match level {
118 Level::Trace => log::Level::Trace,
119 Level::Debug => log::Level::Debug,
120 Level::Log => log::Level::Info,
121 Level::Info => log::Level::Info,
122 Level::Warn => log::Level::Warn,
123 Level::Error => log::Level::Error,
124 };
125
126 let msg = values
127 .into_iter()
128 .map(print_value)
129 .collect::<Vec<_>>()
130 .join(" ");
131
132 log::log!(log_level, "{}", msg);
133 }
134 }
135}
136
137#[cfg(feature = "log")]
138pub use self::log::LogConsole;