Crate custom_print

source ·
Expand description

The custom-print crate helps you to define print, println and dbg macros in wasm and customize them for other targets without any dependencies.

About

This crate helps you to define print-like macros, dbg and panic_hook on wasm32-unknown-unknown target without wasm-bindgen dependency. Also, it can be used on another targets to override default std write-like macros, add try_ macros variants, or to specify panic hook function. It works on stable Rust, supports no-alloc and no-std environments and has no dependencies.

In most cases it is suggested to use macros define_macros, define_macro or define_init_panic_hook. These macros define macros or functions with the specified names that use FmtWriter, FmtTryWriter, ConcatWriter, ConcatTryWriter, IoWriter or IoTryWriter with the specified closure, unsafe function or extern function.

Usage

First, add the following to your Cargo.toml:

[dependencies]
custom-print = "1.0.0"

This crate depends on the standard library by default. To use this crate in a #![no_std] context but with heap-allocations enabled, use default-features = false in your Cargo.toml as shown below:

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

Examples

An example with an extern functions that takes a UTF-8 chars pointer and byte length with no std prelude:

#![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");
}

An example with a closure that takes an str reference in no_std and no_alloc context:

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

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

An example with a function that takes a c_char pointer and overriding std::print and std::println functions:

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");
}

Macro generation macros support specifying custom attributes, so you can re-export the generated macros and use them in other crates:

// 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");
}

You can find more usage examples in the tests and examples repository folders.

Macro expansion

The example with define_macros and define_init_panic_hook with extern functions:

#![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");
}

partially expands to:

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"
   );
}

Feature Flags

Similar crates

  • web-log provides print, println, eprint, eprintln, requires wasm-bindgen.
  • wasm-rs-dbg provides dbg, requires web-sys.
  • console_log provides logging with trace, debug, warn, error etc., requires log and web-sys.
  • console_error_panic_hook provides panic_hook and panic hook set functions, requires wasm-bindgen.

Troubleshooting

Macro name is ambiguous

Errors like `println` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution) occur because of the inability to overwrite standard rust macros in textual scope with macro-expanded macros.

Use can use proxy macros to replace std macros in textual scope:

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

Alternatively, use can override macro in the path-based scope:

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

See define_macro for more details.

Println, dbg and others do nothing in submodules

It looks like you have overridden print-like macros in the path-based scope, but you have not overridden them in submodules. Use proxy macros as it shown above or do not forget to override it in submodules.

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

You can always use cargo expand to find out where the problem is.

The trait bound [closure]: IntoWriteFn<_> is not satisfied

Errors like: the trait bound `...: IntoWriteFn<_>` is not satisfied or the trait bound `...: IntoTryWriteFn<_>` is not satisfied, with note: required by ``...Writer::<F1>::from_closure `` errors occur because of the inability to determine the appropriate type of wrapper for the closure.

Specify closure arguments if you haven’t already, or use helper closure that takes acceptable arguments (&str, &[u8], etc.) and convert them to the arguments your function requires.

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Macros

  • Prints and returns the value of a given expression for quick and dirty debugging with the specified write macro, writer, format and error-handling policy.
  • Defines dbg macro that prints and returns the value of a given expression for quick and dirty debugging.
  • Defines a dbg-like macro with a given name that uses specified write macro, error-handling policy, format string and writer.
  • Defines flush macro that calls flush method of the specified writer.
  • Defines init_panic_hook function that set panic hook with the specified writer.
  • Defines custom print-like and dbg-like macro.
  • Defines multiple print-like and dbg-like macros.
  • Defines panic_hook function that can be used as panic hook that uses the specified writer.
  • Defines print macro that defines a print macro that uses the specified writer.
  • Defines a print-like macro with a given name that uses specified write macro, error-handling policy and writer.
  • Defines println macro that defines a println macro that uses the specified writer.
  • Defines try_dbg macro that prints and returns the value of a given expression wrapped in for quick and dirty debugging or return an error if write failed.
  • Defines try_flush macro that calls flush method of the specified writer.
  • Defines try_print macro that defines a fallible print macro that uses the specified writer.
  • Defines try_println macro that defines a fallible println macro that uses the specified writer.
  • Defines a fallible writer from writer expression arguments or from the provided one.
  • Defines a writer from writer expression arguments or from the provided one.
  • Defines a writer expression from another expression, unsafe function or extern function.
  • Sets panic_hook that uses the specified writer.
  • Calls another write macro with the specified writer, arguments and error-handling policy.

Structs

  • A writer that calls write_str once with a combined string.
  • A writer that calls write_str once with a combined string.
  • A wrapper for flush function for<R> FnMut(*const c_char) -> R.
  • A writer that calls write_str for each formatted chunk, but do not require allocations.
  • A writer that calls write_str for each formatted chunk, but do not require allocations.
  • A writer that uses write_bytes and has both write and flush methods.
  • A writer that uses write_bytes and has both write and flush methods.
  • A wrapper for write functions for<R> FnMut(*const c_char) -> R.
  • A wrapper for write functions for<R> FnMut(&CStr) -> R.
  • A wrapper for write functions for<R> FnMut(CString) -> R.
  • A wrapper for write functions for<R> FnMut(&[u8]) -> R.
  • A wrapper for write functions for<R> FnMut(*const c_char) -> R.
  • A wrapper for write functions for<R> FnMut(&CStr) -> R.
  • A wrapper for write functions for<R> FnMut(CString) -> R.
  • A wrapper for write functions for<R> FnMut(usize, *const u8) -> R.
  • A wrapper for write functions for<R> FnMut(*const u8, usize) -> R.
  • A wrapper for write functions for<R> FnMut(&str) -> R.
  • A wrapper for write functions for<R> FnMut(String) -> R.

Enums

  • A helper error type that cannot be instantiated.

Traits