Commit 894a991714

Ryan Liptak <squeek502@hotmail.com>
2025-10-03 23:25:12
Add depth function to `Walker.Entry`
This enables depth-related use cases without any dependency on the Walker's internal stack which doesn't always pertain to the actual depth of the current entry (i.e. recursing into a directory immediately affects the stack).
1 parent 98dd885
Changed files (3)
lib/std/fs/Dir.zig
@@ -732,16 +732,14 @@ pub const SelectiveWalker = struct {
         });
     }
 
-    pub fn depth(self: *SelectiveWalker) usize {
-        return self.stack.items.len;
-    }
-
     pub fn deinit(self: *SelectiveWalker) void {
         self.name_buffer.deinit(self.allocator);
         self.stack.deinit(self.allocator);
     }
 
     /// Leaves the current directory, continuing walking one level up.
+    /// If the current entry is a directory entry, then the "current directory"
+    /// will pertain to that entry if `enter` is called before `leave`.
     pub fn leave(self: *SelectiveWalker) void {
         var item = self.stack.pop().?;
         if (self.stack.items.len != 0) {
@@ -789,6 +787,13 @@ pub const Walker = struct {
         basename: [:0]const u8,
         path: [:0]const u8,
         kind: Dir.Entry.Kind,
+
+        /// Returns the depth of the entry relative to the initial directory.
+        /// Returns 1 for a direct child of the initial directory, 2 for an entry
+        /// within a direct child of the initial directory, etc.
+        pub fn depth(self: Walker.Entry) usize {
+            return mem.countScalar(u8, self.path, fs.path.sep) + 1;
+        }
     };
 
     const StackItem = struct {
lib/std/fs/test.zig
@@ -1765,14 +1765,14 @@ test "walker" {
 
     // iteration order of walker is undefined, so need lookup maps to check against
 
-    const expected_paths = std.StaticStringMap(void).initComptime(.{
-        .{"dir1"},
-        .{"dir2"},
-        .{"dir3"},
-        .{"dir4"},
-        .{"dir3" ++ fs.path.sep_str ++ "sub1"},
-        .{"dir3" ++ fs.path.sep_str ++ "sub2"},
-        .{"dir3" ++ fs.path.sep_str ++ "sub2" ++ fs.path.sep_str ++ "subsub1"},
+    const expected_paths = std.StaticStringMap(usize).initComptime(.{
+        .{ "dir1", 1 },
+        .{ "dir2", 1 },
+        .{ "dir3", 1 },
+        .{ "dir4", 1 },
+        .{ "dir3" ++ fs.path.sep_str ++ "sub1", 2 },
+        .{ "dir3" ++ fs.path.sep_str ++ "sub2", 2 },
+        .{ "dir3" ++ fs.path.sep_str ++ "sub2" ++ fs.path.sep_str ++ "subsub1", 3 },
     });
 
     const expected_basenames = std.StaticStringMap(void).initComptime(.{
@@ -1802,6 +1802,10 @@ test "walker" {
             std.debug.print("found unexpected path: {f}\n", .{std.ascii.hexEscape(entry.path, .lower)});
             return err;
         };
+        testing.expectEqual(expected_paths.get(entry.path).?, entry.depth()) catch |err| {
+            std.debug.print("path reported unexpected depth: {f}\n", .{std.ascii.hexEscape(entry.path, .lower)});
+            return err;
+        };
         // make sure that the entry.dir is the containing dir
         var entry_dir = try entry.dir.openDir(entry.basename, .{});
         defer entry_dir.close();
@@ -1851,6 +1855,10 @@ test "selective walker, skip entries that start with ." {
     var num_walked: usize = 0;
     while (try walker.next()) |entry| {
         if (entry.basename[0] == '.') continue;
+        if (entry.kind == .directory) {
+            try walker.enter(entry);
+        }
+
         testing.expect(expected_basenames.has(entry.basename)) catch |err| {
             std.debug.print("found unexpected basename: {f}\n", .{std.ascii.hexEscape(entry.basename, .lower)});
             return err;
@@ -1859,16 +1867,11 @@ test "selective walker, skip entries that start with ." {
             std.debug.print("found unexpected path: {f}\n", .{std.ascii.hexEscape(entry.path, .lower)});
             return err;
         };
-
-        testing.expectEqual(expected_paths.get(entry.path).?, walker.depth()) catch |err| {
-            std.debug.print("path reported unexpected depth: {f}, {d}, expected {d}\n", .{ std.ascii.hexEscape(entry.path, .lower), walker.depth(), expected_paths.get(entry.path).? });
+        testing.expectEqual(expected_paths.get(entry.path).?, entry.depth()) catch |err| {
+            std.debug.print("path reported unexpected depth: {f}\n", .{std.ascii.hexEscape(entry.path, .lower)});
             return err;
         };
 
-        if (entry.kind == .directory) {
-            try walker.enter(entry);
-        }
-
         // make sure that the entry.dir is the containing dir
         var entry_dir = try entry.dir.openDir(entry.basename, .{});
         defer entry_dir.close();
tools/update_mingw.zig
@@ -117,7 +117,7 @@ pub fn main() !void {
         while (try walker.next()) |entry| {
             switch (entry.kind) {
                 .directory => {
-                    switch (walker.depth()) {
+                    switch (entry.depth()) {
                         1 => if (def_dirs.has(entry.basename)) {
                             try walker.enter(entry);
                             continue;