Skip to content

std.zig: finish updating to new I/O API #24488

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

Merged
merged 10 commits into from
Jul 20, 2025
Merged
18 changes: 9 additions & 9 deletions lib/compiler/objcopy.zig
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ const assert = std.debug.assert;
const fatal = std.process.fatal;
const Server = std.zig.Server;

var stdin_buffer: [1024]u8 = undefined;
var stdout_buffer: [1024]u8 = undefined;

pub fn main() !void {
var arena_instance = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena_instance.deinit();
Expand All @@ -22,11 +25,8 @@ pub fn main() !void {
return cmdObjCopy(gpa, arena, args[1..]);
}

fn cmdObjCopy(
gpa: Allocator,
arena: Allocator,
args: []const []const u8,
) !void {
fn cmdObjCopy(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
_ = gpa;
var i: usize = 0;
var opt_out_fmt: ?std.Target.ObjectFormat = null;
var opt_input: ?[]const u8 = null;
Expand Down Expand Up @@ -225,13 +225,13 @@ fn cmdObjCopy(
}

if (listen) {
var stdin_reader = fs.File.stdin().reader(&stdin_buffer);
var stdout_writer = fs.File.stdout().writer(&stdout_buffer);
var server = try Server.init(.{
.gpa = gpa,
.in = .stdin(),
.out = .stdout(),
.in = &stdin_reader.interface,
.out = &stdout_writer.interface,
.zig_version = builtin.zig_version_string,
});
defer server.deinit();

var seen_update = false;
while (true) {
Expand Down
6 changes: 4 additions & 2 deletions lib/compiler/resinator/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ const hasDisjointCodePage = @import("disjoint_code_page.zig").hasDisjointCodePag
const fmtResourceType = @import("res.zig").NameOrOrdinal.fmtResourceType;
const aro = @import("aro");

var stdout_buffer: [1024]u8 = undefined;

pub fn main() !void {
var gpa: std.heap.GeneralPurposeAllocator(.{}) = .init;
defer std.debug.assert(gpa.deinit() == .ok);
Expand Down Expand Up @@ -41,12 +43,12 @@ pub fn main() !void {
cli_args = args[3..];
}

var stdout_writer2 = std.fs.File.stdout().writer(&stdout_buffer);
var error_handler: ErrorHandler = switch (zig_integration) {
true => .{
.server = .{
.out = std.fs.File.stdout(),
.out = &stdout_writer2.interface,
.in = undefined, // won't be receiving messages
.receive_fifo = undefined, // won't be receiving messages
},
},
false => .{
Expand Down
15 changes: 8 additions & 7 deletions lib/compiler/test_runner.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
const builtin = @import("builtin");

const std = @import("std");
const io = std.io;
const testing = std.testing;
const assert = std.debug.assert;

Expand All @@ -11,8 +10,10 @@ pub const std_options: std.Options = .{
};

var log_err_count: usize = 0;
var fba_buffer: [8192]u8 = undefined;
var fba = std.heap.FixedBufferAllocator.init(&fba_buffer);
var fba_buffer: [8192]u8 = undefined;
var stdin_buffer: [4096]u8 = undefined;
var stdout_buffer: [4096]u8 = undefined;

const crippled = switch (builtin.zig_backend) {
.stage2_powerpc,
Expand Down Expand Up @@ -67,13 +68,13 @@ pub fn main() void {

fn mainServer() !void {
@disableInstrumentation();
var stdin_reader = std.fs.File.stdin().readerStreaming(&stdin_buffer);
var stdout_writer = std.fs.File.stdout().writerStreaming(&stdout_buffer);
var server = try std.zig.Server.init(.{
.gpa = fba.allocator(),
.in = .stdin(),
.out = .stdout(),
.in = &stdin_reader.interface,
.out = &stdout_writer.interface,
.zig_version = builtin.zig_version_string,
});
defer server.deinit();

if (builtin.fuzz) {
const coverage_id = fuzzer_coverage_id();
Expand Down Expand Up @@ -103,7 +104,7 @@ fn mainServer() !void {
defer testing.allocator.free(expected_panic_msgs);

for (test_fns, names, expected_panic_msgs) |test_fn, *name, *expected_panic_msg| {
name.* = @as(u32, @intCast(string_bytes.items.len));
name.* = @intCast(string_bytes.items.len);
try string_bytes.ensureUnusedCapacity(testing.allocator, test_fn.name.len + 1);
string_bytes.appendSliceAssumeCapacity(test_fn.name);
string_bytes.appendAssumeCapacity(0);
Expand Down
2 changes: 1 addition & 1 deletion lib/std/Build/Step/Run.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1742,7 +1742,7 @@ fn sendMessage(file: std.fs.File, tag: std.zig.Client.Message.Tag) !void {
.tag = tag,
.bytes_len = 0,
};
try file.writeAll(std.mem.asBytes(&header));
try file.writeAll(@ptrCast(&header));
}

fn sendRunTestMessage(file: std.fs.File, tag: std.zig.Client.Message.Tag, index: u32) !void {
Expand Down
34 changes: 17 additions & 17 deletions lib/std/Io/Reader.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1108,9 +1108,9 @@ pub fn takeVarInt(r: *Reader, comptime Int: type, endian: std.builtin.Endian, n:
/// Asserts the buffer was initialized with a capacity at least `@sizeOf(T)`.
///
/// See also:
/// * `peekStructReference`
/// * `peekStructPointer`
/// * `takeStruct`
pub fn takeStructReference(r: *Reader, comptime T: type) Error!*align(1) T {
pub fn takeStructPointer(r: *Reader, comptime T: type) Error!*align(1) T {
// Only extern and packed structs have defined in-memory layout.
comptime assert(@typeInfo(T).@"struct".layout != .auto);
return @ptrCast(try r.takeArray(@sizeOf(T)));
Expand All @@ -1122,9 +1122,9 @@ pub fn takeStructReference(r: *Reader, comptime T: type) Error!*align(1) T {
/// Asserts the buffer was initialized with a capacity at least `@sizeOf(T)`.
///
/// See also:
/// * `takeStructReference`
/// * `takeStructPointer`
/// * `peekStruct`
pub fn peekStructReference(r: *Reader, comptime T: type) Error!*align(1) T {
pub fn peekStructPointer(r: *Reader, comptime T: type) Error!*align(1) T {
// Only extern and packed structs have defined in-memory layout.
comptime assert(@typeInfo(T).@"struct".layout != .auto);
return @ptrCast(try r.peekArray(@sizeOf(T)));
Expand All @@ -1136,14 +1136,14 @@ pub fn peekStructReference(r: *Reader, comptime T: type) Error!*align(1) T {
/// when `endian` is comptime-known and matches the host endianness.
///
/// See also:
/// * `takeStructReference`
/// * `takeStructPointer`
/// * `peekStruct`
pub inline fn takeStruct(r: *Reader, comptime T: type, endian: std.builtin.Endian) Error!T {
switch (@typeInfo(T)) {
.@"struct" => |info| switch (info.layout) {
.auto => @compileError("ill-defined memory layout"),
.@"extern" => {
var res = (try r.takeStructReference(T)).*;
var res = (try r.takeStructPointer(T)).*;
if (native_endian != endian) std.mem.byteSwapAllFields(T, &res);
return res;
},
Expand All @@ -1162,13 +1162,13 @@ pub inline fn takeStruct(r: *Reader, comptime T: type, endian: std.builtin.Endia
///
/// See also:
/// * `takeStruct`
/// * `peekStructReference`
/// * `peekStructPointer`
pub inline fn peekStruct(r: *Reader, comptime T: type, endian: std.builtin.Endian) Error!T {
switch (@typeInfo(T)) {
.@"struct" => |info| switch (info.layout) {
.auto => @compileError("ill-defined memory layout"),
.@"extern" => {
var res = (try r.peekStructReference(T)).*;
var res = (try r.peekStructPointer(T)).*;
if (native_endian != endian) std.mem.byteSwapAllFields(T, &res);
return res;
},
Expand Down Expand Up @@ -1557,27 +1557,27 @@ test takeVarInt {
try testing.expectError(error.EndOfStream, r.takeVarInt(u16, .little, 1));
}

test takeStructReference {
test takeStructPointer {
var r: Reader = .fixed(&.{ 0x12, 0x00, 0x34, 0x56 });
const S = extern struct { a: u8, b: u16 };
switch (native_endian) {
.little => try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x5634 }), (try r.takeStructReference(S)).*),
.big => try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), (try r.takeStructReference(S)).*),
.little => try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x5634 }), (try r.takeStructPointer(S)).*),
.big => try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), (try r.takeStructPointer(S)).*),
}
try testing.expectError(error.EndOfStream, r.takeStructReference(S));
try testing.expectError(error.EndOfStream, r.takeStructPointer(S));
}

test peekStructReference {
test peekStructPointer {
var r: Reader = .fixed(&.{ 0x12, 0x00, 0x34, 0x56 });
const S = extern struct { a: u8, b: u16 };
switch (native_endian) {
.little => {
try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x5634 }), (try r.peekStructReference(S)).*);
try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x5634 }), (try r.peekStructReference(S)).*);
try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x5634 }), (try r.peekStructPointer(S)).*);
try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x5634 }), (try r.peekStructPointer(S)).*);
},
.big => {
try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), (try r.peekStructReference(S)).*);
try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), (try r.peekStructReference(S)).*);
try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), (try r.peekStructPointer(S)).*);
try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), (try r.peekStructPointer(S)).*);
},
}
}
Expand Down
19 changes: 18 additions & 1 deletion lib/std/Io/Writer.zig
Original file line number Diff line number Diff line change
Expand Up @@ -860,7 +860,15 @@ pub inline fn writeSliceEndian(
if (native_endian == endian) {
return writeAll(w, @ptrCast(slice));
} else {
return w.writeArraySwap(w, Elem, slice);
return writeSliceSwap(w, Elem, slice);
}
}

pub fn writeSliceSwap(w: *Writer, Elem: type, slice: []const Elem) Error!void {
for (slice) |elem| {
var tmp = elem;
std.mem.byteSwapAllFields(Elem, &tmp);
try w.writeAll(@ptrCast(&tmp));
}
}

Expand Down Expand Up @@ -2630,3 +2638,12 @@ test writeStruct {
}, &buffer);
}
}

test writeSliceEndian {
var buffer: [5]u8 align(2) = undefined;
var w: Writer = .fixed(&buffer);
try w.writeByte('x');
const array: [2]u16 = .{ 0x1234, 0x5678 };
try writeSliceEndian(&w, u16, &array, .big);
try testing.expectEqualSlices(u8, &.{ 'x', 0x12, 0x34, 0x56, 0x78 }, &buffer);
}
7 changes: 7 additions & 0 deletions lib/std/debug.zig
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,13 @@ pub fn assertReadable(slice: []const volatile u8) void {
for (slice) |*byte| _ = byte.*;
}

/// Invokes detectable illegal behavior when the provided array is not aligned
/// to the provided amount.
pub fn assertAligned(ptr: anytype, comptime alignment: std.mem.Alignment) void {
const aligned_ptr: *align(alignment.toByteUnits()) anyopaque = @alignCast(@ptrCast(ptr));
_ = aligned_ptr;
}

/// Equivalent to `@panic` but with a formatted message.
pub fn panic(comptime format: []const u8, args: anytype) noreturn {
@branchHint(.cold);
Expand Down
36 changes: 20 additions & 16 deletions lib/std/mem.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2179,22 +2179,8 @@ pub fn byteSwapAllFields(comptime S: type, ptr: *S) void {
const BackingInt = std.meta.Int(.unsigned, @bitSizeOf(S));
ptr.* = @bitCast(@byteSwap(@as(BackingInt, @bitCast(ptr.*))));
},
.array => {
for (ptr) |*item| {
switch (@typeInfo(@TypeOf(item.*))) {
.@"struct", .@"union", .array => byteSwapAllFields(@TypeOf(item.*), item),
.@"enum" => {
item.* = @enumFromInt(@byteSwap(@intFromEnum(item.*)));
},
.bool => {},
.float => |float_info| {
item.* = @bitCast(@byteSwap(@as(std.meta.Int(.unsigned, float_info.bits), @bitCast(item.*))));
},
else => {
item.* = @byteSwap(item.*);
},
}
}
.array => |info| {
byteSwapAllElements(info.child, ptr);
},
else => {
ptr.* = @byteSwap(ptr.*);
Expand Down Expand Up @@ -2258,6 +2244,24 @@ test byteSwapAllFields {
}, k);
}

pub fn byteSwapAllElements(comptime Elem: type, slice: []Elem) void {
for (slice) |*elem| {
switch (@typeInfo(@TypeOf(elem.*))) {
.@"struct", .@"union", .array => byteSwapAllFields(@TypeOf(elem.*), elem),
.@"enum" => {
elem.* = @enumFromInt(@byteSwap(@intFromEnum(elem.*)));
},
.bool => {},
.float => |float_info| {
elem.* = @bitCast(@byteSwap(@as(std.meta.Int(.unsigned, float_info.bits), @bitCast(elem.*))));
},
else => {
elem.* = @byteSwap(elem.*);
},
}
}
}

/// Returns an iterator that iterates over the slices of `buffer` that are not
/// any of the items in `delimiters`.
///
Expand Down
1 change: 1 addition & 0 deletions lib/std/zig.zig
Original file line number Diff line number Diff line change
Expand Up @@ -905,4 +905,5 @@ test {
_ = system;
_ = target;
_ = c_translation;
_ = llvm;
}
7 changes: 3 additions & 4 deletions lib/std/zig/LibCInstallation.zig
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ fn findNativeIncludeDirWindows(

for (installs) |install| {
result_buf.shrinkAndFree(0);
try result_buf.writer().print("{s}\\Include\\{s}\\ucrt", .{ install.path, install.version });
try result_buf.print("{s}\\Include\\{s}\\ucrt", .{ install.path, install.version });

var dir = fs.cwd().openDir(result_buf.items, .{}) catch |err| switch (err) {
error.FileNotFound,
Expand Down Expand Up @@ -417,7 +417,7 @@ fn findNativeCrtDirWindows(

for (installs) |install| {
result_buf.shrinkAndFree(0);
try result_buf.writer().print("{s}\\Lib\\{s}\\ucrt\\{s}", .{ install.path, install.version, arch_sub_dir });
try result_buf.print("{s}\\Lib\\{s}\\ucrt\\{s}", .{ install.path, install.version, arch_sub_dir });

var dir = fs.cwd().openDir(result_buf.items, .{}) catch |err| switch (err) {
error.FileNotFound,
Expand Down Expand Up @@ -484,8 +484,7 @@ fn findNativeKernel32LibDir(

for (installs) |install| {
result_buf.shrinkAndFree(0);
const stream = result_buf.writer();
try stream.print("{s}\\Lib\\{s}\\um\\{s}", .{ install.path, install.version, arch_sub_dir });
try result_buf.print("{s}\\Lib\\{s}\\um\\{s}", .{ install.path, install.version, arch_sub_dir });

var dir = fs.cwd().openDir(result_buf.items, .{}) catch |err| switch (err) {
error.FileNotFound,
Expand Down
Loading