macro_rules! define_macros {
(
$( #[$meta1:meta] )*
{ $( $( #[$meta2:meta] )* $template:ident $(as $name:ident)? ),* $(,)? },
$( $args:tt )*
) => { ... };
}
Expand description
Defines multiple print
-like and dbg
-like macros.
The first argument braced in curly braces and contains
comma-seperated macro template names and optionally their custom macro names.
See the define_macro
declaration for the list of available templates.
The rest tokens specified in $($args)*
are used as input for define_writer
macro.
Depending on the specified templates, the macro uses
define_print
, define_println
, define_dbg
, define_flush
,
define_try_print
, define_try_println
, define_try_dbg
or define_try_flush
for each generated macro.
If you need to define a single print
-like or dbg
-like macro, use define_macro
.
§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_macros!({ cprint, cprintln }, once: crate::write);
macro_rules! print { ($($args:tt)*) => { cprint!($($args)*); } }
macro_rules! println { ($($args:tt)*) => { cprintln!($($args)*); } }
mod submodule { /* println is already defined in all submodules */ }
Alternatively, use can rebind macro from the textual scope to the path-based scope, but then it will be necessary not to forget to import macro into submodules scope:
custom_print::define_macros!({ cprint, cprintln }, once: crate::write);
use cprint as print;
use cprintln as println;
mod submodule { use crate::{print, println}; /* ... */ }
§Examples
An example with a simple string writer:
use core::fmt::Write;
let mut string = String::new();
custom_print::define_macros!({ cprint, cprintln }, &mut string);
assert_eq!(cprintln!("first"), ());
assert_eq!(string, "first\n");
assert_eq!(cprint!("second"), ());
assert_eq!(string, "first\nsecond");
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_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));
fn main() {
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
:
#![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");
}
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_macros!({cprint, 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,");