authorgravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2026-04-12 14:17:45 -07:00
committergravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2026-04-12 14:17:45 -07:00
log121c3cf37a8edff8e23e3fcf946c677970140e5a
tree389b1af7ca5391a88f46cd41bc130658a4451281
parent27e0c4ec7689f804bb7bac3c467468a2cc996bb2
signaturebadge-check Signed by SSH key SHA256:4hHJbtBRU58AYXwjL7fkz2fnQHdiye8x1QpTCQ0sHNw

implement ref_delta packed object type


1 files changed, 73 insertions(+), 7 deletions(-)

git.zig+73-7
...@@ -950,7 +950,7 @@ pub const Repository = struct {...@@ -950,7 +950,7 @@ pub const Repository = struct {
950 r.tags.deinit(r.gpa);950 r.tags.deinit(r.gpa);
951 }951 }
952952
953 pub fn getObject(r: *Repository, arena: std.mem.Allocator, oid: Id) !?GitObject {953 pub fn getObject(r: *Repository, arena: std.mem.Allocator, oid: Id) anyerror!?GitObject {
954 const t = tracer.trace(@src(), " {s}", .{oid});954 const t = tracer.trace(@src(), " {s}", .{oid});
955 defer t.end();955 defer t.end();
956956
...@@ -1042,10 +1042,10 @@ pub const Repository = struct {...@@ -1042,10 +1042,10 @@ pub const Repository = struct {
1042 // parse .pack1042 // parse .pack
1043 // std.log.debug("pack_index={d} pack_offset={d}", .{ pack_index, pack_offset });1043 // std.log.debug("pack_index={d} pack_offset={d}", .{ pack_index, pack_offset });
10441044
1045 return try r.getPackedObject(oid, pack_index, pack_offset);1045 return try r.getPackedObject(arena, oid, pack_index, pack_offset);
1046 }1046 }
10471047
1048 fn getPackedObject(r: *Repository, maybe_oid: ?Id, pack_index: usize, pack_offset: usize) !GitObject {1048 fn getPackedObject(r: *Repository, arena: std.mem.Allocator, maybe_oid: ?Id, pack_index: usize, pack_offset: usize) !GitObject {
1049 const t = tracer.trace(@src(), " {?s} {d} {d}", .{ maybe_oid, pack_index, pack_offset });1049 const t = tracer.trace(@src(), " {?s} {d} {d}", .{ maybe_oid, pack_index, pack_offset });
1050 defer t.end();1050 defer t.end();
10511051
...@@ -1096,7 +1096,7 @@ pub const Repository = struct {...@@ -1096,7 +1096,7 @@ pub const Repository = struct {
1096 offset += 1;1096 offset += 1;
1097 }1097 }
1098 const base_pack_offset = pack_offset - offset;1098 const base_pack_offset = pack_offset - offset;
1099 const base_obj = try r.getPackedObject(null, pack_index, base_pack_offset);1099 const base_obj = try r.getPackedObject(arena, null, pack_index, base_pack_offset);
1100 // std.log.debug("base: type={s} content=[{d}]", .{ @tagName(base_obj.type), base_obj.content.len });1100 // std.log.debug("base: type={s} content=[{d}]", .{ @tagName(base_obj.type), base_obj.content.len });
11011101
1102 const compressed_content = packedobj_fbs.rest()[0..size];1102 const compressed_content = packedobj_fbs.rest()[0..size];
...@@ -1106,7 +1106,6 @@ pub const Repository = struct {...@@ -1106,7 +1106,6 @@ pub const Repository = struct {
1106 defer list.deinit(r.gpa);1106 defer list.deinit(r.gpa);
1107 try list.ensureUnusedCapacity(r.gpa, size);1107 try list.ensureUnusedCapacity(r.gpa, size);
1108 try std.compress.flate.inflate.decompress(.zlib, bufr.anyReadable(), list.writer(r.gpa));1108 try std.compress.flate.inflate.decompress(.zlib, bufr.anyReadable(), list.writer(r.gpa));
1109
1110 // std.log.debug("transformation data={d}", .{list.items});1109 // std.log.debug("transformation data={d}", .{list.items});
11111110
1112 var unpackedobj_fbs = nio.FixedBufferStream([]const u8).init(list.items);1111 var unpackedobj_fbs = nio.FixedBufferStream([]const u8).init(list.items);
...@@ -1167,8 +1166,75 @@ pub const Repository = struct {...@@ -1167,8 +1166,75 @@ pub const Repository = struct {
1167 return obj;1166 return obj;
1168 },1167 },
1169 .ref_delta => {1168 .ref_delta => {
1170 std.log.debug("type={s} size={d}", .{ @tagName(ty), size });1169 // std.log.debug("type={s} size={d}", .{ @tagName(ty), size });
1171 unreachable;1170 const base_oid = extras.to_hex(packedobj_fbs.takeSlice(20)[0..20].*);
1171 const base_obj = (try r.getObject(arena, &base_oid)).?;
1172
1173 const compressed_content = packedobj_fbs.rest()[0..size];
1174 var bufr = nio.FixedBufferStream([]const u8).init(compressed_content);
1175
1176 var list: std.ArrayListUnmanaged(u8) = .empty;
1177 defer list.deinit(r.gpa);
1178 try list.ensureUnusedCapacity(r.gpa, size);
1179 try std.compress.flate.inflate.decompress(.zlib, bufr.anyReadable(), list.writer(r.gpa));
1180 // std.log.debug("transformation data={d}", .{list.items});
1181
1182 var unpackedobj_fbs = nio.FixedBufferStream([]const u8).init(list.items);
1183
1184 var list2: std.ArrayListUnmanaged(u8) = .empty;
1185 errdefer list2.deinit(r.gpa);
1186
1187 var base_size: usize = 0;
1188 while (true) {
1189 const c2: usize = unpackedobj_fbs.takeByte();
1190 base_size = (base_size << 7) | (c2 & 0x7f);
1191 if (c2 & 0x80 == 0) break;
1192 base_size += 1;
1193 }
1194 // std.log.debug("base_size={d}", .{base_size});
1195
1196 var obj_size: usize = 0;
1197 while (true) {
1198 const c2: usize = unpackedobj_fbs.takeByte();
1199 obj_size = (obj_size << 7) | (c2 & 0x7f);
1200 if (c2 & 0x80 == 0) break;
1201 obj_size += 1;
1202 }
1203 // std.log.debug("obj_size={d}", .{obj_size});
1204
1205 while (unpackedobj_fbs.pos < unpackedobj_fbs.buffer.len) {
1206 const c2 = unpackedobj_fbs.takeByte();
1207 if (c2 & 0x80 > 0) {
1208 // copy range from base
1209 var b: extras.RingBuffer(u8, 7) = .{};
1210 for (0..7) |i| {
1211 const mask = @as(u8, 1) << @intCast(i);
1212 b.append(if (c2 & mask > 0) unpackedobj_fbs.takeByte() else 0);
1213 }
1214 const start: u32 = @bitCast(b.items[0..4].*);
1215 const nbytes: u24 = @bitCast(b.items[4..7].*);
1216 // std.log.debug("- copy from base: start={d} nbytes={d}", .{ start, nbytes });
1217 const bytes = base_obj.content[start..][0..nbytes];
1218 // std.log.debug("{s}\n", .{bytes});
1219 try list2.appendSlice(r.gpa, bytes);
1220 } else {
1221 // append new data
1222 const nbytes = c2 & 0x7f;
1223 // std.log.debug("- append new bytes={d}", .{nbytes});
1224 if (nbytes == 0) continue;
1225 const bytes = unpackedobj_fbs.takeSlice(nbytes);
1226 // std.log.debug("{s}\n", .{bytes});
1227 try list2.appendSlice(r.gpa, bytes);
1228 }
1229 }
1230
1231 // std.log.debug("- done", .{});
1232 // std.log.debug("{s}\n", .{list2.items});
1233 const _type = base_obj.type;
1234 const content = try list2.toOwnedSlice(r.gpa);
1235 const obj: GitObject = .{ .type = _type, .content = content };
1236 if (maybe_oid) |oid| try r.unpacked_objects.put(r.gpa, oid, obj);
1237 return obj;
1172 },1238 },
1173 }1239 }
1174 comptime unreachable;1240 comptime unreachable;