1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#[cfg(target_arch = "wasm32")]
extern "C" {
    fn log_debug(msg: *const u8, len: i32);
    fn log_info(msg: *const u8, len: i32);
    fn log_warn(msg: *const u8, len: i32);
    fn log_error(msg: *const u8, len: i32);
    fn log_panic(msg: *const u8, len: i32, file: *const u8, flen: i32, line: i32, column: i32);
}

#[derive(Default)]
pub struct WasmLog;

impl log::Log for WasmLog {
    fn enabled(&self, metadata: &log::Metadata) -> bool {
        metadata.level() <= log::Level::Info
    }

    #[cfg(target_arch = "wasm32")]
    fn log(&self, record: &log::Record) {
        let (log, name): (unsafe extern "C" fn(*const u8, i32), &str) = match record.level() {
            log::Level::Trace => (log_debug, "trace"),
            log::Level::Debug => (log_debug, "debug"),
            log::Level::Warn => (log_warn, "warn"),
            log::Level::Info => (log_info, "info"),
            log::Level::Error => (log_error, "error"),
        };
        let msg = &format!("{}", format_args!("%c{}%c\t{}", name, record.args()));
        unsafe { log(msg.as_ptr(), msg.len() as i32) }
    }
    #[cfg(not(target_arch = "wasm32"))]
    fn log(&self, record: &log::Record) {
        println!("{}", format_args!("{}", record.args()));
    }

    fn flush(&self) {}
}

#[cfg(target_arch = "wasm32")]
pub fn init_panic_handler() {
    std::panic::set_hook(Box::new(|info| {
        let (file, line, column) = if let Some(loc) = info.location() {
            (loc.file(), loc.line() as i32, loc.column() as i32)
        } else {
            ("<unknown>", 0, 0)
        };
        if let Some(payload) = info.payload().downcast_ref::<&str>() {
            unsafe {
                log_panic(
                    payload.as_ptr(),
                    payload.len() as i32,
                    file.as_ptr(),
                    file.len() as i32,
                    line,
                    column,
                )
            }
        } else if let Some(message) = info.message() {
            let msg = format!("{}", message);
            unsafe {
                log_panic(
                    msg.as_ptr(),
                    msg.len() as i32,
                    file.as_ptr(),
                    file.len() as i32,
                    line,
                    column,
                )
            }
        }
    }));
}