fomat_macros/
lib.rs

1//! This crate provides alternative syntax for
2//! `write!`, `writeln!`, `print!`, `println!` and `format!` macros.
3//! It also introduces macros to print on `stderr`.
4//!
5//! The names of macros in this crate are formed by
6//! removing the letter `r` from their `std` counterparts.
7//!
8//! Index: [**examples**](#examples) • 
9//! [**syntax**](#syntax-overview):
10//! [`"string"`](#string-literals),
11//! [`()`, `[]`](#expressions-in--and--brackets),
12//! [`{}`](#curly-braces),
13//! [`for`](#for-loops),
14//! [`if`](#if-and-if-let),
15//! [`match`](#match),
16//! [`=`](#debugging-shorthand) • 
17//! [**troubleshooting**](#troubleshooting) • 
18//! [**macros**](#macros)
19//!
20//! # Examples
21//!
22//! ```
23//! use fomat_macros::pintln;
24//!
25//! fn main() {
26//!     pintln!("Hello, World!");
27//!     pintln!("Display trait: "(2+2));
28//!     pintln!("Debug trait: "[vec![1, 2, 3]]);
29//!     pintln!("Multiple " "parameters" (1) " " [2]);
30//!
31//!     pintln!("Formatting parameters: " {(1./3.):5.2}); // 0.333
32//!     pintln!("Debug: "[= 2 + 2]); // Debug: 2 + 2 = 4
33//! }
34//! ```
35//!
36//! This crate also contains a small templating language,
37//! allowing you to mix constructs like `for` with
38//! the printing syntax. The following should print `1 :: 2 :: 3 :: nil`.
39//!
40//! ```
41//! # use fomat_macros::pintln;
42//! # fn main() {
43//! let list = [1, 2, 3];
44//! pintln!( for x in &list { (x) " :: " } "nil" );
45//! # }
46//! ```
47//!
48//! You can also use the macros without importing them
49//! ```
50//! fomat_macros::pintln!("2 + 2 = "(2 + 2));
51//! ```
52//!
53//! # Syntax overview
54//!
55//! All the macros share the same syntax, so
56//! it will be described in this section.
57//!
58//! The macros take list of *things* to print as an argument.
59//! Each *thing* could be either a string literal, something
60//! inside brackets (`()`, `[]` or `{}`) or a Rust construct
61//! (`for`, `if let`, `if` or `match`). There has to be
62//! no separator (like a comma) between those *things*.
63//!
64//! Whitespace is ignored outside the string literals.
65//!
66//! ## String literals
67//!
68//! String literals will be formatted directly as they are.
69//! Note that this also applies to `{` and `}` characters.
70//!
71//! ```
72//! # use fomat_macros::fomat;
73//! # fn main() {
74//! let s = fomat!("Hi." "{}");
75//! assert_eq!(s, "Hi.{}");
76//! # }
77//! ```
78//!
79//! ## Expressions in `()` and `[]` brackets.
80//!
81//! Expressions in these brackets will be evaluated and
82//! printed using:
83//!
84//! * `Display` trait for `(expr)` (equivalent to `{}` format).
85//! * `Debug` trait for `[expr]` (equivalent to `{:?}` format).
86//!
87//! Like in `std`, they are implicitly borrowed.
88//!
89//! ```
90//! # use fomat_macros::fomat;
91//! # fn main() {
92//! let s = fomat!( ("string") (2 + 2) ", " [vec![1]] );
93//! assert_eq!(s, "string4, [1]")
94//! # }
95//! ```
96//!
97//! ## Curly braces
98//!
99//! ### `write!` passthrough
100//!
101//! If you want to use regular `format!` syntax for some
102//! part of your string, place `format!` arguments
103//! inside the curly braces:
104//!
105//! ```
106//! # use fomat_macros::wite;
107//! # fn main() {
108//! use std::io::Write;
109//!
110//! let mut v = vec![];
111//! wite!(v, "foo " {"{} baz {}", "bar", "quux"});
112//! assert_eq!(v, "foo bar baz quux".as_bytes());
113//! # }
114//! ```
115//!
116//! ### Single argument
117//!
118//! If you only want to print a single argument
119//! with a custom format parameters,
120//! you can use the `{token_tree:format_parameters}`
121//! syntax.
122//!
123//! The following will use binary format,
124//! zero-aligned to 8 places.
125//!
126//! ```
127//! # use fomat_macros::fomat;
128//! # fn main() {
129//! let s = fomat!({13:08b});
130//! assert_eq!(s, "00001101");
131//! # }
132//! ```
133//!
134//! Please note that there can be only a single
135//! token tree before the colon – usually
136//! a literal or an identifier. Anything
137//! longer has to be wrapped in parentheses
138//! (like that `{(10+3):08b}`).
139//!
140//! ## For loops
141//!
142//! For loops use the regular Rust syntax,
143//! except the body
144//! will use this printing syntax again.
145//!
146//! ```
147//! # use fomat_macros::fomat;
148//! # fn main() {
149//! let list = [1, 2, 3];
150//! let s = fomat!( for x in &list { (x) " :: " } "nil" );
151//! assert_eq!(s, "1 :: 2 :: 3 :: nil");
152//! # }
153//! ```
154//!
155//! For loops can also use an optional separator,
156//! denoted by `sep` or `separated` keyword.
157//!
158//! ```
159//! # use fomat_macros::fomat;
160//! # fn main() {
161//! # let list = ["a", "b"];
162//! let s = fomat!(
163//!    for (i, x) in list.iter().enumerate() { (i) " → " (x) }
164//!    separated { ", " }
165//! );
166//! assert_eq!(s, "0 → a, 1 → b");
167//! # }
168//! ```
169//!
170//! For loops (and other syntax elements) can also be nested:
171//!
172//! ```
173//! # use fomat_macros::fomat;
174//! # fn main() {
175//! let matrix = [[0, 1], [2, 3]];
176//! assert_eq!(
177//!     fomat!( for row in &matrix { for x in row { {x:3} } "\n" } ),
178//!     "  0  1\n  2  3\n"
179//! );
180//! # }
181//! ```
182//!
183//! ## If and if let
184//!
185//! They use the regular Rust syntax,
186//! except of the body (inside `{}`),
187//! which uses the printing syntax.
188//!
189//! The benefits of using this syntax instead
190//! of getting `if` "outside" of the printing
191//! macros is apparent when the conditional is
192//! a part of a longer string (you don't
193//! have to split this into three separate `write!`s):
194//!
195//! ```
196//! # use fomat_macros::fomat;
197//! # fn main() {
198//! let opt = Some(5);
199//! let s = fomat!(
200//!     "a\n"
201//!     if let Some(x) = opt { (x) "\n" } else { "nothing\n" }
202//!     "b\n"
203//! );
204//! assert_eq!(s, "a\n5\nb\n");
205//! # }
206//! ```
207//!
208//! The `else` clause is optional.
209//!
210//! `else if`-chaining is not supported. As a workaround,
211//! use `else { if ... }` or `match`.
212//!
213//! ## Match
214//!
215//! Match uses the regular Rust syntax,
216//! except arms has to use `{}` blocks,
217//! which will be interpreted using printing syntax.
218//!
219//! ```
220//! # use fomat_macros::fomat;
221//! # fn main() {
222//! let v = [Some(1), None, Some(2)];
223//! let s = fomat!(
224//!     for x in &v {
225//!         match *x {
226//!             Some(x) => { (x) }
227//!             None => { "_" }
228//!         }
229//!     }
230//! );
231//! assert_eq!(s, "1_2");
232//! # }
233//! ```
234//!
235//! Match arms should not be separated by commas.
236//!
237//! ## Debugging shorthand
238//!
239//! If you want to print both the expression and the value,
240//! place equal sign as a first character in brackets.
241//! The trait used to print the value will depend on
242//! the kind of brackets used.
243//!
244//! ```
245//! # use fomat_macros::fomat;
246//! # fn main() {
247//! let word = "foo";
248//! let arr = [10];
249//! let s = fomat!( (=word) ", " [=&arr] ", " {=5:#b} );
250//! assert_eq!(s, "word = foo, &arr = [10], 5 = 0b101");
251//! # }
252//! ```
253//!
254//! # Troubleshooting
255//!
256//! ## Recursion depth
257//!
258//! If you hit the error about recursion depth,
259//! which occurs when you try to print more than
260//! about 50 elements, you can use this workaround
261//! instead of increasing the limit: split everything
262//! into two (or more) dummy `if true` blocks.
263//!
264//! ## Errors in macro parsing
265//!
266//! If you hit `expected a literal`, that either means
267//! either you've made a syntactic mistake
268//! or really a string literal is expected here.
269//! Remember, naked identifiers won't be printed
270//! unless you put them in parentheses.
271
272use std::fmt;
273
274#[doc(hidden)]
275pub struct DisplayOnce<F> {
276    closure: std::cell::Cell<Option<F>>
277}
278
279impl<F> DisplayOnce<F>
280where
281    F: FnOnce(&mut fmt::Formatter) -> fmt::Result
282{
283    pub fn new(f: F) -> Self {
284        Self { closure: std::cell::Cell::new(Some(f)) }
285    }
286}
287
288impl<F> fmt::Display for DisplayOnce<F>
289where
290    F: FnOnce(&mut fmt::Formatter) -> fmt::Result
291{
292    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
293        match self.closure.replace(None).take() {
294            Some(closure) => closure(f),
295            None => Ok(())
296        }
297    }
298}
299
300/// Wrapper implementing Display for every closure with matching signature
301///
302/// This wrapper implements Display for every closure implementing
303/// `Fn(&mut fmt::Formatter) -> fmt::Result`.
304///
305/// Can be create using [`lazy_fomat`][lazy_fomat]
306pub struct DisplayFn<F>(F);
307
308impl<F> DisplayFn<F>
309where
310    F: Fn(&mut fmt::Formatter) -> fmt::Result
311{
312    /// Creates an object which `Display::fmt` impl will call this closure.
313    pub fn new(f: F) -> Self { Self(f) }
314}
315
316
317impl<F> fmt::Display for DisplayFn<F>
318where
319    F: Fn(&mut fmt::Formatter) -> fmt::Result
320{
321    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
322        (self.0)(f)
323    }
324}
325
326
327/// Writes to a specified writer. Analogous to `write!`.
328///
329/// See the crate root for general help on the syntax.
330///
331/// The first argument should be something that implements either `io::Write`
332/// or `fmt::Write`. This expression will be evaluated once.
333///
334/// The list of things to write should be written after
335/// the first comma, without any further delimiters.
336///
337/// # Return value
338///
339/// This macro returns `io::Result<()>` or `fmt::Result`,
340/// just as `write!` from `std`.
341///
342/// # Examples
343///
344/// ```
345/// # use fomat_macros::wite;
346/// # fn main() {
347/// use ::std::io::Write;
348/// use ::std::io::BufWriter;
349/// let mut v = vec![];
350/// let world = "World";
351/// wite!(v, "Hello, "(world)"!").unwrap();
352/// wite!(BufWriter::new(&mut v), " "(2+2)).unwrap();
353/// assert_eq!(v, "Hello, World! 4".as_bytes());
354/// # }
355/// ```
356#[macro_export]
357macro_rules! wite {
358    // single tt rules ---------------------------------------------------------
359    (@one $w:ident, ($e:expr)) => { ::std::fmt::Display::fmt(&$e, $w) };
360    (@one $w:ident, [$e:expr]) => { ::std::fmt::Debug::fmt(&$e, $w) };
361    (@one $w:ident, {$e:tt : $($fmt:tt)*}) => {
362        write!($w, concat!("{:", $crate::wite!(@stringify-dense $($fmt)*), "}"), $e)
363    };
364    (@one $w:ident, {$($arg:tt)*}) => {
365        write!($w, $($arg)*)
366    };
367    (@one $w:ident, $string:tt) => { $w.write_str(concat!($string)) };
368
369    (@stringify-dense) => { "" };
370    (@stringify-dense $($tt:tt)+) => { concat!( $(stringify!($tt)),+ ) };
371
372    // expression parsing (manually, because we can't use :expr before `{`)
373    (@expr.. $w:ident {$($before:tt)*} ($($e:tt)*) {$($block:tt)*} $($rest:tt)* ) => {
374        $crate::wite!(@rec $w, $($before)* ($($e)*) {$($block)*} $($rest)*)
375    };
376    (@expr.. $w:ident {$($before:tt)*} ($($expr:tt)*) $tt:tt $($rest:tt)* ) => {
377        $crate::wite!(@expr.. $w {$($before)*} ($($expr)* $tt) $($rest)*)
378    };
379    (@expr $w:ident {$($before:tt)*} ($($expr:tt)*) $tt:tt $($rest:tt)* ) => {
380        $crate::wite!(@expr.. $w {$($before)*} ($($expr)* $tt) $($rest)*)
381    };
382
383    // recursive parsing -------------------------------------------------------
384    // for
385    (@rec $w:ident,
386        for $p:pat in ($e:expr) { $($body:tt)* }
387        sep { $($sep:tt)* }
388        $($rest:tt)*
389    ) => {
390        {
391            let mut first_iteration = true;
392            for $p in $e {
393                if first_iteration {
394                    first_iteration = false;
395                } else {
396                    $crate::wite!(@rec $w, $($sep)*);
397                }
398                $crate::wite!(@rec $w, $($body)*);
399            }
400            $crate::wite!(@rec $w, $($rest)*);
401        }
402    };
403    (@rec $w:ident,
404        for $p:pat in ($e:expr) { $($body:tt)* }
405        separated { $($sep:tt)* }
406        $($rest:tt)*
407    ) => {
408        $crate::wite!(@rec $w, for $p in ($e) { $($body)* } sep { $($sep)* }$($rest)*)
409    };
410    (@rec $w:ident, for $p:pat in ($e:expr) { $($body:tt)* } $($rest:tt)*) => {
411        $crate::wite!(@rec $w, for $p in ($e) { $($body)* } sep {} $($rest)*)
412    };
413    (@rec $w:ident, for $p:pat in $($tt:tt)* ) => {
414        $crate::wite!(@expr $w { for $p in } () $($tt)*)
415    };
416
417    // match
418    (@rec $w:ident,
419        match ($e:expr) {
420            $( $($p:pat)|+ $(if $g:expr)* => { $($body:tt)* } )*
421        }
422        $($rest:tt)*
423    ) => {
424        {
425            match $e {
426                $(
427                    $($p)|+ $(if $g)* => {
428                        $crate::wite!(@rec $w, $($body)*)
429                    }
430                )*
431            }
432            $crate::wite!(@rec $w, $($rest)*);
433        }
434    };
435    (@rec $w:ident, match $($tt:tt)* ) => {
436        $crate::wite!(@expr $w { match } () $($tt)*)
437    };
438
439    // if let
440    (@rec $w:ident,
441        if let $p:pat = ($e:expr) { $($then:tt)* }
442        else { $($els:tt)* }
443        $($rest:tt)*
444    ) => {
445        {
446            if let $p = $e {
447                $crate::wite!(@rec $w, $($then)*);
448            } else {
449                $crate::wite!(@rec $w, $($els)*);
450            }
451            $crate::wite!(@rec $w, $($rest)*);
452        }
453    };
454    (@rec $w:ident,
455        if let $p:pat = ($e:expr) { $($then:tt)* }
456        else if $($rest:tt)*
457    ) => {
458        $crate::wite!(@ifelseerror)
459    };
460    (@rec $w:ident,
461        if let $p:pat = ($e:expr) { $($then:tt)* }
462        $($rest:tt)*
463    ) => {
464        $crate::wite!(@rec $w, if let $p = ($e) { $($then)* } else {} $($rest)*);
465    };
466    (@rec $w:ident, if let $p:pat = $($tt:tt)* ) => {
467        $crate::wite!(@expr $w { if let $p = } () $($tt)*)
468    };
469
470    // if
471    (@rec $w:ident,
472        if ($cond:expr) { $($then:tt)* }
473        else { $($els:tt)* }
474        $($rest:tt)*
475    ) => {
476        {
477            if $cond {
478                $crate::wite!(@rec $w, $($then)*);
479            } else {
480                $crate::wite!(@rec $w, $($els)*);
481            }
482            $crate::wite!(@rec $w, $($rest)*);
483        }
484    };
485    (@rec $w:ident,
486        if ($cont:expr) { $($then:tt)* }
487        else if $($rest:tt)*
488    ) => {
489        $crate::wite!(@ifelseerror)
490    };
491    (@rec $w:ident, if ($cond:expr) { $($then:tt)* } $($rest:tt)* ) => {
492        $crate::wite!(@rec $w, if ($cond) { $($then)* } else {} $($rest)*);
493    };
494    (@rec $w:ident, if $($tt:tt)* ) => {
495        $crate::wite!(@expr $w { if } () $($tt)*)
496    };
497
498    // equal-sign debugging
499    (@rec $w:ident, (= $e:expr) $($rest:tt)*) => {
500        $crate::wite!(@rec $w, (concat!(stringify!($e), " = ")) ($e) $($rest)*)
501    };
502    (@rec $w:ident, [= $e:expr] $($rest:tt)*) => {
503        $crate::wite!(@rec $w, (concat!(stringify!($e), " = ")) [$e] $($rest)*)
504    };
505    (@rec $w:ident, {= $e:tt : $($fmt:tt)*} $($rest:tt)*) => {
506        $crate::wite!(@rec $w, (concat!(stringify!($e), " = ")) {$e : $($fmt)*} $($rest)*)
507    };
508
509    // single tt
510    (@rec $w:ident, $part:tt $($rest:tt)*) => {
511        {
512            match $crate::wite!(@one $w, $part) {
513                Ok(_) => (),
514                error => return error,
515            }
516            $crate::wite!(@rec $w, $($rest)*);
517        }
518    };
519
520    // terminator
521    (@rec $w:ident, ) => { () };
522
523    (@ifelseerror) => {
524        {
525            let ERROR: () = "`else if` is not supported";
526            let NOTE: () = "use `match` or `else { if ... }` instead";
527        }
528    };
529
530    // entry point -------------------------------------------------------------
531    ($writer:expr, $($part:tt)*) => {
532        write!(
533            $writer,
534            "{}",
535            $crate::DisplayOnce::new(|f| {
536                $crate::wite!(@rec f, $($part)*);
537                Ok(())
538            })
539        )
540    };
541}
542
543/// Writes to a specified writer, with an appended newline. Analogous to `writeln!`.
544///
545/// See the documentation for [`wite!`](macro.wite.html).
546///
547/// When there are no arguments, the comma may be omitted.
548///
549/// # Examples
550///
551/// ```no_run
552/// # use fomat_macros::witeln;
553/// # fn main() {
554/// # use ::std::io::Write;
555/// # let mut file = vec![];
556/// witeln!(file).unwrap();
557/// witeln!(file, "Hi").unwrap();
558/// # }
559/// ```
560#[macro_export]
561macro_rules! witeln {
562    ($writer:expr, $($arg:tt)*) => { $crate::wite!($writer, $($arg)* "\n") };
563    ($writer:expr) => { $crate::wite!($writer, "\n") };
564}
565
566/// Prints to stdout. Analogous to `print!`.
567///
568/// See the crate root for general help on the syntax.
569///
570/// # Return value
571///
572/// The macro returns `()`.
573///
574/// # Panics
575///
576/// The macro panics when printing was not successful.
577///
578/// # Behaviour in `#[test]`
579///
580/// The behaviour when testing is similar to `print!`:
581/// the output of this macro will be captured by the
582/// testing framework (meaning that by default `cargo test`
583/// won't show the output).
584///
585/// The only limitation and difference from `print!` is
586/// that when `pint!` is called by a different crate
587/// than the one being tested, the output won't be captured
588/// and will allways be printed to stdout.
589///
590/// # Examples
591///
592/// ```no_run
593/// # use fomat_macros::pint;
594/// # fn main() {
595/// pint!("four = "(2+2));
596/// # }
597/// ```
598#[macro_export]
599macro_rules! pint {
600    ($($arg:tt)*) => {
601        {
602            {
603                #[cfg(not(test))] {
604                    use ::std::io::Write;
605                    let o = ::std::io::stdout();
606                    $crate::wite!(o.lock(), $($arg)*).unwrap();
607                }
608                #[cfg(test)] {
609                    print!("{}", $crate::fomat!($($arg)*))
610                }
611            }
612        }
613    }
614}
615
616/// Prints to stdout, with an appended newline. Analoguous to `println!`.
617///
618/// See the docs for [`print!`](macro.pint.html) for more details.
619///
620/// # Examples
621///
622/// ```no_run
623/// # use fomat_macros::pintln;
624/// # fn main() {
625/// pintln!();
626/// pintln!((2 * 2));
627/// # }
628/// ```
629#[macro_export]
630macro_rules! pintln {
631    ($($arg:tt)*) => {
632        {
633            #[cfg(not(test))] {
634                $crate::pint!($($arg)* "\n")
635            }
636            #[cfg(test)] {
637                print!("{}", fomat!($($arg)* "\n"))
638            }
639        }
640    }
641}
642
643/// Prints to stderr. Analogous to `eprint!`.
644///
645/// See the crate root for general help on the syntax.
646///
647/// # Return value
648///
649/// None
650///
651/// # Panics
652///
653/// This macro, in contrary to `pint!`, silently ignores
654/// all errors.
655///
656/// # Examples
657///
658/// ```no_run
659/// # use fomat_macros::epint;
660/// # fn main() {
661/// epint!("foo")
662/// # }
663/// ```
664#[macro_export]
665macro_rules! epint {
666    ($($arg:tt)*) => {
667        {
668            use ::std::io::Write;
669            let o = ::std::io::stderr();
670            $crate::wite!(o.lock(), $($arg)*).unwrap();
671        }
672    }
673}
674
675/// Same as `epint`
676#[macro_export]
677#[deprecated(since="0.2.1", note="use `epint` instead")]
678macro_rules! perr { ($($arg:tt)*) => { $crate::epint!($($arg)*) } }
679
680/// Prints to stderr, with an appended newline. Analogous to `eprintln!`.
681///
682/// See the docs for [`epint!`](macro.epint.html) for more info.
683///
684/// # Examples
685///
686/// ```no_run
687/// # use fomat_macros::epintln;
688/// # fn main() {
689/// let x = 3;
690/// epintln!((=x));
691/// # }
692/// ```
693#[macro_export]
694macro_rules! epintln {
695    ($($arg:tt)*) => { $crate::epint!($($arg)* "\n") }
696}
697
698/// Same as `epintln`
699#[macro_export]
700#[deprecated(since="0.2.1", note="use `epint` instead")]
701macro_rules! perrln { ($($arg:tt)*) => { $crate::epintln!($($arg)*) } }
702
703/// Creates a formatted string. Analogous to `format!`.
704///
705/// See the crate root for general help on the syntax.
706///
707/// This macro returns `String` containing the formatted text.
708///
709/// # Panics
710///
711/// The macro will panic if formatting fails (which shoudn't happen for any
712/// of `std` types).
713///
714/// # Examples
715///
716/// ```
717/// # use fomat_macros::fomat;
718/// # fn main() {
719/// let v = [1, 2];
720///
721/// let s = fomat!("Hello, "[v]);
722/// assert_eq!(s, "Hello, [1, 2]");
723///
724/// let s = fomat!(for x in &v { (x*x) ";" });
725/// assert_eq!(s, "1;4;");
726/// # }
727/// ```
728#[macro_export]
729macro_rules! fomat {
730    // capacity estimation -----------------------------------------------------
731    (@cap ($len:expr, $multiplier:expr)) => {
732        ($len, $multiplier)
733    };
734
735    // skip all irrelevant tts and conditional bodies
736    (@cap ($($lm:tt)*) for $p:pat in $($tt:tt)*) => {
737        $crate::fomat!(@cap-ignore ($($lm)*) $($tt)*)
738    };
739    (@cap ($($lm:tt)*) sep $($tt:tt)*) => {
740        $crate::fomat!(@cap-ignore ($($lm)*) $($tt)*)
741    };
742    (@cap ($($lm:tt)*) separated $($tt:tt)*) => {
743        $crate::fomat!(@cap-ignore ($($lm)*) $($tt)*)
744    };
745    (@cap ($($lm:tt)*) if let $p:pat = $($tt:tt)*) => {
746        $crate::fomat!(@cap-ignore ($($lm)*) $($tt)*)
747    };
748    (@cap ($($lm:tt)*) if $($tt:tt)*) => {
749        $crate::fomat!(@cap-ignore ($($lm)*) $($tt)*)
750    };
751    (@cap ($($lm:tt)*) else $($tt:tt)*) => {
752        $crate::fomat!(@cap-ignore ($($lm)*) $($tt)*)
753    };
754    (@cap ($($lm:tt)*) match $($tt:tt)*) => {
755        $crate::fomat!(@cap-ignore ($($lm)*) $($tt)*)
756    };
757
758    // When there's any unconditional string interpolation,
759    // we multiply the initial capacity by 2
760    // (which would probably happen anyway).
761    (@cap ($len:expr, $mul:expr) ($($x:tt)*) $($rest:tt)*) => {
762        $crate::fomat!(@cap ($len, 2) $($rest)*)
763    };
764    (@cap ($len:expr, $mul:expr) [$($x:tt)*] $($rest:tt)*) => {
765        $crate::fomat!(@cap ($len, 2) $($rest)*)
766    };
767    (@cap ($len:expr, $mul:expr) {$($x:tt)*} $($rest:tt)*) => {
768        $crate::fomat!(@cap ($len, 2) $($rest)*)
769    };
770
771    // Now the only legal tt is a string literal
772    (@cap ($len:expr, $mul:expr) $string:tt $($rest:tt)*) => {
773        // Concat forces the token to be a string literal.
774        $crate::fomat!(@cap ($len + concat!($string).len(), $mul) $($rest)*)
775    };
776
777    // Ignores everything till after next block
778    (@cap-ignore ($($lm:tt)*) { $($block:tt)* } $($rest:tt)*) => {
779        $crate::fomat!(@cap ($($lm)*) $($rest)*)
780    };
781    (@cap-ignore ($($lm:tt)*) $tt:tt $($rest:tt)*) => {
782        $crate::fomat!(@cap-ignore ($($lm)*) $($rest)*)
783    };
784
785    // entry points ------------------------------------------------------------
786    () => { String::new() };
787    ($($arg:tt)*) => {
788        {
789            use ::std::fmt::Write;
790            let (len, mul) = $crate::fomat!(@cap (0, 1) $($arg)*);
791            let mut _s = String::with_capacity(len * mul);
792            $crate::wite!(_s, $($arg)*).ok();
793            _s
794        }
795    }
796}
797
798/// Creates a displayable object based on its arguments.
799///
800/// This macro works in a similar way to [`fomat`](fomat),
801/// but instead of `String` it returns an object ([`DisplayFn`](DisplayFn))
802/// that implements [`Display`][std::fmt::Display] and can be printed later
803/// (using `format`, `fomat` or calling `Display::fmt` directly).
804///
805/// See the [crate root](crate) for general help on the syntax.
806///
807/// Prefix the arguments with `move` to force moving all variables
808/// (can help when `'static` bound is required).
809///
810/// # Examples
811///
812/// Direct usage
813///
814/// ```
815/// # use fomat_macros::{fomat, lazy_fomat};
816/// let fence = lazy_fomat!(for _ in 0..5 { "-" });
817/// let s = fomat!((fence)" hello "(fence));
818///
819/// assert_eq!(s, "----- hello -----");
820/// ```
821///
822/// Returning `impl Display`
823///
824/// ```
825/// # use fomat_macros::lazy_fomat;
826/// fn greet(name: String) -> impl ::std::fmt::Display {
827///     lazy_fomat!(move "Hello, "(name)"!")
828/// }
829///
830/// assert_eq!(greet("World".into()).to_string(), "Hello, World!");
831/// ```
832#[macro_export]
833macro_rules! lazy_fomat {
834    (move $($arg:tt)*) => {
835        $crate::DisplayFn::new(move |f| {
836            $crate::wite!(@rec f, $($arg)*);
837            Ok(())
838        })
839    };
840    ($($arg:tt)*) => {
841        $crate::DisplayFn::new(|f| {
842            $crate::wite!(@rec f, $($arg)*);
843            Ok(())
844        })
845    };
846}
847
848#[test]
849fn basics() {
850    let world = "World";
851    assert_eq!(fomat!("Hello, "(world)"!"), "Hello, World!");
852    let x = 3;
853    assert_eq!(fomat!((x)" * 2 = "(x * 2)), "3 * 2 = 6");
854}
855
856#[test]
857fn empty() {
858    assert_eq!(fomat!(), "");
859}
860
861#[test]
862fn debug() {
863    let v = [1,2,3];
864    assert_eq!(fomat!([v] "."), "[1, 2, 3].");
865}
866
867#[test]
868fn test_if() {
869    let s = fomat!(
870        if true { "A" "A" } else { "X" }
871        if false { "X" } else { "D" "D" }
872        if true { "T" "T" }
873        if false { "X" }
874        if let Some(x) = Some(5) { (x) (x) } else { "E" "E" }
875        if let None = Some(5) { "X" } else { "F" "F" }
876        if let Some(x) = Some(5) { (x) }
877        if let None = Some(5) { "X" }
878        if {let t = true; t} { "K" }
879        "."
880    );
881    assert_eq!(s, "AADDTT55FF5K.");
882}
883
884#[test]
885fn format() {
886    assert_eq!( fomat!({5:02}), "05" );
887    assert_eq!( fomat!({"{}-{}", 4, 2}), "4-2" );
888}
889
890#[test]
891fn separator() {
892    let v = [1, 2, 3];
893    let s1 = fomat!( for x in &v { (x) } separated { "-" "-" } "." );
894    let s2 = fomat!( for x in &v { (x) } sep { "--" } "." );
895    assert_eq!(s1, "1--2--3.");
896    assert_eq!(s2, "1--2--3.");
897}
898
899#[test]
900fn test_match() {
901    let s = fomat!(
902        match Some(5) {
903            Some(x) if x > 3 => { (x) "!" }
904            Some(2) | None => {}
905            _ => {}
906        }
907        "."
908    );
909    assert_eq!(s, "5!.");
910}
911
912#[test]
913fn capacity() {
914    assert_eq!(fomat!("Hello, " "world!").capacity(), 13);
915    assert_eq!(fomat!("Hello, "[40+2]).capacity(), 14);
916    let s = fomat!(
917        "Hello"
918        for x in [1][1..].iter() { (x) "a" }
919        if let Some(()) = None { "b" }
920        if false { "c" } else {}
921        match 1 { 2 => { "e" } _ => {} }
922        "!"
923    );
924    assert_eq!(s.capacity(), 6);
925}
926
927#[test]
928fn fmt_write() {
929    use std::fmt;
930    struct Foo;
931
932    impl fmt::Display for Foo {
933        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
934            wite!(f, "foo"(42))
935        }
936    }
937
938    assert_eq!(format!("{}", Foo), "foo42");
939}
940
941#[test]
942fn equal_sign() {
943    let x = 5;
944    let v = [10];
945    assert_eq!(fomat!((=x) "."), "x = 5.");
946    assert_eq!(fomat!([=&v] "."), "&v = [10].");
947    assert_eq!(fomat!({=13:05b} "."), "13 = 01101.");
948}
949
950#[test]
951fn depth() {
952    let _ = fomat!(
953        "1" "2" "3" "4" "5" "6" "7" "8" "9" "0"
954        "1" "2" "3" "4" "5" "6" "7" "8" "9" "0"
955        "1" "2" "3" "4" "5" "6" "7" "8" "9" "0"
956        "1" "2" "3" "4" "5" "6" "7" "8" "9" "0"
957        "1" "2" "3" "4" "5" "6" "7" "8" "9" "0"
958    );
959}
960
961#[test]
962fn non_static_writer() {
963    use std::io::Write;
964    use std::io::Result;
965    use std::fmt::Arguments;
966
967    struct Prepender<'a, T: Write> {
968        prefix: &'a str,
969        writer: T,
970    }
971
972    impl<'a, T: Write> Write for Prepender<'a, T> {
973        fn write(&mut self, buf: &[u8]) -> Result<usize> {
974            self.writer.write(buf)
975        }
976
977        fn flush(&mut self) -> Result<()> {
978            self.writer.flush()
979        }
980
981        fn write_fmt(&mut self, fmt: Arguments) -> Result<()> {
982            self.writer.write_all(self.prefix.as_bytes())?;
983            self.writer.write_fmt(fmt)
984        }
985    }
986
987    let mut buf = vec![];
988    witeln!(
989        Prepender { prefix: &"foo ".to_owned(), writer: &mut buf },
990        (2+2)
991    ).unwrap();
992    assert_eq!(buf, "foo 4\n".as_bytes());
993}
994
995#[test]
996fn no_semicolon() {
997    if true { pint!("foo") } else { epint!("bar") }
998    pintln!("foo" "bar")
999}
1000
1001#[test]
1002fn move_and_borrow() {
1003    // Test if fomat! arguments can move some and borrow other variables.
1004    let iter = vec![1, 2, 3].into_iter();
1005    let borrow_me = vec![1, 2, 3];
1006    let s = fomat!(for x in iter { (x) } (borrow_me.len()));
1007    assert_eq!(s, "1233");
1008    assert_eq!(borrow_me, [1, 2, 3]);
1009}