use std::marker::PhantomData;
use std::sync::atomic::{AtomicU32, Ordering};
use logforth::append::Append;
use logforth::diagnostic::Diagnostic;
use logforth::record::Record;
#[derive(Debug, Default)]
pub struct WebConsoleAppend;
impl Append for WebConsoleAppend {
fn append(
&self,
record: &Record,
_diags: &[Box<dyn Diagnostic>],
) -> Result<(), logforth::Error> {
let message = format!("{}: {}", record.target(), record.payload());
let message = wasm_bindgen::JsValue::from_str(&message);
match record.level() {
logforth::record::Level::Error => web_sys::console::error_1(&message),
logforth::record::Level::Warn => web_sys::console::warn_1(&message),
logforth::record::Level::Info => web_sys::console::info_1(&message),
logforth::record::Level::Debug => web_sys::console::debug_1(&message),
_ => web_sys::console::log_1(&message),
}
Ok(())
}
fn flush(&self) -> Result<(), logforth::Error> {
Ok(())
}
}
static MARK_ID: AtomicU32 = AtomicU32::new(0);
pub struct WebMarkGuard {
name: Option<&'static str>,
id: u32,
_not_send: PhantomData<*const ()>,
}
#[must_use]
pub fn enter_mark(name: &'static str) -> WebMarkGuard {
let id = MARK_ID.fetch_add(1, Ordering::Relaxed);
if let Some(performance) = performance() {
let _ = performance.mark(&mark_name(name, id, "start"));
}
WebMarkGuard {
name: Some(name),
id,
_not_send: PhantomData,
}
}
#[must_use]
pub const fn dummy_mark() -> WebMarkGuard {
WebMarkGuard {
name: None,
id: 0,
_not_send: PhantomData,
}
}
impl Drop for WebMarkGuard {
fn drop(&mut self) {
let Some(name) = self.name else { return };
let Some(performance) = performance() else {
return;
};
let _ = performance.mark(&mark_name(name, self.id, "end"));
let _ = performance.measure_with_start_mark_and_end_mark(
name,
&mark_name(name, self.id, "start"),
&mark_name(name, self.id, "end"),
);
}
}
fn performance() -> Option<web_sys::Performance> {
web_sys::window().and_then(|w| w.performance())
}
fn mark_name(name: &str, id: u32, kind: &str) -> String {
format!("{name}::{id}::{kind}")
}
#[cfg(feature = "fastrace")]
#[expect(
dead_code,
reason = "wired by the deployment integration (Deployment::init) on wasm32-unknown-unknown"
)]
pub fn install_unload_flush() {
use wasm_bindgen::JsCast as _;
use wasm_bindgen::closure::Closure;
let Some(window) = web_sys::window() else {
return;
};
let callback = Closure::<dyn FnMut()>::new(fastrace::flush);
let options = web_sys::AddEventListenerOptions::new();
options.set_once(true);
let _ = window.add_event_listener_with_callback_and_add_event_listener_options(
"pagehide",
callback.as_ref().unchecked_ref(),
&options,
);
callback.forget();
}