feature. See also
. The project being documented here (as the example) is the Zig library itself.
Dir.SelectiveWalker
pub const SelectiveWalker = struct
File
Code
pub const SelectiveWalker = struct {
stack: std.ArrayList(StackItem),
name_buffer: std.ArrayList(u8),
allocator: Allocator,
pub const Error = Iterator.Error || Allocator.Error;
const StackItem = struct {
iter: Iterator,
dirname_len: usize,
};
pub fn next(self: *SelectiveWalker, io: Io) Error!?Walker.Entry {
while (self.stack.items.len > 0) {
const top = &self.stack.items[self.stack.items.len - 1];
var dirname_len = top.dirname_len;
if (top.iter.next(io) catch |err| {
// walking if they want, which means that we need to pop the directory
// that errored from the stack. Otherwise, all future `next` calls would
// likely just fail with the same error.
var item = self.stack.pop().?;
if (self.stack.items.len != 0) {
item.iter.reader.dir.close(io);
}
return err;
}) |entry| {
self.name_buffer.shrinkRetainingCapacity(dirname_len);
if (self.name_buffer.items.len != 0) {
try self.name_buffer.append(self.allocator, path.sep);
dirname_len += 1;
}
try self.name_buffer.ensureUnusedCapacity(self.allocator, entry.name.len + 1);
self.name_buffer.appendSliceAssumeCapacity(entry.name);
self.name_buffer.appendAssumeCapacity(0);
const walker_entry: Walker.Entry = .{
.dir = top.iter.reader.dir,
.basename = self.name_buffer.items[dirname_len .. self.name_buffer.items.len - 1 :0],
.path = self.name_buffer.items[0 .. self.name_buffer.items.len - 1 :0],
.kind = entry.kind,
};
return walker_entry;
} else {
var item = self.stack.pop().?;
if (self.stack.items.len != 0) {
item.iter.reader.dir.close(io);
}
}
}
return null;
}
pub fn enter(self: *SelectiveWalker, io: Io, entry: Walker.Entry) !void {
if (entry.kind != .directory) {
@branchHint(.cold);
return;
}
var new_dir = entry.dir.openDir(io, entry.basename, .{ .iterate = true }) catch |err| {
switch (err) {
error.NameTooLong => unreachable,
else => |e| return e,
}
};
errdefer new_dir.close(io);
try self.stack.append(self.allocator, .{
.iter = new_dir.iterateAssumeFirstIteration(),
.dirname_len = self.name_buffer.items.len - 1,
});
}
pub fn deinit(self: *SelectiveWalker) void {
self.name_buffer.deinit(self.allocator);
self.stack.deinit(self.allocator);
}
pub fn leave(self: *SelectiveWalker, io: Io) void {
var item = self.stack.pop().?;
if (self.stack.items.len != 0) {
@branchHint(.likely);
item.iter.reader.dir.close(io);
}
}
}