lib/sandbox/src/change.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

  1 const std = @import("std");
  2 
  3 const Allocator = std.mem.Allocator;
  4 
  5 pub const Operation = enum {
  6     put,
  7     delete,
  8 };
  9 
 10 pub const Kind = enum {
 11     file,
 12     directory,
 13     sym_link,
 14     other,
 15 };
 16 
 17 pub const Entry = struct {
 18     path: []u8,
 19     kind: Kind,
 20     hash: []u8 = &.{},
 21     target: []u8 = &.{},
 22     bytes: u64 = 0,
 23 
 24     pub fn clone(self: Entry, allocator: Allocator) Allocator.Error!Entry {
 25         const path = try allocator.dupe(u8, self.path);
 26         errdefer allocator.free(path);
 27         const hash = try allocator.dupe(u8, self.hash);
 28         errdefer allocator.free(hash);
 29         const target = try allocator.dupe(u8, self.target);
 30         return .{
 31             .path = path,
 32             .kind = self.kind,
 33             .hash = hash,
 34             .target = target,
 35             .bytes = self.bytes,
 36         };
 37     }
 38 
 39     pub fn deinit(self: *Entry, allocator: Allocator) void {
 40         allocator.free(self.path);
 41         allocator.free(self.hash);
 42         allocator.free(self.target);
 43         self.* = undefined;
 44     }
 45 };
 46 
 47 pub const Change = struct {
 48     operation: Operation,
 49     entry: Entry,
 50 
 51     pub fn clone(self: Change, allocator: Allocator) Allocator.Error!Change {
 52         return .{
 53             .operation = self.operation,
 54             .entry = try self.entry.clone(allocator),
 55         };
 56     }
 57 
 58     pub fn deinit(self: *Change, allocator: Allocator) void {
 59         self.entry.deinit(allocator);
 60         self.* = undefined;
 61     }
 62 };
 63 
 64 pub const Set = struct {
 65     allocator: Allocator,
 66     items: std.ArrayList(Change) = .empty,
 67 
 68     pub fn init(allocator: Allocator) Set {
 69         return .{ .allocator = allocator };
 70     }
 71 
 72     pub fn deinit(self: *Set) void {
 73         for (self.items.items) |*item| item.deinit(self.allocator);
 74         self.items.deinit(self.allocator);
 75         self.* = undefined;
 76     }
 77 
 78     pub fn append(self: *Set, operation: Operation, entry: Entry) Allocator.Error!void {
 79         try self.items.append(self.allocator, .{
 80             .operation = operation,
 81             .entry = try entry.clone(self.allocator),
 82         });
 83     }
 84 
 85     pub fn len(self: *const Set) usize {
 86         return self.items.items.len;
 87     }
 88 
 89     pub fn get(self: *const Set, index: usize) ?Change {
 90         if (index >= self.items.items.len) return null;
 91         return self.items.items[index];
 92     }
 93 
 94     pub fn find(self: *const Set, path: []const u8) ?Change {
 95         for (self.items.items) |item| {
 96             if (std.mem.eql(u8, item.entry.path, path)) return item;
 97         }
 98         return null;
 99     }
100 };
101 
102 pub fn sameEntry(left: Entry, right: Entry) bool {
103     return left.kind == right.kind and
104         left.bytes == right.bytes and
105         std.mem.eql(u8, left.path, right.path) and
106         std.mem.eql(u8, left.hash, right.hash) and
107         std.mem.eql(u8, left.target, right.target);
108 }
109 
110 test "change set owns cloned entries" {
111     var set = Set.init(std.testing.allocator);
112     defer set.deinit();
113 
114     var path = try std.testing.allocator.dupe(u8, "a.txt");
115     defer std.testing.allocator.free(path);
116     var hash = try std.testing.allocator.dupe(u8, "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
117     defer std.testing.allocator.free(hash);
118 
119     try set.append(.put, .{
120         .path = path,
121         .kind = .file,
122         .hash = hash,
123         .bytes = 4,
124     });
125     path[0] = 'b';
126     hash["sha256:".len] = 'b';
127 
128     const found = set.find("a.txt").?;
129     try std.testing.expectEqual(Operation.put, found.operation);
130     try std.testing.expectEqual(Kind.file, found.entry.kind);
131     try std.testing.expectEqualStrings("sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", found.entry.hash);
132 }