authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-05-09 16:59:13-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-01 16:35:29-07:00
log06b44a0afa849556f613fcc5939db99fec38883f
tree2ba6b36cc75c0480a7ccdd7ba5ec8344e1d7dee5
parentd603121dc355fee44b86a7fdf3666dce6e3ab677

update git fetching logic to new reader/writer API

- flatten std.crypto.hash.Sha1 and give it a writable interface that optimizes splats - flatten std.hash.crc and give it a writable interface that optimizes splats - remove old writer impls from std.crypto - add fs.File.Writer.moveToReader - add fs.File.Writer.seekTo - add std.io.Reader.Hashed and std.io.Writer.Hashed which are passthrough streams. Instead of passing through to null writer, use the writable interface implemented directly on hashers which doesn't have to account for passing through the data. - add std.io.BufferedWriter.writeSplatAll

28 files changed, 1190 insertions(+), 916 deletions(-)

lib/std/compress/flate.zig+5
......@@ -1,5 +1,10 @@
11const std = @import("../std.zig");
22
3/// When decompressing, the output buffer is used as the history window, so
4/// less than this may result in failure to decompress streams that were
5/// compressed with a larger window.
6pub const max_window_len = 1 << 16;
7
38/// Deflate is a lossless data compression file format that uses a combination
49/// of LZ77 and Huffman coding.
510pub const deflate = @import("flate/deflate.zig");
lib/std/compress/flate/inflate.zig+4
......@@ -403,6 +403,10 @@ pub fn Inflate(comptime container: Container, comptime Lookahead: type) type {
403403 },
404404 };
405405 }
406
407 pub fn readable(self: *Self, buffer: []u8) std.io.BufferedReader {
408 return reader(self).buffered(buffer);
409 }
406410 };
407411}
408412
lib/std/compress/zlib.zig+5
......@@ -2,6 +2,11 @@ const std = @import("../std.zig");
22const deflate = @import("flate/deflate.zig");
33const inflate = @import("flate/inflate.zig");
44
5/// When decompressing, the output buffer is used as the history window, so
6/// less than this may result in failure to decompress streams that were
7/// compressed with a larger window.
8pub const max_window_len = std.compress.flate.max_window_len;
9
510/// Decompress compressed data from reader and write plain data to the writer.
611pub fn decompress(reader: *std.io.BufferedReader, writer: *std.io.BufferedWriter) !void {
712 try inflate.decompress(.zlib, reader, writer);
lib/std/crypto.zig+3-3
......@@ -1,5 +1,7 @@
11//! Cryptography.
22
3const std = @import("std.zig");
4const assert = std.debug.assert;
35const root = @import("root");
46
57pub const timing_safe = @import("crypto/timing_safe.zig");
......@@ -119,7 +121,7 @@ pub const hash = struct {
119121 pub const blake2 = @import("crypto/blake2.zig");
120122 pub const Blake3 = @import("crypto/blake3.zig").Blake3;
121123 pub const Md5 = @import("crypto/md5.zig").Md5;
122 pub const Sha1 = @import("crypto/sha1.zig").Sha1;
124 pub const Sha1 = @import("crypto/Sha1.zig");
123125 pub const sha2 = @import("crypto/sha2.zig");
124126 pub const sha3 = @import("crypto/sha3.zig");
125127 pub const composition = @import("crypto/hash_composition.zig");
......@@ -217,8 +219,6 @@ pub const random = @import("crypto/tlcsprng.zig").interface;
217219/// Encoding and decoding
218220pub const codecs = @import("crypto/codecs.zig");
219221
220const std = @import("std.zig");
221
222222pub const errors = @import("crypto/errors.zig");
223223
224224pub const tls = @import("crypto/tls.zig");
lib/std/crypto/Sha1.zig created+424
......@@ -0,0 +1,424 @@
1//! The SHA-1 function is now considered cryptographically broken.
2//! Namely, it is feasible to find multiple inputs producing the same hash.
3//! For a fast-performing, cryptographically secure hash function, see SHA512/256, BLAKE2 or BLAKE3.
4
5const Sha1 = @This();
6const std = @import("../std.zig");
7const mem = std.mem;
8const math = std.math;
9const assert = std.debug.assert;
10
11pub const block_length = 64;
12pub const digest_length = 20;
13pub const Options = struct {};
14
15s: [5]u32,
16/// Streaming Cache
17buf: [64]u8,
18buf_end: u8,
19total_len: u64,
20
21pub fn init(options: Options) Sha1 {
22 _ = options;
23 return .{
24 .s = [_]u32{
25 0x67452301,
26 0xEFCDAB89,
27 0x98BADCFE,
28 0x10325476,
29 0xC3D2E1F0,
30 },
31 .buf = undefined,
32 .buf_end = 0,
33 .total_len = 0,
34 };
35}
36
37pub fn hash(b: []const u8, out: *[digest_length]u8, options: Options) void {
38 var d = Sha1.init(options);
39 d.update(b);
40 d.final(out);
41}
42
43pub fn update(d: *Sha1, b: []const u8) void {
44 var off: usize = 0;
45
46 // Partial buffer exists from previous update. Copy into buffer then hash.
47 const unused_buf = d.buf[d.buf_end..];
48 if (unused_buf.len < d.buf.len and b.len >= unused_buf.len) {
49 @memcpy(unused_buf, b[0..unused_buf.len]);
50 off += unused_buf.len;
51 round(&d.s, &d.buf);
52 d.buf_end = 0;
53 }
54
55 // Full middle blocks.
56 while (off + 64 <= b.len) : (off += 64) {
57 round(&d.s, b[off..][0..64]);
58 }
59
60 // Copy any remainder for next pass.
61 const remainder = b[off..];
62 @memcpy(d.buf[d.buf_end..][0..remainder.len], remainder);
63 d.buf_end = @intCast(d.buf_end + remainder.len);
64 d.total_len += b.len;
65}
66
67pub fn peek(d: Sha1) [digest_length]u8 {
68 var copy = d;
69 return copy.finalResult();
70}
71
72pub fn final(d: *Sha1, out: *[digest_length]u8) void {
73 // The buffer here will never be completely full.
74 @memset(d.buf[d.buf_end..], 0);
75
76 // Append padding bits.
77 d.buf[d.buf_end] = 0x80;
78 d.buf_end += 1;
79
80 // > 448 mod 512 so need to add an extra round to wrap around.
81 if (64 - d.buf_end < 8) {
82 round(&d.s, d.buf[0..]);
83 @memset(d.buf[0..], 0);
84 }
85
86 // Append message length.
87 var i: usize = 1;
88 var len = d.total_len >> 5;
89 d.buf[63] = @as(u8, @intCast(d.total_len & 0x1f)) << 3;
90 while (i < 8) : (i += 1) {
91 d.buf[63 - i] = @as(u8, @intCast(len & 0xff));
92 len >>= 8;
93 }
94
95 round(&d.s, d.buf[0..]);
96
97 for (d.s, 0..) |s, j| {
98 mem.writeInt(u32, out[4 * j ..][0..4], s, .big);
99 }
100}
101
102pub fn finalResult(d: *Sha1) [digest_length]u8 {
103 var result: [digest_length]u8 = undefined;
104 d.final(&result);
105 return result;
106}
107
108pub fn round(d_s: *[5]u32, b: *const [64]u8) void {
109 var s: [16]u32 = undefined;
110
111 var v: [5]u32 = [_]u32{
112 d_s[0],
113 d_s[1],
114 d_s[2],
115 d_s[3],
116 d_s[4],
117 };
118
119 const round0a = comptime [_]RoundParam{
120 .abcdei(0, 1, 2, 3, 4, 0),
121 .abcdei(4, 0, 1, 2, 3, 1),
122 .abcdei(3, 4, 0, 1, 2, 2),
123 .abcdei(2, 3, 4, 0, 1, 3),
124 .abcdei(1, 2, 3, 4, 0, 4),
125 .abcdei(0, 1, 2, 3, 4, 5),
126 .abcdei(4, 0, 1, 2, 3, 6),
127 .abcdei(3, 4, 0, 1, 2, 7),
128 .abcdei(2, 3, 4, 0, 1, 8),
129 .abcdei(1, 2, 3, 4, 0, 9),
130 .abcdei(0, 1, 2, 3, 4, 10),
131 .abcdei(4, 0, 1, 2, 3, 11),
132 .abcdei(3, 4, 0, 1, 2, 12),
133 .abcdei(2, 3, 4, 0, 1, 13),
134 .abcdei(1, 2, 3, 4, 0, 14),
135 .abcdei(0, 1, 2, 3, 4, 15),
136 };
137 inline for (round0a) |r| {
138 s[r.i] = mem.readInt(u32, b[r.i * 4 ..][0..4], .big);
139
140 v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], @as(u32, 5)) +% 0x5A827999 +% s[r.i & 0xf] +% ((v[r.b] & v[r.c]) | (~v[r.b] & v[r.d]));
141 v[r.b] = math.rotl(u32, v[r.b], @as(u32, 30));
142 }
143
144 const round0b = comptime [_]RoundParam{
145 .abcdei(4, 0, 1, 2, 3, 16),
146 .abcdei(3, 4, 0, 1, 2, 17),
147 .abcdei(2, 3, 4, 0, 1, 18),
148 .abcdei(1, 2, 3, 4, 0, 19),
149 };
150 inline for (round0b) |r| {
151 const t = s[(r.i - 3) & 0xf] ^ s[(r.i - 8) & 0xf] ^ s[(r.i - 14) & 0xf] ^ s[(r.i - 16) & 0xf];
152 s[r.i & 0xf] = math.rotl(u32, t, @as(u32, 1));
153
154 v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], @as(u32, 5)) +% 0x5A827999 +% s[r.i & 0xf] +% ((v[r.b] & v[r.c]) | (~v[r.b] & v[r.d]));
155 v[r.b] = math.rotl(u32, v[r.b], @as(u32, 30));
156 }
157
158 const round1 = comptime [_]RoundParam{
159 .abcdei(0, 1, 2, 3, 4, 20),
160 .abcdei(4, 0, 1, 2, 3, 21),
161 .abcdei(3, 4, 0, 1, 2, 22),
162 .abcdei(2, 3, 4, 0, 1, 23),
163 .abcdei(1, 2, 3, 4, 0, 24),
164 .abcdei(0, 1, 2, 3, 4, 25),
165 .abcdei(4, 0, 1, 2, 3, 26),
166 .abcdei(3, 4, 0, 1, 2, 27),
167 .abcdei(2, 3, 4, 0, 1, 28),
168 .abcdei(1, 2, 3, 4, 0, 29),
169 .abcdei(0, 1, 2, 3, 4, 30),
170 .abcdei(4, 0, 1, 2, 3, 31),
171 .abcdei(3, 4, 0, 1, 2, 32),
172 .abcdei(2, 3, 4, 0, 1, 33),
173 .abcdei(1, 2, 3, 4, 0, 34),
174 .abcdei(0, 1, 2, 3, 4, 35),
175 .abcdei(4, 0, 1, 2, 3, 36),
176 .abcdei(3, 4, 0, 1, 2, 37),
177 .abcdei(2, 3, 4, 0, 1, 38),
178 .abcdei(1, 2, 3, 4, 0, 39),
179 };
180 inline for (round1) |r| {
181 const t = s[(r.i - 3) & 0xf] ^ s[(r.i - 8) & 0xf] ^ s[(r.i - 14) & 0xf] ^ s[(r.i - 16) & 0xf];
182 s[r.i & 0xf] = math.rotl(u32, t, @as(u32, 1));
183
184 v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], @as(u32, 5)) +% 0x6ED9EBA1 +% s[r.i & 0xf] +% (v[r.b] ^ v[r.c] ^ v[r.d]);
185 v[r.b] = math.rotl(u32, v[r.b], @as(u32, 30));
186 }
187
188 const round2 = comptime [_]RoundParam{
189 .abcdei(0, 1, 2, 3, 4, 40),
190 .abcdei(4, 0, 1, 2, 3, 41),
191 .abcdei(3, 4, 0, 1, 2, 42),
192 .abcdei(2, 3, 4, 0, 1, 43),
193 .abcdei(1, 2, 3, 4, 0, 44),
194 .abcdei(0, 1, 2, 3, 4, 45),
195 .abcdei(4, 0, 1, 2, 3, 46),
196 .abcdei(3, 4, 0, 1, 2, 47),
197 .abcdei(2, 3, 4, 0, 1, 48),
198 .abcdei(1, 2, 3, 4, 0, 49),
199 .abcdei(0, 1, 2, 3, 4, 50),
200 .abcdei(4, 0, 1, 2, 3, 51),
201 .abcdei(3, 4, 0, 1, 2, 52),
202 .abcdei(2, 3, 4, 0, 1, 53),
203 .abcdei(1, 2, 3, 4, 0, 54),
204 .abcdei(0, 1, 2, 3, 4, 55),
205 .abcdei(4, 0, 1, 2, 3, 56),
206 .abcdei(3, 4, 0, 1, 2, 57),
207 .abcdei(2, 3, 4, 0, 1, 58),
208 .abcdei(1, 2, 3, 4, 0, 59),
209 };
210 inline for (round2) |r| {
211 const t = s[(r.i - 3) & 0xf] ^ s[(r.i - 8) & 0xf] ^ s[(r.i - 14) & 0xf] ^ s[(r.i - 16) & 0xf];
212 s[r.i & 0xf] = math.rotl(u32, t, @as(u32, 1));
213
214 v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], @as(u32, 5)) +% 0x8F1BBCDC +% s[r.i & 0xf] +% ((v[r.b] & v[r.c]) ^ (v[r.b] & v[r.d]) ^ (v[r.c] & v[r.d]));
215 v[r.b] = math.rotl(u32, v[r.b], @as(u32, 30));
216 }
217
218 const round3 = comptime [_]RoundParam{
219 .abcdei(0, 1, 2, 3, 4, 60),
220 .abcdei(4, 0, 1, 2, 3, 61),
221 .abcdei(3, 4, 0, 1, 2, 62),
222 .abcdei(2, 3, 4, 0, 1, 63),
223 .abcdei(1, 2, 3, 4, 0, 64),
224 .abcdei(0, 1, 2, 3, 4, 65),
225 .abcdei(4, 0, 1, 2, 3, 66),
226 .abcdei(3, 4, 0, 1, 2, 67),
227 .abcdei(2, 3, 4, 0, 1, 68),
228 .abcdei(1, 2, 3, 4, 0, 69),
229 .abcdei(0, 1, 2, 3, 4, 70),
230 .abcdei(4, 0, 1, 2, 3, 71),
231 .abcdei(3, 4, 0, 1, 2, 72),
232 .abcdei(2, 3, 4, 0, 1, 73),
233 .abcdei(1, 2, 3, 4, 0, 74),
234 .abcdei(0, 1, 2, 3, 4, 75),
235 .abcdei(4, 0, 1, 2, 3, 76),
236 .abcdei(3, 4, 0, 1, 2, 77),
237 .abcdei(2, 3, 4, 0, 1, 78),
238 .abcdei(1, 2, 3, 4, 0, 79),
239 };
240 inline for (round3) |r| {
241 const t = s[(r.i - 3) & 0xf] ^ s[(r.i - 8) & 0xf] ^ s[(r.i - 14) & 0xf] ^ s[(r.i - 16) & 0xf];
242 s[r.i & 0xf] = math.rotl(u32, t, @as(u32, 1));
243
244 v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], @as(u32, 5)) +% 0xCA62C1D6 +% s[r.i & 0xf] +% (v[r.b] ^ v[r.c] ^ v[r.d]);
245 v[r.b] = math.rotl(u32, v[r.b], @as(u32, 30));
246 }
247
248 d_s[0] +%= v[0];
249 d_s[1] +%= v[1];
250 d_s[2] +%= v[2];
251 d_s[3] +%= v[3];
252 d_s[4] +%= v[4];
253}
254
255pub fn writable(sha1: *Sha1, buffer: []u8) std.io.BufferedWriter {
256 return .{
257 .unbuffered_writer = .{
258 .context = sha1,
259 .vtable = &.{
260 .writeSplat = writeSplat,
261 .writeFile = std.io.Writer.unimplementedWriteFile,
262 },
263 },
264 .buffer = buffer,
265 };
266}
267
268fn writeSplat(context: ?*anyopaque, data: []const []const u8, splat: usize) std.io.Writer.Error!usize {
269 const sha1: *Sha1 = @ptrCast(@alignCast(context));
270 const start_total = sha1.total_len;
271 if (sha1.buf_end == 0) {
272 try writeSplatAligned(sha1, data, splat);
273 const n: usize = @intCast(sha1.total_len - start_total);
274 if (n > 0) return n;
275 }
276 for (data[0 .. data.len - 1]) |slice| {
277 const copy_len = @min(slice.len, sha1.buf.len - sha1.buf_end);
278 @memcpy(sha1.buf[sha1.buf_end..][0..copy_len], slice[0..copy_len]);
279 sha1.total_len += copy_len;
280 if (sha1.buf.len - sha1.buf_end - copy_len == 0) {
281 round(&sha1.s, &sha1.buf);
282 sha1.buf_end = 0;
283 return @intCast(sha1.total_len - start_total);
284 }
285 sha1.buf_end = @intCast(sha1.buf_end + copy_len);
286 }
287 const slice = data[data.len - 1];
288 for (0..splat) |_| {
289 const copy_len = @min(slice.len, sha1.buf.len - sha1.buf_end);
290 @memcpy(sha1.buf[sha1.buf_end..][0..copy_len], slice[0..copy_len]);
291 sha1.total_len += copy_len;
292 if (sha1.buf.len - sha1.buf_end - copy_len == 0) {
293 round(&sha1.s, &sha1.buf);
294 sha1.buf_end = 0;
295 return @intCast(sha1.total_len - start_total);
296 }
297 sha1.buf_end = @intCast(sha1.buf_end + copy_len);
298 }
299 return @intCast(sha1.total_len - start_total);
300}
301
302fn writeSplatAligned(sha1: *Sha1, data: []const []const u8, splat: usize) std.io.Writer.Error!void {
303 assert(sha1.buf_end == 0);
304 for (data[0 .. data.len - 1]) |slice| {
305 var off: usize = 0;
306 while (off < slice.len) {
307 if (off + 64 > slice.len) {
308 sha1.total_len += off;
309 return;
310 }
311 round(&sha1.s, slice[off..][0..64]);
312 off += 64;
313 }
314 sha1.total_len += off;
315 }
316 const last = data[data.len - 1];
317 if (last.len * splat < 64) return;
318 if (last.len == 1) {
319 @memset(&sha1.buf, last[0]);
320 for (0..splat / 64) |_| round(&sha1.s, &sha1.buf);
321 sha1.total_len += (splat / 64) * 64;
322 return;
323 }
324 if (last.len >= 64) {
325 for (0..splat) |_| {
326 var off: usize = 0;
327 while (off < last.len) {
328 if (off + 64 > last.len) {
329 sha1.total_len += off;
330 return;
331 }
332 round(&sha1.s, last[off..][0..64]);
333 off += 64;
334 }
335 }
336 sha1.total_len += last.len * splat;
337 return;
338 }
339 // Opportunity: if last.len is less than 64, we could fill up the buffer
340 // with the pattern repeated then do rounds.
341}
342
343const RoundParam = struct {
344 a: usize,
345 b: usize,
346 c: usize,
347 d: usize,
348 e: usize,
349 i: u32,
350
351 fn abcdei(a: usize, b: usize, c: usize, d: usize, e: usize, i: u32) RoundParam {
352 return .{
353 .a = a,
354 .b = b,
355 .c = c,
356 .d = d,
357 .e = e,
358 .i = i,
359 };
360 }
361};
362
363const htest = @import("test.zig");
364
365test "sha1 single" {
366 try htest.assertEqualHash(Sha1, "da39a3ee5e6b4b0d3255bfef95601890afd80709", "");
367 try htest.assertEqualHash(Sha1, "a9993e364706816aba3e25717850c26c9cd0d89d", "abc");
368 try htest.assertEqualHash(Sha1, "a49b2446a02c645bf419f995b67091253a04a259", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
369}
370
371test "sha1 streaming" {
372 var h = Sha1.init(.{});
373 var out: [20]u8 = undefined;
374
375 h.final(&out);
376 try htest.assertEqual("da39a3ee5e6b4b0d3255bfef95601890afd80709", out[0..]);
377
378 h = Sha1.init(.{});
379 h.update("abc");
380 h.final(&out);
381 try htest.assertEqual("a9993e364706816aba3e25717850c26c9cd0d89d", out[0..]);
382
383 h = Sha1.init(.{});
384 h.update("a");
385 h.update("b");
386 h.update("c");
387 h.final(&out);
388 try htest.assertEqual("a9993e364706816aba3e25717850c26c9cd0d89d", out[0..]);
389}
390
391test "sha1 aligned final" {
392 var block = [_]u8{0} ** Sha1.block_length;
393 var out: [Sha1.digest_length]u8 = undefined;
394
395 var h = Sha1.init(.{});
396 h.update(&block);
397 h.final(out[0..]);
398}
399
400test "splat" {
401 var vecs = [_][]const u8{
402 "hello",
403 "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstuyyyyyyyyyyyyyyyyyyyyyyyyy",
404 "x",
405 };
406 const splat_len = 512;
407 const update_result = r: {
408 var sha1: Sha1 = .init(.{});
409 sha1.update(vecs[0]);
410 sha1.update(vecs[1]);
411 var buffer: [splat_len]u8 = undefined;
412 @memset(&buffer, vecs[2][0]);
413 sha1.update(&buffer);
414 break :r sha1.finalResult();
415 };
416 const stream_result = r: {
417 var sha1: Sha1 = .init(.{});
418 var bw = sha1.writable(&.{});
419 try bw.writeSplatAll(&vecs, splat_len);
420 try std.testing.expectEqual(vecs[0].len + vecs[1].len + vecs[2].len * splat_len, sha1.total_len);
421 break :r sha1.finalResult();
422 };
423 try std.testing.expectEqualSlices(u8, &update_result, &stream_result);
424}
lib/std/crypto/aegis.zig-12
......@@ -801,18 +801,6 @@ fn AegisMac(comptime T: type) type {
801801 ctx.update(msg);
802802 ctx.final(out);
803803 }
804
805 pub const Error = error{};
806 pub const Writer = std.io.Writer(*Mac, Error, write);
807
808 fn write(self: *Mac, bytes: []const u8) Error!usize {
809 self.update(bytes);
810 return bytes.len;
811 }
812
813 pub fn writer(self: *Mac) Writer {
814 return .{ .context = self };
815 }
816804 };
817805}
818806
lib/std/crypto/blake2.zig-12
......@@ -185,18 +185,6 @@ pub fn Blake2s(comptime out_bits: usize) type {
185185 r.* ^= v[i] ^ v[i + 8];
186186 }
187187 }
188
189 pub const Error = error{};
190 pub const Writer = std.io.Writer(*Self, Error, write);
191
192 fn write(self: *Self, bytes: []const u8) Error!usize {
193 self.update(bytes);
194 return bytes.len;
195 }
196
197 pub fn writer(self: *Self) Writer {
198 return .{ .context = self };
199 }
200188 };
201189}
202190
lib/std/crypto/blake3.zig-12
......@@ -474,18 +474,6 @@ pub const Blake3 = struct {
474474 }
475475 output.rootOutputBytes(out_slice);
476476 }
477
478 pub const Error = error{};
479 pub const Writer = std.io.Writer(*Blake3, Error, write);
480
481 fn write(self: *Blake3, bytes: []const u8) Error!usize {
482 self.update(bytes);
483 return bytes.len;
484 }
485
486 pub fn writer(self: *Blake3) Writer {
487 return .{ .context = self };
488 }
489477};
490478
491479// Use named type declarations to workaround crash with anonymous structs (issue #4373).
lib/std/crypto/codecs/asn1.zig+8-15
......@@ -90,39 +90,32 @@ pub const Tag = struct {
9090 };
9191 }
9292
93 pub fn encode(self: Tag, writer: anytype) @TypeOf(writer).Error!void {
94 var tag1 = FirstTag{
93 pub fn encode(self: Tag, writer: *std.io.BufferedWriter) std.io.Writer.Error!void {
94 var tag1: FirstTag = .{
9595 .number = undefined,
9696 .constructed = self.constructed,
9797 .class = self.class,
9898 };
99
100 var buffer: [3]u8 = undefined;
101 var stream = std.io.fixedBufferStream(&buffer);
102 var writer2 = stream.writer();
103
10499 switch (@intFromEnum(self.number)) {
105100 0...std.math.maxInt(u5) => |n| {
106101 tag1.number = @intCast(n);
107 writer2.writeByte(@bitCast(tag1)) catch unreachable;
102 try writer.writeByte(@bitCast(tag1));
108103 },
109104 std.math.maxInt(u5) + 1...std.math.maxInt(u7) => |n| {
110105 tag1.number = 15;
111106 const tag2 = NextTag{ .number = @intCast(n), .continues = false };
112 writer2.writeByte(@bitCast(tag1)) catch unreachable;
113 writer2.writeByte(@bitCast(tag2)) catch unreachable;
107 try writer.writeByte(@bitCast(tag1));
108 try writer.writeByte(@bitCast(tag2));
114109 },
115110 else => |n| {
116111 tag1.number = 15;
117112 const tag2 = NextTag{ .number = @intCast(n >> 7), .continues = true };
118113 const tag3 = NextTag{ .number = @truncate(n), .continues = false };
119 writer2.writeByte(@bitCast(tag1)) catch unreachable;
120 writer2.writeByte(@bitCast(tag2)) catch unreachable;
121 writer2.writeByte(@bitCast(tag3)) catch unreachable;
114 try writer.writeByte(@bitCast(tag1));
115 try writer.writeByte(@bitCast(tag2));
116 try writer.writeByte(@bitCast(tag3));
122117 },
123118 }
124
125 _ = try writer.write(stream.getWritten());
126119 }
127120
128121 const FirstTag = packed struct(u8) { number: u5, constructed: bool, class: Tag.Class };
lib/std/crypto/codecs/asn1/Oid.zig+24-13
......@@ -4,9 +4,12 @@
44//! organizations, or policy documents.
55encoded: []const u8,
66
7pub const InitError = std.fmt.ParseIntError || error{MissingPrefix} || std.io.FixedBufferStream(u8).WriteError;
7pub const EncodeError = error{
8 WriteFailed,
9 MissingPrefix,
10};
811
9pub fn fromDot(dot_notation: []const u8, out: []u8) InitError!Oid {
12pub fn encode(dot_notation: []const u8, out: *std.io.BufferedWriter) EncodeError!void {
1013 var split = std.mem.splitScalar(u8, dot_notation, '.');
1114 const first_str = split.next() orelse return error.MissingPrefix;
1215 const second_str = split.next() orelse return error.MissingPrefix;
......@@ -14,10 +17,7 @@ pub fn fromDot(dot_notation: []const u8, out: []u8) InitError!Oid {
1417 const first = try std.fmt.parseInt(u8, first_str, 10);
1518 const second = try std.fmt.parseInt(u8, second_str, 10);
1619
17 var stream = std.io.fixedBufferStream(out);
18 var writer = stream.writer();
19
20 try writer.writeByte(first * 40 + second);
20 try out.writeByte(first * 40 + second);
2121
2222 var i: usize = 1;
2323 while (split.next()) |s| {
......@@ -28,16 +28,26 @@ pub fn fromDot(dot_notation: []const u8, out: []u8) InitError!Oid {
2828 const place = std.math.pow(Arc, encoding_base, n_bytes - @as(Arc, @intCast(j)));
2929 const digit: u8 = @intCast(@divFloor(parsed, place));
3030
31 try writer.writeByte(digit | 0x80);
31 try out.writeByte(digit | 0x80);
3232 parsed -= digit * place;
3333
3434 i += 1;
3535 }
36 try writer.writeByte(@intCast(parsed));
36 try out.writeByte(@intCast(parsed));
3737 i += 1;
3838 }
39}
3940
40 return .{ .encoded = stream.getWritten() };
41pub const InitError = std.fmt.ParseIntError || error{ MissingPrefix, BufferTooSmall };
42
43pub fn fromDot(dot_notation: []const u8, out: []u8) InitError!Oid {
44 var bw: std.io.BufferedWriter = undefined;
45 bw.initFixed(out);
46 encode(dot_notation, &bw) catch |err| switch (err) {
47 error.WriteFailed => return error.BufferTooSmall,
48 else => |e| return e,
49 };
50 return .{ .encoded = bw.getWritten() };
4151}
4252
4353test fromDot {
......@@ -48,7 +58,7 @@ test fromDot {
4858 }
4959}
5060
51pub fn toDot(self: Oid, writer: anytype) @TypeOf(writer).Error!void {
61pub fn toDot(self: Oid, writer: *std.io.BufferedWriter) std.io.Writer.Error!void {
5262 const encoded = self.encoded;
5363 const first = @divTrunc(encoded[0], 40);
5464 const second = encoded[0] - first * 40;
......@@ -80,9 +90,10 @@ test toDot {
8090 var buf: [256]u8 = undefined;
8191
8292 for (test_cases) |t| {
83 var stream = std.io.fixedBufferStream(&buf);
84 try toDot(Oid{ .encoded = t.encoded }, stream.writer());
85 try std.testing.expectEqualStrings(t.dot_notation, stream.getWritten());
93 var bw: std.io.BufferedWriter = undefined;
94 bw.initFixed(&buf);
95 try toDot(Oid{ .encoded = t.encoded }, &bw);
96 try std.testing.expectEqualStrings(t.dot_notation, bw.getWritten());
8697 }
8798}
8899
lib/std/crypto/phc_encoding.zig+5-3
......@@ -196,9 +196,11 @@ pub fn serialize(params: anytype, str: []u8) Error![]const u8 {
196196
197197/// Compute the number of bytes required to serialize `params`
198198pub fn calcSize(params: anytype) usize {
199 var buf = io.countingWriter(io.null_writer);
200 serializeTo(params, buf.writer()) catch unreachable;
201 return @as(usize, @intCast(buf.bytes_written));
199 var null_writer: std.io.Writer.Null = .{};
200 var trash: [128]u8 = undefined;
201 var bw = null_writer.writable(&trash);
202 serializeTo(params, &bw) catch unreachable;
203 return bw.count;
202204}
203205
204206fn serializeTo(params: anytype, out: *std.io.BufferedWriter) !void {
lib/std/crypto/sha1.zig deleted-319
......@@ -1,319 +0,0 @@
1const std = @import("../std.zig");
2const mem = std.mem;
3const math = std.math;
4
5const RoundParam = struct {
6 a: usize,
7 b: usize,
8 c: usize,
9 d: usize,
10 e: usize,
11 i: u32,
12};
13
14fn roundParam(a: usize, b: usize, c: usize, d: usize, e: usize, i: u32) RoundParam {
15 return RoundParam{
16 .a = a,
17 .b = b,
18 .c = c,
19 .d = d,
20 .e = e,
21 .i = i,
22 };
23}
24
25/// The SHA-1 function is now considered cryptographically broken.
26/// Namely, it is feasible to find multiple inputs producing the same hash.
27/// For a fast-performing, cryptographically secure hash function, see SHA512/256, BLAKE2 or BLAKE3.
28pub const Sha1 = struct {
29 const Self = @This();
30 pub const block_length = 64;
31 pub const digest_length = 20;
32 pub const Options = struct {};
33
34 s: [5]u32,
35 // Streaming Cache
36 buf: [64]u8 = undefined,
37 buf_len: u8 = 0,
38 total_len: u64 = 0,
39
40 pub fn init(options: Options) Self {
41 _ = options;
42 return Self{
43 .s = [_]u32{
44 0x67452301,
45 0xEFCDAB89,
46 0x98BADCFE,
47 0x10325476,
48 0xC3D2E1F0,
49 },
50 };
51 }
52
53 pub fn hash(b: []const u8, out: *[digest_length]u8, options: Options) void {
54 var d = Sha1.init(options);
55 d.update(b);
56 d.final(out);
57 }
58
59 pub fn update(d: *Self, b: []const u8) void {
60 var off: usize = 0;
61
62 // Partial buffer exists from previous update. Copy into buffer then hash.
63 if (d.buf_len != 0 and d.buf_len + b.len >= 64) {
64 off += 64 - d.buf_len;
65 @memcpy(d.buf[d.buf_len..][0..off], b[0..off]);
66
67 d.round(d.buf[0..]);
68 d.buf_len = 0;
69 }
70
71 // Full middle blocks.
72 while (off + 64 <= b.len) : (off += 64) {
73 d.round(b[off..][0..64]);
74 }
75
76 // Copy any remainder for next pass.
77 @memcpy(d.buf[d.buf_len..][0 .. b.len - off], b[off..]);
78 d.buf_len += @as(u8, @intCast(b[off..].len));
79
80 d.total_len += b.len;
81 }
82
83 pub fn peek(d: Self) [digest_length]u8 {
84 var copy = d;
85 return copy.finalResult();
86 }
87
88 pub fn final(d: *Self, out: *[digest_length]u8) void {
89 // The buffer here will never be completely full.
90 @memset(d.buf[d.buf_len..], 0);
91
92 // Append padding bits.
93 d.buf[d.buf_len] = 0x80;
94 d.buf_len += 1;
95
96 // > 448 mod 512 so need to add an extra round to wrap around.
97 if (64 - d.buf_len < 8) {
98 d.round(d.buf[0..]);
99 @memset(d.buf[0..], 0);
100 }
101
102 // Append message length.
103 var i: usize = 1;
104 var len = d.total_len >> 5;
105 d.buf[63] = @as(u8, @intCast(d.total_len & 0x1f)) << 3;
106 while (i < 8) : (i += 1) {
107 d.buf[63 - i] = @as(u8, @intCast(len & 0xff));
108 len >>= 8;
109 }
110
111 d.round(d.buf[0..]);
112
113 for (d.s, 0..) |s, j| {
114 mem.writeInt(u32, out[4 * j ..][0..4], s, .big);
115 }
116 }
117
118 pub fn finalResult(d: *Self) [digest_length]u8 {
119 var result: [digest_length]u8 = undefined;
120 d.final(&result);
121 return result;
122 }
123
124 fn round(d: *Self, b: *const [64]u8) void {
125 var s: [16]u32 = undefined;
126
127 var v: [5]u32 = [_]u32{
128 d.s[0],
129 d.s[1],
130 d.s[2],
131 d.s[3],
132 d.s[4],
133 };
134
135 const round0a = comptime [_]RoundParam{
136 roundParam(0, 1, 2, 3, 4, 0),
137 roundParam(4, 0, 1, 2, 3, 1),
138 roundParam(3, 4, 0, 1, 2, 2),
139 roundParam(2, 3, 4, 0, 1, 3),
140 roundParam(1, 2, 3, 4, 0, 4),
141 roundParam(0, 1, 2, 3, 4, 5),
142 roundParam(4, 0, 1, 2, 3, 6),
143 roundParam(3, 4, 0, 1, 2, 7),
144 roundParam(2, 3, 4, 0, 1, 8),
145 roundParam(1, 2, 3, 4, 0, 9),
146 roundParam(0, 1, 2, 3, 4, 10),
147 roundParam(4, 0, 1, 2, 3, 11),
148 roundParam(3, 4, 0, 1, 2, 12),
149 roundParam(2, 3, 4, 0, 1, 13),
150 roundParam(1, 2, 3, 4, 0, 14),
151 roundParam(0, 1, 2, 3, 4, 15),
152 };
153 inline for (round0a) |r| {
154 s[r.i] = mem.readInt(u32, b[r.i * 4 ..][0..4], .big);
155
156 v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], @as(u32, 5)) +% 0x5A827999 +% s[r.i & 0xf] +% ((v[r.b] & v[r.c]) | (~v[r.b] & v[r.d]));
157 v[r.b] = math.rotl(u32, v[r.b], @as(u32, 30));
158 }
159
160 const round0b = comptime [_]RoundParam{
161 roundParam(4, 0, 1, 2, 3, 16),
162 roundParam(3, 4, 0, 1, 2, 17),
163 roundParam(2, 3, 4, 0, 1, 18),
164 roundParam(1, 2, 3, 4, 0, 19),
165 };
166 inline for (round0b) |r| {
167 const t = s[(r.i - 3) & 0xf] ^ s[(r.i - 8) & 0xf] ^ s[(r.i - 14) & 0xf] ^ s[(r.i - 16) & 0xf];
168 s[r.i & 0xf] = math.rotl(u32, t, @as(u32, 1));
169
170 v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], @as(u32, 5)) +% 0x5A827999 +% s[r.i & 0xf] +% ((v[r.b] & v[r.c]) | (~v[r.b] & v[r.d]));
171 v[r.b] = math.rotl(u32, v[r.b], @as(u32, 30));
172 }
173
174 const round1 = comptime [_]RoundParam{
175 roundParam(0, 1, 2, 3, 4, 20),
176 roundParam(4, 0, 1, 2, 3, 21),
177 roundParam(3, 4, 0, 1, 2, 22),
178 roundParam(2, 3, 4, 0, 1, 23),
179 roundParam(1, 2, 3, 4, 0, 24),
180 roundParam(0, 1, 2, 3, 4, 25),
181 roundParam(4, 0, 1, 2, 3, 26),
182 roundParam(3, 4, 0, 1, 2, 27),
183 roundParam(2, 3, 4, 0, 1, 28),
184 roundParam(1, 2, 3, 4, 0, 29),
185 roundParam(0, 1, 2, 3, 4, 30),
186 roundParam(4, 0, 1, 2, 3, 31),
187 roundParam(3, 4, 0, 1, 2, 32),
188 roundParam(2, 3, 4, 0, 1, 33),
189 roundParam(1, 2, 3, 4, 0, 34),
190 roundParam(0, 1, 2, 3, 4, 35),
191 roundParam(4, 0, 1, 2, 3, 36),
192 roundParam(3, 4, 0, 1, 2, 37),
193 roundParam(2, 3, 4, 0, 1, 38),
194 roundParam(1, 2, 3, 4, 0, 39),
195 };
196 inline for (round1) |r| {
197 const t = s[(r.i - 3) & 0xf] ^ s[(r.i - 8) & 0xf] ^ s[(r.i - 14) & 0xf] ^ s[(r.i - 16) & 0xf];
198 s[r.i & 0xf] = math.rotl(u32, t, @as(u32, 1));
199
200 v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], @as(u32, 5)) +% 0x6ED9EBA1 +% s[r.i & 0xf] +% (v[r.b] ^ v[r.c] ^ v[r.d]);
201 v[r.b] = math.rotl(u32, v[r.b], @as(u32, 30));
202 }
203
204 const round2 = comptime [_]RoundParam{
205 roundParam(0, 1, 2, 3, 4, 40),
206 roundParam(4, 0, 1, 2, 3, 41),
207 roundParam(3, 4, 0, 1, 2, 42),
208 roundParam(2, 3, 4, 0, 1, 43),
209 roundParam(1, 2, 3, 4, 0, 44),
210 roundParam(0, 1, 2, 3, 4, 45),
211 roundParam(4, 0, 1, 2, 3, 46),
212 roundParam(3, 4, 0, 1, 2, 47),
213 roundParam(2, 3, 4, 0, 1, 48),
214 roundParam(1, 2, 3, 4, 0, 49),
215 roundParam(0, 1, 2, 3, 4, 50),
216 roundParam(4, 0, 1, 2, 3, 51),
217 roundParam(3, 4, 0, 1, 2, 52),
218 roundParam(2, 3, 4, 0, 1, 53),
219 roundParam(1, 2, 3, 4, 0, 54),
220 roundParam(0, 1, 2, 3, 4, 55),
221 roundParam(4, 0, 1, 2, 3, 56),
222 roundParam(3, 4, 0, 1, 2, 57),
223 roundParam(2, 3, 4, 0, 1, 58),
224 roundParam(1, 2, 3, 4, 0, 59),
225 };
226 inline for (round2) |r| {
227 const t = s[(r.i - 3) & 0xf] ^ s[(r.i - 8) & 0xf] ^ s[(r.i - 14) & 0xf] ^ s[(r.i - 16) & 0xf];
228 s[r.i & 0xf] = math.rotl(u32, t, @as(u32, 1));
229
230 v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], @as(u32, 5)) +% 0x8F1BBCDC +% s[r.i & 0xf] +% ((v[r.b] & v[r.c]) ^ (v[r.b] & v[r.d]) ^ (v[r.c] & v[r.d]));
231 v[r.b] = math.rotl(u32, v[r.b], @as(u32, 30));
232 }
233
234 const round3 = comptime [_]RoundParam{
235 roundParam(0, 1, 2, 3, 4, 60),
236 roundParam(4, 0, 1, 2, 3, 61),
237 roundParam(3, 4, 0, 1, 2, 62),
238 roundParam(2, 3, 4, 0, 1, 63),
239 roundParam(1, 2, 3, 4, 0, 64),
240 roundParam(0, 1, 2, 3, 4, 65),
241 roundParam(4, 0, 1, 2, 3, 66),
242 roundParam(3, 4, 0, 1, 2, 67),
243 roundParam(2, 3, 4, 0, 1, 68),
244 roundParam(1, 2, 3, 4, 0, 69),
245 roundParam(0, 1, 2, 3, 4, 70),
246 roundParam(4, 0, 1, 2, 3, 71),
247 roundParam(3, 4, 0, 1, 2, 72),
248 roundParam(2, 3, 4, 0, 1, 73),
249 roundParam(1, 2, 3, 4, 0, 74),
250 roundParam(0, 1, 2, 3, 4, 75),
251 roundParam(4, 0, 1, 2, 3, 76),
252 roundParam(3, 4, 0, 1, 2, 77),
253 roundParam(2, 3, 4, 0, 1, 78),
254 roundParam(1, 2, 3, 4, 0, 79),
255 };
256 inline for (round3) |r| {
257 const t = s[(r.i - 3) & 0xf] ^ s[(r.i - 8) & 0xf] ^ s[(r.i - 14) & 0xf] ^ s[(r.i - 16) & 0xf];
258 s[r.i & 0xf] = math.rotl(u32, t, @as(u32, 1));
259
260 v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], @as(u32, 5)) +% 0xCA62C1D6 +% s[r.i & 0xf] +% (v[r.b] ^ v[r.c] ^ v[r.d]);
261 v[r.b] = math.rotl(u32, v[r.b], @as(u32, 30));
262 }
263
264 d.s[0] +%= v[0];
265 d.s[1] +%= v[1];
266 d.s[2] +%= v[2];
267 d.s[3] +%= v[3];
268 d.s[4] +%= v[4];
269 }
270
271 pub const Error = error{};
272 pub const Writer = std.io.Writer(*Self, Error, write);
273
274 fn write(self: *Self, bytes: []const u8) Error!usize {
275 self.update(bytes);
276 return bytes.len;
277 }
278
279 pub fn writer(self: *Self) Writer {
280 return .{ .context = self };
281 }
282};
283
284const htest = @import("test.zig");
285
286test "sha1 single" {
287 try htest.assertEqualHash(Sha1, "da39a3ee5e6b4b0d3255bfef95601890afd80709", "");
288 try htest.assertEqualHash(Sha1, "a9993e364706816aba3e25717850c26c9cd0d89d", "abc");
289 try htest.assertEqualHash(Sha1, "a49b2446a02c645bf419f995b67091253a04a259", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
290}
291
292test "sha1 streaming" {
293 var h = Sha1.init(.{});
294 var out: [20]u8 = undefined;
295
296 h.final(&out);
297 try htest.assertEqual("da39a3ee5e6b4b0d3255bfef95601890afd80709", out[0..]);
298
299 h = Sha1.init(.{});
300 h.update("abc");
301 h.final(&out);
302 try htest.assertEqual("a9993e364706816aba3e25717850c26c9cd0d89d", out[0..]);
303
304 h = Sha1.init(.{});
305 h.update("a");
306 h.update("b");
307 h.update("c");
308 h.final(&out);
309 try htest.assertEqual("a9993e364706816aba3e25717850c26c9cd0d89d", out[0..]);
310}
311
312test "sha1 aligned final" {
313 var block = [_]u8{0} ** Sha1.block_length;
314 var out: [Sha1.digest_length]u8 = undefined;
315
316 var h = Sha1.init(.{});
317 h.update(&block);
318 h.final(out[0..]);
319}
lib/std/crypto/sha2.zig+27-13
......@@ -95,14 +95,19 @@ fn Sha2x32(comptime iv: Iv32, digest_bits: comptime_int) type {
9595 pub const Options = struct {};
9696
9797 s: [8]u32 align(16),
98 // Streaming Cache
99 buf: [64]u8 = undefined,
100 buf_len: u8 = 0,
101 total_len: u64 = 0,
98 /// Streaming Cache
99 buf: [64]u8,
100 buf_len: u8,
101 total_len: u64,
102102
103103 pub fn init(options: Options) Self {
104104 _ = options;
105 return Self{ .s = iv };
105 return .{
106 .s = iv,
107 .buf = undefined,
108 .buf_len = 0,
109 .total_len = 0,
110 };
106111 }
107112
108113 pub fn hash(b: []const u8, out: *[digest_length]u8, options: Options) void {
......@@ -377,16 +382,25 @@ fn Sha2x32(comptime iv: Iv32, digest_bits: comptime_int) type {
377382 for (&d.s, v) |*dv, vv| dv.* +%= vv;
378383 }
379384
380 pub const Error = error{};
381 pub const Writer = std.io.Writer(*Self, Error, write);
382
383 fn write(self: *Self, bytes: []const u8) Error!usize {
384 self.update(bytes);
385 return bytes.len;
385 pub fn writable(this: *@This(), buffer: []u8) std.io.BufferedWriter {
386 return .{
387 .unbuffered_writer = .{
388 .context = this,
389 .vtable = &.{
390 .writeSplat = writeSplat,
391 .writeFile = std.io.Writer.unimplementedWriteFile,
392 },
393 },
394 .buffer = buffer,
395 };
386396 }
387397
388 pub fn writer(self: *Self) Writer {
389 return .{ .context = self };
398 fn writeSplat(context: ?*anyopaque, data: []const []const u8, splat: usize) std.io.Writer.Error!usize {
399 const this: *@This() = @ptrCast(@alignCast(context));
400 const start_total = this.total_len;
401 for (data[0 .. data.len - 1]) |slice| this.update(slice);
402 for (0..splat) |_| this.update(data[data.len - 1]);
403 return @intCast(this.total_len - start_total);
390404 }
391405 };
392406}
lib/std/crypto/sha3.zig-60
......@@ -80,18 +80,6 @@ pub fn Keccak(comptime f: u11, comptime output_bits: u11, comptime default_delim
8080 self.st.pad();
8181 self.st.squeeze(out[0..]);
8282 }
83
84 pub const Error = error{};
85 pub const Writer = std.io.Writer(*Self, Error, write);
86
87 fn write(self: *Self, bytes: []const u8) Error!usize {
88 self.update(bytes);
89 return bytes.len;
90 }
91
92 pub fn writer(self: *Self) Writer {
93 return .{ .context = self };
94 }
9583 };
9684}
9785
......@@ -191,18 +179,6 @@ fn ShakeLike(comptime security_level: u11, comptime default_delim: u8, comptime
191179 pub fn fillBlock(self: *Self) void {
192180 self.st.fillBlock();
193181 }
194
195 pub const Error = error{};
196 pub const Writer = std.io.Writer(*Self, Error, write);
197
198 fn write(self: *Self, bytes: []const u8) Error!usize {
199 self.update(bytes);
200 return bytes.len;
201 }
202
203 pub fn writer(self: *Self) Writer {
204 return .{ .context = self };
205 }
206182 };
207183}
208184
......@@ -284,18 +260,6 @@ fn CShakeLike(comptime security_level: u11, comptime default_delim: u8, comptime
284260 pub fn fillBlock(self: *Self) void {
285261 self.shaker.fillBlock();
286262 }
287
288 pub const Error = error{};
289 pub const Writer = std.io.Writer(*Self, Error, write);
290
291 fn write(self: *Self, bytes: []const u8) Error!usize {
292 self.update(bytes);
293 return bytes.len;
294 }
295
296 pub fn writer(self: *Self) Writer {
297 return .{ .context = self };
298 }
299263 };
300264}
301265
......@@ -390,18 +354,6 @@ fn KMacLike(comptime security_level: u11, comptime default_delim: u8, comptime r
390354 ctx.update(msg);
391355 ctx.final(out);
392356 }
393
394 pub const Error = error{};
395 pub const Writer = std.io.Writer(*Self, Error, write);
396
397 fn write(self: *Self, bytes: []const u8) Error!usize {
398 self.update(bytes);
399 return bytes.len;
400 }
401
402 pub fn writer(self: *Self) Writer {
403 return .{ .context = self };
404 }
405357 };
406358}
407359
......@@ -482,18 +434,6 @@ fn TupleHashLike(comptime security_level: u11, comptime default_delim: u8, compt
482434 }
483435 self.cshaker.squeeze(out);
484436 }
485
486 pub const Error = error{};
487 pub const Writer = std.io.Writer(*Self, Error, write);
488
489 fn write(self: *Self, bytes: []const u8) Error!usize {
490 self.update(bytes);
491 return bytes.len;
492 }
493
494 pub fn writer(self: *Self) Writer {
495 return .{ .context = self };
496 }
497437 };
498438}
499439
lib/std/crypto/siphash.zig-42
......@@ -238,48 +238,6 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize)
238238 pub fn toInt(msg: []const u8, key: *const [key_length]u8) T {
239239 return State.hash(msg, key);
240240 }
241
242 pub fn writer(self: *Self) std.io.Writer {
243 return .{
244 .context = self,
245 .vtable = &.{
246 .writeSplat = &writeSplat,
247 .writeFile = &writeFile,
248 },
249 };
250 }
251
252 fn writeSplat(ctx: ?*anyopaque, data: []const []const u8, splat: usize) std.io.Writer.Error!usize {
253 const self: *Self = @alignCast(@ptrCast(ctx));
254 var len: usize = 0;
255 for (data[0 .. data.len - 1]) |slice| {
256 self.update(slice);
257 len += slice.len;
258 }
259 {
260 const slice = data[data.len - 1];
261 for (0..splat) |_| self.update(slice);
262 len += slice.len * splat;
263 }
264 return len;
265 }
266
267 fn writeFile(
268 ctx: ?*anyopaque,
269 file: std.fs.File,
270 offset: std.io.Writer.Offset,
271 limit: std.io.Writer.Limit,
272 headers_and_trailers: []const []const u8,
273 headers_len: usize,
274 ) std.io.Writer.Error!usize {
275 _ = ctx;
276 _ = file;
277 _ = offset;
278 _ = limit;
279 _ = headers_and_trailers;
280 _ = headers_len;
281 @panic("TODO");
282 }
283241 };
284242}
285243
lib/std/debug/Dwarf.zig+1-1
......@@ -2176,7 +2176,7 @@ pub const ElfModule = struct {
21762176 parent_mapped_mem: ?[]align(std.heap.page_size_min) const u8,
21772177 elf_filename: ?[]const u8,
21782178 ) LoadError!Dwarf.ElfModule {
2179 if (expected_crc) |crc| if (crc != std.hash.crc.Crc32.hash(mapped_mem)) return error.InvalidDebugInfo;
2179 if (expected_crc) |crc| if (crc != std.hash.Crc32.hash(mapped_mem)) return error.InvalidDebugInfo;
21802180
21812181 const hdr: *const elf.Ehdr = @ptrCast(&mapped_mem[0]);
21822182 if (!mem.eql(u8, hdr.e_ident[0..4], elf.MAGIC)) return error.InvalidElfMagic;
lib/std/fs/File.zig+34
......@@ -934,6 +934,10 @@ pub const Reader = struct {
934934 };
935935 }
936936
937 pub fn readable(r: *Reader, buffer: []u8) std.io.BufferedReader {
938 return interface(r).buffered(buffer);
939 }
940
937941 pub fn getSize(r: *Reader) GetEndPosError!u64 {
938942 return r.size orelse {
939943 if (r.size_err) |err| return err;
......@@ -1228,6 +1232,7 @@ pub const Writer = struct {
12281232 pos: u64 = 0,
12291233 sendfile_err: ?SendfileError = null,
12301234 read_err: ?ReadError = null,
1235 seek_err: ?SeekError = null,
12311236
12321237 pub const Mode = Reader.Mode;
12331238
......@@ -1250,6 +1255,20 @@ pub const Writer = struct {
12501255 };
12511256 }
12521257
1258 pub fn writable(w: *Writer, buffer: []u8) std.io.BufferedWriter {
1259 return interface(w).buffered(buffer);
1260 }
1261
1262 pub fn moveToReader(w: *Writer) Reader {
1263 defer w.* = undefined;
1264 return .{
1265 .file = w.file,
1266 .mode = w.mode,
1267 .pos = w.pos,
1268 .seek_err = w.seek_err,
1269 };
1270 }
1271
12531272 pub fn writeSplat(context: ?*anyopaque, data: []const []const u8, splat: usize) std.io.Writer.Error!usize {
12541273 const w: *Writer = @ptrCast(@alignCast(context));
12551274 const handle = w.file.handle;
......@@ -1347,6 +1366,21 @@ pub const Writer = struct {
13471366 }
13481367 return error.Unimplemented;
13491368 }
1369
1370 pub fn seekTo(w: *Writer, offset: u64) SeekError!void {
1371 if (w.seek_err) |err| return err;
1372 switch (w.mode) {
1373 .positional, .positional_reading => {
1374 w.pos = offset;
1375 },
1376 .streaming, .streaming_reading => {
1377 posix.lseek_SET(w.file.handle, offset) catch |err| {
1378 w.seek_err = err;
1379 return err;
1380 };
1381 },
1382 }
1383 }
13501384};
13511385
13521386/// Defaults to positional reading; falls back to streaming.
lib/std/hash.zig+1-2
......@@ -6,9 +6,8 @@ pub const autoHash = auto_hash.autoHash;
66pub const autoHashStrat = auto_hash.hash;
77pub const Strategy = auto_hash.HashStrategy;
88
9// pub for polynomials + generic crc32 construction
109pub const crc = @import("hash/crc.zig");
11pub const Crc32 = crc.Crc32;
10pub const Crc32 = crc.Crc32IsoHdlc;
1211
1312const fnv = @import("hash/fnv.zig");
1413pub const Fnv1a_32 = fnv.Fnv1a_32;
lib/std/hash/crc.zig+237-125
......@@ -1,19 +1,127 @@
1//! This file is auto-generated by tools/update_crc_catalog.zig.
2
3const impl = @import("crc/impl.zig");
4
5pub const Crc = impl.Crc;
6pub const Polynomial = impl.Polynomial;
7pub const Crc32WithPoly = impl.Crc32WithPoly;
8pub const Crc32SmallWithPoly = impl.Crc32SmallWithPoly;
9
10pub const Crc32 = Crc32IsoHdlc;
1const std = @import("../std.zig");
2
3pub fn Generic(comptime W: type, comptime algorithm: Algorithm(W)) type {
4 return struct {
5 const Self = @This();
6 const I = if (@bitSizeOf(W) < 8) u8 else W;
7 const lookup_table = blk: {
8 @setEvalBranchQuota(2500);
9
10 const poly = if (algorithm.reflect_input)
11 @bitReverse(@as(I, algorithm.polynomial)) >> (@bitSizeOf(I) - @bitSizeOf(W))
12 else
13 @as(I, algorithm.polynomial) << (@bitSizeOf(I) - @bitSizeOf(W));
14
15 var table: [256]I = undefined;
16 for (&table, 0..) |*e, i| {
17 var crc: I = i;
18 if (algorithm.reflect_input) {
19 var j: usize = 0;
20 while (j < 8) : (j += 1) {
21 crc = (crc >> 1) ^ ((crc & 1) * poly);
22 }
23 } else {
24 crc <<= @bitSizeOf(I) - 8;
25 var j: usize = 0;
26 while (j < 8) : (j += 1) {
27 crc = (crc << 1) ^ (((crc >> (@bitSizeOf(I) - 1)) & 1) * poly);
28 }
29 }
30 e.* = crc;
31 }
32 break :blk table;
33 };
34
35 crc: I,
36
37 pub fn init() Self {
38 const initial = if (algorithm.reflect_input)
39 @bitReverse(@as(I, algorithm.initial)) >> (@bitSizeOf(I) - @bitSizeOf(W))
40 else
41 @as(I, algorithm.initial) << (@bitSizeOf(I) - @bitSizeOf(W));
42 return .{ .crc = initial };
43 }
44
45 inline fn tableEntry(index: I) I {
46 return lookup_table[@as(u8, @intCast(index & 0xFF))];
47 }
48
49 pub fn updateByte(self: *Self, byte: u8) void {
50 if (@bitSizeOf(I) <= 8) {
51 self.crc = tableEntry(self.crc ^ byte);
52 } else if (algorithm.reflect_input) {
53 const table_index = self.crc ^ byte;
54 self.crc = tableEntry(table_index) ^ (self.crc >> 8);
55 } else {
56 const table_index = (self.crc >> (@bitSizeOf(I) - 8)) ^ byte;
57 self.crc = tableEntry(table_index) ^ (self.crc << 8);
58 }
59 }
60
61 pub fn update(self: *Self, bytes: []const u8) void {
62 for (bytes) |byte| updateByte(self, byte);
63 }
64
65 pub fn final(self: Self) W {
66 var c = self.crc;
67 if (algorithm.reflect_input != algorithm.reflect_output) {
68 c = @bitReverse(c);
69 }
70 if (!algorithm.reflect_output) {
71 c >>= @bitSizeOf(I) - @bitSizeOf(W);
72 }
73 return @intCast(c ^ algorithm.xor_output);
74 }
75
76 pub fn hash(bytes: []const u8) W {
77 var c = Self.init();
78 c.update(bytes);
79 return c.final();
80 }
81
82 pub fn writable(self: *Self, buffer: []u8) std.io.BufferedWriter {
83 return .{
84 .unbuffered_writer = .{
85 .context = self,
86 .vtable = &.{
87 .writeSplat = writeSplat,
88 .writeFile = std.io.Writer.unimplementedWriteFile,
89 },
90 },
91 .buffer = buffer,
92 };
93 }
94
95 fn writeSplat(context: ?*anyopaque, data: []const []const u8, splat: usize) std.io.Writer.Error!usize {
96 const self: *Self = @ptrCast(@alignCast(context));
97 var n: usize = 0;
98 for (data[0 .. data.len - 1]) |slice| {
99 self.update(slice);
100 n += slice.len;
101 }
102 const last = data[data.len - 1];
103 if (last.len == 1) {
104 for (0..splat) |_| self.updateByte(last[0]);
105 return n + splat;
106 } else {
107 for (0..splat) |_| self.update(last);
108 return n + last.len * splat;
109 }
110 }
111 };
112}
11113
12test {
13 _ = @import("crc/test.zig");
114pub fn Algorithm(comptime W: type) type {
115 return struct {
116 polynomial: W,
117 initial: W,
118 reflect_input: bool,
119 reflect_output: bool,
120 xor_output: W,
121 };
14122}
15123
16pub const Crc3Gsm = Crc(u3, .{
124pub const Crc3Gsm = Generic(u3, .{
17125 .polynomial = 0x3,
18126 .initial = 0x0,
19127 .reflect_input = false,
......@@ -21,7 +129,7 @@ pub const Crc3Gsm = Crc(u3, .{
21129 .xor_output = 0x7,
22130});
23131
24pub const Crc3Rohc = Crc(u3, .{
132pub const Crc3Rohc = Generic(u3, .{
25133 .polynomial = 0x3,
26134 .initial = 0x7,
27135 .reflect_input = true,
......@@ -29,7 +137,7 @@ pub const Crc3Rohc = Crc(u3, .{
29137 .xor_output = 0x0,
30138});
31139
32pub const Crc4G704 = Crc(u4, .{
140pub const Crc4G704 = Generic(u4, .{
33141 .polynomial = 0x3,
34142 .initial = 0x0,
35143 .reflect_input = true,
......@@ -37,7 +145,7 @@ pub const Crc4G704 = Crc(u4, .{
37145 .xor_output = 0x0,
38146});
39147
40pub const Crc4Interlaken = Crc(u4, .{
148pub const Crc4Interlaken = Generic(u4, .{
41149 .polynomial = 0x3,
42150 .initial = 0xf,
43151 .reflect_input = false,
......@@ -45,7 +153,7 @@ pub const Crc4Interlaken = Crc(u4, .{
45153 .xor_output = 0xf,
46154});
47155
48pub const Crc5EpcC1g2 = Crc(u5, .{
156pub const Crc5EpcC1g2 = Generic(u5, .{
49157 .polynomial = 0x09,
50158 .initial = 0x09,
51159 .reflect_input = false,
......@@ -53,7 +161,7 @@ pub const Crc5EpcC1g2 = Crc(u5, .{
53161 .xor_output = 0x00,
54162});
55163
56pub const Crc5G704 = Crc(u5, .{
164pub const Crc5G704 = Generic(u5, .{
57165 .polynomial = 0x15,
58166 .initial = 0x00,
59167 .reflect_input = true,
......@@ -61,7 +169,7 @@ pub const Crc5G704 = Crc(u5, .{
61169 .xor_output = 0x00,
62170});
63171
64pub const Crc5Usb = Crc(u5, .{
172pub const Crc5Usb = Generic(u5, .{
65173 .polynomial = 0x05,
66174 .initial = 0x1f,
67175 .reflect_input = true,
......@@ -69,7 +177,7 @@ pub const Crc5Usb = Crc(u5, .{
69177 .xor_output = 0x1f,
70178});
71179
72pub const Crc6Cdma2000A = Crc(u6, .{
180pub const Crc6Cdma2000A = Generic(u6, .{
73181 .polynomial = 0x27,
74182 .initial = 0x3f,
75183 .reflect_input = false,
......@@ -77,7 +185,7 @@ pub const Crc6Cdma2000A = Crc(u6, .{
77185 .xor_output = 0x00,
78186});
79187
80pub const Crc6Cdma2000B = Crc(u6, .{
188pub const Crc6Cdma2000B = Generic(u6, .{
81189 .polynomial = 0x07,
82190 .initial = 0x3f,
83191 .reflect_input = false,
......@@ -85,7 +193,7 @@ pub const Crc6Cdma2000B = Crc(u6, .{
85193 .xor_output = 0x00,
86194});
87195
88pub const Crc6Darc = Crc(u6, .{
196pub const Crc6Darc = Generic(u6, .{
89197 .polynomial = 0x19,
90198 .initial = 0x00,
91199 .reflect_input = true,
......@@ -93,7 +201,7 @@ pub const Crc6Darc = Crc(u6, .{
93201 .xor_output = 0x00,
94202});
95203
96pub const Crc6G704 = Crc(u6, .{
204pub const Crc6G704 = Generic(u6, .{
97205 .polynomial = 0x03,
98206 .initial = 0x00,
99207 .reflect_input = true,
......@@ -101,7 +209,7 @@ pub const Crc6G704 = Crc(u6, .{
101209 .xor_output = 0x00,
102210});
103211
104pub const Crc6Gsm = Crc(u6, .{
212pub const Crc6Gsm = Generic(u6, .{
105213 .polynomial = 0x2f,
106214 .initial = 0x00,
107215 .reflect_input = false,
......@@ -109,7 +217,7 @@ pub const Crc6Gsm = Crc(u6, .{
109217 .xor_output = 0x3f,
110218});
111219
112pub const Crc7Mmc = Crc(u7, .{
220pub const Crc7Mmc = Generic(u7, .{
113221 .polynomial = 0x09,
114222 .initial = 0x00,
115223 .reflect_input = false,
......@@ -117,7 +225,7 @@ pub const Crc7Mmc = Crc(u7, .{
117225 .xor_output = 0x00,
118226});
119227
120pub const Crc7Rohc = Crc(u7, .{
228pub const Crc7Rohc = Generic(u7, .{
121229 .polynomial = 0x4f,
122230 .initial = 0x7f,
123231 .reflect_input = true,
......@@ -125,7 +233,7 @@ pub const Crc7Rohc = Crc(u7, .{
125233 .xor_output = 0x00,
126234});
127235
128pub const Crc7Umts = Crc(u7, .{
236pub const Crc7Umts = Generic(u7, .{
129237 .polynomial = 0x45,
130238 .initial = 0x00,
131239 .reflect_input = false,
......@@ -133,7 +241,7 @@ pub const Crc7Umts = Crc(u7, .{
133241 .xor_output = 0x00,
134242});
135243
136pub const Crc8Autosar = Crc(u8, .{
244pub const Crc8Autosar = Generic(u8, .{
137245 .polynomial = 0x2f,
138246 .initial = 0xff,
139247 .reflect_input = false,
......@@ -141,7 +249,7 @@ pub const Crc8Autosar = Crc(u8, .{
141249 .xor_output = 0xff,
142250});
143251
144pub const Crc8Bluetooth = Crc(u8, .{
252pub const Crc8Bluetooth = Generic(u8, .{
145253 .polynomial = 0xa7,
146254 .initial = 0x00,
147255 .reflect_input = true,
......@@ -149,7 +257,7 @@ pub const Crc8Bluetooth = Crc(u8, .{
149257 .xor_output = 0x00,
150258});
151259
152pub const Crc8Cdma2000 = Crc(u8, .{
260pub const Crc8Cdma2000 = Generic(u8, .{
153261 .polynomial = 0x9b,
154262 .initial = 0xff,
155263 .reflect_input = false,
......@@ -157,7 +265,7 @@ pub const Crc8Cdma2000 = Crc(u8, .{
157265 .xor_output = 0x00,
158266});
159267
160pub const Crc8Darc = Crc(u8, .{
268pub const Crc8Darc = Generic(u8, .{
161269 .polynomial = 0x39,
162270 .initial = 0x00,
163271 .reflect_input = true,
......@@ -165,7 +273,7 @@ pub const Crc8Darc = Crc(u8, .{
165273 .xor_output = 0x00,
166274});
167275
168pub const Crc8DvbS2 = Crc(u8, .{
276pub const Crc8DvbS2 = Generic(u8, .{
169277 .polynomial = 0xd5,
170278 .initial = 0x00,
171279 .reflect_input = false,
......@@ -173,7 +281,7 @@ pub const Crc8DvbS2 = Crc(u8, .{
173281 .xor_output = 0x00,
174282});
175283
176pub const Crc8GsmA = Crc(u8, .{
284pub const Crc8GsmA = Generic(u8, .{
177285 .polynomial = 0x1d,
178286 .initial = 0x00,
179287 .reflect_input = false,
......@@ -181,7 +289,7 @@ pub const Crc8GsmA = Crc(u8, .{
181289 .xor_output = 0x00,
182290});
183291
184pub const Crc8GsmB = Crc(u8, .{
292pub const Crc8GsmB = Generic(u8, .{
185293 .polynomial = 0x49,
186294 .initial = 0x00,
187295 .reflect_input = false,
......@@ -189,7 +297,7 @@ pub const Crc8GsmB = Crc(u8, .{
189297 .xor_output = 0xff,
190298});
191299
192pub const Crc8Hitag = Crc(u8, .{
300pub const Crc8Hitag = Generic(u8, .{
193301 .polynomial = 0x1d,
194302 .initial = 0xff,
195303 .reflect_input = false,
......@@ -197,7 +305,7 @@ pub const Crc8Hitag = Crc(u8, .{
197305 .xor_output = 0x00,
198306});
199307
200pub const Crc8I4321 = Crc(u8, .{
308pub const Crc8I4321 = Generic(u8, .{
201309 .polynomial = 0x07,
202310 .initial = 0x00,
203311 .reflect_input = false,
......@@ -205,7 +313,7 @@ pub const Crc8I4321 = Crc(u8, .{
205313 .xor_output = 0x55,
206314});
207315
208pub const Crc8ICode = Crc(u8, .{
316pub const Crc8ICode = Generic(u8, .{
209317 .polynomial = 0x1d,
210318 .initial = 0xfd,
211319 .reflect_input = false,
......@@ -213,7 +321,7 @@ pub const Crc8ICode = Crc(u8, .{
213321 .xor_output = 0x00,
214322});
215323
216pub const Crc8Lte = Crc(u8, .{
324pub const Crc8Lte = Generic(u8, .{
217325 .polynomial = 0x9b,
218326 .initial = 0x00,
219327 .reflect_input = false,
......@@ -221,7 +329,7 @@ pub const Crc8Lte = Crc(u8, .{
221329 .xor_output = 0x00,
222330});
223331
224pub const Crc8MaximDow = Crc(u8, .{
332pub const Crc8MaximDow = Generic(u8, .{
225333 .polynomial = 0x31,
226334 .initial = 0x00,
227335 .reflect_input = true,
......@@ -229,7 +337,7 @@ pub const Crc8MaximDow = Crc(u8, .{
229337 .xor_output = 0x00,
230338});
231339
232pub const Crc8MifareMad = Crc(u8, .{
340pub const Crc8MifareMad = Generic(u8, .{
233341 .polynomial = 0x1d,
234342 .initial = 0xc7,
235343 .reflect_input = false,
......@@ -237,7 +345,7 @@ pub const Crc8MifareMad = Crc(u8, .{
237345 .xor_output = 0x00,
238346});
239347
240pub const Crc8Nrsc5 = Crc(u8, .{
348pub const Crc8Nrsc5 = Generic(u8, .{
241349 .polynomial = 0x31,
242350 .initial = 0xff,
243351 .reflect_input = false,
......@@ -245,7 +353,7 @@ pub const Crc8Nrsc5 = Crc(u8, .{
245353 .xor_output = 0x00,
246354});
247355
248pub const Crc8Opensafety = Crc(u8, .{
356pub const Crc8Opensafety = Generic(u8, .{
249357 .polynomial = 0x2f,
250358 .initial = 0x00,
251359 .reflect_input = false,
......@@ -253,7 +361,7 @@ pub const Crc8Opensafety = Crc(u8, .{
253361 .xor_output = 0x00,
254362});
255363
256pub const Crc8Rohc = Crc(u8, .{
364pub const Crc8Rohc = Generic(u8, .{
257365 .polynomial = 0x07,
258366 .initial = 0xff,
259367 .reflect_input = true,
......@@ -261,7 +369,7 @@ pub const Crc8Rohc = Crc(u8, .{
261369 .xor_output = 0x00,
262370});
263371
264pub const Crc8SaeJ1850 = Crc(u8, .{
372pub const Crc8SaeJ1850 = Generic(u8, .{
265373 .polynomial = 0x1d,
266374 .initial = 0xff,
267375 .reflect_input = false,
......@@ -269,7 +377,7 @@ pub const Crc8SaeJ1850 = Crc(u8, .{
269377 .xor_output = 0xff,
270378});
271379
272pub const Crc8Smbus = Crc(u8, .{
380pub const Crc8Smbus = Generic(u8, .{
273381 .polynomial = 0x07,
274382 .initial = 0x00,
275383 .reflect_input = false,
......@@ -277,7 +385,7 @@ pub const Crc8Smbus = Crc(u8, .{
277385 .xor_output = 0x00,
278386});
279387
280pub const Crc8Tech3250 = Crc(u8, .{
388pub const Crc8Tech3250 = Generic(u8, .{
281389 .polynomial = 0x1d,
282390 .initial = 0xff,
283391 .reflect_input = true,
......@@ -285,7 +393,7 @@ pub const Crc8Tech3250 = Crc(u8, .{
285393 .xor_output = 0x00,
286394});
287395
288pub const Crc8Wcdma = Crc(u8, .{
396pub const Crc8Wcdma = Generic(u8, .{
289397 .polynomial = 0x9b,
290398 .initial = 0x00,
291399 .reflect_input = true,
......@@ -293,7 +401,7 @@ pub const Crc8Wcdma = Crc(u8, .{
293401 .xor_output = 0x00,
294402});
295403
296pub const Crc10Atm = Crc(u10, .{
404pub const Crc10Atm = Generic(u10, .{
297405 .polynomial = 0x233,
298406 .initial = 0x000,
299407 .reflect_input = false,
......@@ -301,7 +409,7 @@ pub const Crc10Atm = Crc(u10, .{
301409 .xor_output = 0x000,
302410});
303411
304pub const Crc10Cdma2000 = Crc(u10, .{
412pub const Crc10Cdma2000 = Generic(u10, .{
305413 .polynomial = 0x3d9,
306414 .initial = 0x3ff,
307415 .reflect_input = false,
......@@ -309,7 +417,7 @@ pub const Crc10Cdma2000 = Crc(u10, .{
309417 .xor_output = 0x000,
310418});
311419
312pub const Crc10Gsm = Crc(u10, .{
420pub const Crc10Gsm = Generic(u10, .{
313421 .polynomial = 0x175,
314422 .initial = 0x000,
315423 .reflect_input = false,
......@@ -317,7 +425,7 @@ pub const Crc10Gsm = Crc(u10, .{
317425 .xor_output = 0x3ff,
318426});
319427
320pub const Crc11Flexray = Crc(u11, .{
428pub const Crc11Flexray = Generic(u11, .{
321429 .polynomial = 0x385,
322430 .initial = 0x01a,
323431 .reflect_input = false,
......@@ -325,7 +433,7 @@ pub const Crc11Flexray = Crc(u11, .{
325433 .xor_output = 0x000,
326434});
327435
328pub const Crc11Umts = Crc(u11, .{
436pub const Crc11Umts = Generic(u11, .{
329437 .polynomial = 0x307,
330438 .initial = 0x000,
331439 .reflect_input = false,
......@@ -333,7 +441,7 @@ pub const Crc11Umts = Crc(u11, .{
333441 .xor_output = 0x000,
334442});
335443
336pub const Crc12Cdma2000 = Crc(u12, .{
444pub const Crc12Cdma2000 = Generic(u12, .{
337445 .polynomial = 0xf13,
338446 .initial = 0xfff,
339447 .reflect_input = false,
......@@ -341,7 +449,7 @@ pub const Crc12Cdma2000 = Crc(u12, .{
341449 .xor_output = 0x000,
342450});
343451
344pub const Crc12Dect = Crc(u12, .{
452pub const Crc12Dect = Generic(u12, .{
345453 .polynomial = 0x80f,
346454 .initial = 0x000,
347455 .reflect_input = false,
......@@ -349,7 +457,7 @@ pub const Crc12Dect = Crc(u12, .{
349457 .xor_output = 0x000,
350458});
351459
352pub const Crc12Gsm = Crc(u12, .{
460pub const Crc12Gsm = Generic(u12, .{
353461 .polynomial = 0xd31,
354462 .initial = 0x000,
355463 .reflect_input = false,
......@@ -357,7 +465,7 @@ pub const Crc12Gsm = Crc(u12, .{
357465 .xor_output = 0xfff,
358466});
359467
360pub const Crc12Umts = Crc(u12, .{
468pub const Crc12Umts = Generic(u12, .{
361469 .polynomial = 0x80f,
362470 .initial = 0x000,
363471 .reflect_input = false,
......@@ -365,7 +473,7 @@ pub const Crc12Umts = Crc(u12, .{
365473 .xor_output = 0x000,
366474});
367475
368pub const Crc13Bbc = Crc(u13, .{
476pub const Crc13Bbc = Generic(u13, .{
369477 .polynomial = 0x1cf5,
370478 .initial = 0x0000,
371479 .reflect_input = false,
......@@ -373,7 +481,7 @@ pub const Crc13Bbc = Crc(u13, .{
373481 .xor_output = 0x0000,
374482});
375483
376pub const Crc14Darc = Crc(u14, .{
484pub const Crc14Darc = Generic(u14, .{
377485 .polynomial = 0x0805,
378486 .initial = 0x0000,
379487 .reflect_input = true,
......@@ -381,7 +489,7 @@ pub const Crc14Darc = Crc(u14, .{
381489 .xor_output = 0x0000,
382490});
383491
384pub const Crc14Gsm = Crc(u14, .{
492pub const Crc14Gsm = Generic(u14, .{
385493 .polynomial = 0x202d,
386494 .initial = 0x0000,
387495 .reflect_input = false,
......@@ -389,7 +497,7 @@ pub const Crc14Gsm = Crc(u14, .{
389497 .xor_output = 0x3fff,
390498});
391499
392pub const Crc15Can = Crc(u15, .{
500pub const Crc15Can = Generic(u15, .{
393501 .polynomial = 0x4599,
394502 .initial = 0x0000,
395503 .reflect_input = false,
......@@ -397,7 +505,7 @@ pub const Crc15Can = Crc(u15, .{
397505 .xor_output = 0x0000,
398506});
399507
400pub const Crc15Mpt1327 = Crc(u15, .{
508pub const Crc15Mpt1327 = Generic(u15, .{
401509 .polynomial = 0x6815,
402510 .initial = 0x0000,
403511 .reflect_input = false,
......@@ -405,7 +513,7 @@ pub const Crc15Mpt1327 = Crc(u15, .{
405513 .xor_output = 0x0001,
406514});
407515
408pub const Crc16Arc = Crc(u16, .{
516pub const Crc16Arc = Generic(u16, .{
409517 .polynomial = 0x8005,
410518 .initial = 0x0000,
411519 .reflect_input = true,
......@@ -413,7 +521,7 @@ pub const Crc16Arc = Crc(u16, .{
413521 .xor_output = 0x0000,
414522});
415523
416pub const Crc16Cdma2000 = Crc(u16, .{
524pub const Crc16Cdma2000 = Generic(u16, .{
417525 .polynomial = 0xc867,
418526 .initial = 0xffff,
419527 .reflect_input = false,
......@@ -421,7 +529,7 @@ pub const Crc16Cdma2000 = Crc(u16, .{
421529 .xor_output = 0x0000,
422530});
423531
424pub const Crc16Cms = Crc(u16, .{
532pub const Crc16Cms = Generic(u16, .{
425533 .polynomial = 0x8005,
426534 .initial = 0xffff,
427535 .reflect_input = false,
......@@ -429,7 +537,7 @@ pub const Crc16Cms = Crc(u16, .{
429537 .xor_output = 0x0000,
430538});
431539
432pub const Crc16Dds110 = Crc(u16, .{
540pub const Crc16Dds110 = Generic(u16, .{
433541 .polynomial = 0x8005,
434542 .initial = 0x800d,
435543 .reflect_input = false,
......@@ -437,7 +545,7 @@ pub const Crc16Dds110 = Crc(u16, .{
437545 .xor_output = 0x0000,
438546});
439547
440pub const Crc16DectR = Crc(u16, .{
548pub const Crc16DectR = Generic(u16, .{
441549 .polynomial = 0x0589,
442550 .initial = 0x0000,
443551 .reflect_input = false,
......@@ -445,7 +553,7 @@ pub const Crc16DectR = Crc(u16, .{
445553 .xor_output = 0x0001,
446554});
447555
448pub const Crc16DectX = Crc(u16, .{
556pub const Crc16DectX = Generic(u16, .{
449557 .polynomial = 0x0589,
450558 .initial = 0x0000,
451559 .reflect_input = false,
......@@ -453,7 +561,7 @@ pub const Crc16DectX = Crc(u16, .{
453561 .xor_output = 0x0000,
454562});
455563
456pub const Crc16Dnp = Crc(u16, .{
564pub const Crc16Dnp = Generic(u16, .{
457565 .polynomial = 0x3d65,
458566 .initial = 0x0000,
459567 .reflect_input = true,
......@@ -461,7 +569,7 @@ pub const Crc16Dnp = Crc(u16, .{
461569 .xor_output = 0xffff,
462570});
463571
464pub const Crc16En13757 = Crc(u16, .{
572pub const Crc16En13757 = Generic(u16, .{
465573 .polynomial = 0x3d65,
466574 .initial = 0x0000,
467575 .reflect_input = false,
......@@ -469,7 +577,7 @@ pub const Crc16En13757 = Crc(u16, .{
469577 .xor_output = 0xffff,
470578});
471579
472pub const Crc16Genibus = Crc(u16, .{
580pub const Crc16Genibus = Generic(u16, .{
473581 .polynomial = 0x1021,
474582 .initial = 0xffff,
475583 .reflect_input = false,
......@@ -477,7 +585,7 @@ pub const Crc16Genibus = Crc(u16, .{
477585 .xor_output = 0xffff,
478586});
479587
480pub const Crc16Gsm = Crc(u16, .{
588pub const Crc16Gsm = Generic(u16, .{
481589 .polynomial = 0x1021,
482590 .initial = 0x0000,
483591 .reflect_input = false,
......@@ -485,7 +593,7 @@ pub const Crc16Gsm = Crc(u16, .{
485593 .xor_output = 0xffff,
486594});
487595
488pub const Crc16Ibm3740 = Crc(u16, .{
596pub const Crc16Ibm3740 = Generic(u16, .{
489597 .polynomial = 0x1021,
490598 .initial = 0xffff,
491599 .reflect_input = false,
......@@ -493,7 +601,7 @@ pub const Crc16Ibm3740 = Crc(u16, .{
493601 .xor_output = 0x0000,
494602});
495603
496pub const Crc16IbmSdlc = Crc(u16, .{
604pub const Crc16IbmSdlc = Generic(u16, .{
497605 .polynomial = 0x1021,
498606 .initial = 0xffff,
499607 .reflect_input = true,
......@@ -501,7 +609,7 @@ pub const Crc16IbmSdlc = Crc(u16, .{
501609 .xor_output = 0xffff,
502610});
503611
504pub const Crc16IsoIec144433A = Crc(u16, .{
612pub const Crc16IsoIec144433A = Generic(u16, .{
505613 .polynomial = 0x1021,
506614 .initial = 0xc6c6,
507615 .reflect_input = true,
......@@ -509,7 +617,7 @@ pub const Crc16IsoIec144433A = Crc(u16, .{
509617 .xor_output = 0x0000,
510618});
511619
512pub const Crc16Kermit = Crc(u16, .{
620pub const Crc16Kermit = Generic(u16, .{
513621 .polynomial = 0x1021,
514622 .initial = 0x0000,
515623 .reflect_input = true,
......@@ -517,7 +625,7 @@ pub const Crc16Kermit = Crc(u16, .{
517625 .xor_output = 0x0000,
518626});
519627
520pub const Crc16Lj1200 = Crc(u16, .{
628pub const Crc16Lj1200 = Generic(u16, .{
521629 .polynomial = 0x6f63,
522630 .initial = 0x0000,
523631 .reflect_input = false,
......@@ -525,7 +633,7 @@ pub const Crc16Lj1200 = Crc(u16, .{
525633 .xor_output = 0x0000,
526634});
527635
528pub const Crc16M17 = Crc(u16, .{
636pub const Crc16M17 = Generic(u16, .{
529637 .polynomial = 0x5935,
530638 .initial = 0xffff,
531639 .reflect_input = false,
......@@ -533,7 +641,7 @@ pub const Crc16M17 = Crc(u16, .{
533641 .xor_output = 0x0000,
534642});
535643
536pub const Crc16MaximDow = Crc(u16, .{
644pub const Crc16MaximDow = Generic(u16, .{
537645 .polynomial = 0x8005,
538646 .initial = 0x0000,
539647 .reflect_input = true,
......@@ -541,7 +649,7 @@ pub const Crc16MaximDow = Crc(u16, .{
541649 .xor_output = 0xffff,
542650});
543651
544pub const Crc16Mcrf4xx = Crc(u16, .{
652pub const Crc16Mcrf4xx = Generic(u16, .{
545653 .polynomial = 0x1021,
546654 .initial = 0xffff,
547655 .reflect_input = true,
......@@ -549,7 +657,7 @@ pub const Crc16Mcrf4xx = Crc(u16, .{
549657 .xor_output = 0x0000,
550658});
551659
552pub const Crc16Modbus = Crc(u16, .{
660pub const Crc16Modbus = Generic(u16, .{
553661 .polynomial = 0x8005,
554662 .initial = 0xffff,
555663 .reflect_input = true,
......@@ -557,7 +665,7 @@ pub const Crc16Modbus = Crc(u16, .{
557665 .xor_output = 0x0000,
558666});
559667
560pub const Crc16Nrsc5 = Crc(u16, .{
668pub const Crc16Nrsc5 = Generic(u16, .{
561669 .polynomial = 0x080b,
562670 .initial = 0xffff,
563671 .reflect_input = true,
......@@ -565,7 +673,7 @@ pub const Crc16Nrsc5 = Crc(u16, .{
565673 .xor_output = 0x0000,
566674});
567675
568pub const Crc16OpensafetyA = Crc(u16, .{
676pub const Crc16OpensafetyA = Generic(u16, .{
569677 .polynomial = 0x5935,
570678 .initial = 0x0000,
571679 .reflect_input = false,
......@@ -573,7 +681,7 @@ pub const Crc16OpensafetyA = Crc(u16, .{
573681 .xor_output = 0x0000,
574682});
575683
576pub const Crc16OpensafetyB = Crc(u16, .{
684pub const Crc16OpensafetyB = Generic(u16, .{
577685 .polynomial = 0x755b,
578686 .initial = 0x0000,
579687 .reflect_input = false,
......@@ -581,7 +689,7 @@ pub const Crc16OpensafetyB = Crc(u16, .{
581689 .xor_output = 0x0000,
582690});
583691
584pub const Crc16Profibus = Crc(u16, .{
692pub const Crc16Profibus = Generic(u16, .{
585693 .polynomial = 0x1dcf,
586694 .initial = 0xffff,
587695 .reflect_input = false,
......@@ -589,7 +697,7 @@ pub const Crc16Profibus = Crc(u16, .{
589697 .xor_output = 0xffff,
590698});
591699
592pub const Crc16Riello = Crc(u16, .{
700pub const Crc16Riello = Generic(u16, .{
593701 .polynomial = 0x1021,
594702 .initial = 0xb2aa,
595703 .reflect_input = true,
......@@ -597,7 +705,7 @@ pub const Crc16Riello = Crc(u16, .{
597705 .xor_output = 0x0000,
598706});
599707
600pub const Crc16SpiFujitsu = Crc(u16, .{
708pub const Crc16SpiFujitsu = Generic(u16, .{
601709 .polynomial = 0x1021,
602710 .initial = 0x1d0f,
603711 .reflect_input = false,
......@@ -605,7 +713,7 @@ pub const Crc16SpiFujitsu = Crc(u16, .{
605713 .xor_output = 0x0000,
606714});
607715
608pub const Crc16T10Dif = Crc(u16, .{
716pub const Crc16T10Dif = Generic(u16, .{
609717 .polynomial = 0x8bb7,
610718 .initial = 0x0000,
611719 .reflect_input = false,
......@@ -613,7 +721,7 @@ pub const Crc16T10Dif = Crc(u16, .{
613721 .xor_output = 0x0000,
614722});
615723
616pub const Crc16Teledisk = Crc(u16, .{
724pub const Crc16Teledisk = Generic(u16, .{
617725 .polynomial = 0xa097,
618726 .initial = 0x0000,
619727 .reflect_input = false,
......@@ -621,7 +729,7 @@ pub const Crc16Teledisk = Crc(u16, .{
621729 .xor_output = 0x0000,
622730});
623731
624pub const Crc16Tms37157 = Crc(u16, .{
732pub const Crc16Tms37157 = Generic(u16, .{
625733 .polynomial = 0x1021,
626734 .initial = 0x89ec,
627735 .reflect_input = true,
......@@ -629,7 +737,7 @@ pub const Crc16Tms37157 = Crc(u16, .{
629737 .xor_output = 0x0000,
630738});
631739
632pub const Crc16Umts = Crc(u16, .{
740pub const Crc16Umts = Generic(u16, .{
633741 .polynomial = 0x8005,
634742 .initial = 0x0000,
635743 .reflect_input = false,
......@@ -637,7 +745,7 @@ pub const Crc16Umts = Crc(u16, .{
637745 .xor_output = 0x0000,
638746});
639747
640pub const Crc16Usb = Crc(u16, .{
748pub const Crc16Usb = Generic(u16, .{
641749 .polynomial = 0x8005,
642750 .initial = 0xffff,
643751 .reflect_input = true,
......@@ -645,7 +753,7 @@ pub const Crc16Usb = Crc(u16, .{
645753 .xor_output = 0xffff,
646754});
647755
648pub const Crc16Xmodem = Crc(u16, .{
756pub const Crc16Xmodem = Generic(u16, .{
649757 .polynomial = 0x1021,
650758 .initial = 0x0000,
651759 .reflect_input = false,
......@@ -653,7 +761,7 @@ pub const Crc16Xmodem = Crc(u16, .{
653761 .xor_output = 0x0000,
654762});
655763
656pub const Crc17CanFd = Crc(u17, .{
764pub const Crc17CanFd = Generic(u17, .{
657765 .polynomial = 0x1685b,
658766 .initial = 0x00000,
659767 .reflect_input = false,
......@@ -661,7 +769,7 @@ pub const Crc17CanFd = Crc(u17, .{
661769 .xor_output = 0x00000,
662770});
663771
664pub const Crc21CanFd = Crc(u21, .{
772pub const Crc21CanFd = Generic(u21, .{
665773 .polynomial = 0x102899,
666774 .initial = 0x000000,
667775 .reflect_input = false,
......@@ -669,7 +777,7 @@ pub const Crc21CanFd = Crc(u21, .{
669777 .xor_output = 0x000000,
670778});
671779
672pub const Crc24Ble = Crc(u24, .{
780pub const Crc24Ble = Generic(u24, .{
673781 .polynomial = 0x00065b,
674782 .initial = 0x555555,
675783 .reflect_input = true,
......@@ -677,7 +785,7 @@ pub const Crc24Ble = Crc(u24, .{
677785 .xor_output = 0x000000,
678786});
679787
680pub const Crc24FlexrayA = Crc(u24, .{
788pub const Crc24FlexrayA = Generic(u24, .{
681789 .polynomial = 0x5d6dcb,
682790 .initial = 0xfedcba,
683791 .reflect_input = false,
......@@ -685,7 +793,7 @@ pub const Crc24FlexrayA = Crc(u24, .{
685793 .xor_output = 0x000000,
686794});
687795
688pub const Crc24FlexrayB = Crc(u24, .{
796pub const Crc24FlexrayB = Generic(u24, .{
689797 .polynomial = 0x5d6dcb,
690798 .initial = 0xabcdef,
691799 .reflect_input = false,
......@@ -693,7 +801,7 @@ pub const Crc24FlexrayB = Crc(u24, .{
693801 .xor_output = 0x000000,
694802});
695803
696pub const Crc24Interlaken = Crc(u24, .{
804pub const Crc24Interlaken = Generic(u24, .{
697805 .polynomial = 0x328b63,
698806 .initial = 0xffffff,
699807 .reflect_input = false,
......@@ -701,7 +809,7 @@ pub const Crc24Interlaken = Crc(u24, .{
701809 .xor_output = 0xffffff,
702810});
703811
704pub const Crc24LteA = Crc(u24, .{
812pub const Crc24LteA = Generic(u24, .{
705813 .polynomial = 0x864cfb,
706814 .initial = 0x000000,
707815 .reflect_input = false,
......@@ -709,7 +817,7 @@ pub const Crc24LteA = Crc(u24, .{
709817 .xor_output = 0x000000,
710818});
711819
712pub const Crc24LteB = Crc(u24, .{
820pub const Crc24LteB = Generic(u24, .{
713821 .polynomial = 0x800063,
714822 .initial = 0x000000,
715823 .reflect_input = false,
......@@ -717,7 +825,7 @@ pub const Crc24LteB = Crc(u24, .{
717825 .xor_output = 0x000000,
718826});
719827
720pub const Crc24Openpgp = Crc(u24, .{
828pub const Crc24Openpgp = Generic(u24, .{
721829 .polynomial = 0x864cfb,
722830 .initial = 0xb704ce,
723831 .reflect_input = false,
......@@ -725,7 +833,7 @@ pub const Crc24Openpgp = Crc(u24, .{
725833 .xor_output = 0x000000,
726834});
727835
728pub const Crc24Os9 = Crc(u24, .{
836pub const Crc24Os9 = Generic(u24, .{
729837 .polynomial = 0x800063,
730838 .initial = 0xffffff,
731839 .reflect_input = false,
......@@ -733,7 +841,7 @@ pub const Crc24Os9 = Crc(u24, .{
733841 .xor_output = 0xffffff,
734842});
735843
736pub const Crc30Cdma = Crc(u30, .{
844pub const Crc30Cdma = Generic(u30, .{
737845 .polynomial = 0x2030b9c7,
738846 .initial = 0x3fffffff,
739847 .reflect_input = false,
......@@ -741,7 +849,7 @@ pub const Crc30Cdma = Crc(u30, .{
741849 .xor_output = 0x3fffffff,
742850});
743851
744pub const Crc31Philips = Crc(u31, .{
852pub const Crc31Philips = Generic(u31, .{
745853 .polynomial = 0x04c11db7,
746854 .initial = 0x7fffffff,
747855 .reflect_input = false,
......@@ -749,7 +857,7 @@ pub const Crc31Philips = Crc(u31, .{
749857 .xor_output = 0x7fffffff,
750858});
751859
752pub const Crc32Aixm = Crc(u32, .{
860pub const Crc32Aixm = Generic(u32, .{
753861 .polynomial = 0x814141ab,
754862 .initial = 0x00000000,
755863 .reflect_input = false,
......@@ -757,7 +865,7 @@ pub const Crc32Aixm = Crc(u32, .{
757865 .xor_output = 0x00000000,
758866});
759867
760pub const Crc32Autosar = Crc(u32, .{
868pub const Crc32Autosar = Generic(u32, .{
761869 .polynomial = 0xf4acfb13,
762870 .initial = 0xffffffff,
763871 .reflect_input = true,
......@@ -765,7 +873,7 @@ pub const Crc32Autosar = Crc(u32, .{
765873 .xor_output = 0xffffffff,
766874});
767875
768pub const Crc32Base91D = Crc(u32, .{
876pub const Crc32Base91D = Generic(u32, .{
769877 .polynomial = 0xa833982b,
770878 .initial = 0xffffffff,
771879 .reflect_input = true,
......@@ -773,7 +881,7 @@ pub const Crc32Base91D = Crc(u32, .{
773881 .xor_output = 0xffffffff,
774882});
775883
776pub const Crc32Bzip2 = Crc(u32, .{
884pub const Crc32Bzip2 = Generic(u32, .{
777885 .polynomial = 0x04c11db7,
778886 .initial = 0xffffffff,
779887 .reflect_input = false,
......@@ -781,7 +889,7 @@ pub const Crc32Bzip2 = Crc(u32, .{
781889 .xor_output = 0xffffffff,
782890});
783891
784pub const Crc32CdRomEdc = Crc(u32, .{
892pub const Crc32CdRomEdc = Generic(u32, .{
785893 .polynomial = 0x8001801b,
786894 .initial = 0x00000000,
787895 .reflect_input = true,
......@@ -789,7 +897,7 @@ pub const Crc32CdRomEdc = Crc(u32, .{
789897 .xor_output = 0x00000000,
790898});
791899
792pub const Crc32Cksum = Crc(u32, .{
900pub const Crc32Cksum = Generic(u32, .{
793901 .polynomial = 0x04c11db7,
794902 .initial = 0x00000000,
795903 .reflect_input = false,
......@@ -797,7 +905,7 @@ pub const Crc32Cksum = Crc(u32, .{
797905 .xor_output = 0xffffffff,
798906});
799907
800pub const Crc32Iscsi = Crc(u32, .{
908pub const Crc32Iscsi = Generic(u32, .{
801909 .polynomial = 0x1edc6f41,
802910 .initial = 0xffffffff,
803911 .reflect_input = true,
......@@ -805,7 +913,7 @@ pub const Crc32Iscsi = Crc(u32, .{
805913 .xor_output = 0xffffffff,
806914});
807915
808pub const Crc32IsoHdlc = Crc(u32, .{
916pub const Crc32IsoHdlc = Generic(u32, .{
809917 .polynomial = 0x04c11db7,
810918 .initial = 0xffffffff,
811919 .reflect_input = true,
......@@ -813,7 +921,7 @@ pub const Crc32IsoHdlc = Crc(u32, .{
813921 .xor_output = 0xffffffff,
814922});
815923
816pub const Crc32Jamcrc = Crc(u32, .{
924pub const Crc32Jamcrc = Generic(u32, .{
817925 .polynomial = 0x04c11db7,
818926 .initial = 0xffffffff,
819927 .reflect_input = true,
......@@ -821,7 +929,7 @@ pub const Crc32Jamcrc = Crc(u32, .{
821929 .xor_output = 0x00000000,
822930});
823931
824pub const Crc32Koopman = Crc(u32, .{
932pub const Crc32Koopman = Generic(u32, .{
825933 .polynomial = 0x741b8cd7,
826934 .initial = 0xffffffff,
827935 .reflect_input = true,
......@@ -829,7 +937,7 @@ pub const Crc32Koopman = Crc(u32, .{
829937 .xor_output = 0xffffffff,
830938});
831939
832pub const Crc32Mef = Crc(u32, .{
940pub const Crc32Mef = Generic(u32, .{
833941 .polynomial = 0x741b8cd7,
834942 .initial = 0xffffffff,
835943 .reflect_input = true,
......@@ -837,7 +945,7 @@ pub const Crc32Mef = Crc(u32, .{
837945 .xor_output = 0x00000000,
838946});
839947
840pub const Crc32Mpeg2 = Crc(u32, .{
948pub const Crc32Mpeg2 = Generic(u32, .{
841949 .polynomial = 0x04c11db7,
842950 .initial = 0xffffffff,
843951 .reflect_input = false,
......@@ -845,7 +953,7 @@ pub const Crc32Mpeg2 = Crc(u32, .{
845953 .xor_output = 0x00000000,
846954});
847955
848pub const Crc32Xfer = Crc(u32, .{
956pub const Crc32Xfer = Generic(u32, .{
849957 .polynomial = 0x000000af,
850958 .initial = 0x00000000,
851959 .reflect_input = false,
......@@ -853,7 +961,7 @@ pub const Crc32Xfer = Crc(u32, .{
853961 .xor_output = 0x00000000,
854962});
855963
856pub const Crc40Gsm = Crc(u40, .{
964pub const Crc40Gsm = Generic(u40, .{
857965 .polynomial = 0x0004820009,
858966 .initial = 0x0000000000,
859967 .reflect_input = false,
......@@ -861,7 +969,7 @@ pub const Crc40Gsm = Crc(u40, .{
861969 .xor_output = 0xffffffffff,
862970});
863971
864pub const Crc64Ecma182 = Crc(u64, .{
972pub const Crc64Ecma182 = Generic(u64, .{
865973 .polynomial = 0x42f0e1eba9ea3693,
866974 .initial = 0x0000000000000000,
867975 .reflect_input = false,
......@@ -869,7 +977,7 @@ pub const Crc64Ecma182 = Crc(u64, .{
869977 .xor_output = 0x0000000000000000,
870978});
871979
872pub const Crc64GoIso = Crc(u64, .{
980pub const Crc64GoIso = Generic(u64, .{
873981 .polynomial = 0x000000000000001b,
874982 .initial = 0xffffffffffffffff,
875983 .reflect_input = true,
......@@ -877,7 +985,7 @@ pub const Crc64GoIso = Crc(u64, .{
877985 .xor_output = 0xffffffffffffffff,
878986});
879987
880pub const Crc64Ms = Crc(u64, .{
988pub const Crc64Ms = Generic(u64, .{
881989 .polynomial = 0x259c84cba6426349,
882990 .initial = 0xffffffffffffffff,
883991 .reflect_input = true,
......@@ -885,7 +993,7 @@ pub const Crc64Ms = Crc(u64, .{
885993 .xor_output = 0x0000000000000000,
886994});
887995
888pub const Crc64Redis = Crc(u64, .{
996pub const Crc64Redis = Generic(u64, .{
889997 .polynomial = 0xad93d23594c935a9,
890998 .initial = 0x0000000000000000,
891999 .reflect_input = true,
......@@ -893,7 +1001,7 @@ pub const Crc64Redis = Crc(u64, .{
8931001 .xor_output = 0x0000000000000000,
8941002});
8951003
896pub const Crc64We = Crc(u64, .{
1004pub const Crc64We = Generic(u64, .{
8971005 .polynomial = 0x42f0e1eba9ea3693,
8981006 .initial = 0xffffffffffffffff,
8991007 .reflect_input = false,
......@@ -901,7 +1009,7 @@ pub const Crc64We = Crc(u64, .{
9011009 .xor_output = 0xffffffffffffffff,
9021010});
9031011
904pub const Crc64Xz = Crc(u64, .{
1012pub const Crc64Xz = Generic(u64, .{
9051013 .polynomial = 0x42f0e1eba9ea3693,
9061014 .initial = 0xffffffffffffffff,
9071015 .reflect_input = true,
......@@ -909,10 +1017,14 @@ pub const Crc64Xz = Crc(u64, .{
9091017 .xor_output = 0xffffffffffffffff,
9101018});
9111019
912pub const Crc82Darc = Crc(u82, .{
1020pub const Crc82Darc = Generic(u82, .{
9131021 .polynomial = 0x0308c0111011401440411,
9141022 .initial = 0x000000000000000000000,
9151023 .reflect_input = true,
9161024 .reflect_output = true,
9171025 .xor_output = 0x000000000000000000000,
9181026});
1027
1028test {
1029 _ = @import("crc/test.zig");
1030}
lib/std/hash/crc/impl.zig deleted-112
......@@ -1,112 +0,0 @@
1// There is a generic CRC implementation "Crc()" which can be parameterized via
2// the Algorithm struct for a plethora of uses.
3//
4// The primary interface for all of the standard CRC algorithms is the
5// generated file "crc.zig", which uses the implementation code here to define
6// many standard CRCs.
7
8const std = @import("std");
9
10pub fn Algorithm(comptime W: type) type {
11 return struct {
12 polynomial: W,
13 initial: W,
14 reflect_input: bool,
15 reflect_output: bool,
16 xor_output: W,
17 };
18}
19
20pub fn Crc(comptime W: type, comptime algorithm: Algorithm(W)) type {
21 return struct {
22 const Self = @This();
23 const I = if (@bitSizeOf(W) < 8) u8 else W;
24 const lookup_table = blk: {
25 @setEvalBranchQuota(2500);
26
27 const poly = if (algorithm.reflect_input)
28 @bitReverse(@as(I, algorithm.polynomial)) >> (@bitSizeOf(I) - @bitSizeOf(W))
29 else
30 @as(I, algorithm.polynomial) << (@bitSizeOf(I) - @bitSizeOf(W));
31
32 var table: [256]I = undefined;
33 for (&table, 0..) |*e, i| {
34 var crc: I = i;
35 if (algorithm.reflect_input) {
36 var j: usize = 0;
37 while (j < 8) : (j += 1) {
38 crc = (crc >> 1) ^ ((crc & 1) * poly);
39 }
40 } else {
41 crc <<= @bitSizeOf(I) - 8;
42 var j: usize = 0;
43 while (j < 8) : (j += 1) {
44 crc = (crc << 1) ^ (((crc >> (@bitSizeOf(I) - 1)) & 1) * poly);
45 }
46 }
47 e.* = crc;
48 }
49 break :blk table;
50 };
51
52 crc: I,
53
54 pub fn init() Self {
55 const initial = if (algorithm.reflect_input)
56 @bitReverse(@as(I, algorithm.initial)) >> (@bitSizeOf(I) - @bitSizeOf(W))
57 else
58 @as(I, algorithm.initial) << (@bitSizeOf(I) - @bitSizeOf(W));
59 return Self{ .crc = initial };
60 }
61
62 inline fn tableEntry(index: I) I {
63 return lookup_table[@as(u8, @intCast(index & 0xFF))];
64 }
65
66 pub fn update(self: *Self, bytes: []const u8) void {
67 var i: usize = 0;
68 if (@bitSizeOf(I) <= 8) {
69 while (i < bytes.len) : (i += 1) {
70 self.crc = tableEntry(self.crc ^ bytes[i]);
71 }
72 } else if (algorithm.reflect_input) {
73 while (i < bytes.len) : (i += 1) {
74 const table_index = self.crc ^ bytes[i];
75 self.crc = tableEntry(table_index) ^ (self.crc >> 8);
76 }
77 } else {
78 while (i < bytes.len) : (i += 1) {
79 const table_index = (self.crc >> (@bitSizeOf(I) - 8)) ^ bytes[i];
80 self.crc = tableEntry(table_index) ^ (self.crc << 8);
81 }
82 }
83 }
84
85 pub fn final(self: Self) W {
86 var c = self.crc;
87 if (algorithm.reflect_input != algorithm.reflect_output) {
88 c = @bitReverse(c);
89 }
90 if (!algorithm.reflect_output) {
91 c >>= @bitSizeOf(I) - @bitSizeOf(W);
92 }
93 return @as(W, @intCast(c ^ algorithm.xor_output));
94 }
95
96 pub fn hash(bytes: []const u8) W {
97 var c = Self.init();
98 c.update(bytes);
99 return c.final();
100 }
101 };
102}
103
104pub const Polynomial = enum(u32) {
105 IEEE = @compileError("use Crc with algorithm .Crc32IsoHdlc"),
106 Castagnoli = @compileError("use Crc with algorithm .Crc32Iscsi"),
107 Koopman = @compileError("use Crc with algorithm .Crc32Koopman"),
108 _,
109};
110
111pub const Crc32WithPoly = @compileError("use Crc instead");
112pub const Crc32SmallWithPoly = @compileError("use Crc instead");
lib/std/io/BufferedReader.zig+34-2
......@@ -35,6 +35,10 @@ pub fn bufferContents(br: *BufferedReader) []u8 {
3535 return br.buffer[br.seek..br.end];
3636}
3737
38pub fn bufferedLen(br: *const BufferedReader) usize {
39 return br.end - br.seek;
40}
41
3842/// Although `BufferedReader` can easily satisfy the `Reader` interface, it's
3943/// generally more practical to pass a `BufferedReader` instance itself around,
4044/// since it will result in fewer calls across vtable boundaries.
......@@ -49,6 +53,10 @@ pub fn reader(br: *BufferedReader) Reader {
4953 };
5054}
5155
56pub fn hashed(br: *BufferedReader, hasher: anytype) Reader.Hashed(@TypeOf(hasher)) {
57 return .{ .in = br, .hasher = hasher };
58}
59
5260/// Equivalent semantics to `std.io.Reader.VTable.readVec`.
5361pub fn readVec(br: *BufferedReader, data: []const []u8) Reader.Error!usize {
5462 return readVecLimit(br, data, .unlimited);
......@@ -401,6 +409,30 @@ pub fn readSliceShort(br: *BufferedReader, buffer: []u8) Reader.ShortError!usize
401409 }
402410}
403411
412/// Fill `buffer` with the next `buffer.len` bytes from the stream, advancing
413/// the seek position.
414///
415/// Invalidates previously returned values from `peek`.
416///
417/// If the provided buffer cannot be filled completely, `error.EndOfStream` is
418/// returned instead.
419///
420/// The function is inline to avoid the dead code in case `endian` is
421/// comptime-known and matches host endianness.
422///
423/// See also:
424/// * `readSlice`
425/// * `readSliceEndianAlloc`
426pub inline fn readSliceEndian(
427 br: *BufferedReader,
428 comptime Elem: type,
429 buffer: []Elem,
430 endian: std.builtin.Endian,
431) Reader.Error!void {
432 try readSlice(br, @ptrCast(buffer));
433 if (native_endian != endian) for (buffer) |*elem| std.mem.byteSwapAllFields(Elem, elem);
434}
435
404436pub const ReadAllocError = Reader.Error || Allocator.Error;
405437
406438/// The function is inline to avoid the dead code in case `endian` is
......@@ -408,14 +440,14 @@ pub const ReadAllocError = Reader.Error || Allocator.Error;
408440pub inline fn readSliceEndianAlloc(
409441 br: *BufferedReader,
410442 allocator: Allocator,
411 Elem: type,
443 comptime Elem: type,
412444 len: usize,
413445 endian: std.builtin.Endian,
414446) ReadAllocError![]Elem {
415447 const dest = try allocator.alloc(Elem, len);
416448 errdefer allocator.free(dest);
417449 try readSlice(br, @ptrCast(dest));
418 if (native_endian != endian) std.mem.byteSwapAllFields(Elem, dest);
450 if (native_endian != endian) for (dest) |*elem| std.mem.byteSwapAllFields(Elem, elem);
419451 return dest;
420452}
421453
lib/std/io/BufferedWriter.zig+37-3
......@@ -58,6 +58,10 @@ pub fn initFixed(bw: *BufferedWriter, buffer: []u8) void {
5858 };
5959}
6060
61pub fn hashed(bw: *BufferedWriter, hasher: anytype) Writer.Hashed(@TypeOf(hasher)) {
62 return .{ .out = bw, .hasher = hasher };
63}
64
6165/// This function is available when using `initFixed`.
6266pub fn getWritten(bw: *const BufferedWriter) []u8 {
6367 assert(bw.unbuffered_writer.vtable == &fixed_vtable);
......@@ -157,7 +161,7 @@ pub fn advance(bw: *BufferedWriter, n: usize) void {
157161}
158162
159163/// The `data` parameter is mutable because this function needs to mutate the
160/// fields in order to handle partial writes from `Writer.VTable.writeVec`.
164/// fields in order to handle partial writes from `Writer.VTable.writeSplat`.
161165pub fn writeVecAll(bw: *BufferedWriter, data: [][]const u8) Writer.Error!void {
162166 var index: usize = 0;
163167 var truncate: usize = 0;
......@@ -175,6 +179,36 @@ pub fn writeVecAll(bw: *BufferedWriter, data: [][]const u8) Writer.Error!void {
175179 }
176180}
177181
182/// The `data` parameter is mutable because this function needs to mutate the
183/// fields in order to handle partial writes from `Writer.VTable.writeSplat`.
184pub fn writeSplatAll(bw: *BufferedWriter, data: [][]const u8, splat: usize) Writer.Error!void {
185 var index: usize = 0;
186 var truncate: usize = 0;
187 var remaining_splat = splat;
188 while (index + 1 < data.len) {
189 {
190 const untruncated = data[index];
191 data[index] = untruncated[truncate..];
192 defer data[index] = untruncated;
193 truncate += try bw.writeSplat(data[index..], remaining_splat);
194 }
195 while (truncate >= data[index].len) {
196 if (index + 1 < data.len) {
197 truncate -= data[index].len;
198 index += 1;
199 } else {
200 const last = data[data.len - 1];
201 remaining_splat -= @divExact(truncate, last.len);
202 while (remaining_splat > 0) {
203 const n = try bw.writeSplat(data[data.len - 1 ..][0..1], remaining_splat);
204 remaining_splat -= @divExact(n, last.len);
205 }
206 return;
207 }
208 }
209 }
210}
211
178212/// If the number of bytes to write based on `data` and `splat` fits inside
179213/// `unusedCapacitySlice`, this function is guaranteed to not fail, not call
180214/// into the underlying writer, and return the full number of bytes.
......@@ -443,7 +477,7 @@ pub fn splatBytesAll(bw: *BufferedWriter, bytes: []const u8, splat: usize) Write
443477
444478/// Writes the same slice many times, allowing short writes.
445479///
446/// Does maximum of one underlying `Writer.VTable.writeVec`.
480/// Does maximum of one underlying `Writer.VTable.writeSplat`.
447481pub fn splatBytes(bw: *BufferedWriter, bytes: []const u8, n: usize) Writer.Error!usize {
448482 return passthruWriteSplat(bw, &.{bytes}, n);
449483}
......@@ -621,7 +655,7 @@ pub const WriteFileOptions = struct {
621655 /// size here will save one syscall.
622656 limit: Writer.Limit = .unlimited,
623657 /// Headers and trailers must be passed together so that in case `len` is
624 /// zero, they can be forwarded directly to `Writer.VTable.writeVec`.
658 /// zero, they can be forwarded directly to `Writer.VTable.writeSplat`.
625659 ///
626660 /// The parameter is mutable because this function needs to mutate the
627661 /// fields in order to handle partial writes from `Writer.VTable.writeFile`.
lib/std/io/Reader.zig+68
......@@ -331,3 +331,71 @@ test "readAlloc when the backing reader provides one byte at a time" {
331331 defer std.testing.allocator.free(res);
332332 try std.testing.expectEqualStrings(str, res);
333333}
334
335/// Provides a `Reader` implementation by passing data from an underlying
336/// reader through `Hasher.update`.
337///
338/// The underlying reader is best unbuffered.
339///
340/// This implementation makes suboptimal buffering decisions due to being
341/// generic. A better solution will involve creating a reader for each hash
342/// function, where the discard buffer can be tailored to the hash
343/// implementation details.
344pub fn Hashed(comptime Hasher: type) type {
345 return struct {
346 in: *BufferedReader,
347 hasher: Hasher,
348
349 pub fn readable(this: *@This(), buffer: []u8) BufferedReader {
350 return .{
351 .unbuffered_reader = .{
352 .context = this,
353 .vtable = &.{
354 .read = @This().read,
355 .readVec = @This().readVec,
356 .discard = @This().discard,
357 },
358 },
359 .buffer = buffer,
360 .end = 0,
361 .seek = 0,
362 };
363 }
364
365 fn read(context: ?*anyopaque, bw: *BufferedWriter, limit: Limit) RwError!usize {
366 const this: *@This() = @alignCast(@ptrCast(context));
367 const slice = limit.slice(try bw.writableSliceGreedy(1));
368 const n = try this.in.readVec(&.{slice});
369 this.hasher.update(slice[0..n]);
370 bw.advance(n);
371 return n;
372 }
373
374 fn discard(context: ?*anyopaque, limit: Limit) Error!usize {
375 const this: *@This() = @alignCast(@ptrCast(context));
376 var bw = this.hasher.writable(&.{});
377 const n = this.in.read(&bw, limit) catch |err| switch (err) {
378 error.WriteFailed => unreachable,
379 else => |e| return e,
380 };
381 return n;
382 }
383
384 fn readVec(context: ?*anyopaque, data: []const []u8) Error!usize {
385 const this: *@This() = @alignCast(@ptrCast(context));
386 const n = try this.in.readVec(data);
387 var remaining: usize = n;
388 for (data) |slice| {
389 if (remaining < slice.len) {
390 this.hasher.update(slice[0..remaining]);
391 return n;
392 } else {
393 remaining -= slice.len;
394 this.hasher.update(slice);
395 }
396 }
397 assert(remaining == 0);
398 return n;
399 }
400 };
401}
lib/std/io/Writer.zig+84-4
......@@ -136,8 +136,8 @@ pub fn failingWriteSplat(context: ?*anyopaque, data: []const []const u8, splat:
136136pub fn failingWriteFile(
137137 context: ?*anyopaque,
138138 file: std.fs.File,
139 offset: std.io.Writer.Offset,
140 limit: std.io.Writer.Limit,
139 offset: Offset,
140 limit: Limit,
141141 headers_and_trailers: []const []const u8,
142142 headers_len: usize,
143143) FileError!usize {
......@@ -158,11 +158,13 @@ pub const failing: Writer = .{
158158 },
159159};
160160
161/// For use when the `Writer` implementation can cannot offer a more efficient
162/// implementation than a basic read/write loop on the file.
161163pub fn unimplementedWriteFile(
162164 context: ?*anyopaque,
163165 file: std.fs.File,
164 offset: std.io.Writer.Offset,
165 limit: std.io.Writer.Limit,
166 offset: Offset,
167 limit: Limit,
166168 headers_and_trailers: []const []const u8,
167169 headers_len: usize,
168170) FileError!usize {
......@@ -175,6 +177,84 @@ pub fn unimplementedWriteFile(
175177 return error.Unimplemented;
176178}
177179
180/// Provides a `Writer` implementation based on calling `Hasher.update`, sending
181/// all data also to an underlying `std.io.BufferedWriter`.
182///
183/// When using this, the underlying writer is best unbuffered because all
184/// writes are passed on directly to it.
185///
186/// This implementation makes suboptimal buffering decisions due to being
187/// generic. A better solution will involve creating a writer for each hash
188/// function, where the splat buffer can be tailored to the hash implementation
189/// details.
190pub fn Hashed(comptime Hasher: type) type {
191 return struct {
192 out: *std.io.BufferedWriter,
193 hasher: Hasher,
194
195 pub fn writable(this: *@This(), buffer: []u8) std.io.BufferedWriter {
196 return .{
197 .unbuffered_writer = .{
198 .context = this,
199 .vtable = &.{
200 .writeSplat = @This().writeSplat,
201 .writeFile = Writer.unimplementedWriteFile,
202 },
203 },
204 .buffer = buffer,
205 };
206 }
207
208 fn writeSplat(context: ?*anyopaque, data: []const []const u8, splat: usize) Writer.Error!usize {
209 const this: *@This() = @alignCast(@ptrCast(context));
210 const n = try this.out.writeSplat(data, splat);
211 const short_data = data[0 .. data.len - @intFromBool(splat == 0)];
212 var remaining: usize = n;
213 for (short_data) |slice| {
214 if (remaining < slice.len) {
215 this.hasher.update(slice[0..remaining]);
216 return n;
217 } else {
218 remaining -= slice.len;
219 this.hasher.update(slice);
220 }
221 }
222 const remaining_splat = switch (splat) {
223 0, 1 => {
224 assert(remaining == 0);
225 return n;
226 },
227 else => splat - 1,
228 };
229 const last = data[data.len - 1];
230 assert(remaining == remaining_splat * last.len);
231 switch (last.len) {
232 0 => {
233 assert(remaining == 0);
234 return n;
235 },
236 1 => {
237 var buffer: [64]u8 = undefined;
238 @memset(&buffer, last[0]);
239 while (remaining > 0) {
240 const update_len = @min(remaining, buffer.len);
241 this.hasher.update(buffer[0..update_len]);
242 remaining -= update_len;
243 }
244 return n;
245 },
246 else => {},
247 }
248 while (remaining > 0) {
249 const update_len = @min(remaining, last.len);
250 this.hasher.update(last[0..update_len]);
251 remaining -= update_len;
252 }
253 return n;
254 }
255 };
256}
257
178258test {
179259 _ = Null;
180260}
lib/std/io/Writer/Null.zig+4
......@@ -19,6 +19,10 @@ pub fn writer(nw: *NullWriter) Writer {
1919 };
2020}
2121
22pub fn writable(nw: *NullWriter, buffer: []u8) std.io.BufferedWriter {
23 return writer(nw).buffered(buffer);
24}
25
2226fn writeSplat(context: ?*anyopaque, data: []const []const u8, splat: usize) Writer.Error!usize {
2327 _ = context;
2428 const headers = data[0 .. data.len - 1];
lib/std/mem.zig+3-1
......@@ -2196,7 +2196,9 @@ pub fn byteSwapAllFields(comptime S: type, ptr: *S) void {
21962196 }
21972197 }
21982198 },
2199 else => @compileError("byteSwapAllFields expects a struct or array as the first argument"),
2199 else => {
2200 ptr.* = @byteSwap(ptr.*);
2201 },
22002202 }
22012203}
22022204
src/Package/Fetch/git.zig+179-158
......@@ -11,6 +11,7 @@ const Allocator = mem.Allocator;
1111const Sha1 = std.crypto.hash.Sha1;
1212const Sha256 = std.crypto.hash.sha2.Sha256;
1313const assert = std.debug.assert;
14const zlib = std.compress.zlib;
1415
1516/// The ID of a Git object.
1617pub const Oid = union(Format) {
......@@ -52,7 +53,6 @@ pub const Oid = union(Format) {
5253 };
5354 }
5455
55 // Must be public for use from HashedReader and HashedWriter.
5656 pub fn update(hasher: *Hasher, b: []const u8) void {
5757 switch (hasher.*) {
5858 inline else => |*inner| inner.update(b),
......@@ -64,6 +64,12 @@ pub const Oid = union(Format) {
6464 inline else => |*inner, tag| @unionInit(Oid, @tagName(tag), inner.finalResult()),
6565 };
6666 }
67
68 pub fn writable(hasher: *Hasher, buffer: []u8) std.io.BufferedWriter {
69 return switch (hasher.*) {
70 inline else => |*inner| inner.writable(buffer),
71 };
72 }
6773 };
6874
6975 pub fn fromBytes(oid_format: Format, bytes: []const u8) Oid {
......@@ -73,9 +79,18 @@ pub const Oid = union(Format) {
7379 };
7480 }
7581
76 pub fn readBytes(oid_format: Format, reader: anytype) @TypeOf(reader).NoEofError!Oid {
82 pub fn readBytes(oid_format: Format, reader: *std.io.BufferedReader) std.io.Reader.Error!Oid {
7783 return switch (oid_format) {
78 inline else => |tag| @unionInit(Oid, @tagName(tag), try reader.readBytesNoEof(tag.byteLength())),
84 .sha1 => {
85 var result: Oid = .{ .sha1 = undefined };
86 try reader.readSlice(&result.sha1);
87 return result;
88 },
89 .sha256 => {
90 var result: Oid = .{ .sha256 = undefined };
91 try reader.readSlice(&result.sha256);
92 return result;
93 },
7994 };
8095 }
8196
......@@ -167,8 +182,15 @@ pub const Diagnostics = struct {
167182pub const Repository = struct {
168183 odb: Odb,
169184
170 pub fn init(allocator: Allocator, format: Oid.Format, pack_file: std.fs.File, index_file: std.fs.File) !Repository {
171 return .{ .odb = try Odb.init(allocator, format, pack_file, index_file) };
185 pub fn init(
186 repo: *Repository,
187 allocator: Allocator,
188 format: Oid.Format,
189 pack_file: *std.fs.File.Reader,
190 index_file: *std.fs.File.Reader,
191 ) !void {
192 repo.* = .{ .odb = undefined };
193 try repo.odb.init(allocator, format, pack_file, index_file);
172194 }
173195
174196 pub fn deinit(repository: *Repository) void {
......@@ -337,24 +359,32 @@ pub const Repository = struct {
337359/// [pack-format](https://git-scm.com/docs/pack-format).
338360const Odb = struct {
339361 format: Oid.Format,
340 pack_file: std.fs.File,
362 pack_file: *std.fs.File.Reader,
341363 index_header: IndexHeader,
342 index_file: std.fs.File,
364 index_file: *std.fs.File.Reader,
343365 cache: ObjectCache = .{},
344366 allocator: Allocator,
345367
346368 /// Initializes the database from open pack and index files.
347 fn init(allocator: Allocator, format: Oid.Format, pack_file: std.fs.File, index_file: std.fs.File) !Odb {
369 fn init(
370 odb: *Odb,
371 allocator: Allocator,
372 format: Oid.Format,
373 pack_file: *std.fs.File.Reader,
374 index_file: *std.fs.File.Reader,
375 ) !void {
348376 try pack_file.seekTo(0);
349377 try index_file.seekTo(0);
350 const index_header = try IndexHeader.read(index_file.reader());
351 return .{
378 odb.* = .{
352379 .format = format,
353380 .pack_file = pack_file,
354 .index_header = index_header,
381 .index_header = undefined,
355382 .index_file = index_file,
356383 .allocator = allocator,
357384 };
385 var buffer: [1032]u8 = undefined;
386 var index_file_br = index_file.readable(&buffer);
387 try odb.index_header.read(&index_file_br);
358388 }
359389
360390 fn deinit(odb: *Odb) void {
......@@ -364,27 +394,30 @@ const Odb = struct {
364394
365395 /// Reads the object at the current position in the database.
366396 fn readObject(odb: *Odb) !Object {
367 var base_offset = try odb.pack_file.getPos();
397 var pack_read_buffer: [64]u8 = undefined;
398 var base_offset = odb.pack_file.pos;
399 var pack_br = odb.pack_file.readable(&pack_read_buffer);
368400 var base_header: EntryHeader = undefined;
369401 var delta_offsets: std.ArrayListUnmanaged(u64) = .empty;
370402 defer delta_offsets.deinit(odb.allocator);
371403 const base_object = while (true) {
372404 if (odb.cache.get(base_offset)) |base_object| break base_object;
373405
374 base_header = try EntryHeader.read(odb.format, odb.pack_file.reader());
406 base_header = try EntryHeader.read(odb.format, &pack_br);
375407 switch (base_header) {
376408 .ofs_delta => |ofs_delta| {
377409 try delta_offsets.append(odb.allocator, base_offset);
378410 base_offset = std.math.sub(u64, base_offset, ofs_delta.offset) catch return error.InvalidFormat;
379411 try odb.pack_file.seekTo(base_offset);
412 pack_br = odb.pack_file.readable(&pack_read_buffer);
380413 },
381414 .ref_delta => |ref_delta| {
382415 try delta_offsets.append(odb.allocator, base_offset);
383416 try odb.seekOid(ref_delta.base_object);
384 base_offset = try odb.pack_file.getPos();
417 base_offset = odb.pack_file.pos - pack_br.bufferedLen();
385418 },
386419 else => {
387 const base_data = try readObjectRaw(odb.allocator, odb.pack_file.reader(), base_header.uncompressedLength());
420 const base_data = try readObjectRaw(odb.allocator, &pack_br, base_header.uncompressedLength());
388421 errdefer odb.allocator.free(base_data);
389422 const base_object: Object = .{ .type = base_header.objectType(), .data = base_data };
390423 try odb.cache.put(odb.allocator, base_offset, base_object);
......@@ -414,7 +447,8 @@ const Odb = struct {
414447 const found_index = while (start_index < end_index) {
415448 const mid_index = start_index + (end_index - start_index) / 2;
416449 try odb.index_file.seekTo(IndexHeader.size + mid_index * oid_length);
417 const mid_oid = try Oid.readBytes(odb.format, odb.index_file.reader());
450 var br = odb.index_file.interface().unbuffered();
451 const mid_oid = try Oid.readBytes(odb.format, &br);
418452 switch (mem.order(u8, mid_oid.slice(), oid.slice())) {
419453 .lt => start_index = mid_index + 1,
420454 .gt => end_index = mid_index,
......@@ -424,13 +458,16 @@ const Odb = struct {
424458
425459 const n_objects = odb.index_header.fan_out_table[255];
426460 const offset_values_start = IndexHeader.size + n_objects * (oid_length + 4);
461 var buffer: [8]u8 = undefined;
427462 try odb.index_file.seekTo(offset_values_start + found_index * 4);
428 const l1_offset: packed struct { value: u31, big: bool } = @bitCast(try odb.index_file.reader().readInt(u32, .big));
463 var br = odb.index_file.interface().buffered(&buffer);
464 const l1_offset: packed struct { value: u31, big: bool } = @bitCast(try br.takeInt(u32, .big));
429465 const pack_offset = pack_offset: {
430466 if (l1_offset.big) {
431467 const l2_offset_values_start = offset_values_start + n_objects * 4;
432468 try odb.index_file.seekTo(l2_offset_values_start + l1_offset.value * 4);
433 break :pack_offset try odb.index_file.reader().readInt(u64, .big);
469 br = odb.index_file.interface().buffered(&buffer);
470 break :pack_offset try br.takeInt(u64, .big);
434471 } else {
435472 break :pack_offset l1_offset.value;
436473 }
......@@ -556,7 +593,7 @@ const Packet = union(enum) {
556593 const max_data_length = 65516;
557594
558595 /// Reads a packet in pkt-line format.
559 fn read(reader: anytype, buf: *[max_data_length]u8) !Packet {
596 fn read(reader: *std.io.BufferedReader, buf: *[max_data_length]u8) !Packet {
560597 const length = std.fmt.parseUnsigned(u16, &try reader.readBytesNoEof(4), 16) catch return error.InvalidPacket;
561598 switch (length) {
562599 0 => return .flush,
......@@ -571,7 +608,7 @@ const Packet = union(enum) {
571608 }
572609
573610 /// Writes a packet in pkt-line format.
574 fn write(packet: Packet, writer: anytype) !void {
611 fn write(packet: Packet, writer: *std.io.BufferedWriter) !void {
575612 switch (packet) {
576613 .flush => try writer.writeAll("0000"),
577614 .delimiter => try writer.writeAll("0001"),
......@@ -1070,21 +1107,12 @@ const PackHeader = struct {
10701107 const signature = "PACK";
10711108 const supported_version = 2;
10721109
1073 fn read(reader: anytype) !PackHeader {
1074 const actual_signature = reader.readBytesNoEof(4) catch |e| switch (e) {
1075 error.EndOfStream => return error.InvalidHeader,
1076 else => |other| return other,
1077 };
1078 if (!mem.eql(u8, &actual_signature, signature)) return error.InvalidHeader;
1079 const version = reader.readInt(u32, .big) catch |e| switch (e) {
1080 error.EndOfStream => return error.InvalidHeader,
1081 else => |other| return other,
1082 };
1110 fn read(reader: *std.io.BufferedReader) !PackHeader {
1111 const actual_signature = try reader.take(4);
1112 if (!mem.eql(u8, actual_signature, signature)) return error.InvalidHeader;
1113 const version = try reader.takeInt(u32, .big);
10831114 if (version != supported_version) return error.UnsupportedVersion;
1084 const total_objects = reader.readInt(u32, .big) catch |e| switch (e) {
1085 error.EndOfStream => return error.InvalidHeader,
1086 else => |other| return other,
1087 };
1115 const total_objects = try reader.takeInt(u32, .big);
10881116 return .{ .total_objects = total_objects };
10891117 }
10901118};
......@@ -1133,12 +1161,9 @@ const EntryHeader = union(Type) {
11331161 };
11341162 }
11351163
1136 fn read(format: Oid.Format, reader: anytype) !EntryHeader {
1164 fn read(format: Oid.Format, reader: *std.io.BufferedReader) !EntryHeader {
11371165 const InitialByte = packed struct { len: u4, type: u3, has_next: bool };
1138 const initial: InitialByte = @bitCast(reader.readByte() catch |e| switch (e) {
1139 error.EndOfStream => return error.InvalidFormat,
1140 else => |other| return other,
1141 });
1166 const initial: InitialByte = @bitCast(try reader.takeByte());
11421167 const rest_len = if (initial.has_next) try readSizeVarInt(reader) else 0;
11431168 var uncompressed_length: u64 = initial.len;
11441169 uncompressed_length |= std.math.shlExact(u64, rest_len, 4) catch return error.InvalidFormat;
......@@ -1162,25 +1187,25 @@ const EntryHeader = union(Type) {
11621187 }
11631188};
11641189
1165fn readSizeVarInt(r: anytype) !u64 {
1190fn readSizeVarInt(r: *std.io.BufferedReader) !u64 {
11661191 const Byte = packed struct { value: u7, has_next: bool };
1167 var b: Byte = @bitCast(try r.readByte());
1192 var b: Byte = @bitCast(try r.takeByte());
11681193 var value: u64 = b.value;
11691194 var shift: u6 = 0;
11701195 while (b.has_next) {
1171 b = @bitCast(try r.readByte());
1196 b = @bitCast(try r.takeByte());
11721197 shift = std.math.add(u6, shift, 7) catch return error.InvalidFormat;
11731198 value |= @as(u64, b.value) << shift;
11741199 }
11751200 return value;
11761201}
11771202
1178fn readOffsetVarInt(r: anytype) !u64 {
1203fn readOffsetVarInt(r: *std.io.BufferedReader) !u64 {
11791204 const Byte = packed struct { value: u7, has_next: bool };
1180 var b: Byte = @bitCast(try r.readByte());
1205 var b: Byte = @bitCast(try r.takeByte());
11811206 var value: u64 = b.value;
11821207 while (b.has_next) {
1183 b = @bitCast(try r.readByte());
1208 b = @bitCast(try r.takeByte());
11841209 value = std.math.shlExact(u64, value + 1, 7) catch return error.InvalidFormat;
11851210 value |= b.value;
11861211 }
......@@ -1194,19 +1219,12 @@ const IndexHeader = struct {
11941219 const supported_version = 2;
11951220 const size = 4 + 4 + @sizeOf([256]u32);
11961221
1197 fn read(reader: anytype) !IndexHeader {
1198 var header_bytes = try reader.readBytesNoEof(size);
1199 if (!mem.eql(u8, header_bytes[0..4], signature)) return error.InvalidHeader;
1200 const version = mem.readInt(u32, header_bytes[4..8], .big);
1222 fn read(index_header: *IndexHeader, br: *std.io.BufferedReader) !void {
1223 const sig = try br.take(4);
1224 if (!mem.eql(u8, sig, signature)) return error.InvalidHeader;
1225 const version = try br.takeInt(u32, .big);
12011226 if (version != supported_version) return error.UnsupportedVersion;
1202
1203 var fan_out_table: [256]u32 = undefined;
1204 var fan_out_table_stream = std.io.fixedBufferStream(header_bytes[8..]);
1205 const fan_out_table_reader = fan_out_table_stream.reader();
1206 for (&fan_out_table) |*entry| {
1207 entry.* = fan_out_table_reader.readInt(u32, .big) catch unreachable;
1208 }
1209 return .{ .fan_out_table = fan_out_table };
1227 try br.readSliceEndian(u32, &index_header.fan_out_table, .big);
12101228 }
12111229};
12121230
......@@ -1217,7 +1235,12 @@ const IndexEntry = struct {
12171235
12181236/// Writes out a version 2 index for the given packfile, as documented in
12191237/// [pack-format](https://git-scm.com/docs/pack-format).
1220pub fn indexPack(allocator: Allocator, format: Oid.Format, pack: std.fs.File, index_writer: anytype) !void {
1238pub fn indexPack(
1239 allocator: Allocator,
1240 format: Oid.Format,
1241 pack: *std.fs.File.Reader,
1242 index_writer: *std.fs.File.Writer,
1243) !void {
12211244 try pack.seekTo(0);
12221245
12231246 var index_entries: std.AutoHashMapUnmanaged(Oid, IndexEntry) = .empty;
......@@ -1270,8 +1293,10 @@ pub fn indexPack(allocator: Allocator, format: Oid.Format, pack: std.fs.File, in
12701293 }
12711294 @memset(fan_out_table[fan_out_index..], count);
12721295
1273 var index_hashed_writer = std.compress.hashedWriter(index_writer, Oid.Hasher.init(format));
1274 const writer = index_hashed_writer.writer();
1296 var index_writer_bw = index_writer.writable(&.{});
1297 var index_hashed_writer = index_writer_bw.hashed(Oid.Hasher.init(format));
1298 var write_buffer: [256]u8 = undefined;
1299 var writer = index_hashed_writer.writable(&write_buffer);
12751300 try writer.writeAll(IndexHeader.signature);
12761301 try writer.writeInt(u32, IndexHeader.supported_version, .big);
12771302 for (fan_out_table) |fan_out_entry| {
......@@ -1303,8 +1328,9 @@ pub fn indexPack(allocator: Allocator, format: Oid.Format, pack: std.fs.File, in
13031328 }
13041329
13051330 try writer.writeAll(pack_checksum.slice());
1331 try writer.flush();
13061332 const index_checksum = index_hashed_writer.hasher.finalResult();
1307 try index_writer.writeAll(index_checksum.slice());
1333 try index_writer_bw.writeAll(index_checksum.slice());
13081334}
13091335
13101336/// Performs the first pass over the packfile data for index construction.
......@@ -1314,50 +1340,46 @@ pub fn indexPack(allocator: Allocator, format: Oid.Format, pack: std.fs.File, in
13141340fn indexPackFirstPass(
13151341 allocator: Allocator,
13161342 format: Oid.Format,
1317 pack: std.fs.File,
1343 pack: *std.fs.File.Reader,
13181344 index_entries: *std.AutoHashMapUnmanaged(Oid, IndexEntry),
13191345 pending_deltas: *std.ArrayListUnmanaged(IndexEntry),
13201346) !Oid {
1321 var pack_buffered_reader = std.io.bufferedReader(pack.reader());
1322 var pack_counting_reader = std.io.countingReader(pack_buffered_reader.reader());
1323 var pack_hashed_reader = std.compress.hashedReader(pack_counting_reader.reader(), Oid.Hasher.init(format));
1324 const pack_reader = pack_hashed_reader.reader();
1325
1326 const pack_header = try PackHeader.read(pack_reader);
1327
1328 var current_entry: u32 = 0;
1329 while (current_entry < pack_header.total_objects) : (current_entry += 1) {
1330 const entry_offset = pack_counting_reader.bytes_read;
1331 var entry_crc32_reader = std.compress.hashedReader(pack_reader, std.hash.Crc32.init());
1332 const entry_header = try EntryHeader.read(format, entry_crc32_reader.reader());
1347 var pack_br = pack.readable(&.{});
1348 var pack_hashed_reader = pack_br.hashed(Oid.Hasher.init(format));
1349 var pack_buffer: [2048]u8 = undefined; // Reasonably large buffer for file system.
1350 var pack_hashed_br = pack_hashed_reader.readable(&pack_buffer);
1351
1352 const pack_header = try PackHeader.read(&pack_hashed_br);
1353
1354 for (0..pack_header.total_objects) |_| {
1355 const entry_offset = pack.pos - pack_hashed_br.bufferContents().len;
1356 var entry_crc32_reader = pack_hashed_br.hashed(std.hash.Crc32.init());
1357 var entry_buffer: [64]u8 = undefined; // Buffer only needed for loading EntryHeader.
1358 var entry_crc32_br = entry_crc32_reader.readable(&entry_buffer);
1359 const entry_header = try EntryHeader.read(format, &entry_crc32_br);
1360 var entry_decompress_stream: zlib.Decompressor = .init(&entry_crc32_br);
1361 // Decompress uses large output buffer; no input buffer needed.
1362 var entry_decompress_br = entry_decompress_stream.readable(&.{});
13331363 switch (entry_header) {
13341364 .commit, .tree, .blob, .tag => |object| {
1335 var entry_decompress_stream = std.compress.zlib.decompressor(entry_crc32_reader.reader());
1336 var entry_counting_reader = std.io.countingReader(entry_decompress_stream.reader());
1337 var entry_hashed_writer = std.compress.hashedWriter(std.io.null_writer, Oid.Hasher.init(format));
1338 const entry_writer = entry_hashed_writer.writer();
1365 var oid_hasher = Oid.Hasher.init(format);
1366 var oid_hasher_buffer: [zlib.max_window_len]u8 = undefined;
1367 var oid_hasher_bw = oid_hasher.writable(&oid_hasher_buffer);
13391368 // The object header is not included in the pack data but is
1340 // part of the object's ID
1341 try entry_writer.print("{s} {}\x00", .{ @tagName(entry_header), object.uncompressed_length });
1342 var fifo = std.fifo.LinearFifo(u8, .{ .Static = 4096 }).init();
1343 try fifo.pump(entry_counting_reader.reader(), entry_writer);
1344 if (entry_counting_reader.bytes_read != object.uncompressed_length) {
1345 return error.InvalidObject;
1346 }
1347 const oid = entry_hashed_writer.hasher.finalResult();
1369 // part of the object's ID.
1370 try oid_hasher_bw.print("{s} {d}\x00", .{ @tagName(entry_header), object.uncompressed_length });
1371 const n = try entry_decompress_br.readRemaining(&oid_hasher_bw);
1372 if (n != object.uncompressed_length) return error.InvalidObject;
1373 try oid_hasher_bw.flush();
1374 const oid = oid_hasher.finalResult();
13481375 try index_entries.put(allocator, oid, .{
13491376 .offset = entry_offset,
13501377 .crc32 = entry_crc32_reader.hasher.final(),
13511378 });
13521379 },
13531380 inline .ofs_delta, .ref_delta => |delta| {
1354 var entry_decompress_stream = std.compress.zlib.decompressor(entry_crc32_reader.reader());
1355 var entry_counting_reader = std.io.countingReader(entry_decompress_stream.reader());
1356 var fifo = std.fifo.LinearFifo(u8, .{ .Static = 4096 }).init();
1357 try fifo.pump(entry_counting_reader.reader(), std.io.null_writer);
1358 if (entry_counting_reader.bytes_read != delta.uncompressed_length) {
1359 return error.InvalidObject;
1360 }
1381 const n = try entry_decompress_br.discardRemaining();
1382 if (n != delta.uncompressed_length) return error.InvalidObject;
13611383 try pending_deltas.append(allocator, .{
13621384 .offset = entry_offset,
13631385 .crc32 = entry_crc32_reader.hasher.final(),
......@@ -1367,15 +1389,11 @@ fn indexPackFirstPass(
13671389 }
13681390
13691391 const pack_checksum = pack_hashed_reader.hasher.finalResult();
1370 const recorded_checksum = try Oid.readBytes(format, pack_buffered_reader.reader());
1392 const recorded_checksum = try Oid.readBytes(format, &pack_br);
13711393 if (!mem.eql(u8, pack_checksum.slice(), recorded_checksum.slice())) {
13721394 return error.CorruptedPack;
13731395 }
1374 _ = pack_reader.readByte() catch |e| switch (e) {
1375 error.EndOfStream => return pack_checksum,
1376 else => |other| return other,
1377 };
1378 return error.InvalidFormat;
1396 return pack_checksum;
13791397}
13801398
13811399/// Attempts to determine the final object ID of the given deltified object.
......@@ -1384,7 +1402,7 @@ fn indexPackFirstPass(
13841402fn indexPackHashDelta(
13851403 allocator: Allocator,
13861404 format: Oid.Format,
1387 pack: std.fs.File,
1405 pack: *std.fs.File.Reader,
13881406 delta: IndexEntry,
13891407 index_entries: std.AutoHashMapUnmanaged(Oid, IndexEntry),
13901408 cache: *ObjectCache,
......@@ -1398,7 +1416,9 @@ fn indexPackHashDelta(
13981416 if (cache.get(base_offset)) |base_object| break base_object;
13991417
14001418 try pack.seekTo(base_offset);
1401 base_header = try EntryHeader.read(format, pack.reader());
1419 var pack_read_buffer: [64]u8 = undefined;
1420 var pack_br = pack.readable(&pack_read_buffer);
1421 base_header = try EntryHeader.read(format, &pack_br);
14021422 switch (base_header) {
14031423 .ofs_delta => |ofs_delta| {
14041424 try delta_offsets.append(allocator, base_offset);
......@@ -1409,7 +1429,7 @@ fn indexPackHashDelta(
14091429 base_offset = (index_entries.get(ref_delta.base_object) orelse return null).offset;
14101430 },
14111431 else => {
1412 const base_data = try readObjectRaw(allocator, pack.reader(), base_header.uncompressedLength());
1432 const base_data = try readObjectRaw(allocator, &pack_br, base_header.uncompressedLength());
14131433 errdefer allocator.free(base_data);
14141434 const base_object: Object = .{ .type = base_header.objectType(), .data = base_data };
14151435 try cache.put(allocator, base_offset, base_object);
......@@ -1421,9 +1441,12 @@ fn indexPackHashDelta(
14211441 const base_data = try resolveDeltaChain(allocator, format, pack, base_object, delta_offsets.items, cache);
14221442
14231443 var entry_hasher: Oid.Hasher = .init(format);
1424 var entry_hashed_writer = std.compress.hashedWriter(std.io.null_writer, &entry_hasher);
1425 try entry_hashed_writer.writer().print("{s} {}\x00", .{ @tagName(base_object.type), base_data.len });
1426 entry_hasher.update(base_data);
1444 var entry_hasher_buffer: [64]u8 = undefined;
1445 var entry_hasher_bw = entry_hasher.writable(&entry_hasher_buffer);
1446 // Writes to hashers cannot fail.
1447 entry_hasher_bw.print("{s} {d}\x00", .{ @tagName(base_object.type), base_data.len }) catch unreachable;
1448 entry_hasher_bw.writeAll(base_data) catch unreachable;
1449 entry_hasher_bw.flush() catch unreachable;
14271450 return entry_hasher.finalResult();
14281451}
14291452
......@@ -1434,7 +1457,7 @@ fn indexPackHashDelta(
14341457fn resolveDeltaChain(
14351458 allocator: Allocator,
14361459 format: Oid.Format,
1437 pack: std.fs.File,
1460 pack: *std.fs.File.Reader,
14381461 base_object: Object,
14391462 delta_offsets: []const u64,
14401463 cache: *ObjectCache,
......@@ -1446,21 +1469,22 @@ fn resolveDeltaChain(
14461469
14471470 const delta_offset = delta_offsets[i];
14481471 try pack.seekTo(delta_offset);
1449 const delta_header = try EntryHeader.read(format, pack.reader());
1450 const delta_data = try readObjectRaw(allocator, pack.reader(), delta_header.uncompressedLength());
1451 defer allocator.free(delta_data);
1452 var delta_stream = std.io.fixedBufferStream(delta_data);
1453 const delta_reader = delta_stream.reader();
1454 _ = try readSizeVarInt(delta_reader); // base object size
1455 const expanded_size = try readSizeVarInt(delta_reader);
1456
1472 var pack_read_buffer: [64]u8 = undefined;
1473 var pack_br = pack.readable(&pack_read_buffer);
1474 const delta_header = try EntryHeader.read(format, &pack_br);
1475 _ = delta_header;
1476 var delta_decompress: zlib.Decompressor = .init(&pack_br);
1477 var delta_decompress_buffer: [zlib.max_window_len]u8 = undefined;
1478 var delta_reader = delta_decompress.readable(&delta_decompress_buffer);
1479 _ = try readSizeVarInt(&delta_reader); // base object size
1480 const expanded_size = try readSizeVarInt(&delta_reader);
14571481 const expanded_alloc_size = std.math.cast(usize, expanded_size) orelse return error.ObjectTooLarge;
14581482 const expanded_data = try allocator.alloc(u8, expanded_alloc_size);
14591483 errdefer allocator.free(expanded_data);
1460 var expanded_delta_stream = std.io.fixedBufferStream(expanded_data);
1461 var base_stream = std.io.fixedBufferStream(base_data);
1462 try expandDelta(&base_stream, delta_reader, expanded_delta_stream.writer());
1463 if (expanded_delta_stream.pos != expanded_size) return error.InvalidObject;
1484 var expanded_delta_stream: std.io.BufferedWriter = undefined;
1485 expanded_delta_stream.initFixed(expanded_data);
1486 try expandDelta(base_data, &delta_reader, &expanded_delta_stream);
1487 if (expanded_delta_stream.end != expanded_size) return error.InvalidObject;
14641488
14651489 try cache.put(allocator, delta_offset, .{ .type = base_object.type, .data = expanded_data });
14661490 base_data = expanded_data;
......@@ -1468,31 +1492,23 @@ fn resolveDeltaChain(
14681492 return base_data;
14691493}
14701494
1471/// Reads the complete contents of an object from `reader`. This function may
1472/// read more bytes than required from `reader`, so the reader position after
1473/// returning is not reliable.
1474fn readObjectRaw(allocator: Allocator, reader: anytype, size: u64) ![]u8 {
1495/// Reads the complete contents of an object from `reader`.
1496fn readObjectRaw(gpa: Allocator, reader: *std.io.BufferedReader, size: u64) ![]u8 {
14751497 const alloc_size = std.math.cast(usize, size) orelse return error.ObjectTooLarge;
1476 var buffered_reader = std.io.bufferedReader(reader);
1477 var decompress_stream = std.compress.zlib.decompressor(buffered_reader.reader());
1478 const data = try allocator.alloc(u8, alloc_size);
1479 errdefer allocator.free(data);
1480 try decompress_stream.reader().readNoEof(data);
1481 _ = decompress_stream.reader().readByte() catch |e| switch (e) {
1482 error.EndOfStream => return data,
1483 else => |other| return other,
1484 };
1485 return error.InvalidFormat;
1498 var decompress: zlib.Decompressor = .init(reader);
1499 var buffer: std.ArrayListUnmanaged(u8) = .empty;
1500 defer buffer.deinit(gpa);
1501 try decompress.reader().readRemainingArrayList(gpa, null, &buffer, .limited(alloc_size), zlib.max_window_len);
1502 if (buffer.items.len < size) return error.EndOfStream;
1503 return buffer.toOwnedSlice(gpa);
14861504}
14871505
1488/// Expands delta data from `delta_reader` to `writer`. `base_object` must
1489/// support `reader` and `seekTo` (such as a `std.io.FixedBufferStream`).
1490///
14911506/// The format of the delta data is documented in
14921507/// [pack-format](https://git-scm.com/docs/pack-format).
1493fn expandDelta(base_object: anytype, delta_reader: *std.io.BufferedReader, writer: *std.io.BufferedWriter) !void {
1508fn expandDelta(base_object: []const u8, delta_reader: *std.io.BufferedReader, writer: *std.io.BufferedWriter) !void {
1509 var base_offset: u32 = 0;
14941510 while (true) {
1495 const inst: packed struct { value: u7, copy: bool } = @bitCast(delta_reader.readByte() catch |e| switch (e) {
1511 const inst: packed struct { value: u7, copy: bool } = @bitCast(delta_reader.takeByte() catch |e| switch (e) {
14961512 error.EndOfStream => return,
14971513 else => |other| return other,
14981514 });
......@@ -1507,23 +1523,22 @@ fn expandDelta(base_object: anytype, delta_reader: *std.io.BufferedReader, write
15071523 size3: bool,
15081524 } = @bitCast(inst.value);
15091525 const offset_parts: packed struct { offset1: u8, offset2: u8, offset3: u8, offset4: u8 } = .{
1510 .offset1 = if (available.offset1) try delta_reader.readByte() else 0,
1511 .offset2 = if (available.offset2) try delta_reader.readByte() else 0,
1512 .offset3 = if (available.offset3) try delta_reader.readByte() else 0,
1513 .offset4 = if (available.offset4) try delta_reader.readByte() else 0,
1526 .offset1 = if (available.offset1) try delta_reader.takeByte() else 0,
1527 .offset2 = if (available.offset2) try delta_reader.takeByte() else 0,
1528 .offset3 = if (available.offset3) try delta_reader.takeByte() else 0,
1529 .offset4 = if (available.offset4) try delta_reader.takeByte() else 0,
15141530 };
1515 const offset: u32 = @bitCast(offset_parts);
1531 base_offset = @bitCast(offset_parts);
15161532 const size_parts: packed struct { size1: u8, size2: u8, size3: u8 } = .{
1517 .size1 = if (available.size1) try delta_reader.readByte() else 0,
1518 .size2 = if (available.size2) try delta_reader.readByte() else 0,
1519 .size3 = if (available.size3) try delta_reader.readByte() else 0,
1533 .size1 = if (available.size1) try delta_reader.takeByte() else 0,
1534 .size2 = if (available.size2) try delta_reader.takeByte() else 0,
1535 .size3 = if (available.size3) try delta_reader.takeByte() else 0,
15201536 };
15211537 var size: u24 = @bitCast(size_parts);
15221538 if (size == 0) size = 0x10000;
1523 try base_object.seekTo(offset);
15241539
1525 var base_object_br = base_object.reader();
1526 try base_object_br.readAll(writer, .limited(size));
1540 try writer.writeAll(base_object[base_offset..][0..size]);
1541 base_offset += size;
15271542 } else if (inst.value != 0) {
15281543 try delta_reader.readAll(writer, .limited(inst.value));
15291544 } else {
......@@ -1557,7 +1572,8 @@ fn runRepositoryTest(comptime format: Oid.Format, head_commit: []const u8) !void
15571572
15581573 var index_file = try git_dir.dir.createFile("testrepo.idx", .{ .read = true });
15591574 defer index_file.close();
1560 try indexPack(testing.allocator, format, pack_file, index_file.writer());
1575 var index_file_writer = index_file.writer();
1576 try indexPack(testing.allocator, format, pack_file, &index_file_writer);
15611577
15621578 // Arbitrary size limit on files read while checking the repository contents
15631579 // (all files in the test repo are known to be smaller than this)
......@@ -1571,7 +1587,8 @@ fn runRepositoryTest(comptime format: Oid.Format, head_commit: []const u8) !void
15711587 const testrepo_idx = @embedFile("git/testdata/testrepo-" ++ @tagName(format) ++ ".idx");
15721588 try testing.expectEqualSlices(u8, testrepo_idx, index_file_data);
15731589
1574 var repository = try Repository.init(testing.allocator, format, pack_file, index_file);
1590 var index_file_reader = index_file_writer.moveToReader();
1591 var repository = try Repository.init(testing.allocator, format, pack_file, &index_file_reader);
15751592 defer repository.deinit();
15761593
15771594 var worktree = testing.tmpDir(.{ .iterate = true });
......@@ -1652,10 +1669,12 @@ test "SHA-256 packfile indexing and checkout" {
16521669/// Checks out a commit of a packfile. Intended for experimenting with and
16531670/// benchmarking possible optimizations to the indexing and checkout behavior.
16541671pub fn main() !void {
1655 const allocator = std.heap.c_allocator;
1672 var debug_allocator: std.heap.DebugAllocator(.{}) = .init;
1673 defer _ = debug_allocator.deinit();
1674 const gpa = if (std.debug.runtime_safety) debug_allocator.allocator() else std.heap.smp_allocator;
16561675
1657 const args = try std.process.argsAlloc(allocator);
1658 defer std.process.argsFree(allocator, args);
1676 const args = try std.process.argsAlloc(gpa);
1677 defer std.process.argsFree(gpa, args);
16591678 if (args.len != 5) {
16601679 return error.InvalidArguments; // Arguments: format packfile commit worktree
16611680 }
......@@ -1674,15 +1693,17 @@ pub fn main() !void {
16741693 std.debug.print("Starting index...\n", .{});
16751694 var index_file = try git_dir.createFile("idx", .{ .read = true });
16761695 defer index_file.close();
1677 var index_buffered_writer = std.io.bufferedWriter(index_file.writer());
1678 try indexPack(allocator, format, pack_file, index_buffered_writer.writer());
1679 try index_buffered_writer.flush();
1696 var index_file_writer = index_file.writer();
1697 var pack_file_reader = pack_file.reader();
1698 try indexPack(gpa, format, &pack_file_reader, &index_file_writer);
16801699 try index_file.sync();
16811700
16821701 std.debug.print("Starting checkout...\n", .{});
1683 var repository = try Repository.init(allocator, format, pack_file, index_file);
1702 var index_file_reader = index_file_writer.moveToReader();
1703 var repository: Repository = undefined;
1704 try repository.init(gpa, format, &pack_file_reader, &index_file_reader);
16841705 defer repository.deinit();
1685 var diagnostics: Diagnostics = .{ .allocator = allocator };
1706 var diagnostics: Diagnostics = .{ .allocator = gpa };
16861707 defer diagnostics.deinit();
16871708 try repository.checkout(worktree, commit, &diagnostics);
16881709
src/main.zig+3-4
......@@ -3330,12 +3330,11 @@ fn buildOutputType(
33303330 // for the hashing algorithm here and in the cache are the same.
33313331 // We are providing our own cache key, because this file has nothing
33323332 // to do with the cache manifest.
3333 var hasher = Cache.Hasher.init("0123456789abcdef");
33343333 var file_writer = f.writer();
3335 var file_writer_bw = file_writer.interface().unbuffered();
3336 var hasher_writer = hasher.writer(&file_writer_bw);
3334 var file_writer_bw = file_writer.writable(&.{});
3335 var hasher_writer = file_writer_bw.hashed(Cache.Hasher.init("0123456789abcdef"));
33373336 var buffer: [1000]u8 = undefined;
3338 var bw = hasher_writer.interface().buffered(&buffer);
3337 var bw = hasher_writer.writable(&buffer);
33393338 bw.writeFileAll(.stdin(), .{}) catch |err| switch (err) {
33403339 error.WriteFailed => fatal("failed to write {s}: {s}", .{ dump_path, file_writer.err.? }),
33413340 else => fatal("failed to pipe stdin to {s}: {s}", .{ dump_path, err }),