Module fmt/spec
Format specifications — the ${value:spec} vocabulary (STD_API_AUDIT D3.10).
The grammar is Rust's, minus dynamic width/precision:
spec := [[fill]align][+][#][0][width][.precision][kind]
align := "<" | ">" | "^"
kind := "x" | "X" | "b" | "o"
Example
{ FormatSpec } :: import "std/fmt/spec";
s := FormatSpec.parse(">8.2");
s.pad(`3.14159`, Alignment.Left); // " 3.14"
Widths and precisions are RUNE counts, not byte counts — _apply_width,
pad and pad_numeric all measure with chars().count(), so é occupies
one column and a truncation can never cut a rune in half. That is the one
place in the string world where the unit is deliberately not bytes: a
format spec describes a COLUMN, and D4's byte basis would have made
accented rows come out ragged.
Stability
unstable — two shapes are still open, and both are breaking to change.
The grammar is missing Rust's DYNAMIC width and precision ({:w$},
{:.p$}), as the module header says. Yo has no format macro to collect the
extra arguments, so adding them means inventing a spelling
(spec.with_width(n)? a second pad overload?) rather than extending the
parse table.
And parse is TOTAL: it never reports a bad spec, it ignores what it does
not recognise, so "{:.2x" degrades silently to something a caller did not
ask for. That is the right default for interpolation — a typo in a log line
should not abort the program — but it also means a spec typo is invisible
forever, and giving parse a Result later is breaking. Freezing waits on
deciding both, not on a release count.
Types
A parsed format specification. Produced by parse, never written by hand —
which is why the optional parts are Option rather than sentinels.
Fields
| Name | Type | Description |
|---|---|---|
fill | rune | Padding character. Defaults to a space. |
align | Option(Alignment) | Explicit alignment, if the spec gave one. |
plus | bool |
|
alt | bool |
|
zero | bool |
|
width | usize | Minimum width in CHARACTERS. |
precision | Option(usize) |
|
kind | rune | Radix selector: |
impl(FormatSpec, ...)
empty : (FormatSpec) fn() -> FormatSpecThe default spec: no width, no precision, no radix.
Returns: FormatSpec
parse : (FormatSpec) fn(s : str) -> FormatSpecParse a spec. TOTAL: anything unrecognised is ignored rather than
rejected, so a malformed spec degrades to plain to_string() output
instead of failing at runtime.
Parameters
| Name | Type | Notes |
|---|---|---|
s | str |
Returns: FormatSpec
pad : (FormatSpec) fn(self : FormatSpec, body : String, dflt : Alignment) -> StringApply width/fill/alignment (and text truncation) to an already-rendered
body. dflt is the alignment used when the spec did not give one —
Left for text, Right for numbers, as in Rust.
Parameters
| Name | Type | Notes |
|---|---|---|
self | FormatSpec | |
body | String | |
dflt | Alignment |
Returns: String
pad_numeric : (FormatSpec) fn(self : FormatSpec, sign : String, prefix : String, digits : String) -> StringNumber-aware padding: with 0 set and no explicit alignment, the zero
fill goes BETWEEN the sign/prefix and the digits, so -0042 and
0x0000002a are reachable. Otherwise this is ordinary right-aligned
padding over the whole rendering.
Parameters
| Name | Type | Notes |
|---|---|---|
self | FormatSpec | |
sign | String | |
prefix | String | |
digits | String |
Returns: String