#compile-time #const-fn #const #format #time-formatting #proc-macro

no-std compile-fmt

Compile-time formatting and derived functionality (e.g., panics / assertions)

1 unstable release

0.1.0 Dec 28, 2023

#124 in Value formatting

Download history 12712/week @ 2024-07-28 7829/week @ 2024-08-04 9455/week @ 2024-08-11 12210/week @ 2024-08-18 5782/week @ 2024-08-25 4953/week @ 2024-09-01 8699/week @ 2024-09-08 9816/week @ 2024-09-15 6221/week @ 2024-09-22 5539/week @ 2024-09-29 12680/week @ 2024-10-06 9412/week @ 2024-10-13 10815/week @ 2024-10-20 8783/week @ 2024-10-27 5812/week @ 2024-11-03 5877/week @ 2024-11-10

31,367 downloads per month
Used in 75 crates (2 directly)

MIT/Apache

65KB
1K SLoC

Compile-Time Formatting

Build Status License: MIT OR Apache-2.0 rust 1.65+ required no_std supported

Documentation: crate docs (main)

This crate allows formatting values in compile time (e.g., in const fns). The formatted values are not required to be constants; e.g., arguments or local vars in const fn can be formatted.

Features:

  • Zero dependencies.
  • Unconditionally #[no_std]-compatible.
  • The formatting logic is space-efficient; i.e., it allocates the least amount of bytes that can provably to be sufficient for all possible provided inputs.
  • Does not rely on proc macros. This makes the library more lightweight.

Why?

A guiding use case for the crate is richer dynamic compile-time panic messages. It can be used in other contexts as well (including in runtime).

Usage

Add this to your Crate.toml:

[dependencies]
compile-fmt = "0.1.0"

Basic usage

use compile_fmt::{compile_assert, clip, fmt};

const fn check_str(s: &str) {
    const MAX_LEN: usize = 16;
    compile_assert!(
        s.len() <= MAX_LEN,
        "String '", s => clip(MAX_LEN, ""), "' is too long; \
         expected no more than ", MAX_LEN, " bytes, got ",
        s.len() => fmt::<usize>(), " bytes"
    );
    // ^ `clip` and `fmt` specify how dynamic (non-constant) args
    // should be formatted
  
    // main logic
}

let res = std::panic::catch_unwind(|| {
    check_str("very long string indeed");
});
let err = res.unwrap_err();
let panic_message = err.downcast_ref::<String>().unwrap();
assert_eq!(
    panic_message,
    "String 'very long string…' is too long; expected no more than \
     16 bytes, got 23 bytes"
);

See crate docs for more examples of usage.

Limitations

  • Only a few types from the standard library can be formatted: integers, chars and strings.
  • Formatting specifiers do not support hex encoding, debug formatting etc.
  • Padding logic assumes that any Unicode char has identical displayed width, which isn't really true (e.g., there are chars that have zero width and instead combine with the previous char). The same assumption is made by the std padding logic.

Alternatives and similar tools

  • const_panic provides functionality covering the guiding use case (compile-time panics). It supports more types and formats at the cost of being more complex. It also uses a different approach to compute produced message sizes.
  • const_format provides general-purpose formatting of constant values. It doesn't seem to support "dynamic" / non-constant args.

Contributing

All contributions are welcome! See the contributing guide to help you get involved.

License

compile-fmt is licensed under either of Apache License, Version 2.0 or MIT license at your option.

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in compile-fmt by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

No runtime deps