Skip to content
CryoCryo home
Stdlibfmt

spec

import std::fmt::spec; · source

Format specs

type struct FmtSpec {
    fill:          u32;
    align:         u8;
    alternate:     boolean;
    zero_pad:      boolean;
    width:         u64;
    has_precision: boolean;
    precision:     u64;
    radix:         u8;

    static empty() -> FmtSpec;
}
function fmt_parse_spec(spec: Str) -> FmtSpec;

An f-string hole may carry a spec after a colon. The grammar is a subset of Rust's:

spec := [[fill]align][#][0][width][.precision][type]
align := '<' | '>' | '^'         (left, right, centre)
type  := 'x' | 'X' | 'o' | 'b'   (hex lower/upper, octal, binary)
f"{value:>8}"        // right-align in a field of 8
f"{byte:#04x}"       // 0x0f  - `#` adds the radix prefix, `0` zero-pads
f"{ratio:.3}"        // three fractional digits
f"{label:*^12}"      // centred, padded with '*'

width is a minimum field width measured in Unicode scalars. .precision truncates a Display value to that many scalars, or sets the fractional digits of a float. Alignment defaults to left for text and numbers alike — chosen for predictability over a type-dependent default — and an explicit > or ^, or the 0 flag, overrides it.

For a signed integer, a decimal spec keeps the sign, while a radix formats the two's-complement bit pattern at the value's own width with no sign.

FmtSpec is the parsed form of that grammar, and fmt_parse_spec is the parser. fmt_append_fmt calls it at runtime for every hole that has a spec, then routes the value through the width-aware writers below.

Field values

const RADIX_NONE: u8 = 0;
const RADIX_HEX_LOWER: u8 = 1;
const RADIX_HEX_UPPER: u8 = 2;
const RADIX_OCT: u8 = 3;
const RADIX_BIN: u8 = 4;
const ALIGN_DEFAULT: u8 = 0;
const ALIGN_LEFT: u8 = 1;
const ALIGN_RIGHT: u8 = 2;
const ALIGN_CENTER: u8 = 3;
const FILL_SPACE: u32 = 0x20;
const FILL_ZERO: u32 = 0x30;

Writers

type struct BodyText {
    text:     String;
    head_len: u64;

    drop(mut &this) -> void;
}
function fmt_uint_body(val: u64, spec: &FmtSpec) -> BodyText;
function fmt_sint_body(val: i64, masked: u64, spec: &FmtSpec) -> BodyText;
function fmt_float_body(val: f64, spec: &FmtSpec) -> BodyText;

function fmt_display_body<T>(value: &T, spec: &FmtSpec) -> BodyText
where T: Display;

function fmt_pad(out: mut &String, body: Str, head_len: u64, spec: &FmtSpec) -> void;

A spec is applied in two steps: a *_body function renders the value to text and reports how many leading bytes are the "head" — the sign and any radix prefix, which zero-padding must keep leftmost — and fmt_pad applies fill, alignment, and width around it. They are public so a Display impl that wants to honour a spec itself can reuse them.