2个版本 (1个稳定版)
1.0.0 | 2023年6月14日 |
---|---|
0.1.0 | 2021年6月12日 |
#220 在 WebAssembly
120KB
1.5K SLoC
custom-print
custom-print
包帮助您在wasm和其他目标中定义 print
、println
和 dbg
宏,而不需要任何依赖。
关于
此包帮助您在 wasm32-unknown-unknown
目标上定义类似 print
的宏、dbg
和 panic_hook
,无需依赖 wasm-bindgen
。它还可以用于其他目标以覆盖默认的 std write
类型的宏、添加 try_
宏变体或指定 panic hook 函数。它在稳定 Rust 上运行,支持 no-alloc
和 no-std
环境,且没有依赖。
在大多数情况下,建议使用宏 define_macros
、define_macro
或 define_init_panic_hook
。这些宏定义具有指定名称的宏或函数,它们使用 FmtWriter
、FmtTryWriter
、ConcatWriter
、ConcatTryWriter
、IoWriter
或 IoTryWriter
,并使用指定的闭包、不安全函数或外部函数。
用法
首先,将以下内容添加到您的 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_std
和 no_alloc
环境中使用 str
引用的闭包的示例
#![no_std]
custom_print::define_macros!({ print, println }, fmt, |_value: &str| { /* ... */ });
fn main() {
println!("println");
print!("print");
}
以下是一个接受 c_char
指针并覆盖 std::print
和 std::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_macros
和 define_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"
);
}
文档
功能标志
alloc
(由std
隐含,因此默认启用):启用WriteStringFn
和ConcatWriter
类型。std
(默认启用):启用IoWriter
、{Try}Write{CStr|CString|CCharPtr}Fn
、define_panic_hook
和define_init_panic_hook
。
类似软件包
web-log
提供print
、println
、eprint
、eprintln
,需要 wasm-bindgen。wasm-rs-dbg
提供dbg
,需要 web-sys。console_log
提供带有trace
、debug
、warn
、error
等的日志记录,需要 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 satisfied
或 the trait bound `...: IntoTryWriteFn<_>` is not satisfied
,以及错误 note: required by ``...Writer::<F1>::from_closure
发生是因为无法确定闭包的正确包装器类型。
如果您还没有指定闭包参数,请使用接受参数的辅助闭包(如 &str
、&[u8]
等)并将它们转换为函数所需的参数。
许可
以下任一许可
- Apache License,版本 2.0(《LICENSE-APACHE》或 https://apache.ac.cn/licenses/LICENSE-2.0》)
- MIT 许可证(《LICENSE-MIT》或 https://opensource.org/licenses/MIT》)
由您选择。
贡献
除非您明确声明,否则根据 Apache-2.0 许可证定义的任何有意提交以包含在作品中的贡献,应如上所述双重许可,不附加任何额外条款或条件。