code wiki / (root) / bytes_fmt.nx

bytes_fmt.nx source

↩ module page · 123 lines · 3905 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 17import "syscalls.nx" 18 19// Emit decimal integer into out starting at pos. Returns digits 20// written. Used by both variants. 21func bf_emit_uint(out: *u8, pos: i64, n: i64) -> i64 { 22 if n == 0 { 23 out[pos] = 0x30 24 return 1 25 } 26 let buf: *u8 = sys_mmap(32) 27 var v: i64 = n 28 var k: i64 = 0 29 while v > 0 { 30 buf[k] = 0x30 + (v % 10) 31 v = v / 10 32 k = k + 1 33 } 34 var i: i64 = 0 35 while i < k { 36 out[pos + i] = buf[k - 1 - i] 37 i = i + 1 38 } 39 return k 40} 41 42// Shared formatter: writes "<whole>.<tenth> <unit>" to out starting 43// at pos. `scale` = 1024 (binary) or 1000 (decimal). 44// Returns total bytes written. 45func bf_fmt_scaled(bytes: i64, scale: i64, binary_units: i64, 46 out: *u8, pos: i64) -> i64 { 47 var p: i64 = pos 48 var abs: i64 = bytes 49 if abs < 0 { 50 out[p] = 0x2D // '-' 51 p = p + 1 52 abs = 0 - abs 53 } 54 // Select unit by order-of-magnitude. 55 var value: i64 = abs 56 var remainder: i64 = 0 57 var unit: i64 = 0 // 0 = B, 1 = K, 2 = M, 3 = G, 4 = T, 5 = P 58 while value >= scale { 59 remainder = value % scale 60 value = value / scale 61 unit = unit + 1 62 if unit >= 5 { unit = 5 } 63 } 64 65 // Whole part. 66 p = p + bf_emit_uint(out, p, value) 67 68 // Fractional part: one digit = (remainder * 10) / scale. 69 // Only for non-byte units. 70 if unit > 0 { 71 out[p] = 0x2E // '.' 72 p = p + 1 73 let tenth: i64 = (remainder * 10) / scale 74 out[p] = 0x30 + tenth 75 p = p + 1 76 } 77 78 // Space + unit suffix. 79 out[p] = 0x20 80 p = p + 1 81 if unit == 0 { out[p] = 0x42; p = p + 1; return p - pos } // "B" 82 // Unit letter. 83 if unit == 1 { out[p] = 0x4B; p = p + 1 } // 'K' 84 if unit == 2 { out[p] = 0x4D; p = p + 1 } // 'M' 85 if unit == 3 { out[p] = 0x47; p = p + 1 } // 'G' 86 if unit == 4 { out[p] = 0x54; p = p + 1 } // 'T' 87 if unit == 5 { out[p] = 0x50; p = p + 1 } // 'P' 88 if binary_units == 1 { 89 out[p] = 0x69 // 'i' -- KiB/MiB 90 p = p + 1 91 } 92 out[p] = 0x42 // 'B' 93 p = p + 1 94 return p - pos 95} 96 97// Binary (1024-based, KiB / MiB / GiB). Preferred for storage 98// display. 99func bytes_fmt_binary(bytes: i64, out: *u8, pos: i64) -> i64 { 100 return bf_fmt_scaled(bytes, 1024, 1, out, pos) 101} 102 103// Decimal (1000-based, KB / MB / GB). Preferred for marketing / 104// network throughput reporting (matches vendor specs). 105func bytes_fmt_decimal(bytes: i64, out: *u8, pos: i64) -> i64 { 106 return bf_fmt_scaled(bytes, 1000, 0, out, pos) 107} 108 109// Compile-only smoke: 2048 bytes -> "2.0 KiB" (binary) or 110// "2.0 KB" (decimal)... actually 2048 / 1000 = 2, remainder 48; 111// tenth = 480/1000 = 0 -> "2.0 KB". 112func main() -> i64 { 113 let out: *u8 = sys_mmap(32) 114 let n: i64 = bytes_fmt_binary(2048, out, 0) 115 // "2.0 KiB" = 7 chars 116 if n != 7 { return 1 } 117 if out[0] != 0x32 { return 2 } // '2' 118 if out[1] != 0x2E { return 3 } // '.' 119 if out[4] != 0x4B { return 4 } // 'K' 120 if out[5] != 0x69 { return 5 } // 'i' 121 if out[6] != 0x42 { return 6 } // 'B' 122 return 0 123}