#print #dbg #log #web #logging

无std custom-print

在wasm和其他目标中定义自定义的println和dbg宏

2个版本 (1个稳定版)

1.0.0 2023年6月14日
0.1.0 2021年6月12日

#220WebAssembly

MIT/Apache

120KB
1.5K SLoC

custom-print

CI Latest Version Documentation GitHub license Rust Version

custom-print 包帮助您在wasm和其他目标中定义 printprintlndbg 宏,而不需要任何依赖。

关于

此包帮助您在 wasm32-unknown-unknown 目标上定义类似 print 的宏、dbgpanic_hook,无需依赖 wasm-bindgen。它还可以用于其他目标以覆盖默认的 std write 类型的宏、添加 try_ 宏变体或指定 panic hook 函数。它在稳定 Rust 上运行,支持 no-allocno-std 环境,且没有依赖。

在大多数情况下,建议使用宏 define_macrosdefine_macrodefine_init_panic_hook。这些宏定义具有指定名称的宏或函数,它们使用 FmtWriterFmtTryWriterConcatWriterConcatTryWriterIoWriterIoTryWriter,并使用指定的闭包、不安全函数或外部函数。

用法

首先,将以下内容添加到您的 Cargo.toml

[dependencies]
custom-print = "1.0.0"

此软件包默认依赖于标准库。要在启用堆分配的 #![no_std] 环境中使用此软件包,请在您的 Cargo.toml 中使用如下所示的 default-features = false

[dependencies.custom-print]
version = "1.0.0"
default-features = false
features = ["alloc"]

示例

以下是一个使用没有 std 预言的 extern 函数的示例

#![no_std]
extern crate std;

custom_print::define_macros!({ print, println },
    concat, extern "C" fn console_log(_: *const u8, _: usize));
custom_print::define_macros!({ eprint, eprintln, dbg },
    concat, extern "C" fn console_warn(_: *const u8, _: usize));
custom_print::define_init_panic_hook!(
    concat, extern "C" fn console_error(_: *const u8, _: usize));

fn main() {
    init_panic_hook();
    println!("println");
    print!("print");
    eprintln!("eprintln");
    eprint!("eprint");
    dbg!("dbg");
}

以下是一个在 no_stdno_alloc 环境中使用 str 引用的闭包的示例

#![no_std]
custom_print::define_macros!({ print, println }, fmt, |_value: &str| { /* ... */ });

fn main() {
    println!("println");
    print!("print");
}

以下是一个接受 c_char 指针并覆盖 std::printstd::println 函数的函数的示例

fn write(_value: *const std::os::raw::c_char) { /* ... */ }

custom_print::define_macros!({ cprint, cprintln }, concat, crate::write);
macro_rules! print { ($($args:tt)*) => { cprint!($($args)*); } }
macro_rules! println { ($($args:tt)*) => { cprintln!($($args)*); } }

fn main() {
    println!("println");
    print!("print");
}

宏生成宏支持指定自定义属性,因此您可以重新导出生成的宏并在其他软件包中使用它们

// foo crate:

custom_print::define_macros!(
    #[macro_export] { print, println, cprint, cprintln },
    fmt, |_value: &str| { /* ... */ }
);

fn func() {
    cprintln!("cprintln");
    cprint!("cprint");
}

// bar crate:

fn main() {
    foo::println!("println");
    foo::print!("print");
}

您可以在测试和示例仓库文件夹中找到更多使用示例。

宏展开

以下示例展示了使用外部函数的 define_macrosdefine_init_panic_hook

#![no_std]
extern crate std;

custom_print::define_macros!({ print, println, try_println },
    concat, extern "C" fn console_log(_: *const u8, _: usize));
custom_print::define_macros!({ eprint, eprintln, dbg },
    concat, extern "C" fn console_warn(_: *const u8, _: usize));
custom_print::define_init_panic_hook!(
    concat, extern "C" fn console_error(_: *const u8, _: usize));

fn main() {
    init_panic_hook();
    println!("Greetings from println");
    let _ = try_println!("Greetings from try_println");
    eprintln!("Greetings from eprintln");
    let _ = dbg!("Greetings from dbg");
}

部分展开为

fn init_panic_hook() {
    fn panic_hook(info: &::std::panic::PanicInfo<'_>) {
        ::core::writeln!(
            ::custom_print::ConcatWriter::from_closure({
                extern "C" { fn console_error(_: *const u8, _: usize); }
                |arg1: *const u8, arg2: usize| unsafe { console_error(arg1, arg2) }
            }),
            "{}",
            info
        ).expect("failed writing panic info");
    }
    ::std::panic::set_hook(::std::boxed::Box::new(panic_hook))
}

fn main() {
    init_panic_hook();

    ::core::writeln!(
        ::custom_print::ConcatWriter::from_closure({
            extern "C" { fn console_log(_: *const u8, _: usize); }
            |arg1: *const u8, arg2: usize| unsafe { console_log(arg1, arg2) }
        }),
        "Greetings from println"
    ).expect("failed writing");

    let _ = ::core::writeln!(
        ::custom_print::ConcatTryWriter::from_closure({
            extern "C" { fn console_log(_: *const u8, _: usize); }
            |arg1: *const u8, arg2: usize| unsafe { console_log(arg1, arg2) }
        }),
        "Greetings from try_println"
    );

    ::core::writeln!(
        ::custom_print::ConcatWriter::from_closure({
            extern "C" { fn console_warn(_: *const u8, _: usize); }
            |arg1: *const u8, arg2: usize| unsafe { console_warn(arg1, arg2) }
        }),
        "Greetings from eprintln"
    ).expect("failed writing");

    let _ = ::custom_print::dbgwrite!(
        ::core::writeln,
        ::custom_print::ConcatWriter::from_closure({
            extern "C" { fn console_error(_: *const u8, _: usize); }
            |arg1: *const u8, arg2: usize| unsafe { console_error(arg1, arg2) }
        }),
        expect,
        ":?",
        "Greetings from dbg"
    );
}

文档

API 文档

功能标志

类似软件包

  • web-log 提供 printprintlneprinteprintln,需要 wasm-bindgen。
  • wasm-rs-dbg 提供 dbg,需要 web-sys。
  • console_log 提供带有 tracedebugwarnerror 等的日志记录,需要 log 和 web-sys。
  • console_error_panic_hook 提供 panic_hook 和 panic hook set 函数,需要 wasm-bindgen。

故障排除

宏名称不明确

以下错误是由于无法在文本作用域中用宏展开的宏覆盖标准Rust宏而发生的:`println` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)

可以使用代理宏来替换文本作用域中的 std

custom_print::define_macro!(cprintln, once: write_fn);
macro_rules! println { ($($args:tt)*) => { cprintln!($($args)*); } }

或者,可以在路径作用域中覆盖宏

custom_print::define_macro!(cprintln, once: write_fn);
use cprintln as println;

有关更多信息,请参阅 define_macro

println、dbg 等在子模块中不起作用

看起来你在路径作用域中覆盖了 print-样式的宏,但未在子模块中覆盖它们。如上所示使用代理宏,或者别忘了在子模块中覆盖它们。

custom_print::define_macro!(cprintln, once: write_fn);
use cprintln as println;
mod submodule {
    use cprintln as println;
}

您始终可以使用 cargo expand 来找出问题的位置。

特质边界 [closure]: IntoWriteFn<_> 不满足

如:错误 the trait bound `...: IntoWriteFn<_>` is not satisfiedthe trait bound `...: IntoTryWriteFn<_>` is not satisfied,以及错误 note: required by ``...Writer::<F1>::from_closure 发生是因为无法确定闭包的正确包装器类型。

如果您还没有指定闭包参数,请使用接受参数的辅助闭包(如 &str&[u8] 等)并将它们转换为函数所需的参数。

许可

以下任一许可

由您选择。

贡献

除非您明确声明,否则根据 Apache-2.0 许可证定义的任何有意提交以包含在作品中的贡献,应如上所述双重许可,不附加任何额外条款或条件。

无运行时依赖