support Writer instead of OutStream
Start implementing https://github.com/ziglang/zig/issues/4917 which is to rename instream/outstream to reader/writer. This first change allows code to use Writer/writer instead of OutStream/outStream, but still maintains the old outstream names with "Deprecated" comments.
This commit is contained in:
parent
f5b584cc13
commit
7481582774
@ -53,7 +53,7 @@ pub const LineInfo = struct {
|
||||
/// Tries to write to stderr, unbuffered, and ignores any error returned.
|
||||
/// Does not append a newline.
|
||||
var stderr_file: File = undefined;
|
||||
var stderr_file_out_stream: File.OutStream = undefined;
|
||||
var stderr_file_writer: File.Writer = undefined;
|
||||
|
||||
var stderr_stream: ?*File.OutStream = null;
|
||||
var stderr_mutex = std.Mutex.init();
|
||||
@ -70,8 +70,8 @@ pub fn getStderrStream() *File.OutStream {
|
||||
return st;
|
||||
} else {
|
||||
stderr_file = io.getStdErr();
|
||||
stderr_file_out_stream = stderr_file.outStream();
|
||||
const st = &stderr_file_out_stream;
|
||||
stderr_file_writer = stderr_file.outStream();
|
||||
const st = &stderr_file_writer;
|
||||
stderr_stream = st;
|
||||
return st;
|
||||
}
|
||||
|
@ -648,9 +648,17 @@ pub const File = struct {
|
||||
return .{ .context = file };
|
||||
}
|
||||
|
||||
pub const OutStream = io.OutStream(File, WriteError, write);
|
||||
pub const Writer = io.Writer(File, WriteError, write);
|
||||
|
||||
pub fn outStream(file: File) OutStream {
|
||||
/// Deprecated: use `Writer`
|
||||
pub const OutStream = Writer;
|
||||
|
||||
pub fn writer(file: File) Writer {
|
||||
return .{ .context = file };
|
||||
}
|
||||
|
||||
/// Deprecated: use `writer`
|
||||
pub fn outStream(file: File) Writer {
|
||||
return .{ .context = file };
|
||||
}
|
||||
|
||||
|
@ -102,11 +102,17 @@ pub fn getStdIn() File {
|
||||
}
|
||||
|
||||
pub const InStream = @import("io/in_stream.zig").InStream;
|
||||
pub const OutStream = @import("io/out_stream.zig").OutStream;
|
||||
pub const Writer = @import("io/writer.zig").Writer;
|
||||
/// Deprecated: use `Writer`
|
||||
pub const OutStream = Writer;
|
||||
pub const SeekableStream = @import("io/seekable_stream.zig").SeekableStream;
|
||||
|
||||
pub const BufferedOutStream = @import("io/buffered_out_stream.zig").BufferedOutStream;
|
||||
pub const bufferedOutStream = @import("io/buffered_out_stream.zig").bufferedOutStream;
|
||||
pub const BufferedWriter = @import("io/buffered_writer.zig").BufferedWriter;
|
||||
pub const bufferedWriter = @import("io/buffered_writer.zig").bufferedWriter;
|
||||
/// Deprecated: use `BufferedWriter`
|
||||
pub const BufferedOutStream = BufferedWriter;
|
||||
/// Deprecated: use `bufferedWriter`
|
||||
pub const bufferedOutStream = bufferedWriter;
|
||||
|
||||
pub const BufferedInStream = @import("io/buffered_in_stream.zig").BufferedInStream;
|
||||
pub const bufferedInStream = @import("io/buffered_in_stream.zig").bufferedInStream;
|
||||
@ -117,20 +123,36 @@ pub const peekStream = @import("io/peek_stream.zig").peekStream;
|
||||
pub const FixedBufferStream = @import("io/fixed_buffer_stream.zig").FixedBufferStream;
|
||||
pub const fixedBufferStream = @import("io/fixed_buffer_stream.zig").fixedBufferStream;
|
||||
|
||||
pub const COutStream = @import("io/c_out_stream.zig").COutStream;
|
||||
pub const cOutStream = @import("io/c_out_stream.zig").cOutStream;
|
||||
pub const CWriter = @import("io/c_writer.zig").CWriter;
|
||||
pub const cWriter = @import("io/c_writer.zig").cWriter;
|
||||
/// Deprecated: use `CWriter`
|
||||
pub const COutStream = CWriter;
|
||||
/// Deprecated: use `cWriter`
|
||||
pub const cOutStream = cWriter;
|
||||
|
||||
pub const CountingOutStream = @import("io/counting_out_stream.zig").CountingOutStream;
|
||||
pub const countingOutStream = @import("io/counting_out_stream.zig").countingOutStream;
|
||||
pub const CountingWriter = @import("io/counting_writer.zig").CountingWriter;
|
||||
pub const countingWriter = @import("io/counting_writer.zig").countingWriter;
|
||||
/// Deprecated: use `CountingWriter`
|
||||
pub const CountingOutStream = CountingWriter;
|
||||
/// Deprecated: use `countingWriter`
|
||||
pub const countingOutStream = countingWriter;
|
||||
|
||||
pub const MultiOutStream = @import("io/multi_out_stream.zig").MultiOutStream;
|
||||
pub const multiOutStream = @import("io/multi_out_stream.zig").multiOutStream;
|
||||
pub const MultiWriter = @import("io/multi_writer.zig").MultiWriter;
|
||||
pub const multiWriter = @import("io/multi_writer.zig").multiWriter;
|
||||
/// Deprecated: use `MultiWriter`
|
||||
pub const MultiOutStream = MultiWriter;
|
||||
/// Deprecated: use `multiWriter`
|
||||
pub const multiOutStream = multiWriter;
|
||||
|
||||
pub const BitInStream = @import("io/bit_in_stream.zig").BitInStream;
|
||||
pub const bitInStream = @import("io/bit_in_stream.zig").bitInStream;
|
||||
|
||||
pub const BitOutStream = @import("io/bit_out_stream.zig").BitOutStream;
|
||||
pub const bitOutStream = @import("io/bit_out_stream.zig").bitOutStream;
|
||||
pub const BitWriter = @import("io/bit_writer.zig").BitWriter;
|
||||
pub const bitWriter = @import("io/bit_writer.zig").bitWriter;
|
||||
/// Deprecated: use `BitWriter`
|
||||
pub const BitOutStream = BitWriter;
|
||||
/// Deprecated: use `bitWriter`
|
||||
pub const bitOutStream = bitWriter;
|
||||
|
||||
pub const Packing = @import("io/serialization.zig").Packing;
|
||||
|
||||
@ -144,29 +166,34 @@ pub const BufferedAtomicFile = @import("io/buffered_atomic_file.zig").BufferedAt
|
||||
|
||||
pub const StreamSource = @import("io/stream_source.zig").StreamSource;
|
||||
|
||||
/// An OutStream that doesn't write to anything.
|
||||
pub const null_out_stream = @as(NullOutStream, .{ .context = {} });
|
||||
/// A Writer that doesn't write to anything.
|
||||
pub const null_writer = @as(NullWriter, .{ .context = {} });
|
||||
|
||||
const NullOutStream = OutStream(void, error{}, dummyWrite);
|
||||
/// Deprecated: use `null_writer`
|
||||
pub const null_out_stream = null_writer;
|
||||
|
||||
const NullWriter = Writer(void, error{}, dummyWrite);
|
||||
/// Deprecated: use NullWriter
|
||||
const NullOutStream = NullWriter;
|
||||
fn dummyWrite(context: void, data: []const u8) error{}!usize {
|
||||
return data.len;
|
||||
}
|
||||
|
||||
test "null_out_stream" {
|
||||
null_out_stream.writeAll("yay" ** 10) catch |err| switch (err) {};
|
||||
test "null_writer" {
|
||||
null_writer.writeAll("yay" ** 10) catch |err| switch (err) {};
|
||||
}
|
||||
|
||||
test "" {
|
||||
_ = @import("io/bit_in_stream.zig");
|
||||
_ = @import("io/bit_out_stream.zig");
|
||||
_ = @import("io/bit_writer.zig");
|
||||
_ = @import("io/buffered_atomic_file.zig");
|
||||
_ = @import("io/buffered_in_stream.zig");
|
||||
_ = @import("io/buffered_out_stream.zig");
|
||||
_ = @import("io/c_out_stream.zig");
|
||||
_ = @import("io/counting_out_stream.zig");
|
||||
_ = @import("io/buffered_writer.zig");
|
||||
_ = @import("io/c_writer.zig");
|
||||
_ = @import("io/counting_writer.zig");
|
||||
_ = @import("io/fixed_buffer_stream.zig");
|
||||
_ = @import("io/in_stream.zig");
|
||||
_ = @import("io/out_stream.zig");
|
||||
_ = @import("io/writer.zig");
|
||||
_ = @import("io/peek_stream.zig");
|
||||
_ = @import("io/seekable_stream.zig");
|
||||
_ = @import("io/serialization.zig");
|
||||
|
@ -1,197 +1,5 @@
|
||||
const std = @import("../std.zig");
|
||||
const builtin = std.builtin;
|
||||
const io = std.io;
|
||||
const testing = std.testing;
|
||||
const assert = std.debug.assert;
|
||||
const trait = std.meta.trait;
|
||||
const meta = std.meta;
|
||||
const math = std.math;
|
||||
/// Deprecated: use `std.io.bit_writer.BitWriter`
|
||||
pub const BitOutStream = @import("./bit_writer.zig").BitWriter;
|
||||
|
||||
/// Creates a stream which allows for writing bit fields to another stream
|
||||
pub fn BitOutStream(endian: builtin.Endian, comptime OutStreamType: type) type {
|
||||
return struct {
|
||||
out_stream: OutStreamType,
|
||||
bit_buffer: u8,
|
||||
bit_count: u4,
|
||||
|
||||
pub const Error = OutStreamType.Error;
|
||||
pub const OutStream = io.OutStream(*Self, Error, write);
|
||||
|
||||
const Self = @This();
|
||||
const u8_bit_count = comptime meta.bitCount(u8);
|
||||
const u4_bit_count = comptime meta.bitCount(u4);
|
||||
|
||||
pub fn init(out_stream: OutStreamType) Self {
|
||||
return Self{
|
||||
.out_stream = out_stream,
|
||||
.bit_buffer = 0,
|
||||
.bit_count = 0,
|
||||
};
|
||||
}
|
||||
|
||||
/// Write the specified number of bits to the stream from the least significant bits of
|
||||
/// the specified unsigned int value. Bits will only be written to the stream when there
|
||||
/// are enough to fill a byte.
|
||||
pub fn writeBits(self: *Self, value: var, bits: usize) Error!void {
|
||||
if (bits == 0) return;
|
||||
|
||||
const U = @TypeOf(value);
|
||||
comptime assert(trait.isUnsignedInt(U));
|
||||
|
||||
//by extending the buffer to a minimum of u8 we can cover a number of edge cases
|
||||
// related to shifting and casting.
|
||||
const u_bit_count = comptime meta.bitCount(U);
|
||||
const buf_bit_count = bc: {
|
||||
assert(u_bit_count >= bits);
|
||||
break :bc if (u_bit_count <= u8_bit_count) u8_bit_count else u_bit_count;
|
||||
};
|
||||
const Buf = std.meta.Int(false, buf_bit_count);
|
||||
const BufShift = math.Log2Int(Buf);
|
||||
|
||||
const buf_value = @intCast(Buf, value);
|
||||
|
||||
const high_byte_shift = @intCast(BufShift, buf_bit_count - u8_bit_count);
|
||||
var in_buffer = switch (endian) {
|
||||
.Big => buf_value << @intCast(BufShift, buf_bit_count - bits),
|
||||
.Little => buf_value,
|
||||
};
|
||||
var in_bits = bits;
|
||||
|
||||
if (self.bit_count > 0) {
|
||||
const bits_remaining = u8_bit_count - self.bit_count;
|
||||
const n = @intCast(u3, if (bits_remaining > bits) bits else bits_remaining);
|
||||
switch (endian) {
|
||||
.Big => {
|
||||
const shift = @intCast(BufShift, high_byte_shift + self.bit_count);
|
||||
const v = @intCast(u8, in_buffer >> shift);
|
||||
self.bit_buffer |= v;
|
||||
in_buffer <<= n;
|
||||
},
|
||||
.Little => {
|
||||
const v = @truncate(u8, in_buffer) << @intCast(u3, self.bit_count);
|
||||
self.bit_buffer |= v;
|
||||
in_buffer >>= n;
|
||||
},
|
||||
}
|
||||
self.bit_count += n;
|
||||
in_bits -= n;
|
||||
|
||||
//if we didn't fill the buffer, it's because bits < bits_remaining;
|
||||
if (self.bit_count != u8_bit_count) return;
|
||||
try self.out_stream.writeByte(self.bit_buffer);
|
||||
self.bit_buffer = 0;
|
||||
self.bit_count = 0;
|
||||
}
|
||||
//at this point we know bit_buffer is empty
|
||||
|
||||
//copy bytes until we can't fill one anymore, then leave the rest in bit_buffer
|
||||
while (in_bits >= u8_bit_count) {
|
||||
switch (endian) {
|
||||
.Big => {
|
||||
const v = @intCast(u8, in_buffer >> high_byte_shift);
|
||||
try self.out_stream.writeByte(v);
|
||||
in_buffer <<= @intCast(u3, u8_bit_count - 1);
|
||||
in_buffer <<= 1;
|
||||
},
|
||||
.Little => {
|
||||
const v = @truncate(u8, in_buffer);
|
||||
try self.out_stream.writeByte(v);
|
||||
in_buffer >>= @intCast(u3, u8_bit_count - 1);
|
||||
in_buffer >>= 1;
|
||||
},
|
||||
}
|
||||
in_bits -= u8_bit_count;
|
||||
}
|
||||
|
||||
if (in_bits > 0) {
|
||||
self.bit_count = @intCast(u4, in_bits);
|
||||
self.bit_buffer = switch (endian) {
|
||||
.Big => @truncate(u8, in_buffer >> high_byte_shift),
|
||||
.Little => @truncate(u8, in_buffer),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// Flush any remaining bits to the stream.
|
||||
pub fn flushBits(self: *Self) Error!void {
|
||||
if (self.bit_count == 0) return;
|
||||
try self.out_stream.writeByte(self.bit_buffer);
|
||||
self.bit_buffer = 0;
|
||||
self.bit_count = 0;
|
||||
}
|
||||
|
||||
pub fn write(self: *Self, buffer: []const u8) Error!usize {
|
||||
// TODO: I'm not sure this is a good idea, maybe flushBits should be forced
|
||||
if (self.bit_count > 0) {
|
||||
for (buffer) |b, i|
|
||||
try self.writeBits(b, u8_bit_count);
|
||||
return buffer.len;
|
||||
}
|
||||
|
||||
return self.out_stream.write(buffer);
|
||||
}
|
||||
|
||||
pub fn outStream(self: *Self) OutStream {
|
||||
return .{ .context = self };
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn bitOutStream(
|
||||
comptime endian: builtin.Endian,
|
||||
underlying_stream: var,
|
||||
) BitOutStream(endian, @TypeOf(underlying_stream)) {
|
||||
return BitOutStream(endian, @TypeOf(underlying_stream)).init(underlying_stream);
|
||||
}
|
||||
|
||||
test "api coverage" {
|
||||
var mem_be = [_]u8{0} ** 2;
|
||||
var mem_le = [_]u8{0} ** 2;
|
||||
|
||||
var mem_out_be = io.fixedBufferStream(&mem_be);
|
||||
var bit_stream_be = bitOutStream(.Big, mem_out_be.outStream());
|
||||
|
||||
try bit_stream_be.writeBits(@as(u2, 1), 1);
|
||||
try bit_stream_be.writeBits(@as(u5, 2), 2);
|
||||
try bit_stream_be.writeBits(@as(u128, 3), 3);
|
||||
try bit_stream_be.writeBits(@as(u8, 4), 4);
|
||||
try bit_stream_be.writeBits(@as(u9, 5), 5);
|
||||
try bit_stream_be.writeBits(@as(u1, 1), 1);
|
||||
|
||||
testing.expect(mem_be[0] == 0b11001101 and mem_be[1] == 0b00001011);
|
||||
|
||||
mem_out_be.pos = 0;
|
||||
|
||||
try bit_stream_be.writeBits(@as(u15, 0b110011010000101), 15);
|
||||
try bit_stream_be.flushBits();
|
||||
testing.expect(mem_be[0] == 0b11001101 and mem_be[1] == 0b00001010);
|
||||
|
||||
mem_out_be.pos = 0;
|
||||
try bit_stream_be.writeBits(@as(u32, 0b110011010000101), 16);
|
||||
testing.expect(mem_be[0] == 0b01100110 and mem_be[1] == 0b10000101);
|
||||
|
||||
try bit_stream_be.writeBits(@as(u0, 0), 0);
|
||||
|
||||
var mem_out_le = io.fixedBufferStream(&mem_le);
|
||||
var bit_stream_le = bitOutStream(.Little, mem_out_le.outStream());
|
||||
|
||||
try bit_stream_le.writeBits(@as(u2, 1), 1);
|
||||
try bit_stream_le.writeBits(@as(u5, 2), 2);
|
||||
try bit_stream_le.writeBits(@as(u128, 3), 3);
|
||||
try bit_stream_le.writeBits(@as(u8, 4), 4);
|
||||
try bit_stream_le.writeBits(@as(u9, 5), 5);
|
||||
try bit_stream_le.writeBits(@as(u1, 1), 1);
|
||||
|
||||
testing.expect(mem_le[0] == 0b00011101 and mem_le[1] == 0b10010101);
|
||||
|
||||
mem_out_le.pos = 0;
|
||||
try bit_stream_le.writeBits(@as(u15, 0b110011010000101), 15);
|
||||
try bit_stream_le.flushBits();
|
||||
testing.expect(mem_le[0] == 0b10000101 and mem_le[1] == 0b01100110);
|
||||
|
||||
mem_out_le.pos = 0;
|
||||
try bit_stream_le.writeBits(@as(u32, 0b1100110100001011), 16);
|
||||
testing.expect(mem_le[0] == 0b00001011 and mem_le[1] == 0b11001101);
|
||||
|
||||
try bit_stream_le.writeBits(@as(u0, 0), 0);
|
||||
}
|
||||
/// Deprecated: use `std.io.bit_writer.bitWriter`
|
||||
pub const bitOutStream = @import("./bit_writer.zig").bitWriter;
|
||||
|
203
lib/std/io/bit_writer.zig
Normal file
203
lib/std/io/bit_writer.zig
Normal file
@ -0,0 +1,203 @@
|
||||
const std = @import("../std.zig");
|
||||
const builtin = std.builtin;
|
||||
const io = std.io;
|
||||
const testing = std.testing;
|
||||
const assert = std.debug.assert;
|
||||
const trait = std.meta.trait;
|
||||
const meta = std.meta;
|
||||
const math = std.math;
|
||||
|
||||
/// Creates a stream which allows for writing bit fields to another stream
|
||||
pub fn BitWriter(endian: builtin.Endian, comptime WriterType: type) type {
|
||||
return struct {
|
||||
forward_writer: WriterType,
|
||||
bit_buffer: u8,
|
||||
bit_count: u4,
|
||||
|
||||
pub const Error = WriterType.Error;
|
||||
pub const Writer = io.Writer(*Self, Error, write);
|
||||
/// Deprecated: use `Writer`
|
||||
pub const OutStream = io.OutStream(*Self, Error, write);
|
||||
|
||||
const Self = @This();
|
||||
const u8_bit_count = comptime meta.bitCount(u8);
|
||||
const u4_bit_count = comptime meta.bitCount(u4);
|
||||
|
||||
pub fn init(forward_writer: WriterType) Self {
|
||||
return Self{
|
||||
.forward_writer = forward_writer,
|
||||
.bit_buffer = 0,
|
||||
.bit_count = 0,
|
||||
};
|
||||
}
|
||||
|
||||
/// Write the specified number of bits to the stream from the least significant bits of
|
||||
/// the specified unsigned int value. Bits will only be written to the stream when there
|
||||
/// are enough to fill a byte.
|
||||
pub fn writeBits(self: *Self, value: var, bits: usize) Error!void {
|
||||
if (bits == 0) return;
|
||||
|
||||
const U = @TypeOf(value);
|
||||
comptime assert(trait.isUnsignedInt(U));
|
||||
|
||||
//by extending the buffer to a minimum of u8 we can cover a number of edge cases
|
||||
// related to shifting and casting.
|
||||
const u_bit_count = comptime meta.bitCount(U);
|
||||
const buf_bit_count = bc: {
|
||||
assert(u_bit_count >= bits);
|
||||
break :bc if (u_bit_count <= u8_bit_count) u8_bit_count else u_bit_count;
|
||||
};
|
||||
const Buf = std.meta.Int(false, buf_bit_count);
|
||||
const BufShift = math.Log2Int(Buf);
|
||||
|
||||
const buf_value = @intCast(Buf, value);
|
||||
|
||||
const high_byte_shift = @intCast(BufShift, buf_bit_count - u8_bit_count);
|
||||
var in_buffer = switch (endian) {
|
||||
.Big => buf_value << @intCast(BufShift, buf_bit_count - bits),
|
||||
.Little => buf_value,
|
||||
};
|
||||
var in_bits = bits;
|
||||
|
||||
if (self.bit_count > 0) {
|
||||
const bits_remaining = u8_bit_count - self.bit_count;
|
||||
const n = @intCast(u3, if (bits_remaining > bits) bits else bits_remaining);
|
||||
switch (endian) {
|
||||
.Big => {
|
||||
const shift = @intCast(BufShift, high_byte_shift + self.bit_count);
|
||||
const v = @intCast(u8, in_buffer >> shift);
|
||||
self.bit_buffer |= v;
|
||||
in_buffer <<= n;
|
||||
},
|
||||
.Little => {
|
||||
const v = @truncate(u8, in_buffer) << @intCast(u3, self.bit_count);
|
||||
self.bit_buffer |= v;
|
||||
in_buffer >>= n;
|
||||
},
|
||||
}
|
||||
self.bit_count += n;
|
||||
in_bits -= n;
|
||||
|
||||
//if we didn't fill the buffer, it's because bits < bits_remaining;
|
||||
if (self.bit_count != u8_bit_count) return;
|
||||
try self.forward_writer.writeByte(self.bit_buffer);
|
||||
self.bit_buffer = 0;
|
||||
self.bit_count = 0;
|
||||
}
|
||||
//at this point we know bit_buffer is empty
|
||||
|
||||
//copy bytes until we can't fill one anymore, then leave the rest in bit_buffer
|
||||
while (in_bits >= u8_bit_count) {
|
||||
switch (endian) {
|
||||
.Big => {
|
||||
const v = @intCast(u8, in_buffer >> high_byte_shift);
|
||||
try self.forward_writer.writeByte(v);
|
||||
in_buffer <<= @intCast(u3, u8_bit_count - 1);
|
||||
in_buffer <<= 1;
|
||||
},
|
||||
.Little => {
|
||||
const v = @truncate(u8, in_buffer);
|
||||
try self.forward_writer.writeByte(v);
|
||||
in_buffer >>= @intCast(u3, u8_bit_count - 1);
|
||||
in_buffer >>= 1;
|
||||
},
|
||||
}
|
||||
in_bits -= u8_bit_count;
|
||||
}
|
||||
|
||||
if (in_bits > 0) {
|
||||
self.bit_count = @intCast(u4, in_bits);
|
||||
self.bit_buffer = switch (endian) {
|
||||
.Big => @truncate(u8, in_buffer >> high_byte_shift),
|
||||
.Little => @truncate(u8, in_buffer),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// Flush any remaining bits to the stream.
|
||||
pub fn flushBits(self: *Self) Error!void {
|
||||
if (self.bit_count == 0) return;
|
||||
try self.forward_writer.writeByte(self.bit_buffer);
|
||||
self.bit_buffer = 0;
|
||||
self.bit_count = 0;
|
||||
}
|
||||
|
||||
pub fn write(self: *Self, buffer: []const u8) Error!usize {
|
||||
// TODO: I'm not sure this is a good idea, maybe flushBits should be forced
|
||||
if (self.bit_count > 0) {
|
||||
for (buffer) |b, i|
|
||||
try self.writeBits(b, u8_bit_count);
|
||||
return buffer.len;
|
||||
}
|
||||
|
||||
return self.forward_writer.write(buffer);
|
||||
}
|
||||
|
||||
pub fn writer(self: *Self) Writer {
|
||||
return .{ .context = self };
|
||||
}
|
||||
/// Deprecated: use `writer`
|
||||
pub fn outStream(self: *Self) OutStream {
|
||||
return .{ .context = self };
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn bitWriter(
|
||||
comptime endian: builtin.Endian,
|
||||
underlying_stream: var,
|
||||
) BitWriter(endian, @TypeOf(underlying_stream)) {
|
||||
return BitWriter(endian, @TypeOf(underlying_stream)).init(underlying_stream);
|
||||
}
|
||||
|
||||
test "api coverage" {
|
||||
var mem_be = [_]u8{0} ** 2;
|
||||
var mem_le = [_]u8{0} ** 2;
|
||||
|
||||
var mem_out_be = io.fixedBufferStream(&mem_be);
|
||||
var bit_stream_be = bitWriter(.Big, mem_out_be.writer());
|
||||
|
||||
try bit_stream_be.writeBits(@as(u2, 1), 1);
|
||||
try bit_stream_be.writeBits(@as(u5, 2), 2);
|
||||
try bit_stream_be.writeBits(@as(u128, 3), 3);
|
||||
try bit_stream_be.writeBits(@as(u8, 4), 4);
|
||||
try bit_stream_be.writeBits(@as(u9, 5), 5);
|
||||
try bit_stream_be.writeBits(@as(u1, 1), 1);
|
||||
|
||||
testing.expect(mem_be[0] == 0b11001101 and mem_be[1] == 0b00001011);
|
||||
|
||||
mem_out_be.pos = 0;
|
||||
|
||||
try bit_stream_be.writeBits(@as(u15, 0b110011010000101), 15);
|
||||
try bit_stream_be.flushBits();
|
||||
testing.expect(mem_be[0] == 0b11001101 and mem_be[1] == 0b00001010);
|
||||
|
||||
mem_out_be.pos = 0;
|
||||
try bit_stream_be.writeBits(@as(u32, 0b110011010000101), 16);
|
||||
testing.expect(mem_be[0] == 0b01100110 and mem_be[1] == 0b10000101);
|
||||
|
||||
try bit_stream_be.writeBits(@as(u0, 0), 0);
|
||||
|
||||
var mem_out_le = io.fixedBufferStream(&mem_le);
|
||||
var bit_stream_le = bitWriter(.Little, mem_out_le.writer());
|
||||
|
||||
try bit_stream_le.writeBits(@as(u2, 1), 1);
|
||||
try bit_stream_le.writeBits(@as(u5, 2), 2);
|
||||
try bit_stream_le.writeBits(@as(u128, 3), 3);
|
||||
try bit_stream_le.writeBits(@as(u8, 4), 4);
|
||||
try bit_stream_le.writeBits(@as(u9, 5), 5);
|
||||
try bit_stream_le.writeBits(@as(u1, 1), 1);
|
||||
|
||||
testing.expect(mem_le[0] == 0b00011101 and mem_le[1] == 0b10010101);
|
||||
|
||||
mem_out_le.pos = 0;
|
||||
try bit_stream_le.writeBits(@as(u15, 0b110011010000101), 15);
|
||||
try bit_stream_le.flushBits();
|
||||
testing.expect(mem_le[0] == 0b10000101 and mem_le[1] == 0b01100110);
|
||||
|
||||
mem_out_le.pos = 0;
|
||||
try bit_stream_le.writeBits(@as(u32, 0b1100110100001011), 16);
|
||||
testing.expect(mem_le[0] == 0b00001011 and mem_le[1] == 0b11001101);
|
||||
|
||||
try bit_stream_le.writeBits(@as(u0, 0), 0);
|
||||
}
|
@ -34,7 +34,7 @@ pub const BufferedAtomicFile = struct {
|
||||
errdefer self.atomic_file.deinit();
|
||||
|
||||
self.file_stream = self.atomic_file.file.outStream();
|
||||
self.buffered_stream = .{ .unbuffered_out_stream = self.file_stream };
|
||||
self.buffered_stream = .{ .unbuffered_writer = self.file_stream };
|
||||
return self;
|
||||
}
|
||||
|
||||
|
@ -1,41 +1,5 @@
|
||||
const std = @import("../std.zig");
|
||||
const io = std.io;
|
||||
/// Deprecated: use `std.io.buffered_writer.BufferedWriter`
|
||||
pub const BufferedOutStream = @import("./buffered_writer.zig").BufferedWriter;
|
||||
|
||||
pub fn BufferedOutStream(comptime buffer_size: usize, comptime OutStreamType: type) type {
|
||||
return struct {
|
||||
unbuffered_out_stream: OutStreamType,
|
||||
fifo: FifoType = FifoType.init(),
|
||||
|
||||
pub const Error = OutStreamType.Error;
|
||||
pub const OutStream = io.OutStream(*Self, Error, write);
|
||||
|
||||
const Self = @This();
|
||||
const FifoType = std.fifo.LinearFifo(u8, std.fifo.LinearFifoBufferType{ .Static = buffer_size });
|
||||
|
||||
pub fn flush(self: *Self) !void {
|
||||
while (true) {
|
||||
const slice = self.fifo.readableSlice(0);
|
||||
if (slice.len == 0) break;
|
||||
try self.unbuffered_out_stream.writeAll(slice);
|
||||
self.fifo.discard(slice.len);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn outStream(self: *Self) OutStream {
|
||||
return .{ .context = self };
|
||||
}
|
||||
|
||||
pub fn write(self: *Self, bytes: []const u8) Error!usize {
|
||||
if (bytes.len >= self.fifo.writableLength()) {
|
||||
try self.flush();
|
||||
return self.unbuffered_out_stream.write(bytes);
|
||||
}
|
||||
self.fifo.writeAssumeCapacity(bytes);
|
||||
return bytes.len;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn bufferedOutStream(underlying_stream: var) BufferedOutStream(4096, @TypeOf(underlying_stream)) {
|
||||
return .{ .unbuffered_out_stream = underlying_stream };
|
||||
}
|
||||
/// Deprecated: use `std.io.buffered_writer.bufferedWriter`
|
||||
pub const bufferedOutStream = @import("./buffered_writer.zig").bufferedWriter
|
||||
|
48
lib/std/io/buffered_writer.zig
Normal file
48
lib/std/io/buffered_writer.zig
Normal file
@ -0,0 +1,48 @@
|
||||
const std = @import("../std.zig");
|
||||
const io = std.io;
|
||||
|
||||
pub fn BufferedWriter(comptime buffer_size: usize, comptime WriterType: type) type {
|
||||
return struct {
|
||||
unbuffered_writer: WriterType,
|
||||
fifo: FifoType = FifoType.init(),
|
||||
|
||||
pub const Error = WriterType.Error;
|
||||
pub const Writer = io.Writer(*Self, Error, write);
|
||||
/// Deprecated: use `Writer`
|
||||
pub const OutStream = Writer;
|
||||
|
||||
const Self = @This();
|
||||
const FifoType = std.fifo.LinearFifo(u8, std.fifo.LinearFifoBufferType{ .Static = buffer_size });
|
||||
|
||||
pub fn flush(self: *Self) !void {
|
||||
while (true) {
|
||||
const slice = self.fifo.readableSlice(0);
|
||||
if (slice.len == 0) break;
|
||||
try self.unbuffered_writer.writeAll(slice);
|
||||
self.fifo.discard(slice.len);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn writer(self: *Self) Writer {
|
||||
return .{ .context = self };
|
||||
}
|
||||
|
||||
/// Deprecated: use writer
|
||||
pub fn outStream(self: *Self) Writer {
|
||||
return .{ .context = self };
|
||||
}
|
||||
|
||||
pub fn write(self: *Self, bytes: []const u8) Error!usize {
|
||||
if (bytes.len >= self.fifo.writableLength()) {
|
||||
try self.flush();
|
||||
return self.unbuffered_writer.write(bytes);
|
||||
}
|
||||
self.fifo.writeAssumeCapacity(bytes);
|
||||
return bytes.len;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn bufferedWriter(underlying_stream: var) BufferedWriter(4096, @TypeOf(underlying_stream)) {
|
||||
return .{ .unbuffered_writer = underlying_stream };
|
||||
}
|
@ -1,44 +1,5 @@
|
||||
const std = @import("../std.zig");
|
||||
const builtin = std.builtin;
|
||||
const io = std.io;
|
||||
const testing = std.testing;
|
||||
/// Deprecated: use `std.io.c_writer.CWriter`
|
||||
pub const COutStream = @import("./c_writer.zig").CWriter;
|
||||
|
||||
pub const COutStream = io.OutStream(*std.c.FILE, std.fs.File.WriteError, cOutStreamWrite);
|
||||
|
||||
pub fn cOutStream(c_file: *std.c.FILE) COutStream {
|
||||
return .{ .context = c_file };
|
||||
}
|
||||
|
||||
fn cOutStreamWrite(c_file: *std.c.FILE, bytes: []const u8) std.fs.File.WriteError!usize {
|
||||
const amt_written = std.c.fwrite(bytes.ptr, 1, bytes.len, c_file);
|
||||
if (amt_written >= 0) return amt_written;
|
||||
switch (std.c._errno().*) {
|
||||
0 => unreachable,
|
||||
os.EINVAL => unreachable,
|
||||
os.EFAULT => unreachable,
|
||||
os.EAGAIN => unreachable, // this is a blocking API
|
||||
os.EBADF => unreachable, // always a race condition
|
||||
os.EDESTADDRREQ => unreachable, // connect was never called
|
||||
os.EDQUOT => return error.DiskQuota,
|
||||
os.EFBIG => return error.FileTooBig,
|
||||
os.EIO => return error.InputOutput,
|
||||
os.ENOSPC => return error.NoSpaceLeft,
|
||||
os.EPERM => return error.AccessDenied,
|
||||
os.EPIPE => return error.BrokenPipe,
|
||||
else => |err| return os.unexpectedErrno(@intCast(usize, err)),
|
||||
}
|
||||
}
|
||||
|
||||
test "" {
|
||||
if (!builtin.link_libc) return error.SkipZigTest;
|
||||
|
||||
const filename = "tmp_io_test_file.txt";
|
||||
const out_file = std.c.fopen(filename, "w") orelse return error.UnableToOpenTestFile;
|
||||
defer {
|
||||
_ = std.c.fclose(out_file);
|
||||
std.fs.cwd().deleteFileZ(filename) catch {};
|
||||
}
|
||||
|
||||
const out_stream = cOutStream(out_file);
|
||||
try out_stream.print("hi: {}\n", .{@as(i32, 123)});
|
||||
}
|
||||
/// Deprecated: use `std.io.c_writer.cWriter`
|
||||
pub const cOutStream = @import("./c_writer.zig").cWriter;
|
||||
|
44
lib/std/io/c_writer.zig
Normal file
44
lib/std/io/c_writer.zig
Normal file
@ -0,0 +1,44 @@
|
||||
const std = @import("../std.zig");
|
||||
const builtin = std.builtin;
|
||||
const io = std.io;
|
||||
const testing = std.testing;
|
||||
|
||||
pub const CWriter = io.Writer(*std.c.FILE, std.fs.File.WriteError, cWriterWrite);
|
||||
|
||||
pub fn cWriter(c_file: *std.c.FILE) CWriter {
|
||||
return .{ .context = c_file };
|
||||
}
|
||||
|
||||
fn cWriterWrite(c_file: *std.c.FILE, bytes: []const u8) std.fs.File.WriteError!usize {
|
||||
const amt_written = std.c.fwrite(bytes.ptr, 1, bytes.len, c_file);
|
||||
if (amt_written >= 0) return amt_written;
|
||||
switch (std.c._errno().*) {
|
||||
0 => unreachable,
|
||||
os.EINVAL => unreachable,
|
||||
os.EFAULT => unreachable,
|
||||
os.EAGAIN => unreachable, // this is a blocking API
|
||||
os.EBADF => unreachable, // always a race condition
|
||||
os.EDESTADDRREQ => unreachable, // connect was never called
|
||||
os.EDQUOT => return error.DiskQuota,
|
||||
os.EFBIG => return error.FileTooBig,
|
||||
os.EIO => return error.InputOutput,
|
||||
os.ENOSPC => return error.NoSpaceLeft,
|
||||
os.EPERM => return error.AccessDenied,
|
||||
os.EPIPE => return error.BrokenPipe,
|
||||
else => |err| return os.unexpectedErrno(@intCast(usize, err)),
|
||||
}
|
||||
}
|
||||
|
||||
test "" {
|
||||
if (!builtin.link_libc) return error.SkipZigTest;
|
||||
|
||||
const filename = "tmp_io_test_file.txt";
|
||||
const out_file = std.c.fopen(filename, "w") orelse return error.UnableToOpenTestFile;
|
||||
defer {
|
||||
_ = std.c.fclose(out_file);
|
||||
std.fs.cwd().deleteFileZ(filename) catch {};
|
||||
}
|
||||
|
||||
const writer = cWriter(out_file);
|
||||
try writer.print("hi: {}\n", .{@as(i32, 123)});
|
||||
}
|
@ -1,39 +1,5 @@
|
||||
const std = @import("../std.zig");
|
||||
const io = std.io;
|
||||
const testing = std.testing;
|
||||
/// Deprecated: use `std.io.counting_writer.CountingWriter`
|
||||
pub const CountingOutStream = @import("./counting_writer.zig").CountingWriter;
|
||||
|
||||
/// An OutStream that counts how many bytes has been written to it.
|
||||
pub fn CountingOutStream(comptime OutStreamType: type) type {
|
||||
return struct {
|
||||
bytes_written: u64,
|
||||
child_stream: OutStreamType,
|
||||
|
||||
pub const Error = OutStreamType.Error;
|
||||
pub const OutStream = io.OutStream(*Self, Error, write);
|
||||
|
||||
const Self = @This();
|
||||
|
||||
pub fn write(self: *Self, bytes: []const u8) Error!usize {
|
||||
const amt = try self.child_stream.write(bytes);
|
||||
self.bytes_written += amt;
|
||||
return amt;
|
||||
}
|
||||
|
||||
pub fn outStream(self: *Self) OutStream {
|
||||
return .{ .context = self };
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn countingOutStream(child_stream: var) CountingOutStream(@TypeOf(child_stream)) {
|
||||
return .{ .bytes_written = 0, .child_stream = child_stream };
|
||||
}
|
||||
|
||||
test "io.CountingOutStream" {
|
||||
var counting_stream = countingOutStream(std.io.null_out_stream);
|
||||
const stream = counting_stream.outStream();
|
||||
|
||||
const bytes = "yay" ** 100;
|
||||
stream.writeAll(bytes) catch unreachable;
|
||||
testing.expect(counting_stream.bytes_written == bytes.len);
|
||||
}
|
||||
/// Deprecated: use `std.io.counting_writer.countingWriter`
|
||||
pub const countingOutStream = @import("./counting_writer.zig").countingWriter;
|
||||
|
46
lib/std/io/counting_writer.zig
Normal file
46
lib/std/io/counting_writer.zig
Normal file
@ -0,0 +1,46 @@
|
||||
const std = @import("../std.zig");
|
||||
const io = std.io;
|
||||
const testing = std.testing;
|
||||
|
||||
/// A Writer that counts how many bytes has been written to it.
|
||||
pub fn CountingWriter(comptime WriterType: type) type {
|
||||
return struct {
|
||||
bytes_written: u64,
|
||||
child_stream: WriterType,
|
||||
|
||||
pub const Error = WriterType.Error;
|
||||
pub const Writer = io.Writer(*Self, Error, write);
|
||||
/// Deprecated: use `Writer`
|
||||
pub const OutStream = Writer;
|
||||
|
||||
const Self = @This();
|
||||
|
||||
pub fn write(self: *Self, bytes: []const u8) Error!usize {
|
||||
const amt = try self.child_stream.write(bytes);
|
||||
self.bytes_written += amt;
|
||||
return amt;
|
||||
}
|
||||
|
||||
pub fn writer(self: *Self) Writer {
|
||||
return .{ .context = self };
|
||||
}
|
||||
|
||||
/// Deprecated: use `writer`
|
||||
pub fn outStream(self: *Self) OutStream {
|
||||
return .{ .context = self };
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn countingWriter(child_stream: var) CountingWriter(@TypeOf(child_stream)) {
|
||||
return .{ .bytes_written = 0, .child_stream = child_stream };
|
||||
}
|
||||
|
||||
test "io.CountingWriter" {
|
||||
var counting_stream = countingWriter(std.io.null_writer);
|
||||
const stream = counting_stream.writer();
|
||||
|
||||
const bytes = "yay" ** 100;
|
||||
stream.writeAll(bytes) catch unreachable;
|
||||
testing.expect(counting_stream.bytes_written == bytes.len);
|
||||
}
|
@ -18,7 +18,9 @@ pub fn FixedBufferStream(comptime Buffer: type) type {
|
||||
pub const GetSeekPosError = error{};
|
||||
|
||||
pub const InStream = io.InStream(*Self, ReadError, read);
|
||||
pub const OutStream = io.OutStream(*Self, WriteError, write);
|
||||
pub const Writer = io.Writer(*Self, WriteError, write);
|
||||
/// Deprecated: use `Writer`
|
||||
pub const OutStream = Writer;
|
||||
|
||||
pub const SeekableStream = io.SeekableStream(
|
||||
*Self,
|
||||
@ -36,6 +38,11 @@ pub fn FixedBufferStream(comptime Buffer: type) type {
|
||||
return .{ .context = self };
|
||||
}
|
||||
|
||||
pub fn writer(self: *Self) Writer {
|
||||
return .{ .context = self };
|
||||
}
|
||||
|
||||
/// Deprecated: use `writer`
|
||||
pub fn outStream(self: *Self) OutStream {
|
||||
return .{ .context = self };
|
||||
}
|
||||
@ -126,7 +133,7 @@ fn NonSentinelSpan(comptime T: type) type {
|
||||
test "FixedBufferStream output" {
|
||||
var buf: [255]u8 = undefined;
|
||||
var fbs = fixedBufferStream(&buf);
|
||||
const stream = fbs.outStream();
|
||||
const stream = fbs.writer();
|
||||
|
||||
try stream.print("{}{}!", .{ "Hello", "World" });
|
||||
testing.expectEqualSlices(u8, "HelloWorld!", fbs.getWritten());
|
||||
@ -136,19 +143,19 @@ test "FixedBufferStream output 2" {
|
||||
var buffer: [10]u8 = undefined;
|
||||
var fbs = fixedBufferStream(&buffer);
|
||||
|
||||
try fbs.outStream().writeAll("Hello");
|
||||
try fbs.writer().writeAll("Hello");
|
||||
testing.expect(mem.eql(u8, fbs.getWritten(), "Hello"));
|
||||
|
||||
try fbs.outStream().writeAll("world");
|
||||
try fbs.writer().writeAll("world");
|
||||
testing.expect(mem.eql(u8, fbs.getWritten(), "Helloworld"));
|
||||
|
||||
testing.expectError(error.NoSpaceLeft, fbs.outStream().writeAll("!"));
|
||||
testing.expectError(error.NoSpaceLeft, fbs.writer().writeAll("!"));
|
||||
testing.expect(mem.eql(u8, fbs.getWritten(), "Helloworld"));
|
||||
|
||||
fbs.reset();
|
||||
testing.expect(fbs.getWritten().len == 0);
|
||||
|
||||
testing.expectError(error.NoSpaceLeft, fbs.outStream().writeAll("Hello world!"));
|
||||
testing.expectError(error.NoSpaceLeft, fbs.writer().writeAll("Hello world!"));
|
||||
testing.expect(mem.eql(u8, fbs.getWritten(), "Hello worl"));
|
||||
}
|
||||
|
||||
|
@ -1,51 +1,5 @@
|
||||
const std = @import("../std.zig");
|
||||
const io = std.io;
|
||||
const testing = std.testing;
|
||||
/// Deprecated: use `std.io.multi_writer.MultiWriter`
|
||||
pub const MultiOutStream = @import("./multi_writer.zig").MultiWriter;
|
||||
|
||||
/// Takes a tuple of streams, and constructs a new stream that writes to all of them
|
||||
pub fn MultiOutStream(comptime OutStreams: type) type {
|
||||
comptime var ErrSet = error{};
|
||||
inline for (@typeInfo(OutStreams).Struct.fields) |field| {
|
||||
const StreamType = field.field_type;
|
||||
ErrSet = ErrSet || StreamType.Error;
|
||||
}
|
||||
|
||||
return struct {
|
||||
const Self = @This();
|
||||
|
||||
streams: OutStreams,
|
||||
|
||||
pub const Error = ErrSet;
|
||||
pub const OutStream = io.OutStream(*Self, Error, write);
|
||||
pub fn outStream(self: *Self) OutStream {
|
||||
return .{ .context = self };
|
||||
}
|
||||
|
||||
pub fn write(self: *Self, bytes: []const u8) Error!usize {
|
||||
var batch = std.event.Batch(Error!void, self.streams.len, .auto_async).init();
|
||||
comptime var i = 0;
|
||||
inline while (i < self.streams.len) : (i += 1) {
|
||||
const stream = self.streams[i];
|
||||
// TODO: remove ptrCast: https://github.com/ziglang/zig/issues/5258
|
||||
batch.add(@ptrCast(anyframe->Error!void, &async stream.writeAll(bytes)));
|
||||
}
|
||||
try batch.wait();
|
||||
return bytes.len;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn multiOutStream(streams: var) MultiOutStream(@TypeOf(streams)) {
|
||||
return .{ .streams = streams };
|
||||
}
|
||||
|
||||
test "MultiOutStream" {
|
||||
var buf1: [255]u8 = undefined;
|
||||
var fbs1 = io.fixedBufferStream(&buf1);
|
||||
var buf2: [255]u8 = undefined;
|
||||
var fbs2 = io.fixedBufferStream(&buf2);
|
||||
var stream = multiOutStream(.{ fbs1.outStream(), fbs2.outStream() });
|
||||
try stream.outStream().print("HI", .{});
|
||||
testing.expectEqualSlices(u8, "HI", fbs1.getWritten());
|
||||
testing.expectEqualSlices(u8, "HI", fbs2.getWritten());
|
||||
}
|
||||
/// Deprecated: use `std.io.multi_writer.multiWriter`
|
||||
pub const multiOutStream = @import("./multi_writer.zig").multiWriter;
|
||||
|
59
lib/std/io/multi_writer.zig
Normal file
59
lib/std/io/multi_writer.zig
Normal file
@ -0,0 +1,59 @@
|
||||
const std = @import("../std.zig");
|
||||
const io = std.io;
|
||||
const testing = std.testing;
|
||||
|
||||
/// Takes a tuple of streams, and constructs a new stream that writes to all of them
|
||||
pub fn MultiWriter(comptime Writers: type) type {
|
||||
comptime var ErrSet = error{};
|
||||
inline for (@typeInfo(Writers).Struct.fields) |field| {
|
||||
const StreamType = field.field_type;
|
||||
ErrSet = ErrSet || StreamType.Error;
|
||||
}
|
||||
|
||||
return struct {
|
||||
const Self = @This();
|
||||
|
||||
streams: Writers,
|
||||
|
||||
pub const Error = ErrSet;
|
||||
pub const Writer = io.Writer(*Self, Error, write);
|
||||
/// Deprecated: use `Writer`
|
||||
pub const OutStream = Writer;
|
||||
|
||||
pub fn writer(self: *Self) Writer {
|
||||
return .{ .context = self };
|
||||
}
|
||||
|
||||
/// Deprecated: use `writer`
|
||||
pub fn outStream(self: *Self) OutStream {
|
||||
return .{ .context = self };
|
||||
}
|
||||
|
||||
pub fn write(self: *Self, bytes: []const u8) Error!usize {
|
||||
var batch = std.event.Batch(Error!void, self.streams.len, .auto_async).init();
|
||||
comptime var i = 0;
|
||||
inline while (i < self.streams.len) : (i += 1) {
|
||||
const stream = self.streams[i];
|
||||
// TODO: remove ptrCast: https://github.com/ziglang/zig/issues/5258
|
||||
batch.add(@ptrCast(anyframe->Error!void, &async stream.writeAll(bytes)));
|
||||
}
|
||||
try batch.wait();
|
||||
return bytes.len;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn multiWriter(streams: var) MultiWriter(@TypeOf(streams)) {
|
||||
return .{ .streams = streams };
|
||||
}
|
||||
|
||||
test "MultiWriter" {
|
||||
var buf1: [255]u8 = undefined;
|
||||
var fbs1 = io.fixedBufferStream(&buf1);
|
||||
var buf2: [255]u8 = undefined;
|
||||
var fbs2 = io.fixedBufferStream(&buf2);
|
||||
var stream = multiWriter(.{ fbs1.writer(), fbs2.writer() });
|
||||
try stream.writer().print("HI", .{});
|
||||
testing.expectEqualSlices(u8, "HI", fbs1.getWritten());
|
||||
testing.expectEqualSlices(u8, "HI", fbs2.getWritten());
|
||||
}
|
@ -1,85 +1,2 @@
|
||||
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, 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);
|
||||
}
|
||||
};
|
||||
}
|
||||
/// Deprecated: use `std.io.writer.Writer`
|
||||
pub const OutStream = @import("./writer.zig").Writer;
|
||||
|
85
lib/std/io/writer.zig
Normal file
85
lib/std/io/writer.zig
Normal file
@ -0,0 +1,85 @@
|
||||
const std = @import("../std.zig");
|
||||
const builtin = std.builtin;
|
||||
const mem = std.mem;
|
||||
|
||||
pub fn Writer(
|
||||
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, 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);
|
||||
}
|
||||
};
|
||||
}
|
@ -49,7 +49,7 @@ pub fn render(allocator: *mem.Allocator, stream: var, tree: *ast.Tree) (@TypeOf(
|
||||
.source_index = 0,
|
||||
.source = tree.source,
|
||||
};
|
||||
const my_stream_stream: std.io.OutStream(*MyStream, MyStream.StreamError, MyStream.write) = .{
|
||||
const my_stream_stream: std.io.Writer(*MyStream, MyStream.StreamError, MyStream.write) = .{
|
||||
.context = &my_stream,
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user