The main goal here is to make the function pointers comptime, so that we don't have to do the crazy stuff with async function frames. Since InStream, OutStream, and SeekableStream are already generic across error sets, it's not really worse to make them generic across the vtable as well. See #764 for the open issue acknowledging that using generics for these abstractions is a design flaw. See #130 for the efforts to make these abstractions non-generic. This commit also changes the OutStream API so that `write` returns number of bytes written, and `writeAll` is the one that loops until the whole buffer is written.
86 lines
3.0 KiB
Zig
86 lines
3.0 KiB
Zig
const std = @import("../std.zig");
|
|
const builtin = std.builtin;
|
|
const mem = std.mem;
|
|
|
|
pub fn OutStream(
|
|
comptime Context: type,
|
|
comptime WriteError: type,
|
|
comptime writeFn: fn (context: Context, bytes: []const u8) WriteError!usize,
|
|
) type {
|
|
return struct {
|
|
context: Context,
|
|
|
|
const Self = @This();
|
|
pub const Error = WriteError;
|
|
|
|
pub fn write(self: Self, bytes: []const u8) Error!usize {
|
|
return writeFn(self.context, bytes);
|
|
}
|
|
|
|
pub fn writeAll(self: Self, bytes: []const u8) Error!void {
|
|
var index: usize = 0;
|
|
while (index != bytes.len) {
|
|
index += try self.write(bytes[index..]);
|
|
}
|
|
}
|
|
|
|
pub fn print(self: Self, comptime format: []const u8, args: var) Error!void {
|
|
return std.fmt.format(self, Error, writeAll, format, args);
|
|
}
|
|
|
|
pub fn writeByte(self: Self, byte: u8) Error!void {
|
|
const array = [1]u8{byte};
|
|
return self.writeAll(&array);
|
|
}
|
|
|
|
pub fn writeByteNTimes(self: Self, byte: u8, n: usize) Error!void {
|
|
var bytes: [256]u8 = undefined;
|
|
mem.set(u8, bytes[0..], byte);
|
|
|
|
var remaining: usize = n;
|
|
while (remaining > 0) {
|
|
const to_write = std.math.min(remaining, bytes.len);
|
|
try self.writeAll(bytes[0..to_write]);
|
|
remaining -= to_write;
|
|
}
|
|
}
|
|
|
|
/// Write a native-endian integer.
|
|
/// TODO audit non-power-of-two int sizes
|
|
pub fn writeIntNative(self: Self, comptime T: type, value: T) Error!void {
|
|
var bytes: [(T.bit_count + 7) / 8]u8 = undefined;
|
|
mem.writeIntNative(T, &bytes, value);
|
|
return self.writeAll(&bytes);
|
|
}
|
|
|
|
/// Write a foreign-endian integer.
|
|
/// TODO audit non-power-of-two int sizes
|
|
pub fn writeIntForeign(self: Self, comptime T: type, value: T) Error!void {
|
|
var bytes: [(T.bit_count + 7) / 8]u8 = undefined;
|
|
mem.writeIntForeign(T, &bytes, value);
|
|
return self.writeAll(&bytes);
|
|
}
|
|
|
|
/// TODO audit non-power-of-two int sizes
|
|
pub fn writeIntLittle(self: Self, comptime T: type, value: T) Error!void {
|
|
var bytes: [(T.bit_count + 7) / 8]u8 = undefined;
|
|
mem.writeIntLittle(T, &bytes, value);
|
|
return self.writeAll(&bytes);
|
|
}
|
|
|
|
/// TODO audit non-power-of-two int sizes
|
|
pub fn writeIntBig(self: Self, comptime T: type, value: T) Error!void {
|
|
var bytes: [(T.bit_count + 7) / 8]u8 = undefined;
|
|
mem.writeIntBig(T, &bytes, value);
|
|
return self.writeAll(&bytes);
|
|
}
|
|
|
|
/// TODO audit non-power-of-two int sizes
|
|
pub fn writeInt(self: Self, comptime T: type, value: T, endian: builtin.Endian) Error!void {
|
|
var bytes: [(T.bit_count + 7) / 8]u8 = undefined;
|
|
mem.writeInt(T, &bytes, value, endian);
|
|
return self.writeAll(&bytes);
|
|
}
|
|
};
|
|
}
|