use wasm_bindgen::prelude::*;
use web_sys::console;
pub fn set_panic_hook() {
console_error_panic_hook::set_once();
}
pub fn log(message: &str) {
console::log_1(&JsValue::from_str(message));
}
pub fn warn(message: &str) {
console::warn_1(&JsValue::from_str(message));
}
pub fn error(message: &str) {
console::error_1(&JsValue::from_str(message));
}
pub fn debug(message: &str) {
console::debug_1(&JsValue::from_str(message));
}
pub fn measure_time<F, R>(name: &str, f: F) -> R
where
F: FnOnce() -> R,
{
let start = js_sys::Date::now();
let result = f();
let elapsed = js_sys::Date::now() - start;
log(&format!("{} took {:.2}ms", name, elapsed));
result
}
#[wasm_bindgen]
pub fn is_web_worker() -> bool {
js_sys::eval("typeof WorkerGlobalScope !== 'undefined'")
.map(|v| v.is_truthy())
.unwrap_or(false)
}
#[wasm_bindgen]
pub fn is_wasm_supported() -> bool {
js_sys::eval("typeof WebAssembly !== 'undefined'")
.map(|v| v.is_truthy())
.unwrap_or(false)
}
#[wasm_bindgen]
pub fn get_performance_metrics() -> Result<JsValue, JsValue> {
let window = web_sys::window().ok_or_else(|| JsValue::from_str("No window object"))?;
let performance = window
.performance()
.ok_or_else(|| JsValue::from_str("No performance object"))?;
let timing = performance.timing();
let metrics = serde_json::json!({
"navigation_start": timing.navigation_start(),
"dom_complete": timing.dom_complete(),
"load_event_end": timing.load_event_end(),
});
serde_wasm_bindgen::to_value(&metrics)
.map_err(|e| JsValue::from_str(&format!("Failed to serialize metrics: {}", e)))
}
#[wasm_bindgen]
pub fn get_memory_info() -> Result<JsValue, JsValue> {
let window = web_sys::window().ok_or_else(|| JsValue::from_str("No window object"))?;
let performance = window
.performance()
.ok_or_else(|| JsValue::from_str("No performance object"))?;
let result = js_sys::Reflect::get(&performance, &JsValue::from_str("memory"));
if let Ok(memory) = result {
if !memory.is_undefined() {
return Ok(memory);
}
}
Ok(js_sys::Object::new().into())
}
pub fn format_bytes(bytes: f64) -> String {
const UNITS: &[&str] = &["B", "KB", "MB", "GB", "TB"];
let mut size = bytes;
let mut unit_index = 0;
while size >= 1024.0 && unit_index < UNITS.len() - 1 {
size /= 1024.0;
unit_index += 1;
}
format!("{:.2} {}", size, UNITS[unit_index])
}
#[wasm_bindgen]
pub fn generate_uuid() -> String {
let result = js_sys::eval(
"typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function' ? crypto.randomUUID() : null"
);
if let Ok(uuid) = result {
if let Some(uuid_str) = uuid.as_string() {
return uuid_str;
}
}
use getrandom::getrandom;
let mut bytes = [0u8; 16];
if getrandom(&mut bytes).is_ok() {
bytes[6] = (bytes[6] & 0x0f) | 0x40;
bytes[8] = (bytes[8] & 0x3f) | 0x80;
format!(
"{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
bytes[0], bytes[1], bytes[2], bytes[3],
bytes[4], bytes[5],
bytes[6], bytes[7],
bytes[8], bytes[9],
bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15]
)
} else {
format!("{}-{}", js_sys::Date::now(), js_sys::Math::random())
}
}
#[wasm_bindgen]
pub fn is_local_storage_available() -> bool {
js_sys::eval("typeof localStorage !== 'undefined'")
.map(|v| v.is_truthy())
.unwrap_or(false)
}
#[wasm_bindgen]
pub fn is_indexed_db_available() -> bool {
js_sys::eval("typeof indexedDB !== 'undefined'")
.map(|v| v.is_truthy())
.unwrap_or(false)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_format_bytes() {
assert_eq!(format_bytes(100.0), "100.00 B");
assert_eq!(format_bytes(1024.0), "1.00 KB");
assert_eq!(format_bytes(1024.0 * 1024.0), "1.00 MB");
}
}