Macro custom_print::define_macro
source · 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,");