size: 2 KiB

1const std = @import("std");
2const fs = std.fs;
3const mem = std.mem;
4const t = std.testing;
5
6pub fn println(comptime fmt: []const u8, args: anytype) void {
7 std.debug.print(fmt ++ "\n", args);
8}
9
10pub fn dirSize(gpa: mem.Allocator, dir: fs.Dir) !u64 {
11 var walker = try dir.walk(gpa);
12 defer walker.deinit();
13
14 var size: u64 = 0;
15 while (try walker.next()) |entry| {
16 if (entry.kind != .sym_link) {
17 size += (try dir.statFile(entry.path)).size;
18 }
19 }
20 return size;
21}
22
23/// Not ideal because it truncates instead of rounding to the nearest value.
24pub fn humanReadableSize(arena: mem.Allocator, n_bytes: u64) ![]const u8 {
25 const units: []const []const u8 = &.{ "B", "KiB", "MiB", "GiB", "TiB" };
26 const multiplier: u64 = 1024;
27 var threshold: u64 = multiplier;
28 var unitIdx: usize = 0;
29
30 for (units, 0..) |_, i| {
31 unitIdx = i;
32 if (n_bytes < threshold) {
33 break;
34 }
35 threshold *= multiplier;
36 }
37
38 return std.fmt.allocPrint(
39 arena,
40 "{d} {s}",
41 .{
42 n_bytes / std.math.pow(u64, 1024, unitIdx),
43 units[unitIdx],
44 },
45 );
46}
47
48test "humanReadableSize" {
49 var arena_impl = std.heap.ArenaAllocator.init(t.allocator_instance.allocator());
50 defer arena_impl.deinit();
51 const arena = arena_impl.allocator();
52
53 try t.expectEqualStrings("12 B", try humanReadableSize(arena, 12));
54 try t.expectEqualStrings("1023 B", try humanReadableSize(arena, 1023));
55 try t.expectEqualStrings("1 KiB", try humanReadableSize(arena, 1024));
56 try t.expectEqualStrings("1 KiB", try humanReadableSize(arena, 1024 + 1023));
57 try t.expectEqualStrings("2 KiB", try humanReadableSize(arena, 1024 + 1024));
58 try t.expectEqualStrings("2 MiB", try humanReadableSize(arena, 1024 * 1024 * 2));
59 try t.expectEqualStrings("3 GiB", try humanReadableSize(arena, 1024 * 1024 * 1024 * 3));
60 try t.expectEqualStrings("4 TiB", try humanReadableSize(arena, 1024 * 1024 * 1024 * 1024 * 4));
61 try t.expectEqualStrings("1024 TiB", try humanReadableSize(arena, 1024 * 1024 * 1024 * 1024 * 1024));
62}
63
64pub const BlobType = enum { image, video, other };
65
66pub fn blobType(path: []const u8) BlobType {
67 const img_exts: []const []const u8 = &.{
68 ".apng",
69 ".avif",
70 ".gif",
71 ".jpeg",
72 ".jpg",
73 ".png",
74 ".svg",
75 ".webp",
76 ".bmp",
77 };
78 for (img_exts) |ext| {
79 if (std.ascii.endsWithIgnoreCase(path, ext)) return .image;
80 }
81
82 const video_exts: []const []const u8 = &.{
83 ".mp4",
84 ".webm",
85 };
86 for (video_exts) |ext| {
87 if (std.ascii.endsWithIgnoreCase(path, ext)) return .video;
88 }
89
90 return .other;
91}