devela 0.28.0

A development substrate of coherence.
Documentation
// devela::lang::prog::ffi::js::console
//
//! Defines [`JsConsole`].
//
// TOC
// - struct JsConsole
// - impl methods
// - extern impls
// - impl traits

use crate::{_js_unsafe_ffi_doc, macro_apply};
use crate::{DiagLevel, DiagOut, Infallible, TextOut};
#[allow(unused_imports)]
use devela::{_js_doc, _js_extern};

#[doc = crate::_tags!(runtime namespace)]
/// Javascript Console.
#[doc = crate::_doc_meta!{location("lang/prog/ffi/js")}]
#[macro_apply(crate::__doc_show(feature = "unsafe_ffi"))]
#[derive(Debug)]
pub struct JsConsole;

/// # Javascript API console
///
/// - <https://console.spec.whatwg.org/>
/// - <https://developer.mozilla.org/en-US/docs/Web/API/console>
#[rustfmt::skip]
#[cfg(not(feature = "safe_lang"))]
#[macro_apply(crate::_js_unsafe_ffi_doc)]
impl JsConsole {
    #[doc = _js_doc!(console "clear")]
    /// Clears the console if possible.
    pub fn clear() { console_clear() }

    #[doc = _js_doc!(console "debug")]
    /// Outputs a message to the console with the debug log level.
    pub fn debug(text: &str) { unsafe { console_debug(text.as_ptr(), text.len()); } }

    #[doc = _js_doc!(console "error")]
    /// Outputs a message to the console with the error log level.
    pub fn error(text: &str) { unsafe { console_error(text.as_ptr(), text.len()); } }

    #[doc = _js_doc!(console "info")]
    /// Outputs a message to the console with the info log level.
    pub fn info(text: &str) { unsafe { console_info(text.as_ptr(), text.len()); } }

    #[doc = _js_doc!(console "log")]
    /// Outputs a message to the console.
    pub fn log(text: &str) { unsafe { console_log(text.as_ptr(), text.len()); } }

    #[doc = _js_doc!(console "trace")]
    /// Outputs a stack trace.
    pub fn trace() { console_trace(); }

    #[doc = _js_doc!(console "warn")]
    /// Outputs a message to the console with the warning log level.
    pub fn warn(text: &str) { unsafe { console_warn(text.as_ptr(), text.len()); } }

    //

    #[doc = _js_doc!(console "count")]
    /// Logs the number of times that this particular call to count has been called.
    pub fn count(label: &str) { unsafe { console_count(label.as_ptr(), label.len()); } }

    #[doc = _js_doc!(console "countReset")]
    /// Resets the counter used with [`count`][Self::count].
    pub fn count_reset(label: &str) {
        unsafe { console_count_reset(label.as_ptr(), label.len()); } }

    //

    #[doc = _js_doc!(console "group")]
    /// Creates a new inline group, indenting all following output by another level.
    pub fn group(text: &str) { unsafe { console_group(text.as_ptr(), text.len()); } }

    #[doc = _js_doc!(console "groupCollapsed")]
    /// Like [`group`][Self::group] but starts with the inline group collapsed.
    pub fn group_collapsed(text: &str) {
        unsafe { console_group_collapsed(text.as_ptr(), text.len()); } }

    #[doc = _js_doc!(console "groupEnd")]
    /// Exits the current inline group.
    pub fn group_end() { console_group_end(); }

    //

    #[doc = _js_doc!(console "time")]
    /// Starts a timer with the given `name`.
    pub fn time(name: &str) { unsafe { console_time(name.as_ptr(), name.len()); } }

    #[doc = _js_doc!(console "timeEnd")]
    /// Stops a timer with the given name, started with [`time_end`][Self::time_end].
    pub fn time_end(name: &str) { unsafe { console_time_end(name.as_ptr(), name.len()); } }

    #[doc = _js_doc!(console "timeLog")]
    /// Logs a timer with the given name, started with [`time_log`][Self::time_log].
    pub fn time_log(name: &str) { unsafe { console_time_log(name.as_ptr(), name.len()); } }
}
_js_extern! {
    [ module: "api_console" ]
    safe fn console_clear();
    unsafe fn console_debug(str_ptr: *const u8, str_len: usize);
    unsafe fn console_error(str_ptr: *const u8, str_len: usize);
    unsafe fn console_info(str_ptr: *const u8, str_len: usize);
    unsafe fn console_log(str_ptr: *const u8, str_len: usize);
    safe fn console_trace();
    unsafe fn console_warn(str_ptr: *const u8, str_len: usize);
    //
    unsafe fn console_count(str_ptr: *const u8, str_len: usize);
    unsafe fn console_count_reset(str_ptr: *const u8, str_len: usize);
    //
    unsafe fn console_group(str_ptr: *const u8, str_len: usize);
    unsafe fn console_group_collapsed(str_ptr: *const u8, str_len: usize);
    safe fn console_group_end();
    //
    unsafe fn console_time(str_ptr: *const u8, str_len: usize);
    unsafe fn console_time_end(str_ptr: *const u8, str_len: usize);
    unsafe fn console_time_log(str_ptr: *const u8, str_len: usize);
}

/// Emits leveled diagnostics to the JavaScript console.
///
/// This implementation maps [`DiagOut`] directly onto the browser's native
/// console levels, preserving the semantic distinction between trace, debug,
/// info, warning, and error output.
///
/// See also [`TextOut`] for plain text emission.
#[cfg(not(feature = "safe_lang"))]
#[macro_apply(_js_unsafe_ffi_doc)]
impl DiagOut for JsConsole {
    type Error = Infallible;

    fn diag(&mut self, level: DiagLevel, text: &str) -> Result<(), Self::Error> {
        match level {
            DiagLevel::Trace => Self::debug(text), // FUTURE `trace` when message-bearing
            DiagLevel::Debug => Self::debug(text),
            DiagLevel::Info => Self::info(text),
            DiagLevel::Warn => Self::warn(text),
            DiagLevel::Error => Self::error(text),
        }
        Ok(())
    }
}

/// Emits UTF-8 text to the JavaScript console.
///
/// This is a convenience text-sink implementation over [`JsConsole`],
/// forwarding plain text through the console's generic log channel.
///
/// For leveled diagnostic output, prefer [`DiagOut`].
#[cfg(not(feature = "safe_lang"))]
#[macro_apply(_js_unsafe_ffi_doc)]
impl TextOut for JsConsole {
    type Error = Infallible;

    fn write_text(&mut self, text: &str) -> Result<(), Self::Error> {
        Self::log(text);
        Ok(())
    }
}