#template #fmt #format #control-flow #specifier

no-std fmtools

Fast, minimal, feature-rich, extended formatting syntax for Rust!

3 releases

0.1.2 Jul 28, 2022
0.1.1 Jul 9, 2022
0.1.0 Jun 24, 2022

#116 in Template engine

Download history 219/week @ 2023-12-10 175/week @ 2023-12-17 128/week @ 2023-12-24 106/week @ 2023-12-31 214/week @ 2024-01-07 207/week @ 2024-01-14 189/week @ 2024-01-21 159/week @ 2024-01-28 198/week @ 2024-02-04 182/week @ 2024-02-11 231/week @ 2024-02-18 281/week @ 2024-02-25 325/week @ 2024-03-03 221/week @ 2024-03-10 214/week @ 2024-03-17 266/week @ 2024-03-24

1,056 downloads per month
Used in 22 crates (6 directly)

MIT license

26KB
428 lines

Formatting Tools

MIT License crates.io docs.rs Build status

Fast, minimal, feature-rich, extended formatting syntax for Rust!

Features include:

  • Arbitrary expressions inside the formatting braces
  • Generates optimized Rust code at compiletime
  • Supports rust-analyzer auto complete, refactoring and more!
  • Supports Rust's standard formatting specifiers
  • Single package, no proc-macro, no_std compatible, no extra dependencies
  • Control flow allows conditional and repeated formatting
  • Capture variables by value or by reference
  • Escape hatch to inject custom formatting code

In your Cargo.toml, add:

[dependencies]
fmtools = "0.1"

Examples

Basic usage

fn basic_usage() -> String {
	let name = "World";

	fmtools::format!("Hello "{name}"!")
}

assert_eq!(basic_usage(), "Hello World!");

The value arguments can be arbitrary expressions. They are inlined in the formatting braces and are outside the string literals.

Formatting specifiers

fn formatting_specifiers() -> String {
	let value = 42;

	fmtools::format!("hex("{value}") = "{value:#x})
}

assert_eq!(formatting_specifiers(), "hex(42) = 0x2a");

The rules for the specifiers are exactly the same as the standard library of Rust.

Let bindings

fn let_bindings() -> String {
	let base = 52;

	fmtools::format! {
		let value = base - 10;
		"value = "{value}
	}
}

assert_eq!(let_bindings(), "value = 42");

Introduce new variable bindings to hold onto temporary values used in the formatting.

Control flow

fn control_flow1() -> String {
	let power = 0.5;

	fmtools::format! {
		"At "
		if power >= 1.0 { "full" }
		else { {power * 100.0:.0}"%" }
		" power"
	}
}

assert_eq!(control_flow1(), "At 50% power");
fn control_flow2() -> String {
	let value = Some(42);

	fmtools::format! {
		"The answer is "
		match value {
			Some(answer) => "Some("{answer}")",
			None => "None",
		}
	}
}

assert_eq!(control_flow2(), "The answer is Some(42)");
fn control_flow3() -> String {
	let values = [1, 2, 3, 4, 5];

	fmtools::format! {
		for &val in &values {
			let result = val * 5;
			"* "{val}" x 5 = "{result}"\n"
		}
	}
}

assert_eq!(control_flow3(), "\
	* 1 x 5 = 5\n\
	* 2 x 5 = 10\n\
	* 3 x 5 = 15\n\
	* 4 x 5 = 20\n\
	* 5 x 5 = 25\n");

Control flow really shows the added value of the extended formatting syntax.

Capture by value

fn capture_by_value() -> String {
	fn inner() -> impl std::fmt::Display {
		let a = 42;
		fmtools::fmt!(move "a = "{a})
	}
	fmtools::format!("{"{inner()}"}")
}

assert_eq!(capture_by_value(), "{a = 42}");

The displayable object can own the captured variables with move and can be returned from functions.

Escape hatch

fn escape_hatch() -> String {
	fmtools::format! {
		"Now entering ["
		|f| f.write_str("escape hatch")?;
		"]"
	}
}

assert_eq!(escape_hatch(), "Now entering [escape hatch]");

Closure syntax provides an escape hatch to inject code if needed. The argument's type is &mut Formatter.

License

Licensed under MIT License, see license.txt.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, shall be licensed as above, without any additional terms or conditions.

Dependencies