fmt
import fmt from "fmt";
let addr: string = fmt.hex(0xBEEF); // "beef"
let pair: string = fmt.hex_padded(10, 2); // "0a"
let price: string = fmt.float_f64(19.999, 2); // "20.00"
let size: string = fmt.bytes_human(1572864); // "1.5 MiB"String interpolation ("{x}") prints integers in decimal and floats in
their shortest form. fmt covers the rest: other bases, a fixed number of
decimals, and byte counts. For aligning text in columns, use
str.pad_left and friends.
Each function comes in two forms. The plain one returns a new string. The
_to one writes into a buffer you pass and returns how many bytes it
wrote, so you can format many numbers without allocating:
var buf: [16]u8;
let n: i64 = fmt.hex_to(buf[..], 48879);
let text: []const u8 = buf[0..n]; // "beef", no allocationA _to function stops the program with a
trap when the buffer is too small. The
*_MAX_LEN constants give a size that is always enough.
fmt is a pure module.
Hexadecimal and binary
| Function | Returns |
|---|---|
hex(v: u64) -> string | v in lowercase hex: "ff", "0" |
hex_padded(v: u64, digits: i64) -> string | At least digits hex digits, zeros in front: "00ff" |
bin(v: u64) -> string | v in binary: "101" |
bin_padded(v: u64, digits: i64) -> string | At least digits binary digits: "00000101" |
hex_to(dst, v), hex_padded_to(dst, v, digits), bin_to(dst, v), bin_padded_to(dst, v, digits) | The same, written into dst: []u8; return the length |
There’s no 0x prefix and no leading zeros unless you ask for a width. A
value that needs more digits than digits is never cut. digits must be
between 0 and 64.
To format a signed number, cast it: fmt.hex(x as u64) gives the
two’s-complement bits, so -1 is "ffffffffffffffff".
let rgb: u64 = 0x336699;
io.println("#{fmt.hex_padded(rgb, 6)}"); // "#336699"
let flags: u64 = 5;
io.println("flags: {fmt.bin_padded(flags, 8)}"); // "flags: 00000101"| Constant | Value |
|---|---|
HEX_MAX_LEN | 16: enough for hex_to of any value |
BIN_MAX_LEN | 64: enough for bin_to of any value |
PADDED_MAX_DIGITS | 64: the largest digits |
Floating point
| Function | Returns |
|---|---|
float_f64(v: f64, precision: i64) -> string | v with precision digits after the point |
float_f64_to(dst, v: f64, precision: i64) -> i64 | The same, into dst |
With precision 0 or more you get exactly that many digits after the point
(and no point for 0), correctly rounded from the exact value of v. With a
negative precision you get the shortest text that reads back as v,
the same as "{v}".
fmt.float_f64(3.14159, 2); // "3.14"
fmt.float_f64(2.5, 0); // "2" (ties round to even)
fmt.float_f64(1.0, 3); // "1.000"
fmt.float_f64(0.1, -1); // "0.1"Rounding is of the stored value: 2.675 is stored as slightly less than
2.675, so fmt.float_f64(2.675, 2) is "2.67". Infinities print as inf
and -inf, not-a-number as nan.
float_f64_to needs up to conv.FMT_F64_SHORTEST_MAX_LEN bytes for the
shortest form and conv.FMT_F64_FIXED_MAX_LEN + precision otherwise (see
conv).
Byte counts
| Function | Returns |
|---|---|
bytes_human(n: i64) -> string | n bytes in binary units: "512 B", "1.5 KiB", "3.2 GiB" |
bytes_human_to(dst, n: i64) -> i64 | The same, into dst |
BYTES_HUMAN_MAX_LEN | 16: enough for any i64 |
Units are powers of 1024: KiB, MiB, GiB, TiB, PiB, EiB. Below 1024 the exact count is shown; from there on one decimal, rounded (halves up). A value that rounds up to 1024 of a unit is shown in the next one, and negative counts get a minus sign.
fmt.bytes_human(1023); // "1023 B"
fmt.bytes_human(1024); // "1.0 KiB"
fmt.bytes_human(1048575); // "1.0 MiB"
fmt.bytes_human(-2048); // "-2.0 KiB"Last modified: