authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-05-06 21:14:09-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-01 16:35:29-07:00
log803215bb186cb4a16f2f9552749a18fa384634e6
tree710a65858933fda3693f5614c9d072fed228bc79
parent110af768bbd80c602ad3314091d6a392ee2fd341

delete std.io.MultiWriter

instead this use case is better served with passthrough streams. For instance, hashing writers should support being passed an underlying writer, and the buffer can go in front of the hasher for optimal code.

3 files changed, 11 insertions(+), 61 deletions(-)

lib/std/io.zig-3
......@@ -16,9 +16,6 @@ pub const BufferedReader = @import("io/BufferedReader.zig");
1616pub const BufferedWriter = @import("io/BufferedWriter.zig");
1717pub const AllocatingWriter = @import("io/AllocatingWriter.zig");
1818
19pub const MultiWriter = @import("io/multi_writer.zig").MultiWriter;
20pub const multiWriter = @import("io/multi_writer.zig").multiWriter;
21
2219pub const ChangeDetectionStream = @import("io/change_detection_stream.zig").ChangeDetectionStream;
2320pub const changeDetectionStream = @import("io/change_detection_stream.zig").changeDetectionStream;
2421
lib/std/io/multi_writer.zig deleted-53
......@@ -1,53 +0,0 @@
1const std = @import("../std.zig");
2const io = std.io;
3
4/// Takes a tuple of streams, and constructs a new stream that writes to all of them
5pub fn MultiWriter(comptime Writers: type) type {
6 comptime var ErrSet = error{};
7 inline for (@typeInfo(Writers).@"struct".fields) |field| {
8 const StreamType = field.type;
9 ErrSet = ErrSet || if (@hasDecl(StreamType, "Error")) StreamType.Error else anyerror;
10 }
11
12 return struct {
13 const Self = @This();
14
15 streams: Writers,
16
17 pub const Error = ErrSet;
18 pub const Writer = io.Writer(*Self, Error, write);
19
20 pub fn writer(self: *Self) Writer {
21 return .{ .context = self };
22 }
23
24 pub fn write(self: *Self, bytes: []const u8) Error!usize {
25 inline for (self.streams) |stream|
26 try stream.writeAll(bytes);
27 return bytes.len;
28 }
29 };
30}
31
32pub fn multiWriter(streams: anytype) MultiWriter(@TypeOf(streams)) {
33 return .{ .streams = streams };
34}
35
36const testing = std.testing;
37
38test "MultiWriter" {
39 var tmp = testing.tmpDir(.{});
40 defer tmp.cleanup();
41 var f = try tmp.dir.createFile("t.txt", .{});
42
43 var buf1: [255]u8 = undefined;
44 var fbs1 = io.fixedBufferStream(&buf1);
45 var buf2: [255]u8 = undefined;
46 var stream = multiWriter(.{ fbs1.writer(), f.writer() });
47
48 try stream.writer().print("HI", .{});
49 f.close();
50
51 try testing.expectEqualSlices(u8, "HI", fbs1.getWritten());
52 try testing.expectEqualSlices(u8, "HI", try tmp.dir.readFile("t.txt", &buf2));
53}
src/main.zig+11-5
......@@ -3331,12 +3331,18 @@ fn buildOutputType(
33313331 // We are providing our own cache key, because this file has nothing
33323332 // to do with the cache manifest.
33333333 var hasher = Cache.Hasher.init("0123456789abcdef");
3334 var w = io.multiWriter(.{ f.writer(), hasher.writer() });
3335 var fifo = std.fifo.LinearFifo(u8, .{ .Static = 4096 }).init();
3336 try fifo.pump(fs.File.stdin().reader().unbuffered(), w.writer().unbuffered());
3334 var file_writer = f.writer();
3335 var file_writer_bw = file_writer.interface().unbuffered();
3336 var hasher_writer = hasher.writer(&file_writer_bw);
3337 var buffer: [1000]u8 = undefined;
3338 var bw = hasher_writer.interface().buffered(&buffer);
3339 bw.writeFileAll(.stdin(), .{}) catch |err| switch (err) {
3340 error.WriteFailed => fatal("failed to write {s}: {s}", .{ dump_path, file_writer.err.? }),
3341 else => fatal("failed to pipe stdin to {s}: {s}", .{ dump_path, err }),
3342 };
3343 try bw.flush();
33373344
3338 var bin_digest: Cache.BinDigest = undefined;
3339 hasher.final(&bin_digest);
3345 const bin_digest: Cache.BinDigest = hasher_writer.final();
33403346
33413347 const sub_path = try std.fmt.allocPrint(arena, "tmp" ++ sep ++ "{x}-stdin{s}", .{
33423348 &bin_digest, ext.canonicalName(target),