Template strings in Wado support format specifiers: `${x:spec}`. As defined in WEP: Template Format Specifiers, Wado uses Rust-compatible format specifiers:
| Specifier | Description | Example |
|---|---|---|
| (none) | Default display | ${x} → "42" |
? |
Debug/Inspect | ${x:?} → "42" |
b |
Binary integers | ${x:b} → "101010" |
o |
Octal integers | ${x:o} → "52" |
x |
Lowercase hex | ${x:x} → "2a" |
X |
Uppercase hex | ${x:X} → "2A" |
e |
Lowercase exponential | ${x:e} → "4.2e1" |
E |
Uppercase exponential | ${x:E} → "4.2E1" |
This WEP defines the trait system and Formatter infrastructure that backs these format specifiers.
Format traits write to a Formatter object that holds format options and a reference to the output buffer. The Formatter does not own its buffer; it writes directly into the caller's &mut String. Format specification fields are embedded directly into Formatter to avoid an extra GC struct allocation.
/// Text alignment for padding
variant Alignment {
Left,
Center,
Right,
}
/// Formatter that writes directly into a referenced output buffer.
/// Format specification fields are embedded to save one GC struct allocation.
struct Formatter {
fill: char,
align: Alignment,
sign_plus: bool,
alternate: bool,
zero_pad: bool,
width: i32, // -1 = not specified
precision: i32, // -1 = not specified
buf: &mut String,
}
impl Formatter {
fn new(buf: &mut String) -> Formatter;
fn write_str(&mut self, s: &String);
fn write_char(&mut self, c: char);
fn width(&self) -> i32;
fn precision(&self) -> i32;
fn alternate(&self) -> bool;
fn sign_plus(&self) -> bool;
}
All format traits follow the same pattern: write to a Formatter.
trait Display {
fn fmt(&self, f: &mut Formatter);
}
trait Binary {
fn fmt(&self, f: &mut Formatter);
}
trait Octal {
fn fmt(&self, f: &mut Formatter);
}
trait LowerHex {
fn fmt(&self, f: &mut Formatter);
}
trait UpperHex {
fn fmt(&self, f: &mut Formatter);
}
trait LowerExp {
fn fmt(&self, f: &mut Formatter);
}
trait UpperExp {
fn fmt(&self, f: &mut Formatter);
}
The :? specifier resolves to the Inspect trait. The :#? specifier resolves to the InspectAlt trait for pretty-printed (indented multi-line) output. The compiler auto-synthesizes Inspect and InspectAlt for all user types; types can provide custom implementations to override.
trait Inspect {
fn inspect(&self, f: &mut Formatter);
}
trait InspectAlt {
fn inspect_alt(&self, f: &mut Formatter);
}
Display comes from the type's own impl Display. The compiler provides one
for the two type kinds whose string form is unambiguous: a plain enum displays
its bare case name (Red, vs Inspect's Color::Red), and a newtype inherits
its base type's Display transparently (Meters = f64 renders 3.14). Any
other type — a struct, variant, or generic container — needs a hand-written
impl Display; ${x} on a type without one is a compile error (use ${x:?}).
DisplayAlt (${x:#}) follows Display. See
Trait Derivation Policy.
Each format trait has an alternate variant activated by the # flag. For Inspect, InspectAlt produces pretty-printed output. For numeric traits, Alt variants add prefixes (0x, 0b, 0o).
| Base Trait | Alt Trait | Syntax | Effect |
|---|---|---|---|
Display |
DisplayAlt |
${:#} |
Delegates to Display |
Inspect |
InspectAlt |
${:#?} |
Pretty-print with indentation |
Binary |
BinaryAlt |
${:#b} |
Add 0b prefix |
Octal |
OctalAlt |
${:#o} |
Add 0o prefix |
LowerHex |
LowerHexAlt |
${:#x} |
Add 0x prefix |
UpperHex |
UpperHexAlt |
${:#X} |
Add 0X prefix |
| Specifier | Resolution |
|---|---|
| (none) | Display::fmt (compile error if T has no Display) |
? |
Inspect::inspect |
# |
DisplayAlt::fmt_alt |
#? |
InspectAlt::inspect_alt |
b |
Binary::fmt |
o |
Octal::fmt |
x |
LowerHex::fmt |
X |
UpperHex::fmt |
e |
LowerExp::fmt |
E |
UpperExp::fmt |
| Type | Traits |
|---|---|
| Integer types | Display, Binary, Octal, LowerHex, UpperHex |
| Float types | Display, LowerExp, UpperExp |
bool, char |
Display |
String |
Display |
Zero padding (${x:08}) inserts zeros after sign/prefix but before digits:
${-42:08} → "-0000042"
${42:#08x} → "0x00002a"
- Accurate formatting: Precision is available during formatting
- Efficient: Write directly to buffer
- Rust-compatible: Familiar design for Rust developers
- Extensible: Easy to add new format options or traits
- Infrastructure complexity: Requires
FormatterandAlignmenttypes - Implementation effort: All primitive formatting needs trait implementations
${:#?}: Pretty-print debug with indentation viaInspectAlttrait
- Dynamic width/precision:
${value:${width}.${precision}}