macro_rules! define_macro {
    ( $( #[$meta:meta] )* print       as $name:ident, $( $args:tt )* ) => { ... };
    ( $( #[$meta:meta] )* println     as $name:ident, $( $args:tt )* ) => { ... };
    ( $( #[$meta:meta] )* dbg         as $name:ident, $( $args:tt )* ) => { ... };
    ( $( #[$meta:meta] )* flush       as $name:ident, $( $args:tt )* ) => { ... };
    ( $( #[$meta:meta] )* try_print   as $name:ident, $( $args:tt )* ) => { ... };
    ( $( #[$meta:meta] )* try_println as $name:ident, $( $args:tt )* ) => { ... };
    ( $( #[$meta:meta] )* try_dbg     as $name:ident, $( $args:tt )* ) => { ... };
    ( $( #[$meta:meta] )* try_flush   as $name:ident, $( $args:tt )* ) => { ... };
    ( $( #[$meta:meta] )* print,        $( $args:tt )* ) => { ... };
    ( $( #[$meta:meta] )* eprint,       $( $args:tt )* ) => { ... };
    ( $( #[$meta:meta] )* cprint,       $( $args:tt )* ) => { ... };
    ( $( #[$meta:meta] )* ceprint,      $( $args:tt )* ) => { ... };
    ( $( #[$meta:meta] )* println,      $( $args:tt )* ) => { ... };
    ( $( #[$meta:meta] )* eprintln,     $( $args:tt )* ) => { ... };
    ( $( #[$meta:meta] )* cprintln,     $( $args:tt )* ) => { ... };
    ( $( #[$meta:meta] )* ceprintln,    $( $args:tt )* ) => { ... };
    ( $( #[$meta:meta] )* dbg,          $( $args:tt )* ) => { ... };
    ( $( #[$meta:meta] )* edbg,         $( $args:tt )* ) => { ... };
    ( $( #[$meta:meta] )* cdbg,         $( $args:tt )* ) => { ... };
    ( $( #[$meta:meta] )* flush,        $( $args:tt )* ) => { ... };
    ( $( #[$meta:meta] )* eflush,       $( $args:tt )* ) => { ... };
    ( $( #[$meta:meta] )* try_print,    $( $args:tt )* ) => { ... };
    ( $( #[$meta:meta] )* try_eprint,   $( $args:tt )* ) => { ... };
    ( $( #[$meta:meta] )* try_println,  $( $args:tt )* ) => { ... };
    ( $( #[$meta:meta] )* try_eprintln, $( $args:tt )* ) => { ... };
    ( $( #[$meta:meta] )* try_dbg,      $( $args:tt )* ) => { ... };
    ( $( #[$meta:meta] )* try_edbg,     $( $args:tt )* ) => { ... };
    ( $( #[$meta:meta] )* try_flush,    $( $args:tt )* ) => { ... };
    ( $( #[$meta:meta] )* try_eflush,   $( $args:tt )* ) => { ... };
}
Expand description

Defines custom print-like and dbg-like macro.

The first argument contains the macro name by which its template is determined, or both the template name and the macro name using the syntax template as name. The rest tokens specified in $($args)* are used as input for define_writer macro.

Depending on the specified template, the macro uses define_print, define_println, define_dbg, define_flush, define_try_print, define_try_println, define_try_dbg or define_try_flush.

If you need to define multiple print-like and dbg-like macros, use define_macros.

Naming

The macros with the try_ prefix are producing fallible write expressions. The macros with the e prefix are proposed to be used with stderr-like writers. The macros with the c prefix are proposed to be used instead of the standard macros or to shadow the standard macros in the following lines of code.

Macro ambiguity

When using std-prelude, std macros cannot be replaced in textual scope using this macro. This is a consequence of the ambiguous precedence between a macro-expanded macro and a macro from the outer scope. Use alternative names like cprint, ceprint, cprintln, ceprintln, cdbg, and then override std macros using proxy macro or use declaration.

Overriding with a proxy macro is a better way because it overrides macros in textual scope and accordingly in all submodules:

custom_print::define_macro!(cprintln, once: crate::write);
macro_rules! println { ($($args:tt)*) => { cprintln!($($args)*); } }
mod submodule { /* println is already defined in all submodules */ }

Alternatively, use can override macro in the path-based scope, but then it will be necessary not to forget to import macro into submodules scope:

custom_print::define_macro!(cprintln, once: crate::write);
use cprintln as println;
mod submodule { use crate::println; /* ... */ }

Examples

An example with a simple string writer:

use core::fmt::Write;
let mut string = String::new();
custom_print::define_macro!(cprint, &mut string);

assert_eq!(cprint!("value"), ());
assert_eq!(string, "value");

An example with an extern functions that takes a UTF-8 chars pointer and byte length and works in no_std context:

#![no_std]
extern crate std;

custom_print::define_macro!(println,
    concat, extern "C" fn console_log(_: *const u8, _: usize));
custom_print::define_macro!(eprintln,
    concat, extern "C" fn console_warn(_: *const u8, _: usize));

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

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

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

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

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

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

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

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

An example with LineWriter and flushing.

use std::io::{self, LineWriter, Write};
use std::sync::Mutex;

let written: Mutex<Vec<u8>> = Mutex::default();

#[derive(Clone, Debug)]
struct CustomWriter<'a>(&'a Mutex<Vec<u8>>);

impl Write for CustomWriter<'_> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let mut written = self.0.lock().unwrap();
        written.extend_from_slice(buf);
        Ok(buf.len())
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

let custom_writer = CustomWriter(&written);
let mut line_writer = LineWriter::new(custom_writer);

custom_print::define_macro!(cprint, line_writer);
custom_print::define_macro!(flush, line_writer);

assert_eq!(cprint!("first,"), ());
assert_eq!(*written.lock().unwrap(), b"");
assert_eq!(cprint!("second\nthird,"), ());
assert_eq!(*written.lock().unwrap(), b"first,second\n");
assert_eq!(flush!(), ());
assert_eq!(*written.lock().unwrap(), b"first,second\nthird,");