| ... | ... | @@ -1119,6 +1119,103 @@ pub fn formatIntBuf(out_buf: []u8, value: anytype, base: u8, uppercase: bool, op |
| 1119 | 1119 | return fbs.pos; |
| 1120 | 1120 | } |
| 1121 | 1121 | |
| 1122 | /// Formats a number of nanoseconds according to its magnitude: |
| 1123 | /// |
| 1124 | /// - #ns |
| 1125 | /// - [#y][#w][#d][#h][#m]#[.###][u|m]s |
| 1126 | pub fn formatDuration(ns: u64, writer: anytype) !void { |
| 1127 | var ns_remaining = ns; |
| 1128 | inline for (.{ |
| 1129 | .{ .ns = 365 * std.time.ns_per_day, .sep = 'y' }, |
| 1130 | .{ .ns = std.time.ns_per_week, .sep = 'w' }, |
| 1131 | .{ .ns = std.time.ns_per_day, .sep = 'd' }, |
| 1132 | .{ .ns = std.time.ns_per_hour, .sep = 'h' }, |
| 1133 | .{ .ns = std.time.ns_per_min, .sep = 'm' }, |
| 1134 | }) |unit| { |
| 1135 | if (ns_remaining >= unit.ns) { |
| 1136 | const units = ns_remaining / unit.ns; |
| 1137 | try formatInt(units, 10, false, .{}, writer); |
| 1138 | try writer.writeByte(unit.sep); |
| 1139 | ns_remaining -= units * unit.ns; |
| 1140 | if (ns_remaining == 0) return; |
| 1141 | } |
| 1142 | } |
| 1143 | |
| 1144 | inline for (.{ |
| 1145 | .{ .ns = std.time.ns_per_s, .sep = "s" }, |
| 1146 | .{ .ns = std.time.ns_per_ms, .sep = "ms" }, |
| 1147 | .{ .ns = std.time.ns_per_us, .sep = "us" }, |
| 1148 | }) |unit| { |
| 1149 | const kunits = ns_remaining * 1000 / unit.ns; |
| 1150 | if (kunits >= 1000) { |
| 1151 | try formatInt(kunits / 1000, 10, false, .{}, writer); |
| 1152 | if (kunits > 1000) { |
| 1153 | // Write up to 3 decimal places |
| 1154 | const frac = kunits % 1000; |
| 1155 | var buf = [_]u8{ '.', 0, 0, 0 }; |
| 1156 | _ = formatIntBuf(buf[1..], frac, 10, false, .{ .fill = '0', .width = 3 }); |
| 1157 | var end: usize = 4; |
| 1158 | while (end > 1) : (end -= 1) { |
| 1159 | if (buf[end - 1] != '0') break; |
| 1160 | } |
| 1161 | try writer.writeAll(buf[0..end]); |
| 1162 | } |
| 1163 | try writer.writeAll(unit.sep); |
| 1164 | return; |
| 1165 | } |
| 1166 | } |
| 1167 | |
| 1168 | try formatInt(ns, 10, false, .{}, writer); |
| 1169 | try writer.writeAll("ns"); |
| 1170 | return; |
| 1171 | } |
| 1172 | |
| 1173 | test "formatDuration" { |
| 1174 | var buf: [24]u8 = undefined; |
| 1175 | inline for (.{ |
| 1176 | .{ .s = "0ns", .d = 0 }, |
| 1177 | .{ .s = "1ns", .d = 1 }, |
| 1178 | .{ .s = "999ns", .d = std.time.ns_per_us - 1 }, |
| 1179 | .{ .s = "1us", .d = std.time.ns_per_us }, |
| 1180 | .{ .s = "1.45us", .d = 1450 }, |
| 1181 | .{ .s = "1.5us", .d = 3 * std.time.ns_per_us / 2 }, |
| 1182 | .{ .s = "999.999us", .d = std.time.ns_per_ms - 1 }, |
| 1183 | .{ .s = "1ms", .d = std.time.ns_per_ms + 1 }, |
| 1184 | .{ .s = "1.5ms", .d = 3 * std.time.ns_per_ms / 2 }, |
| 1185 | .{ .s = "999.999ms", .d = std.time.ns_per_s - 1 }, |
| 1186 | .{ .s = "1s", .d = std.time.ns_per_s }, |
| 1187 | .{ .s = "59.999s", .d = std.time.ns_per_min - 1 }, |
| 1188 | .{ .s = "1m", .d = std.time.ns_per_min }, |
| 1189 | .{ .s = "1h", .d = std.time.ns_per_hour }, |
| 1190 | .{ .s = "1d", .d = std.time.ns_per_day }, |
| 1191 | .{ .s = "1w", .d = std.time.ns_per_week }, |
| 1192 | .{ .s = "1y", .d = 365 * std.time.ns_per_day }, |
| 1193 | .{ .s = "1y52w23h59m59.999s", .d = 730 * std.time.ns_per_day - 1 }, // 365d = 52w1d |
| 1194 | .{ .s = "1y1h1.001s", .d = 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_s + std.time.ns_per_ms }, |
| 1195 | .{ .s = "1y1h1s", .d = 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_s + 999 * std.time.ns_per_us }, |
| 1196 | .{ .s = "1y1h999.999us", .d = 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms - 1 }, |
| 1197 | .{ .s = "1y1h1ms", .d = 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms }, |
| 1198 | .{ .s = "1y1h1ms", .d = 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms + 1 }, |
| 1199 | }) |tc| { |
| 1200 | const slice = try bufPrint(&buf, "{}", .{duration(tc.d)}); |
| 1201 | std.testing.expectEqualStrings(tc.s, slice); |
| 1202 | } |
| 1203 | } |
| 1204 | |
| 1205 | /// Wraps a `u64` to format with `formatDuration`. |
| 1206 | const Duration = struct { |
| 1207 | ns: u64, |
| 1208 | |
| 1209 | pub fn format(self: Duration, comptime fmt: []const u8, options: FormatOptions, writer: anytype) !void { |
| 1210 | return formatDuration(self.ns, writer); |
| 1211 | } |
| 1212 | }; |
| 1213 | |
| 1214 | /// Formats a number of nanoseconds according to its magnitude. See `formatDuration`. |
| 1215 | pub fn duration(ns: u64) Duration { |
| 1216 | return Duration{ .ns = ns }; |
| 1217 | } |
| 1218 | |
| 1122 | 1219 | pub const ParseIntError = error{ |
| 1123 | 1220 | /// The result cannot fit in the type specified |
| 1124 | 1221 | Overflow, |