// strconv — number↔string conversions. Decimal i64 to/from a fixed // buffer. Two error idioms ship side by side: // - Plan 9 style (atoi64): tuple `(value, ok)`. Pre-dates the // tagged-union work; kept for callers that already use it. // - Hare style (stoi64/stou64): `(value | str)`. The error // variant carries a short, allocation-free message describing // why the parse failed. Prefer this for new code. // u64tos — write `v` in decimal into `buf` and return the byte count. // Hare name; the buffer-in shape is the sanctioned Plan 9 subset of // Hare's `u64tos(u, base) const str`. Unsigned-only so callers don't // have to think about wraparound when printing a u64 with the high // bit set. export fn u64tos(buf: []u8, v: u64) i32 = { let tmp: [32]u8; let i: i32 = 0; let n: u64 = v; for (n > 0u64) { tmp[i] = ((n % 10u64) + 48u64): u8; n = n / 10u64; i += 1; }; if (i == 0) { tmp[0] = 48u8; i = 1; }; let out: i32 = 0; for (i > 0) { i -= 1; buf[out] = tmp[i]; out += 1; }; return out; }; export fn i64tos(buf: []u8, v: i64) i32 = { let neg: bool = false; let n: i64 = v; if (n < 0) { neg = true; n = -n; }; let tmp: [32]u8; let i: i32 = 0; for (n > 0) { tmp[i] = ((n % 10) + 48): u8; n = n / 10; i += 1; }; if (i == 0) { tmp[0] = 48u8; i = 1; }; let out: i32 = 0; if (neg) { buf[out] = 45u8; // '-' out += 1; }; for (i > 0) { i -= 1; buf[out] = tmp[i]; out += 1; }; return out; }; export fn atoi64(s: str) (i64, bool) = { let v: i64 = 0; let i: i32 = 0; let neg: bool = false; if (s.len > 0) { if (s[0] == 45u8) { neg = true; i = 1; }; }; if (i >= s.len) { return 0, false; }; for (i < s.len) { let c: u8 = s[i]; if (c < 48u8) { return 0, false; }; if (c > 57u8) { return 0, false; }; v = v * 10 + ((c: i64) - 48); i += 1; }; if (neg) { v = -v; }; return v, true; }; // stoi64 — Hare-style fallible signed decimal parser. The value // variant is i64; the error variant is a short str (subset of Hare's // (invalid | overflow) tagged-union). No locale, no whitespace, no // underscores: a leading '-' is the only non-digit accepted, and only // at position 0. export fn stoi64(s: str) (i64 | str) = { if (s.len == 0) { return "parse: empty"; }; let i: i32 = 0; let neg: bool = false; if (s[0] == 45u8) { neg = true; i = 1; }; if (i >= s.len) { return "parse: lone sign"; }; let v: i64 = 0; for (i < s.len) { let c: u8 = s[i]; if (c < 48u8) { return "parse: invalid digit"; }; if (c > 57u8) { return "parse: invalid digit"; }; v = v * 10 + ((c: i64) - 48); i += 1; }; if (neg) { v = -v; }; return v; }; // stou64 — fallible unsigned decimal parser. No leading sign. Mirrors // Hare's strconv::stou64. export fn stou64(s: str) (u64 | str) = { if (s.len == 0) { return "parse: empty"; }; let v: u64 = 0u64; let i: i32 = 0; for (i < s.len) { let c: u8 = s[i]; if (c < 48u8) { return "parse: invalid digit"; }; if (c > 57u8) { return "parse: invalid digit"; }; v = v * 10u64 + ((c: u64) - 48u64); i += 1; }; return v; };