feature. See also
. The project being documented here (as the example) is the Zig library itself.
Pdb.MsfStream
const MsfStream = struct
File
Code
const MsfStream = struct {
file_reader: *File.Reader,
next_read_pos: u64,
blocks: []u32,
block_size: u32,
interface: Io.Reader,
err: ?Error,
const Error = File.Reader.SeekError;
const empty: MsfStream = .{
.file_reader = undefined,
.next_read_pos = 0,
.blocks = &.{},
.block_size = undefined,
.interface = .ending_instance,
.err = null,
};
fn init(block_size: u32, file_reader: *File.Reader, blocks: []u32, buffer: []u8) MsfStream {
return .{
.file_reader = file_reader,
.next_read_pos = 0,
.blocks = blocks,
.block_size = block_size,
.interface = .{
.vtable = &.{ .stream = stream },
.buffer = buffer,
.seek = 0,
.end = 0,
},
.err = null,
};
}
fn stream(r: *Io.Reader, w: *Io.Writer, limit: Io.Limit) Io.Reader.StreamError!usize {
const ms: *MsfStream = @alignCast(@fieldParentPtr("interface", r));
var block_id: usize = @intCast(ms.next_read_pos / ms.block_size);
if (block_id >= ms.blocks.len) return error.EndOfStream;
var block = ms.blocks[block_id];
var offset = ms.next_read_pos % ms.block_size;
ms.file_reader.seekTo(block * ms.block_size + offset) catch |err| {
ms.err = err;
return error.ReadFailed;
};
var remaining = @backingInt(limit);
while (remaining != 0) {
const stream_len: usize = @min(remaining, ms.block_size - offset);
const n = try ms.file_reader.interface.stream(w, .limited(stream_len));
remaining -= n;
offset += n;
if (offset == ms.block_size) {
offset = 0;
block_id += 1;
if (block_id >= ms.blocks.len) break;
block = ms.blocks[block_id];
ms.file_reader.seekTo(block * ms.block_size) catch |err| {
ms.err = err;
return error.ReadFailed;
};
}
}
const total = @backingInt(limit) - remaining;
ms.next_read_pos += total;
return total;
}
pub fn logicalPos(ms: *const MsfStream) u64 {
return ms.next_read_pos - ms.interface.bufferedLen();
}
pub fn seekBy(ms: *MsfStream, len: i64) !void {
ms.next_read_pos = @as(u64, @intCast(@as(i64, @intCast(ms.logicalPos())) + len));
if (ms.next_read_pos >= ms.blocks.len * ms.block_size) return error.EOF;
ms.interface.tossBuffered();
}
pub fn seekTo(ms: *MsfStream, len: u64) !void {
ms.next_read_pos = len;
if (ms.next_read_pos >= ms.blocks.len * ms.block_size) return error.EOF;
ms.interface.tossBuffered();
}
fn getSize(ms: *const MsfStream) u64 {
return ms.blocks.len * ms.block_size;
}
fn getFilePos(ms: *const MsfStream) u64 {
const pos = ms.logicalPos();
const block_id = pos / ms.block_size;
const block = ms.blocks[block_id];
const offset = pos % ms.block_size;
return block * ms.block_size + offset;
}
}