nx_bytes_fmt.nx source
↩ module page · 131 lines · 4114 B
1// bytes_fmt.nx -- human-readable byte-size formatter.
2//
3// Renders byte counts as "1.2 KB" / "5.3 MB" / "12.0 GB" for
4// logs + UI. Binary (1024-based, KiB/MiB/GiB) + decimal (1000-
5// based, KB/MB/GB) variants both provided.
6//
7// Used by: fs stat reporters, HTTP Content-Length logs, storage
8// quota displays.
9//
10// Invariants:
11// BF1 Output is deterministic: same input bytes -> same output.
12// BF2 Always produces exactly one significant decimal digit
13// (unless the unit is B, where decimals make no sense).
14// BF3 Negative byte counts produce "-<formatted>" (only the
15// magnitude is unit-scaled).
16
17// nx_safety_envelope:
18// intended_use: AUTO_APPLIED -- primitive-specific tuning queued
19// sil_target: SIL1
20// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail]
21// verdict: NOT_YET_EVALUATED
22
23import "nx_syscalls.nx"
24const K_MAGIC_1024: i64 = 1024
25const K_MAGIC_2048: i64 = 2048
26
27// Emit decimal integer into out starting at pos. Returns digits
28// written. Used by both variants.
29func bf_emit_uint(out: *u8, pos: i64, n: i64) -> i64 {
30 if n == 0 {
31 out[pos] = 0x30
32 return 1
33 }
34 let buf: *u8 = sys_mmap(32)
35 var v: i64 = n
36 var k: i64 = 0
37 while v > 0 {
38 buf[k] = 0x30 + (v % 10)
39 v = v / 10
40 k = k + 1
41 }
42 var i: i64 = 0
43 while i < k {
44 out[pos + i] = buf[k - 1 - i]
45 i = i + 1
46 }
47 return k
48}
49
50// Shared formatter: writes "<whole>.<tenth> <unit>" to out starting
51// at pos. `scale` = 1024 (binary) or 1000 (decimal).
52// Returns total bytes written.
53func bf_fmt_scaled(bytes: i64, scale: i64, binary_units: i64,
54 out: *u8, pos: i64) -> i64 {
55 var p: i64 = pos
56 var abs: i64 = bytes
57 if abs < 0 {
58 out[p] = 0x2D // '-'
59 p = p + 1
60 abs = 0 - abs
61 }
62 // Select unit by order-of-magnitude.
63 var value: i64 = abs
64 var remainder: i64 = 0
65 var unit: i64 = 0 // 0 = B, 1 = K, 2 = M, 3 = G, 4 = T, 5 = P
66 while value >= scale {
67 remainder = value % scale
68 value = value / scale
69 unit = unit + 1
70 if unit >= 5 { unit = 5 }
71 }
72
73 // Whole part.
74 p = p + bf_emit_uint(out, p, value)
75
76 // Fractional part: one digit = (remainder * 10) / scale.
77 // Only for non-byte units.
78 if unit > 0 {
79 out[p] = 0x2E // '.'
80 p = p + 1
81 let tenth: i64 = (remainder * 10) / scale
82 out[p] = 0x30 + tenth
83 p = p + 1
84 }
85
86 // Space + unit suffix.
87 out[p] = 0x20
88 p = p + 1
89 if unit == 0 { out[p] = 0x42; p = p + 1; return p - pos } // "B"
90 // Unit letter.
91 if unit == 1 { out[p] = 0x4B; p = p + 1 } // 'K'
92 if unit == 2 { out[p] = 0x4D; p = p + 1 } // 'M'
93 if unit == 3 { out[p] = 0x47; p = p + 1 } // 'G'
94 if unit == 4 { out[p] = 0x54; p = p + 1 } // 'T'
95 if unit == 5 { out[p] = 0x50; p = p + 1 } // 'P'
96 if binary_units == 1 {
97 out[p] = 0x69 // 'i' -- KiB/MiB
98 p = p + 1
99 }
100 out[p] = 0x42 // 'B'
101 p = p + 1
102 return p - pos
103}
104
105// Binary (1024-based, KiB / MiB / GiB). Preferred for storage
106// display.
107func bytes_fmt_binary(bytes: i64, out: *u8, pos: i64) -> i64 {
108 return bf_fmt_scaled(bytes, K_MAGIC_1024, 1, out, pos)
109}
110
111// Decimal (1000-based, KB / MB / GB). Preferred for marketing /
112// network throughput reporting (matches vendor specs).
113func bytes_fmt_decimal(bytes: i64, out: *u8, pos: i64) -> i64 {
114 return bf_fmt_scaled(bytes, 1000, 0, out, pos)
115}
116
117// Compile-only smoke: 2048 bytes -> "2.0 KiB" (binary) or
118// "2.0 KB" (decimal)... actually 2048 / 1000 = 2, remainder 48;
119// tenth = 480/1000 = 0 -> "2.0 KB".
120func main() -> i64 {
121 let out: *u8 = sys_mmap(32)
122 let n: i64 = bytes_fmt_binary(K_MAGIC_2048, out, 0)
123 // "2.0 KiB" = 7 chars
124 if n != 7 { return 1 }
125 if out[0] != 0x32 { return 2 } // '2'
126 if out[1] != 0x2E { return 3 } // '.'
127 if out[4] != 0x4B { return 4 } // 'K'
128 if out[5] != 0x69 { return 5 } // 'i'
129 if out[6] != 0x42 { return 6 } // 'B'
130 return 0
131}