Skip to content

Change ArrayList(non-u8).Writer from compileError to empty struct #18351

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

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
76 changes: 56 additions & 20 deletions lib/std/array_list.zig
Original file line number Diff line number Diff line change
Expand Up @@ -344,16 +344,28 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
@memcpy(self.items[old_len..][0..items.len], items);
}

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(*Self, error{OutOfMemory}, appendWrite);

/// Initializes a Writer which will append to the list.
pub fn writer(self: *Self) Writer {
return .{ .context = self };
}
// The Writer interface is only valid for ArrayList(u8)
//
// The Writer type is omitted rather than being assigned a compileError, because
// iterating declarations at comptime will fail to compile if a type declaration
// evaluates to a compileError and prevents comptime introspection.
//
// Since people generally want to call arraylist.writer() to get a writer, the bogus
// writer function is where the error happens so we still get a good error message
// when incorrectly calling writer() on a non-u8 ArrayList.
pub usingnamespace if (T == u8) struct {
pub const Writer = std.io.Writer(*Self, error{OutOfMemory}, appendWrite);

/// Initializes a Writer which will append to the list.
pub fn writer(self: *Self) Writer {
return .{ .context = self };
}
} else struct {
pub fn writer(_: *Self) void {
@compileError("The Writer interface is only defined for ArrayList(u8) " ++
"but the given type is ArrayList(" ++ @typeName(T) ++ ")");
}
};

/// 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.
Expand Down Expand Up @@ -884,16 +896,28 @@ 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 } };
}
// The Writer interface is only valid for ArrayList(u8)
//
// The Writer type is omitted rather than being assigned a compileError, because
// iterating declarations at comptime will fail to compile if a type declaration
// evaluates to a compileError and prevents comptime introspection.
//
// Since people generally want to call arraylist.writer() to get a writer, the bogus
// writer function is where the error happens so we still get a good error message
// when incorrectly calling writer() on a non-u8 ArrayList.
pub usingnamespace if (T == u8) struct {
pub const Writer = 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 } };
}
} else struct {
pub fn writer(_: *Self, _: Allocator) void {
@compileError("The Writer interface is only defined for ArrayList(u8) " ++
"but the given type is ArrayList(" ++ @typeName(T) ++ ")");
}
};

/// 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.
Expand Down Expand Up @@ -1952,3 +1976,15 @@ test "std.ArrayList(u32).getLastOrNull()" {
const const_list = list;
try testing.expectEqual(const_list.getLastOrNull().?, 2);
}

test "std.ArrayList(non-u8) iterate decls and check type compiles" {
inline for (comptime std.meta.declarations(ArrayList(u32))) |decl| {
if (@TypeOf(@field(ArrayList(u32), decl.name)) == type) {
// do nothing, just ensuring it compiles

// testing.refAllDecls won't work here because it takes the address of all decls
// but the writer() function isn't defined for non-u8 types and produces a compileError
// so attempting to take its address will fail to compile
}
}
}
44 changes: 34 additions & 10 deletions lib/std/bounded_array.zig
Original file line number Diff line number Diff line change
Expand Up @@ -267,16 +267,28 @@ pub fn BoundedArrayAligned(
@memset(self.slice()[old_len..self.len], value);
}

pub const Writer = if (T != u8)
@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);

/// Initializes a writer which will write into the array.
pub fn writer(self: *Self) Writer {
return .{ .context = self };
}
// The Writer interface is only valid for BoundedArray(u8, ...)
//
// The Writer type is omitted rather than being assigned a compileError, because
// iterating declarations at comptime will fail to compile if a type declaration
// evaluates to a compileError and prevents comptime introspection.
//
// Since people generally want to call boundedarray.writer() to get a writer, the bogus
// writer function is where the error happens so we still get a good error message
// when incorrectly calling writer() on a non-u8 BoundedArray.
pub usingnamespace if (T == u8) struct {
pub const Writer = std.io.Writer(*Self, error{Overflow}, appendWrite);

/// Initializes a Writer which will write into the array.
pub fn writer(self: *Self) Writer {
return .{ .context = self };
}
} else struct {
pub fn writer(_: *Self) void {
@compileError("The Writer interface is only defined for BoundedArray(u8, ...) " ++
"but the given type is BoundedArray(" ++ @typeName(T) ++ ", ...)");
}
};

/// 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.
Expand Down Expand Up @@ -412,3 +424,15 @@ test "BoundedArrayAligned" {
try testing.expectEqual(@as(u16, 0), b[0]);
try testing.expectEqual(@as(u16, 65535), b[1]);
}

test "BoundedArray(non-u8) iterate decls and check type compiles" {
inline for (comptime std.meta.declarations(BoundedArray(u32, 8))) |decl| {
if (@TypeOf(@field(BoundedArray(u32, 8), decl.name)) == type) {
// do nothing, just ensuring it compiles

// testing.refAllDecls won't work here because it takes the address of all decls
// but the writer() function isn't defined for non-u8 types and produces a compileError
// so attempting to take its address will fail to compile
}
}
}