Type Function Hashed [src]
Provides a Reader implementation by passing data from an underlying
reader through Hasher.update.
The underlying reader is best unbuffered.
This implementation makes suboptimal buffering decisions due to being
generic. A better solution will involve creating a reader for each hash
function, where the discard buffer can be tailored to the hash
implementation details.
Prototype
pub fn Hashed(comptime Hasher: type) type
Parameters
Hasher: type
Source
pub fn Hashed(comptime Hasher: type) type {
return struct {
in: *Reader,
hasher: Hasher,
reader: Reader,
pub fn init(in: *Reader, hasher: Hasher, buffer: []u8) @This() {
return .{
.in = in,
.hasher = hasher,
.reader = .{
.vtable = &.{
.stream = @This().stream,
.readVec = @This().readVec,
.discard = @This().discard,
},
.buffer = buffer,
.end = 0,
.seek = 0,
},
};
}
fn stream(r: *Reader, w: *Writer, limit: Limit) StreamError!usize {
const this: *@This() = @alignCast(@fieldParentPtr("reader", r));
const data = limit.slice(try w.writableSliceGreedy(1));
var vec: [1][]u8 = .{data};
const n = try this.in.readVec(&vec);
this.hasher.update(data[0..n]);
w.advance(n);
return n;
}
fn readVec(r: *Reader, data: [][]u8) Error!usize {
const this: *@This() = @alignCast(@fieldParentPtr("reader", r));
var vecs: [8][]u8 = undefined; // Arbitrarily chosen amount.
const dest_n, const data_size = try r.writableVector(&vecs, data);
const dest = vecs[0..dest_n];
const n = try this.in.readVec(dest);
var remaining: usize = n;
for (dest) |slice| {
if (remaining < slice.len) {
this.hasher.update(slice[0..remaining]);
remaining = 0;
break;
} else {
remaining -= slice.len;
this.hasher.update(slice);
}
}
assert(remaining == 0);
if (n > data_size) {
r.end += n - data_size;
return data_size;
}
return n;
}
fn discard(r: *Reader, limit: Limit) Error!usize {
const this: *@This() = @alignCast(@fieldParentPtr("reader", r));
const peeked = limit.slice(try this.in.peekGreedy(1));
this.hasher.update(peeked);
this.in.toss(peeked.len);
return peeked.len;
}
};
}