custom_print/macros/define.rs
1/// Defines multiple `print`-like and `dbg`-like macros.
2///
3/// The first argument braced in curly braces and contains
4/// comma-seperated macro template names and optionally their custom macro names.
5/// See the [`define_macro`] declaration for the list of available templates.
6/// The rest tokens specified in `$($args)*` are used as input for [`define_writer`] macro.
7///
8/// Depending on the specified templates, the macro uses
9/// [`define_print`], [`define_println`], [`define_dbg`], [`define_flush`],
10/// [`define_try_print`], [`define_try_println`], [`define_try_dbg`] or [`define_try_flush`]
11/// for each generated macro.
12///
13/// If you need to define a single `print`-like or `dbg`-like macro, use [`define_macro`].
14///
15/// # Macro ambiguity
16///
17/// When using std-prelude, std macros cannot be replaced in [textual scope] using this macro.
18/// This is a consequence of the ambiguous precedence between
19/// a macro-expanded macro and a macro from the outer scope.
20/// Use alternative names like `cprint`, `ceprint`, `cprintln`, `ceprintln`, `cdbg`,
21/// and then override std macros using proxy macro or use declaration.
22///
23/// Overriding with a proxy macro is a better way because
24/// it overrides macros in [textual scope] and accordingly in all submodules:
25/// ```
26/// custom_print::define_macros!({ cprint, cprintln }, once: crate::write);
27/// macro_rules! print { ($($args:tt)*) => { cprint!($($args)*); } }
28/// macro_rules! println { ($($args:tt)*) => { cprintln!($($args)*); } }
29/// # fn main() {}
30/// mod submodule { /* println is already defined in all submodules */ }
31/// ```
32///
33/// Alternatively, use can rebind macro from the [textual scope] to the [path-based scope],
34/// but then it will be necessary not to forget to import macro into submodules scope:
35/// ```
36/// custom_print::define_macros!({ cprint, cprintln }, once: crate::write);
37/// use cprint as print;
38/// use cprintln as println;
39/// # fn main() {}
40/// mod submodule { use crate::{print, println}; /* ... */ }
41/// ```
42///
43/// # Examples
44///
45/// An example with a simple string writer:
46/// ```rust
47/// use core::fmt::Write;
48/// let mut string = String::new();
49/// custom_print::define_macros!({ cprint, cprintln }, &mut string);
50///
51/// assert_eq!(cprintln!("first"), ());
52/// assert_eq!(string, "first\n");
53/// assert_eq!(cprint!("second"), ());
54/// assert_eq!(string, "first\nsecond");
55/// ```
56///
57/// An example with an extern functions that takes a UTF-8 chars pointer and byte length
58/// and works in `no_std` context:
59#[cfg_attr(feature = "alloc", doc = "```rust")]
60#[cfg_attr(not(feature = "alloc"), doc = "```rust,compile_fail")]
61/// #![no_std]
62/// extern crate std;
63///
64/// # pub mod ffi {
65/// # #[no_mangle] pub extern "C" fn console_log(_: *const u8, _: usize) {}
66/// # #[no_mangle] pub extern "C" fn console_warn(_: *const u8, _: usize) {}
67/// # }
68/// #
69/// custom_print::define_macros!({ print, println },
70/// concat, extern "C" fn console_log(_: *const u8, _: usize));
71/// custom_print::define_macros!({ eprint, eprintln, dbg },
72/// concat, extern "C" fn console_warn(_: *const u8, _: usize));
73///
74/// fn main() {
75/// println!("println");
76/// print!("print");
77/// eprintln!("eprintln");
78/// eprint!("eprint");
79/// dbg!("dbg");
80/// }
81/// ```
82///
83/// An example with a closure that takes an [`str`] reference in `no_std` and `no_alloc`:
84#[cfg_attr(feature = "std", doc = " ```rust")]
85#[cfg_attr(not(feature = "std"), doc = " ```rust,compile_fail")]
86/// #![no_std]
87/// custom_print::define_macros!({ print, println }, fmt, |_value: &str| { /* ... */ });
88///
89/// fn main() {
90/// println!("println");
91/// print!("print");
92/// }
93/// ```
94///
95/// An example with a function that takes a [`c_char`] pointer and overriding
96/// [`std::print`] and [`std::println`] functions:
97#[cfg_attr(feature = "std", doc = "```rust")]
98#[cfg_attr(not(feature = "std"), doc = "```rust,compile_fail")]
99/// fn write(_value: *const std::os::raw::c_char) { /* ... */ }
100///
101/// custom_print::define_macros!({ cprint, cprintln }, concat, crate::write);
102/// macro_rules! print { ($($args:tt)*) => { cprint!($($args)*); } }
103/// macro_rules! println { ($($args:tt)*) => { cprintln!($($args)*); } }
104///
105/// fn main() {
106/// println!("println");
107/// print!("print");
108/// }
109/// ```
110///
111/// An example with `LineWriter` and flushing.
112/// ```rust
113/// use std::io::{self, LineWriter, Write};
114/// use std::sync::Mutex;
115///
116/// let written: Mutex<Vec<u8>> = Mutex::default();
117///
118/// #[derive(Clone, Debug)]
119/// struct CustomWriter<'a>(&'a Mutex<Vec<u8>>);
120///
121/// impl Write for CustomWriter<'_> {
122/// fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
123/// let mut written = self.0.lock().unwrap();
124/// written.extend_from_slice(buf);
125/// Ok(buf.len())
126/// }
127///
128/// fn flush(&mut self) -> io::Result<()> {
129/// Ok(())
130/// }
131/// }
132///
133/// let custom_writer = CustomWriter(&written);
134/// let mut line_writer = LineWriter::new(custom_writer);
135///
136/// custom_print::define_macros!({cprint, flush}, line_writer);
137///
138/// assert_eq!(cprint!("first,"), ());
139/// assert_eq!(*written.lock().unwrap(), b"");
140/// assert_eq!(cprint!("second\nthird,"), ());
141/// assert_eq!(*written.lock().unwrap(), b"first,second\n");
142/// assert_eq!(flush!(), ());
143/// assert_eq!(*written.lock().unwrap(), b"first,second\nthird,");
144/// ```
145///
146/// [`c_char`]: https://doc.rust-lang.org/std/os/raw/type.c_char.html
147/// [textual scope]: https://doc.rust-lang.org/nightly/reference/macros-by-example.html#scoping-exporting-and-importing
148/// [path-based scope]: https://doc.rust-lang.org/nightly/reference/macros-by-example.html#scoping-exporting-and-importing
149/// [`define_macro`]: macro.define_macro.html
150/// [`define_writer`]: macro.define_writer.html
151/// [`define_print`]: macro.define_print.html
152/// [`define_println`]: macro.define_println.html
153/// [`define_dbg`]: macro.define_dbg.html
154/// [`define_flush`]: macro.define_flush.html
155/// [`define_try_print`]: macro.define_try_print.html
156/// [`define_try_println`]: macro.define_try_println.html
157/// [`define_try_dbg`]: macro.define_try_dbg.html
158/// [`define_try_flush`]: macro.define_try_flush.html
159#[macro_export]
160macro_rules! define_macros {
161 (
162 $( #[$meta1:meta] )*
163 { $( $( #[$meta2:meta] )* $template:ident $(as $name:ident)? ),* $(,)? },
164 $( $args:tt )*
165 ) => {
166 $crate::_define_macros_impl!(
167 $( #[$meta1] )*
168 { $( $( #[$meta2] )* $template $( as $name )? ),* },
169 $( $args )*
170 );
171 };
172}
173
174#[doc(hidden)]
175#[macro_export]
176macro_rules! _define_macros_impl {
177 (
178 $( #[$meta1:meta] )*
179 { $( #[$meta2:meta] )* $template:ident $(as $name:ident)? $(, $($rest:tt)* )? },
180 $( $args:tt )*
181 ) => {
182 $crate::define_macro!(
183 $( #[$meta1] )*
184 $( #[$meta2] )*
185 $template $(as $name)?, $($args)*
186 );
187 $crate::_define_macros_impl!(
188 $( #[$meta1] )*
189 { $($($rest)*)? }, $($args)*
190 );
191 };
192 ( $( #[$meta1:meta] )* { $(,)? } $(, $( $args:tt )* )? ) => {};
193}
194
195/// Defines custom `print`-like and `dbg`-like macro.
196///
197/// The first argument contains the macro name by which its template is determined,
198/// or both the template name and the macro name using the syntax `template as name`.
199/// The rest tokens specified in `$($args)*` are used as input for [`define_writer`] macro.
200///
201/// Depending on the specified template, the macro uses
202/// [`define_print`], [`define_println`], [`define_dbg`], [`define_flush`],
203/// [`define_try_print`], [`define_try_println`], [`define_try_dbg`] or [`define_try_flush`].
204///
205/// If you need to define multiple `print`-like and `dbg`-like macros, use [`define_macros`].
206///
207/// # Naming
208///
209/// The macros with the `try_` prefix are producing fallible write expressions.
210/// The macros with the `e` prefix are proposed to be used with `stderr`-like writers.
211/// The macros with the `c` prefix are proposed to be used
212/// instead of the standard macros
213/// or to shadow the standard macros in the following lines of code.
214///
215/// # Macro ambiguity
216///
217/// When using std-prelude, std macros cannot be replaced in [textual scope] using this macro.
218/// This is a consequence of the ambiguous precedence between
219/// a macro-expanded macro and a macro from the outer scope.
220/// Use alternative names like `cprint`, `ceprint`, `cprintln`, `ceprintln`, `cdbg`,
221/// and then override std macros using proxy macro or use declaration.
222///
223/// Overriding with a proxy macro is a better way because
224/// it overrides macros in [textual scope] and accordingly in all submodules:
225/// ```
226/// custom_print::define_macro!(cprintln, once: crate::write);
227/// macro_rules! println { ($($args:tt)*) => { cprintln!($($args)*); } }
228/// # fn main() {}
229/// mod submodule { /* println is already defined in all submodules */ }
230/// ```
231///
232/// Alternatively, use can override macro in the [path-based scope],
233/// but then it will be necessary not to forget to import macro into submodules scope:
234/// ```
235/// custom_print::define_macro!(cprintln, once: crate::write);
236/// use cprintln as println;
237/// # fn main() {}
238/// mod submodule { use crate::println; /* ... */ }
239/// ```
240///
241/// # Examples
242///
243/// An example with a simple string writer:
244/// ```rust
245/// use core::fmt::Write;
246/// let mut string = String::new();
247/// custom_print::define_macro!(cprint, &mut string);
248///
249/// assert_eq!(cprint!("value"), ());
250/// assert_eq!(string, "value");
251/// ```
252///
253/// An example with an extern functions that takes a UTF-8 chars pointer and byte length
254/// and works in `no_std` context:
255#[cfg_attr(feature = "alloc", doc = "```rust")]
256#[cfg_attr(not(feature = "alloc"), doc = "```rust,compile_fail")]
257/// #![no_std]
258/// extern crate std;
259///
260/// # pub mod ffi {
261/// # #[no_mangle] pub extern "C" fn console_log(_: *const u8, _: usize) {}
262/// # #[no_mangle] pub extern "C" fn console_warn(_: *const u8, _: usize) {}
263/// # }
264/// #
265/// custom_print::define_macro!(println,
266/// concat, extern "C" fn console_log(_: *const u8, _: usize));
267/// custom_print::define_macro!(eprintln,
268/// concat, extern "C" fn console_warn(_: *const u8, _: usize));
269///
270/// fn main() {
271/// println!("println");
272/// eprintln!("eprintln");
273/// }
274/// ```
275///
276/// An example with a closure that takes an [`str`] reference in `no_std` and `no_alloc`:
277#[cfg_attr(feature = "std", doc = " ```rust")]
278#[cfg_attr(not(feature = "std"), doc = " ```rust,compile_fail")]
279/// #![no_std]
280/// custom_print::define_macro!(println, fmt, |_value: &str| { /* ... */ });
281///
282/// fn main() {
283/// println!("println");
284/// }
285/// ```
286///
287/// An example with a function that takes a [`c_char`] pointer and overriding
288/// [`std::println`] function:
289#[cfg_attr(feature = "std", doc = "```rust")]
290#[cfg_attr(not(feature = "std"), doc = "```rust,compile_fail")]
291/// fn write(_value: *const std::os::raw::c_char) { /* ... */ }
292///
293/// custom_print::define_macro!(cprintln, concat, crate::write);
294/// macro_rules! println { ($($args:tt)*) => { cprintln!($($args)*); } }
295///
296/// fn main() {
297/// println!("println");
298/// }
299/// ```
300///
301/// An example with `LineWriter` and flushing.
302/// ```rust
303/// use std::io::{self, LineWriter, Write};
304/// use std::sync::Mutex;
305///
306/// let written: Mutex<Vec<u8>> = Mutex::default();
307///
308/// #[derive(Clone, Debug)]
309/// struct CustomWriter<'a>(&'a Mutex<Vec<u8>>);
310///
311/// impl Write for CustomWriter<'_> {
312/// fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
313/// let mut written = self.0.lock().unwrap();
314/// written.extend_from_slice(buf);
315/// Ok(buf.len())
316/// }
317///
318/// fn flush(&mut self) -> io::Result<()> {
319/// Ok(())
320/// }
321/// }
322///
323/// let custom_writer = CustomWriter(&written);
324/// let mut line_writer = LineWriter::new(custom_writer);
325///
326/// custom_print::define_macro!(cprint, line_writer);
327/// custom_print::define_macro!(flush, line_writer);
328///
329/// assert_eq!(cprint!("first,"), ());
330/// assert_eq!(*written.lock().unwrap(), b"");
331/// assert_eq!(cprint!("second\nthird,"), ());
332/// assert_eq!(*written.lock().unwrap(), b"first,second\n");
333/// assert_eq!(flush!(), ());
334/// assert_eq!(*written.lock().unwrap(), b"first,second\nthird,");
335/// ```
336///
337/// [`c_char`]: https://doc.rust-lang.org/std/os/raw/type.c_char.html
338/// [textual scope]: https://doc.rust-lang.org/nightly/reference/macros-by-example.html#scoping-exporting-and-importing
339/// [path-based scope]: https://doc.rust-lang.org/nightly/reference/macros-by-example.html#scoping-exporting-and-importing
340/// [`define_writer`]: macro.define_writer.html
341/// [`define_print`]: macro.define_print.html
342/// [`define_println`]: macro.define_println.html
343/// [`define_dbg`]: macro.define_dbg.html
344/// [`define_flush`]: macro.define_flush.html
345/// [`define_try_print`]: macro.define_try_print.html
346/// [`define_try_println`]: macro.define_try_println.html
347/// [`define_try_dbg`]: macro.define_try_dbg.html
348/// [`define_try_flush`]: macro.define_try_flush.html
349#[macro_export]
350macro_rules! define_macro {
351 ( $( #[$meta:meta] )* print as $name:ident, $( $args:tt )* ) => {
352 $crate::define_print! ( $( #[$meta] )* $name, $( $args )* )
353 };
354 ( $( #[$meta:meta] )* println as $name:ident, $( $args:tt )* ) => {
355 $crate::define_println! ( $( #[$meta] )* $name, $( $args )* )
356 };
357 ( $( #[$meta:meta] )* dbg as $name:ident, $( $args:tt )* ) => {
358 $crate::define_dbg! ( $( #[$meta] )* $name, $( $args )* )
359 };
360 ( $( #[$meta:meta] )* flush as $name:ident, $( $args:tt )* ) => {
361 $crate::define_flush! ( $( #[$meta] )* $name, $( $args )* )
362 };
363 ( $( #[$meta:meta] )* try_print as $name:ident, $( $args:tt )* ) => {
364 $crate::define_try_print! ( $( #[$meta] )* $name, $( $args )* )
365 };
366 ( $( #[$meta:meta] )* try_println as $name:ident, $( $args:tt )* ) => {
367 $crate::define_try_println!( $( #[$meta] )* $name, $( $args )* )
368 };
369 ( $( #[$meta:meta] )* try_dbg as $name:ident, $( $args:tt )* ) => {
370 $crate::define_try_dbg! ( $( #[$meta] )* $name, $( $args )* )
371 };
372 ( $( #[$meta:meta] )* try_flush as $name:ident, $( $args:tt )* ) => {
373 $crate::define_try_flush! ( $( #[$meta] )* $name, $( $args )* )
374 };
375
376 ( $( #[$meta:meta] )* print, $( $args:tt )* ) => {
377 $crate::define_print! ( $( #[$meta] )* print, $( $args )* );
378 };
379 ( $( #[$meta:meta] )* eprint, $( $args:tt )* ) => {
380 $crate::define_print! ( $( #[$meta] )* eprint, $( $args )* );
381 };
382 ( $( #[$meta:meta] )* cprint, $( $args:tt )* ) => {
383 $crate::define_print! ( $( #[$meta] )* cprint, $( $args )* );
384 };
385 ( $( #[$meta:meta] )* ceprint, $( $args:tt )* ) => {
386 $crate::define_print! ( $( #[$meta] )* ceprint, $( $args )* );
387 };
388 ( $( #[$meta:meta] )* println, $( $args:tt )* ) => {
389 $crate::define_println!( $( #[$meta] )* println, $( $args )* );
390 };
391 ( $( #[$meta:meta] )* eprintln, $( $args:tt )* ) => {
392 $crate::define_println!( $( #[$meta] )* eprintln, $( $args )* );
393 };
394 ( $( #[$meta:meta] )* cprintln, $( $args:tt )* ) => {
395 $crate::define_println!( $( #[$meta] )* cprintln, $( $args )* );
396 };
397 ( $( #[$meta:meta] )* ceprintln, $( $args:tt )* ) => {
398 $crate::define_println!( $( #[$meta] )* ceprintln, $( $args )* );
399 };
400 ( $( #[$meta:meta] )* dbg, $( $args:tt )* ) => {
401 $crate::define_dbg! ( $( #[$meta] )* dbg, $( $args )* );
402 };
403 ( $( #[$meta:meta] )* edbg, $( $args:tt )* ) => {
404 $crate::define_dbg! ( $( #[$meta] )* edbg, $( $args )* );
405 };
406 ( $( #[$meta:meta] )* cdbg, $( $args:tt )* ) => {
407 $crate::define_dbg! ( $( #[$meta] )* cdbg, $( $args )* );
408 };
409 ( $( #[$meta:meta] )* flush, $( $args:tt )* ) => {
410 $crate::define_flush! ( $( #[$meta] )* flush, $( $args )* );
411 };
412 ( $( #[$meta:meta] )* eflush, $( $args:tt )* ) => {
413 $crate::define_flush! ( $( #[$meta] )* eflush, $( $args )* );
414 };
415
416 ( $( #[$meta:meta] )* try_print, $( $args:tt )* ) => {
417 $crate::define_try_print! ( $( #[$meta] )* try_print, $( $args )* );
418 };
419 ( $( #[$meta:meta] )* try_eprint, $( $args:tt )* ) => {
420 $crate::define_try_print! ( $( #[$meta] )* try_eprint, $( $args )* );
421 };
422 ( $( #[$meta:meta] )* try_println, $( $args:tt )* ) => {
423 $crate::define_try_println!( $( #[$meta] )* try_println, $( $args )* );
424 };
425 ( $( #[$meta:meta] )* try_eprintln, $( $args:tt )* ) => {
426 $crate::define_try_println!( $( #[$meta] )* try_eprintln, $( $args )* );
427 };
428 ( $( #[$meta:meta] )* try_dbg, $( $args:tt )* ) => {
429 $crate::define_try_dbg! ( $( #[$meta] )* try_dbg, $( $args )* );
430 };
431 ( $( #[$meta:meta] )* try_edbg, $( $args:tt )* ) => {
432 $crate::define_try_dbg! ( $( #[$meta] )* try_edbg, $( $args )* );
433 };
434 ( $( #[$meta:meta] )* try_flush, $( $args:tt )* ) => {
435 $crate::define_try_flush! ( $( #[$meta] )* try_flush, $( $args )* );
436 };
437 ( $( #[$meta:meta] )* try_eflush, $( $args:tt )* ) => {
438 $crate::define_try_flush! ( $( #[$meta] )* try_eflush, $( $args )* );
439 };
440}