Hashed
Provides a Writer implementation based on calling Hasher.update, sending
all data also to an underlying Writer.
When using this, the underlying writer is best unbuffered because all writes are passed on directly to it.
This implementation makes suboptimal buffering decisions due to being generic. A better solution will involve creating a writer for each hash function, where the splat buffer can be tailored to the hash implementation details.
Contrast with Hashing which terminates the stream pipeline.
Fields of this type
Fields
Functions in this namespace
Functions
Source
Implementation
pub fn Hashed(comptime Hasher: type) type {
return struct {
out: *Writer,
hasher: Hasher,
writer: Writer,
pub fn init(out: *Writer, buffer: []u8) @This() {
return .initHasher(out, .{}, buffer);
}
pub fn initHasher(out: *Writer, hasher: Hasher, buffer: []u8) @This() {
return .{
.out = out,
.hasher = hasher,
.writer = .{
.buffer = buffer,
.vtable = &.{ .drain = @This().drain },
},
};
}
fn drain(w: *Writer, data: []const []const u8, splat: usize) Error!usize {
const this: *@This() = @alignCast(@fieldParentPtr("writer", w));
const aux = w.buffered();
const aux_n = try this.out.writeSplatHeader(aux, data, splat);
if (aux_n < w.end) {
this.hasher.update(w.buffer[0..aux_n]);
const remaining = w.buffer[aux_n..w.end];
@memmove(w.buffer[0..remaining.len], remaining);
w.end = remaining.len;
return 0;
}
this.hasher.update(aux);
const n = aux_n - w.end;
w.end = 0;
var remaining: usize = n;
for (data[0 .. data.len - 1]) |slice| {
if (remaining <= slice.len) {
this.hasher.update(slice[0..remaining]);
return n;
}
remaining -= slice.len;
this.hasher.update(slice);
}
const pattern = data[data.len - 1];
assert(remaining <= splat * pattern.len);
switch (pattern.len) {
0 => {
assert(remaining == 0);
},
1 => {
var buffer: [64]u8 = undefined;
@memset(&buffer, pattern[0]);
while (remaining > 0) {
const update_len = @min(remaining, buffer.len);
this.hasher.update(buffer[0..update_len]);
remaining -= update_len;
}
},
else => {
while (remaining > 0) {
const update_len = @min(remaining, pattern.len);
this.hasher.update(pattern[0..update_len]);
remaining -= update_len;
}
},
}
return n;
}
};
}