Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

std.io: add GenericStream and AnyStream #19376

Closed
2 changes: 1 addition & 1 deletion lib/compiler/objcopy.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1285,7 +1285,7 @@ const ElfFileHelper = struct {
for (consolidated.items) |cmd| {
switch (cmd) {
.write_data => |data| {
var iovec = [_]std.posix.iovec_const{.{ .iov_base = data.data.ptr, .iov_len = data.data.len }};
var iovec = [_]std.io.WriteBuffers{.{ .ptr = data.data.ptr, .len = data.data.len }};
try out_file.pwritevAll(&iovec, data.out_offset);
},
.copy_range => |range| {
Expand Down
45 changes: 29 additions & 16 deletions lib/std/array_list.zig
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
@compileError("The Writer interface is only defined for ArrayList(u8) " ++
"but the given type is ArrayList(" ++ @typeName(T) ++ ")")
else
std.io.Writer(*Self, Allocator.Error, appendWrite);
std.io.Writer(*Self, Allocator.Error, appendWritev);

/// Initializes a Writer which will append to the list.
pub fn writer(self: *Self) Writer {
Expand All @@ -354,9 +354,13 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
/// Same as `append` except it returns the number of bytes written, which is always the same
/// as `m.len`. The purpose of this function existing is to match `std.io.Writer` API.
/// Invalidates element pointers if additional memory is needed.
fn appendWrite(self: *Self, m: []const u8) Allocator.Error!usize {
try self.appendSlice(m);
return m.len;
fn appendWritev(self: *Self, iov: []std.io.WriteBuffers) Allocator.Error!usize {
var written: usize = 0;
for (iov) |v| {
try self.appendSlice(v.ptr[0..v.len]);
written += v.len;
}
return written;
}

/// Append a value to the list `n` times.
Expand Down Expand Up @@ -930,7 +934,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
@compileError("The Writer interface is only defined for ArrayList(u8) " ++
"but the given type is ArrayList(" ++ @typeName(T) ++ ")")
else
std.io.Writer(WriterContext, Allocator.Error, appendWrite);
std.io.Writer(WriterContext, Allocator.Error, appendWritev);

/// Initializes a Writer which will append to the list.
pub fn writer(self: *Self, allocator: Allocator) Writer {
Expand All @@ -941,12 +945,16 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
/// which is always the same as `m.len`. The purpose of this function
/// existing is to match `std.io.Writer` API.
/// Invalidates element pointers if additional memory is needed.
fn appendWrite(context: WriterContext, m: []const u8) Allocator.Error!usize {
try context.self.appendSlice(context.allocator, m);
return m.len;
fn appendWritev(context: WriterContext, iov: []std.io.WriteBuffers) Allocator.Error!usize {
var written: usize = 0;
for (iov) |v| {
try context.self.appendSlice(context.allocator, v.ptr[0..v.len]);
written += v.len;
}
return written;
}

pub const FixedWriter = std.io.Writer(*Self, Allocator.Error, appendWriteFixed);
pub const FixedWriter = std.io.Writer(*Self, Allocator.Error, appendWritevFixed);

/// Initializes a Writer which will append to the list but will return
/// `error.OutOfMemory` rather than increasing capacity.
Expand All @@ -955,13 +963,18 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
}

/// The purpose of this function existing is to match `std.io.Writer` API.
fn appendWriteFixed(self: *Self, m: []const u8) error{OutOfMemory}!usize {
const available_capacity = self.capacity - self.items.len;
if (m.len > available_capacity)
return error.OutOfMemory;

self.appendSliceAssumeCapacity(m);
return m.len;
fn appendWritevFixed(self: *Self, iov: []std.io.WriteBuffers) error{OutOfMemory}!usize {
var written: usize = 0;
for (iov) |v| {
const m = v.ptr[0..v.len];
const available_capacity = self.capacity - self.items.len;
if (m.len > available_capacity)
return error.OutOfMemory;

self.appendSliceAssumeCapacity(m);
written += m.len;
}
return written;
}

/// Append a value to the list `n` times.
Expand Down
13 changes: 9 additions & 4 deletions lib/std/bounded_array.zig
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ pub fn BoundedArrayAligned(
@compileError("The Writer interface is only defined for BoundedArray(u8, ...) " ++
"but the given type is BoundedArray(" ++ @typeName(T) ++ ", ...)")
else
std.io.Writer(*Self, error{Overflow}, appendWrite);
std.io.Writer(*Self, error{Overflow}, appendWritev);

/// Initializes a writer which will write into the array.
pub fn writer(self: *Self) Writer {
Expand All @@ -280,9 +280,14 @@ pub fn BoundedArrayAligned(

/// Same as `appendSlice` except it returns the number of bytes written, which is always the same
/// as `m.len`. The purpose of this function existing is to match `std.io.Writer` API.
fn appendWrite(self: *Self, m: []const u8) error{Overflow}!usize {
try self.appendSlice(m);
return m.len;
fn appendWritev(self: *Self, iov: []std.io.WriteBuffers) error{Overflow}!usize {
var written: usize = 0;
for (iov) |v| {
const m = v.ptr[0..v.len];
try self.appendSlice(m);
written += m.len;
}
return written;
}
};
}
Expand Down
4 changes: 2 additions & 2 deletions lib/std/c.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ const std = @import("std");
const builtin = @import("builtin");
const c = @This();
const page_size = std.mem.page_size;
const iovec = std.posix.iovec;
const iovec_const = std.posix.iovec_const;
const iovec = std.io.ReadBuffers;
const iovec_const = std.io.WriteBuffers;
const wasi = @import("c/wasi.zig");
const native_abi = builtin.abi;
const native_arch = builtin.cpu.arch;
Expand Down
30 changes: 21 additions & 9 deletions lib/std/compress.zig
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,18 @@ pub fn HashedReader(
hasher: HasherType,

pub const Error = ReaderType.Error;
pub const Reader = std.io.Reader(*@This(), Error, read);
pub const Reader = std.io.Reader(*@This(), Error, readv);

pub fn read(self: *@This(), buf: []u8) Error!usize {
const amt = try self.child_reader.read(buf);
self.hasher.update(buf[0..amt]);
return amt;
pub fn readv(self: *@This(), iov: []std.io.ReadBuffers) Error!usize {
const n_read = try self.child_reader.readv(iov);
var hashed_amt: usize = 0;
for (iov) |v| {
const to_hash = @min(n_read - hashed_amt, v.len);
if (to_hash == 0) break;
self.hasher.update(v.ptr[0..to_hash]);
hashed_amt += to_hash;
}
return n_read;
}

pub fn reader(self: *@This()) Reader {
Expand All @@ -51,10 +57,16 @@ pub fn HashedWriter(
pub const Error = WriterType.Error;
pub const Writer = std.io.Writer(*@This(), Error, write);

pub fn write(self: *@This(), buf: []const u8) Error!usize {
const amt = try self.child_writer.write(buf);
self.hasher.update(buf[0..amt]);
return amt;
pub fn write(self: *@This(), iov: []std.io.WriteBuffers) Error!usize {
const n_written = try self.child_writer.writev(iov);
var hashed_amt: usize = 0;
for (iov) |v| {
const to_hash = @min(n_written - hashed_amt, v.len);
if (to_hash == 0) break;
self.hasher.update(v.ptr[0..to_hash]);
hashed_amt += to_hash;
}
return n_written;
}

pub fn writer(self: *@This()) Writer {
Expand Down
20 changes: 13 additions & 7 deletions lib/std/compress/flate/deflate.zig
Original file line number Diff line number Diff line change
Expand Up @@ -354,16 +354,20 @@ fn Deflate(comptime container: Container, comptime WriterType: type, comptime Bl
}

// Writer interface

pub const Writer = io.Writer(*Self, Error, write);
pub const Writer = io.Writer(*Self, Error, writev);
pub const Error = BlockWriterType.Error;

/// Write `input` of uncompressed data.
/// See compress.
pub fn write(self: *Self, input: []const u8) !usize {
var fbs = io.fixedBufferStream(input);
try self.compress(fbs.reader());
return input.len;
pub fn writev(self: *Self, iov: []std.io.WriteBuffers) !usize {
var written: usize = 0;
for (iov) |v| {
const input = v.ptr[0..v.len];
var fbs = io.fixedBufferStream(input);
try self.compress(fbs.reader());
written += input.len;
}
return written;
}

pub fn writer(self: *Self) Writer {
Expand Down Expand Up @@ -558,7 +562,7 @@ test "tokenization" {
const cww = cw.writer();
var df = try Deflate(container, @TypeOf(cww), TestTokenWriter).init(cww, .{});

_ = try df.write(c.data);
_ = try df.writer().write(c.data);
try df.flush();

// df.token_writer.show();
Expand All @@ -579,6 +583,8 @@ const TestTokenWriter = struct {
pos: usize = 0,
actual: [128]Token = undefined,

pub const Error = error{};

pub fn init(_: anytype) Self {
return .{};
}
Expand Down
8 changes: 5 additions & 3 deletions lib/std/compress/flate/inflate.zig
Original file line number Diff line number Diff line change
Expand Up @@ -340,13 +340,15 @@ pub fn Inflate(comptime container: Container, comptime LookaheadType: type, comp
}

// Reader interface

pub const Reader = std.io.Reader(*Self, Error, read);
pub const Reader = std.io.Reader(*Self, Error, readv);

/// Returns the number of bytes read. It may be less than buffer.len.
/// If the number of bytes read is 0, it means end of stream.
/// End of stream is not an error condition.
pub fn read(self: *Self, buffer: []u8) Error!usize {
pub fn readv(self: *Self, iovecs: []std.io.ReadBuffers) Error!usize {
if (iovecs.len == 0) return 0;
const first = iovecs[0];
const buffer = first.ptr[0..first.len];
const out = try self.get(buffer.len);
@memcpy(buffer[0..out.len], out);
return out.len;
Expand Down
8 changes: 6 additions & 2 deletions lib/std/compress/lzma.zig
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ pub fn Decompress(comptime ReaderType: type) type {
Allocator.Error ||
error{ CorruptInput, EndOfStream, Overflow };

pub const Reader = std.io.Reader(*Self, Error, read);
pub const Reader = std.io.Reader(*Self, Error, readv);

allocator: Allocator,
in_reader: ReaderType,
Expand Down Expand Up @@ -63,7 +63,11 @@ pub fn Decompress(comptime ReaderType: type) type {
self.* = undefined;
}

pub fn read(self: *Self, output: []u8) Error!usize {
pub fn readv(self: *Self, iovecs: []std.io.ReadBuffers) Error!usize {
if (iovecs.len == 0) return 0;
const first = iovecs[0];
const output = first.ptr[0..first.len];

const writer = self.to_read.writer(self.allocator);
while (self.to_read.items.len < output.len) {
switch (try self.state.process(self.allocator, self.in_reader, writer, &self.buffer, &self.decoder)) {
Expand Down
7 changes: 5 additions & 2 deletions lib/std/compress/xz.zig
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ pub fn Decompress(comptime ReaderType: type) type {
const Self = @This();

pub const Error = ReaderType.Error || block.Decoder(ReaderType).Error;
pub const Reader = std.io.Reader(*Self, Error, read);
pub const Reader = std.io.Reader(*Self, Error, readv);

allocator: Allocator,
block_decoder: block.Decoder(ReaderType),
Expand Down Expand Up @@ -71,7 +71,10 @@ pub fn Decompress(comptime ReaderType: type) type {
return .{ .context = self };
}

pub fn read(self: *Self, buffer: []u8) Error!usize {
pub fn readv(self: *Self, iov: []std.io.ReadBuffers) Error!usize {
if (iov.len == 0) return 0;
const first = iov[0];
const buffer = first.ptr[0..first.len];
if (buffer.len == 0)
return 0;

Expand Down
7 changes: 5 additions & 2 deletions lib/std/compress/zstandard.zig
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ pub fn Decompressor(comptime ReaderType: type) type {
OutOfMemory,
};

pub const Reader = std.io.Reader(*Self, Error, read);
pub const Reader = std.io.Reader(*Self, Error, readv);

pub fn init(source: ReaderType, options: DecompressorOptions) Self {
return .{
Expand Down Expand Up @@ -105,7 +105,10 @@ pub fn Decompressor(comptime ReaderType: type) type {
return .{ .context = self };
}

pub fn read(self: *Self, buffer: []u8) Error!usize {
pub fn readv(self: *Self, iov: []std.io.ReadBuffers) Error!usize {
if (iov.len == 0) return 0;
const first = iov[0];
const buffer = first.ptr[0..first.len];
if (buffer.len == 0) return 0;

var size: usize = 0;
Expand Down
8 changes: 6 additions & 2 deletions lib/std/compress/zstandard/readers.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pub const ReversedByteReader = struct {
remaining_bytes: usize,
bytes: []const u8,

const Reader = std.io.Reader(*ReversedByteReader, error{}, readFn);
const Reader = std.io.Reader(*ReversedByteReader, error{}, readvFn);

pub fn init(bytes: []const u8) ReversedByteReader {
return .{
Expand All @@ -17,9 +17,13 @@ pub const ReversedByteReader = struct {
return .{ .context = self };
}

fn readFn(ctx: *ReversedByteReader, buffer: []u8) !usize {
fn readvFn(ctx: *ReversedByteReader, iov: []std.io.ReadBuffers) !usize {
if (iov.len == 0) return 0;
const first = iov[0];
const buffer = first.ptr[0..first.len];
if (ctx.remaining_bytes == 0) return 0;
const byte_index = ctx.remaining_bytes - 1;
std.debug.assert(buffer.len > 0);
buffer[0] = ctx.bytes[byte_index];
// buffer[0] = @bitReverse(ctx.bytes[byte_index]);
ctx.remaining_bytes = byte_index;
Expand Down
12 changes: 8 additions & 4 deletions lib/std/crypto/sha2.zig
Original file line number Diff line number Diff line change
Expand Up @@ -392,11 +392,15 @@ fn Sha2x32(comptime params: Sha2Params32) type {
}

pub const Error = error{};
pub const Writer = std.io.Writer(*Self, Error, write);
pub const Writer = std.io.Writer(*Self, Error, writev);

fn write(self: *Self, bytes: []const u8) Error!usize {
self.update(bytes);
return bytes.len;
fn writev(self: *Self, iov: []std.io.WriteBuffers) Error!usize {
var written: usize = 0;
for (iov) |v| {
self.update(v.ptr[0..v.len]);
written += v.len;
}
return written;
}

pub fn writer(self: *Self) Writer {
Expand Down
12 changes: 8 additions & 4 deletions lib/std/crypto/siphash.zig
Original file line number Diff line number Diff line change
Expand Up @@ -240,11 +240,15 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize)
}

pub const Error = error{};
pub const Writer = std.io.Writer(*Self, Error, write);
pub const Writer = std.io.Writer(*Self, Error, writev);

fn write(self: *Self, bytes: []const u8) Error!usize {
self.update(bytes);
return bytes.len;
fn writev(self: *Self, iov: []std.io.WriteBuffers) Error!usize {
var written: usize = 0;
for (iov) |v| {
self.update(v.ptr[0..v.len]);
written += v.len;
}
return written;
}

pub fn writer(self: *Self) Writer {
Expand Down
9 changes: 5 additions & 4 deletions lib/std/crypto/tls.zig
Original file line number Diff line number Diff line change
Expand Up @@ -460,24 +460,25 @@ pub const Decoder = struct {
}

/// Use this function to increase `their_end`.
pub fn readAtLeast(d: *Decoder, stream: anytype, their_amt: usize) !void {
pub fn readAtLeast(d: *Decoder, reader: std.io.AnyReader, their_amt: usize) !void {
assert(!d.disable_reads);
const existing_amt = d.cap - d.idx;
d.their_end = d.idx + their_amt;
if (their_amt <= existing_amt) return;
const request_amt = their_amt - existing_amt;
const dest = d.buf[d.cap..];
if (request_amt > dest.len) return error.TlsRecordOverflow;
const actual_amt = try stream.readAtLeast(dest, request_amt);

const actual_amt = try reader.readAtLeast(dest, request_amt);
if (actual_amt < request_amt) return error.TlsConnectionTruncated;
d.cap += actual_amt;
}

/// Same as `readAtLeast` but also increases `our_end` by exactly `our_amt`.
/// Use when `our_amt` is calculated by us, not by them.
pub fn readAtLeastOurAmt(d: *Decoder, stream: anytype, our_amt: usize) !void {
pub fn readAtLeastOurAmt(d: *Decoder, reader: std.io.AnyReader, our_amt: usize) !void {
assert(!d.disable_reads);
try readAtLeast(d, stream, our_amt);
try d.readAtLeast(reader, our_amt);
d.our_end = d.idx + our_amt;
}

Expand Down
Loading
Loading