size: 2 KiB
const std = @import("std"); const fs = std.fs; const mem = std.mem; const t = std.testing; pub fn println(comptime fmt: []const u8, args: anytype) void { std.debug.print(fmt ++ "\n", args); } pub fn dirSize(gpa: mem.Allocator, dir: fs.Dir) !u64 { var walker = try dir.walk(gpa); defer walker.deinit(); var size: u64 = 0; while (try walker.next()) |entry| { if (entry.kind != .sym_link) { size += (try dir.statFile(entry.path)).size; } } return size; } /// Not ideal because it truncates instead of rounding to the nearest value. pub fn humanReadableSize(arena: mem.Allocator, n_bytes: u64) ![]const u8 { const units: []const []const u8 = &.{ "B", "KiB", "MiB", "GiB", "TiB" }; const multiplier: u64 = 1024; var threshold: u64 = multiplier; var unitIdx: usize = 0; for (units, 0..) |_, i| { unitIdx = i; if (n_bytes < threshold) { break; } threshold *= multiplier; } return std.fmt.allocPrint( arena, "{d} {s}", .{ n_bytes / std.math.pow(u64, 1024, unitIdx), units[unitIdx], }, ); } test "humanReadableSize" { var arena_impl = std.heap.ArenaAllocator.init(t.allocator_instance.allocator()); defer arena_impl.deinit(); const arena = arena_impl.allocator(); try t.expectEqualStrings("12 B", try humanReadableSize(arena, 12)); try t.expectEqualStrings("1023 B", try humanReadableSize(arena, 1023)); try t.expectEqualStrings("1 KiB", try humanReadableSize(arena, 1024)); try t.expectEqualStrings("1 KiB", try humanReadableSize(arena, 1024 + 1023)); try t.expectEqualStrings("2 KiB", try humanReadableSize(arena, 1024 + 1024)); try t.expectEqualStrings("2 MiB", try humanReadableSize(arena, 1024 * 1024 * 2)); try t.expectEqualStrings("3 GiB", try humanReadableSize(arena, 1024 * 1024 * 1024 * 3)); try t.expectEqualStrings("4 TiB", try humanReadableSize(arena, 1024 * 1024 * 1024 * 1024 * 4)); try t.expectEqualStrings("1024 TiB", try humanReadableSize(arena, 1024 * 1024 * 1024 * 1024 * 1024)); } pub const BlobType = enum { image, video, other }; pub fn blobType(path: []const u8) BlobType { const img_exts: []const []const u8 = &.{ ".apng", ".avif", ".gif", ".jpeg", ".jpg", ".png", ".svg", ".webp", ".bmp", }; for (img_exts) |ext| { if (std.ascii.endsWithIgnoreCase(path, ext)) return .image; } const video_exts: []const []const u8 = &.{ ".mp4", ".webm", }; for (video_exts) |ext| { if (std.ascii.endsWithIgnoreCase(path, ext)) return .video; } return .other; }