Crate compile_fmt
source ·Expand description
Compile-time formatting and derived functionality (e.g., panics / assertions).
What?
This crate allows formatting values in compile time (e.g., in const fn
s). 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. As a consequence, non-constant formatted args require a format specifier.
- 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).
Limitations
- Only a few types from the standard library can be formatted: integers,
char
s andstr
ings. - 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.
Examples
Basic usage
use compile_fmt::{compile_assert, fmt};
const THRESHOLD: usize = 42;
const fn check_value(value: usize) {
compile_assert!(
value <= THRESHOLD,
"Expected ", value => fmt::<usize>(), " to not exceed ", THRESHOLD
);
// main logic
}
Note the formatting spec produced with fmt()
.
Usage with dynamic strings
use compile_fmt::{compile_assert, clip};
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"
);
// main logic
}
Printing dynamically-sized messages
compile_args!
allows specifying capacity of the produced message. This is particularly useful
when formatting enums (e.g., to compile-format errors):
#[derive(Debug)]
enum Error {
Number(u64),
Tuple(usize, char),
}
type ErrorArgs = CompileArgs<55>;
// ^ 55 is the exact lower boundary on capacity. It's valid to specify
// a greater value, e.g. 64.
impl Error {
const fn fmt(&self) -> ErrorArgs {
match *self {
Self::Number(number) => compile_args!(
capacity: ErrorArgs::CAPACITY,
"don't like number ", number => fmt::<u64>()
),
Self::Tuple(pos, ch) => compile_args!(
"don't like char '", ch => fmt::<char>(), "' at position ",
pos => fmt::<usize>()
),
}
}
}
// `Error::fmt()` can be used as a building block for more complex messages:
let err = Error::Tuple(1_234, '?');
let message = compile_args!("Operation failed: ", &err.fmt() => fmt::<&ErrorArgs>());
assert_eq!(
message.as_str(),
"Operation failed: don't like char '?' at position 1234"
);
See docs for macros and format specifiers for more examples.
Macros
- Concatenates arguments in compile time.
- Version of the
assert!
macro with the ability to format args in compile time. - Version of the
panic!
macro with the ability to format args in compile time.
Structs
- ASCII string wrapper.
- Formatted string returned by the
compile_args!
macro, similar toArguments
. - Formatting specification for an
Argument
. - Length of a string measured in bytes and chars.
Traits
- Type that can be formatted. Implemented for standard integer types,
&str
andchar
. - Type that has a known upper boundary for the formatted length.
Functions
- Creates a format that will clip the value to the specified max char width (not byte width!). If clipped, the end of the string will be replaced with the specified replacer, which can be empty.
- Creates a default format for a type that has known bounded formatting width.