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

Draft: Have Reader/Writer be a runtime instead of comptime interface #13808

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 2 additions & 21 deletions lib/std/array_list.zig
Original file line number Diff line number Diff line change
Expand Up @@ -270,11 +270,11 @@ 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, error{OutOfMemory}, appendWrite);
std.io.Writer(error{OutOfMemory});

/// Initializes a Writer which will append to the list.
pub fn writer(self: *Self) Writer {
return .{ .context = self };
return Writer.init(self, appendWrite);
}

/// Same as `append` except it returns the number of bytes written, which is always the same
Expand Down Expand Up @@ -688,25 +688,6 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
allocator: Allocator,
};

pub const Writer = if (T != u8)
@compileError("The Writer interface is only defined for ArrayList(u8) " ++
"but the given type is ArrayList(" ++ @typeName(T) ++ ")")
else
std.io.Writer(WriterContext, error{OutOfMemory}, appendWrite);

/// Initializes a Writer which will append to the list.
pub fn writer(self: *Self, allocator: Allocator) Writer {
return .{ .context = .{ .self = self, .allocator = allocator } };
}

/// 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 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;
}

/// Append a value to the list `n` times.
/// Allocates more memory as necessary.
/// Invalidates pointers if additional memory is needed.
Expand Down
30 changes: 24 additions & 6 deletions lib/std/fs/file.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1372,16 +1372,34 @@ pub const File = struct {
}
}

pub const Reader = io.Reader(File, ReadError, read);
pub const Reader = io.Reader(ReadError);

pub fn reader(file: *const File) Reader {
// HACK: The Reader interface expects a mutable pointer to context, but there is no need
// to have that here, as `readFn` never modifies the memory of the `File` struct.
// We want the `Reader` interface to handle these kinds of situations, but sadly
// there is no way to discard const and compile time, so that would mean that
// `FixedBufferStream` could not be used in that context.
return Reader.init(@intToPtr(*File, @ptrToInt(file)), readFn);
}

pub fn reader(file: File) Reader {
return .{ .context = file };
fn readFn(self: *File, buffer: []u8) ReadError!usize {
return self.read(buffer);
}

pub const Writer = io.Writer(File, WriteError, write);
pub const Writer = io.Writer(WriteError);

pub fn writer(file: File) Writer {
return .{ .context = file };
pub fn writer(file: *const File) Writer {
// HACK: The Writer interface expects a mutable pointer to context, but there is no need
// to have that here, as `writeFn` never modifies the memory of the `File` struct.
// We want the `Writer` interface to handle these kinds of situations, but sadly
// there is no way to discard const and compile time, so that would mean that
// `FixedBufferStream` could not be used in that context.
return Writer.init(@intToPtr(*File, @ptrToInt(file)), writeFn);
}

fn writeFn(self: *File, bytes: []const u8) WriteError!usize {
return self.write(bytes);
}

pub const SeekableStream = io.SeekableStream(
Expand Down
9 changes: 6 additions & 3 deletions lib/std/io.zig
Original file line number Diff line number Diff line change
Expand Up @@ -162,10 +162,13 @@ pub const BufferedAtomicFile = @import("io/buffered_atomic_file.zig").BufferedAt
pub const StreamSource = @import("io/stream_source.zig").StreamSource;

/// A Writer that doesn't write to anything.
pub const null_writer = @as(NullWriter, .{ .context = {} });
pub const null_writer = NullWriter{
.context = undefined,
.writeFn = dummyWrite,
};

const NullWriter = Writer(void, error{}, dummyWrite);
fn dummyWrite(context: void, data: []const u8) error{}!usize {
const NullWriter = Writer(error{});
fn dummyWrite(context: *anyopaque, data: []const u8) error{}!usize {
_ = context;
return data.len;
}
Expand Down
4 changes: 2 additions & 2 deletions lib/std/io/buffered_writer.zig
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pub fn BufferedWriter(comptime buffer_size: usize, comptime WriterType: type) ty
end: usize = 0,

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

const Self = @This();

Expand All @@ -20,7 +20,7 @@ pub fn BufferedWriter(comptime buffer_size: usize, comptime WriterType: type) ty
}

pub fn writer(self: *Self) Writer {
return .{ .context = self };
return Writer.init(self, write);
}

pub fn write(self: *Self, bytes: []const u8) Error!usize {
Expand Down
4 changes: 2 additions & 2 deletions lib/std/io/counting_reader.zig
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ pub fn CountingReader(comptime ReaderType: anytype) type {
bytes_read: u64 = 0,

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

pub fn read(self: *@This(), buf: []u8) Error!usize {
const amt = try self.child_reader.read(buf);
Expand All @@ -18,7 +18,7 @@ pub fn CountingReader(comptime ReaderType: anytype) type {
}

pub fn reader(self: *@This()) Reader {
return .{ .context = self };
return Reader.init(self, read);
}
};
}
Expand Down
4 changes: 2 additions & 2 deletions lib/std/io/counting_writer.zig
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ pub fn CountingWriter(comptime WriterType: type) type {
child_stream: WriterType,

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

const Self = @This();

Expand All @@ -20,7 +20,7 @@ pub fn CountingWriter(comptime WriterType: type) type {
}

pub fn writer(self: *Self) Writer {
return .{ .context = self };
return Writer.init(self, write);
}
};
}
Expand Down
8 changes: 4 additions & 4 deletions lib/std/io/fixed_buffer_stream.zig
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ pub fn FixedBufferStream(comptime Buffer: type) type {
pub const SeekError = error{};
pub const GetSeekPosError = error{};

pub const Reader = io.Reader(*Self, ReadError, read);
pub const Writer = io.Writer(*Self, WriteError, write);
pub const Reader = io.Reader(ReadError);
pub const Writer = io.Writer(WriteError);

pub const SeekableStream = io.SeekableStream(
*Self,
Expand All @@ -33,11 +33,11 @@ pub fn FixedBufferStream(comptime Buffer: type) type {
const Self = @This();

pub fn reader(self: *Self) Reader {
return .{ .context = self };
return Reader.init(self, read);
}

pub fn writer(self: *Self) Writer {
return .{ .context = self };
return Writer.init(self, write);
}

pub fn seekableStream(self: *Self) SeekableStream {
Expand Down
4 changes: 2 additions & 2 deletions lib/std/io/limited_reader.zig
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ pub fn LimitedReader(comptime ReaderType: type) type {
bytes_left: u64,

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

const Self = @This();

Expand All @@ -21,7 +21,7 @@ pub fn LimitedReader(comptime ReaderType: type) type {
}

pub fn reader(self: *Self) Reader {
return .{ .context = self };
return Reader.init(self, read);
}
};
}
Expand Down
43 changes: 33 additions & 10 deletions lib/std/io/reader.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,33 @@ const assert = std.debug.assert;
const mem = std.mem;
const testing = std.testing;

pub fn Reader(
comptime Context: type,
comptime ReadError: type,
/// 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.
comptime readFn: fn (context: Context, buffer: []u8) ReadError!usize,
) type {
pub fn Reader(comptime ReadError: type) type {
return struct {
pub const Error = ReadError;

context: Context,
context: *anyopaque,
readFn: *const fn (context: *anyopaque, buffer: []u8) Error!usize,

const Self = @This();

pub fn init(
context: anytype,
/// 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.
comptime readFn: *const fn (ctx: @TypeOf(context), buffer: []u8) Error!usize,
) Self {
return Self{
.context = context,
.readFn = makeWrapper(context, Error, readFn),
};
}

/// 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 {
return readFn(self.context, buffer);
return self.readFn(self.context, buffer);
}

/// Returns the number of bytes read. If the number read is smaller than `buffer.len`, it
Expand Down Expand Up @@ -363,6 +370,22 @@ pub fn Reader(
};
}

fn makeWrapper(
context: anytype,
comptime Error: type,
comptime readFn: *const fn (ctx: @TypeOf(context), buffer: []u8) Error!usize,
) *const fn (ctx: *anyopaque, buffer: []u8) Error!usize {
const Context = @TypeOf(context.*);
const ContextPtr = @TypeOf(context);
return struct {
fn wrapper(ctx: *anyopaque, buffer: []u8) Error!usize {
const aligned = @alignCast(@alignOf(Context), ctx);
const casted = @ptrCast(ContextPtr, aligned);
return readFn(casted, buffer);
}
}.wrapper;
}

test "Reader" {
var buf = "a\x02".*;
var fis = std.io.fixedBufferStream(&buf);
Expand Down
37 changes: 30 additions & 7 deletions lib/std/io/writer.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,26 @@ const std = @import("../std.zig");
const assert = std.debug.assert;
const mem = std.mem;

pub fn Writer(
comptime Context: type,
comptime WriteError: type,
comptime writeFn: fn (context: Context, bytes: []const u8) WriteError!usize,
) type {
pub fn Writer(comptime WriteError: type) type {
return struct {
context: Context,
context: *anyopaque,
writeFn: *const fn (ctx: *anyopaque, bytes: []const u8) Error!usize,

const Self = @This();
pub const Error = WriteError;

pub fn init(
context: anytype,
comptime writeFn: *const fn (ctx: @TypeOf(context), bytes: []const u8) Error!usize,
) Self {
return Self{
.context = context,
.writeFn = makeWrapper(context, Error, writeFn),
};
}

pub fn write(self: Self, bytes: []const u8) Error!usize {
return writeFn(self.context, bytes);
return self.writeFn(self.context, bytes);
}

pub fn writeAll(self: Self, bytes: []const u8) Error!void {
Expand Down Expand Up @@ -89,3 +96,19 @@ pub fn Writer(
}
};
}

fn makeWrapper(
context: anytype,
comptime Error: type,
comptime writeFn: *const fn (ctx: @TypeOf(context), bytes: []const u8) Error!usize,
) *const fn (ctx: *anyopaque, bytes: []const u8) Error!usize {
const Context = @TypeOf(context.*);
const ContextPtr = @TypeOf(context);
return struct {
fn wrapper(ctx: *anyopaque, bytes: []const u8) Error!usize {
const aligned = @alignCast(@alignOf(Context), ctx);
const casted = @ptrCast(ContextPtr, aligned);
return writeFn(casted, bytes);
}
}.wrapper;
}
4 changes: 2 additions & 2 deletions lib/std/zig/render.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2932,7 +2932,7 @@ fn AutoIndentingStream(comptime UnderlyingWriter: type) type {
return struct {
const Self = @This();
pub const WriteError = UnderlyingWriter.Error;
pub const Writer = std.io.Writer(*Self, WriteError, write);
pub const Writer = std.io.Writer(WriteError);

underlying_writer: UnderlyingWriter,

Expand All @@ -2955,7 +2955,7 @@ fn AutoIndentingStream(comptime UnderlyingWriter: type) type {
indent_next_line: usize = 0,

pub fn writer(self: *Self) Writer {
return .{ .context = self };
return Writer.init(self, write);
}

pub fn write(self: *Self, bytes: []const u8) WriteError!usize {
Expand Down
Loading