Type Function Hashed [src]
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.
Prototype
pub fn Hashed(comptime Hasher: type) type
Parameters
Hasher: type
Source
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;
}
};
}