#print #macro #format #interpolation #template #debugging

yanked fomat-macros-test

Alternative syntax for print/write/format-like macros with a small templating language

Uses old Rust 2015

0.3.1 Nov 16, 2022

#91 in #interpolation

MIT license

32KB
469 lines

fomat-macros

documentation, crate

This crate provides alternative syntax for write!, writeln!, print!, println!, eprint!, eprintln! and format! macros from the Rust standard library.

The names of macros in this crate are formed by removing the letter r from their std counterparts: wite!, witeln!, pint!, pintln!, epint!, epintln!, fomat!.

Installation

Add this to your Cargo.toml:

[dependencies]
fomat-macros = "0.3.1"

And use the macros in your .rs file, eg.:

use fomat_macros::pintln;

This version requires Rust 1.30. For support for older versions, see version 0.2.1.

Examples

pintln!("Hello, world!");
pintln!(); // empty line
pintln!("The answer is "(40 + 2)); // parentheses use the Display trait
pintln!([vec![1, 2, 3]] " -- numbers"); // brackets use the Debug trait

As you can see, instead the format string and arguments, we have a list of things to print without any separators. Each thing may be a string literal or an expression in brackets (apart of () and [] there are also braces {}, which may be used for more advanced format specifiers, see the docs).

You can also use if, if let, match and for constructs inside the macro. They use regular Rust syntax, except everything inside the {} blocks will use the list-of-things-to-print syntax again.

let list = vec![1, 2, 3];
let s = fomat!( for x in &list { (x) " :: " } "nil" );
// s == "1 :: 2 :: 3 :: nil"

For loops can also use an optional separator. For details, see the docs.

There's also a shorthand for debugging, which prints both the expression and value. To enable, put = as the first character inside the any kind of brackets.

let list = vec![1, 2, 3];
epintln!([=list]); // prints list = [1, 2, 3]

Why?

What was the motivation to create this crate?

  • More locality – everything is written in the same order it will be printed. But that might a personal preference.

  • Easier to refactor – especially when you suddenly want to add a conditional print inside a long format string. Compare:

    let s = fomat!(
        "first line\n"
        if condition() { (foo) }
        "third line\n"
    );
    
    let s = {
        use ::std::fmt::Write;
        let mut s = "first line\n".to_owned();
        if condition() { write!(s, "{}", foo).unwrap() }
        write!(s, "third line\n").unwrap();
        s
    };
    
  • Speed! fomat! may be faster than format! (see cargo bench). That's because there's just one virtual call for single invocation of fomat! instead of one per each argument in std::format!.

Limitations

The write! and writeln! macros work on everything that has a .write_fmt method. This crate requires also the .write_str method. It works for any io::Write or fmt::Write, but in unlikely circumstances if you're using something custom, you should consult the source.

Is it a templating language?

Kind of, but please don't use it as HTML-templating language for security critical code, as it performs no escaping of special characters.

No runtime deps