authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-02-16 22:02:45-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-01 16:35:26-07:00
logfced9467e8eaa85315154f9567cf6da23246d1ef
tree86da1f855dc1ce247764469521a7649dfefd30a9
parent221b194f284ecacccd208a2f760381f8d97805d7

std ArrayList unit tests passing


15 files changed, 208 insertions(+), 230 deletions(-)

lib/std/Build/Step/CheckObject.zig+12-12
...@@ -1242,7 +1242,7 @@ const MachODumper = struct {...@@ -1242,7 +1242,7 @@ const MachODumper = struct {
1242 }1242 }
12431243
1244 fn parseRebaseInfo(ctx: ObjectContext, data: []const u8, rebases: *std.ArrayList(u64)) !void {1244 fn parseRebaseInfo(ctx: ObjectContext, data: []const u8, rebases: *std.ArrayList(u64)) !void {
1245 var stream = std.io.fixedBufferStream(data);1245 var stream: std.io.FixedBufferStream = .{ .buffer = data };
1246 var creader = std.io.countingReader(stream.reader());1246 var creader = std.io.countingReader(stream.reader());
1247 const reader = creader.reader();1247 const reader = creader.reader();
12481248
...@@ -1354,7 +1354,7 @@ const MachODumper = struct {...@@ -1354,7 +1354,7 @@ const MachODumper = struct {
1354 }1354 }
13551355
1356 fn parseBindInfo(ctx: ObjectContext, data: []const u8, bindings: *std.ArrayList(Binding)) !void {1356 fn parseBindInfo(ctx: ObjectContext, data: []const u8, bindings: *std.ArrayList(Binding)) !void {
1357 var stream = std.io.fixedBufferStream(data);1357 var stream: std.io.FixedBufferStream = .{ .buffer = data };
1358 var creader = std.io.countingReader(stream.reader());1358 var creader = std.io.countingReader(stream.reader());
1359 const reader = creader.reader();1359 const reader = creader.reader();
13601360
...@@ -1487,8 +1487,8 @@ const MachODumper = struct {...@@ -1487,8 +1487,8 @@ const MachODumper = struct {
1487 data: []const u8,1487 data: []const u8,
1488 pos: usize = 0,1488 pos: usize = 0,
14891489
1490 fn getStream(it: *TrieIterator) std.io.FixedBufferStream([]const u8) {1490 fn getStream(it: *TrieIterator) std.io.FixedBufferStream {
1491 return std.io.fixedBufferStream(it.data[it.pos..]);1491 return .{ .buffer = it.data[it.pos..] };
1492 }1492 }
14931493
1494 fn readUleb128(it: *TrieIterator) !u64 {1494 fn readUleb128(it: *TrieIterator) !u64 {
...@@ -1748,7 +1748,7 @@ const ElfDumper = struct {...@@ -1748,7 +1748,7 @@ const ElfDumper = struct {
17481748
1749 fn parseAndDumpArchive(step: *Step, check: Check, bytes: []const u8) ![]const u8 {1749 fn parseAndDumpArchive(step: *Step, check: Check, bytes: []const u8) ![]const u8 {
1750 const gpa = step.owner.allocator;1750 const gpa = step.owner.allocator;
1751 var stream = std.io.fixedBufferStream(bytes);1751 var stream: std.io.FixedBufferStream = .{ .buffer = bytes };
1752 const reader = stream.reader();1752 const reader = stream.reader();
17531753
1754 const magic = try reader.readBytesNoEof(elf.ARMAG.len);1754 const magic = try reader.readBytesNoEof(elf.ARMAG.len);
...@@ -1805,8 +1805,8 @@ const ElfDumper = struct {...@@ -1805,8 +1805,8 @@ const ElfDumper = struct {
1805 try ctx.objects.append(gpa, .{ .name = name, .off = stream.pos, .len = size });1805 try ctx.objects.append(gpa, .{ .name = name, .off = stream.pos, .len = size });
1806 }1806 }
18071807
1808 var output = std.ArrayList(u8).init(gpa);1808 var output: std.io.AllocatingWriter = undefined;
1809 const writer = output.writer();1809 const writer = output.init(gpa);
18101810
1811 switch (check.kind) {1811 switch (check.kind) {
1812 .archive_symtab => if (ctx.symtab.items.len > 0) {1812 .archive_symtab => if (ctx.symtab.items.len > 0) {
...@@ -1829,7 +1829,7 @@ const ElfDumper = struct {...@@ -1829,7 +1829,7 @@ const ElfDumper = struct {
1829 objects: std.ArrayListUnmanaged(struct { name: []const u8, off: usize, len: usize }) = .empty,1829 objects: std.ArrayListUnmanaged(struct { name: []const u8, off: usize, len: usize }) = .empty,
18301830
1831 fn parseSymtab(ctx: *ArchiveContext, raw: []const u8, ptr_width: enum { p32, p64 }) !void {1831 fn parseSymtab(ctx: *ArchiveContext, raw: []const u8, ptr_width: enum { p32, p64 }) !void {
1832 var stream = std.io.fixedBufferStream(raw);1832 var stream: std.io.FixedBufferStream = .{ .buffer = raw };
1833 const reader = stream.reader();1833 const reader = stream.reader();
1834 const num = switch (ptr_width) {1834 const num = switch (ptr_width) {
1835 .p32 => try reader.readInt(u32, .big),1835 .p32 => try reader.readInt(u32, .big),
...@@ -1914,7 +1914,7 @@ const ElfDumper = struct {...@@ -1914,7 +1914,7 @@ const ElfDumper = struct {
19141914
1915 fn parseAndDumpObject(step: *Step, check: Check, bytes: []const u8) ![]const u8 {1915 fn parseAndDumpObject(step: *Step, check: Check, bytes: []const u8) ![]const u8 {
1916 const gpa = step.owner.allocator;1916 const gpa = step.owner.allocator;
1917 var stream = std.io.fixedBufferStream(bytes);1917 var stream: std.io.FixedBufferStream = .{ .buffer = bytes };
1918 const reader = stream.reader();1918 const reader = stream.reader();
19191919
1920 const hdr = try reader.readStruct(elf.Elf64_Ehdr);1920 const hdr = try reader.readStruct(elf.Elf64_Ehdr);
...@@ -2419,7 +2419,7 @@ const WasmDumper = struct {...@@ -2419,7 +2419,7 @@ const WasmDumper = struct {
24192419
2420 fn parseAndDump(step: *Step, check: Check, bytes: []const u8) ![]const u8 {2420 fn parseAndDump(step: *Step, check: Check, bytes: []const u8) ![]const u8 {
2421 const gpa = step.owner.allocator;2421 const gpa = step.owner.allocator;
2422 var fbs = std.io.fixedBufferStream(bytes);2422 var fbs: std.io.FixedBufferStream = .{ .buffer = bytes };
2423 const reader = fbs.reader();2423 const reader = fbs.reader();
24242424
2425 const buf = try reader.readBytesNoEof(8);2425 const buf = try reader.readBytesNoEof(8);
...@@ -2472,7 +2472,7 @@ const WasmDumper = struct {...@@ -2472,7 +2472,7 @@ const WasmDumper = struct {
2472 data: []const u8,2472 data: []const u8,
2473 bw: *std.io.BufferedWriter,2473 bw: *std.io.BufferedWriter,
2474 ) !void {2474 ) !void {
2475 var fbs = std.io.fixedBufferStream(data);2475 var fbs: std.io.FixedBufferStream = .{ .buffer = data };
2476 const reader = fbs.reader();2476 const reader = fbs.reader();
24772477
2478 try bw.print(2478 try bw.print(
...@@ -2524,7 +2524,7 @@ const WasmDumper = struct {...@@ -2524,7 +2524,7 @@ const WasmDumper = struct {
2524 }2524 }
25252525
2526 fn parseSection(step: *Step, section: std.wasm.Section, data: []const u8, entries: u32, bw: *std.io.BufferedWriter) !void {2526 fn parseSection(step: *Step, section: std.wasm.Section, data: []const u8, entries: u32, bw: *std.io.BufferedWriter) !void {
2527 var fbs = std.io.fixedBufferStream(data);2527 var fbs: std.io.FixedBufferStream = .{ .buffer = data };
2528 const reader = fbs.reader();2528 const reader = fbs.reader();
25292529
2530 switch (section) {2530 switch (section) {
lib/std/Build/Step/Compile.zig+13-9
...@@ -1964,20 +1964,24 @@ fn addFlag(args: *ArrayList([]const u8), comptime name: []const u8, opt: ?bool)...@@ -1964,20 +1964,24 @@ fn addFlag(args: *ArrayList([]const u8), comptime name: []const u8, opt: ?bool)
1964fn checkCompileErrors(compile: *Compile) !void {1964fn checkCompileErrors(compile: *Compile) !void {
1965 // Clear this field so that it does not get printed by the build runner.1965 // Clear this field so that it does not get printed by the build runner.
1966 const actual_eb = compile.step.result_error_bundle;1966 const actual_eb = compile.step.result_error_bundle;
1967 compile.step.result_error_bundle = std.zig.ErrorBundle.empty;1967 compile.step.result_error_bundle = .empty;
19681968
1969 const arena = compile.step.owner.allocator;1969 const arena = compile.step.owner.allocator;
19701970
1971 var actual_errors_list = std.ArrayList(u8).init(arena);1971 const actual_errors = ae: {
1972 try actual_eb.renderToWriter(.{1972 var aw: std.io.AllocatingWriter = undefined;
1973 .ttyconf = .no_color,1973 const bw = aw.init(arena);
1974 .include_reference_trace = false,1974 defer aw.deinit();
1975 .include_source_line = false,1975 try actual_eb.renderToWriter(.{
1976 }, actual_errors_list.writer());1976 .ttyconf = .no_color,
1977 const actual_errors = try actual_errors_list.toOwnedSlice();1977 .include_reference_trace = false,
1978 .include_source_line = false,
1979 }, bw);
1980 break :ae try aw.toOwnedSlice();
1981 };
19781982
1979 // Render the expected lines into a string that we can compare verbatim.1983 // Render the expected lines into a string that we can compare verbatim.
1980 var expected_generated = std.ArrayList(u8).init(arena);1984 var expected_generated: std.ArrayListUnmanaged(u8) = .empty;
1981 const expect_errors = compile.expect_errors.?;1985 const expect_errors = compile.expect_errors.?;
19821986
1983 var actual_line_it = mem.splitScalar(u8, actual_errors, '\n');1987 var actual_line_it = mem.splitScalar(u8, actual_errors, '\n');
lib/std/Uri.zig+7-7
...@@ -34,7 +34,7 @@ pub const Component = union(enum) {...@@ -34,7 +34,7 @@ pub const Component = union(enum) {
34 return switch (component) {34 return switch (component) {
35 .raw => |raw| raw,35 .raw => |raw| raw,
36 .percent_encoded => |percent_encoded| if (std.mem.indexOfScalar(u8, percent_encoded, '%')) |_|36 .percent_encoded => |percent_encoded| if (std.mem.indexOfScalar(u8, percent_encoded, '%')) |_|
37 try std.fmt.allocPrint(arena, "{raw}", .{component})37 try std.fmt.allocPrint(arena, "{fraw}", .{component})
38 else38 else
39 percent_encoded,39 percent_encoded,
40 };40 };
...@@ -44,8 +44,8 @@ pub const Component = union(enum) {...@@ -44,8 +44,8 @@ pub const Component = union(enum) {
44 component: Component,44 component: Component,
45 comptime fmt_str: []const u8,45 comptime fmt_str: []const u8,
46 _: std.fmt.FormatOptions,46 _: std.fmt.FormatOptions,
47 writer: anytype,47 writer: *std.io.BufferedWriter,
48 ) @TypeOf(writer).Error!void {48 ) anyerror!void {
49 if (fmt_str.len == 0) {49 if (fmt_str.len == 0) {
50 try writer.print("std.Uri.Component{{ .{s} = \"{}\" }}", .{50 try writer.print("std.Uri.Component{{ .{s} = \"{}\" }}", .{
51 @tagName(component),51 @tagName(component),
...@@ -97,10 +97,10 @@ pub const Component = union(enum) {...@@ -97,10 +97,10 @@ pub const Component = union(enum) {
97 }97 }
9898
99 pub fn percentEncode(99 pub fn percentEncode(
100 writer: anytype,100 writer: *std.io.BufferedWriter,
101 raw: []const u8,101 raw: []const u8,
102 comptime isValidChar: fn (u8) bool,102 comptime isValidChar: fn (u8) bool,
103 ) @TypeOf(writer).Error!void {103 ) anyerror!void {
104 var start: usize = 0;104 var start: usize = 0;
105 for (raw, 0..) |char, index| {105 for (raw, 0..) |char, index| {
106 if (isValidChar(char)) continue;106 if (isValidChar(char)) continue;
...@@ -822,7 +822,7 @@ test "URI percent decoding" {...@@ -822,7 +822,7 @@ test "URI percent decoding" {
822 const expected = "\\ö/ äöß ~~.adas-https://canvas:123/#ads&&sad";822 const expected = "\\ö/ äöß ~~.adas-https://canvas:123/#ads&&sad";
823 var input = "%5C%C3%B6%2F%20%C3%A4%C3%B6%C3%9F%20~~.adas-https%3A%2F%2Fcanvas%3A123%2F%23ads%26%26sad".*;823 var input = "%5C%C3%B6%2F%20%C3%A4%C3%B6%C3%9F%20~~.adas-https%3A%2F%2Fcanvas%3A123%2F%23ads%26%26sad".*;
824824
825 try std.testing.expectFmt(expected, "{raw}", .{Component{ .percent_encoded = &input }});825 try std.testing.expectFmt(expected, "{fraw}", .{Component{ .percent_encoded = &input }});
826826
827 var output: [expected.len]u8 = undefined;827 var output: [expected.len]u8 = undefined;
828 try std.testing.expectEqualStrings(percentDecodeBackwards(&output, &input), expected);828 try std.testing.expectEqualStrings(percentDecodeBackwards(&output, &input), expected);
...@@ -834,7 +834,7 @@ test "URI percent decoding" {...@@ -834,7 +834,7 @@ test "URI percent decoding" {
834 const expected = "/abc%";834 const expected = "/abc%";
835 var input = expected.*;835 var input = expected.*;
836836
837 try std.testing.expectFmt(expected, "{raw}", .{Component{ .percent_encoded = &input }});837 try std.testing.expectFmt(expected, "{fraw}", .{Component{ .percent_encoded = &input }});
838838
839 var output: [expected.len]u8 = undefined;839 var output: [expected.len]u8 = undefined;
840 try std.testing.expectEqualStrings(percentDecodeBackwards(&output, &input), expected);840 try std.testing.expectEqualStrings(percentDecodeBackwards(&output, &input), expected);
lib/std/array_list.zig-54
...@@ -1828,60 +1828,6 @@ test "ArrayList(T) of struct T" {...@@ -1828,60 +1828,6 @@ test "ArrayList(T) of struct T" {
1828 }1828 }
1829}1829}
18301830
1831test "ArrayList(u8) implements writer" {
1832 const a = testing.allocator;
1833
1834 {
1835 var buffer = ArrayList(u8).init(a);
1836 defer buffer.deinit();
1837
1838 const x: i32 = 42;
1839 const y: i32 = 1234;
1840 try buffer.writer().print("x: {}\ny: {}\n", .{ x, y });
1841
1842 try testing.expectEqualSlices(u8, "x: 42\ny: 1234\n", buffer.items);
1843 }
1844 {
1845 var list = ArrayListAligned(u8, .@"2").init(a);
1846 defer list.deinit();
1847
1848 const writer = list.writer();
1849 try writer.writeAll("a");
1850 try writer.writeAll("bc");
1851 try writer.writeAll("d");
1852 try writer.writeAll("efg");
1853
1854 try testing.expectEqualSlices(u8, list.items, "abcdefg");
1855 }
1856}
1857
1858test "ArrayListUnmanaged(u8) implements writer" {
1859 const a = testing.allocator;
1860
1861 {
1862 var buffer: ArrayListUnmanaged(u8) = .empty;
1863 defer buffer.deinit(a);
1864
1865 const x: i32 = 42;
1866 const y: i32 = 1234;
1867 try buffer.writer(a).print("x: {}\ny: {}\n", .{ x, y });
1868
1869 try testing.expectEqualSlices(u8, "x: 42\ny: 1234\n", buffer.items);
1870 }
1871 {
1872 var list: ArrayListAlignedUnmanaged(u8, .@"2") = .empty;
1873 defer list.deinit(a);
1874
1875 const writer = list.writer(a);
1876 try writer.writeAll("a");
1877 try writer.writeAll("bc");
1878 try writer.writeAll("d");
1879 try writer.writeAll("efg");
1880
1881 try testing.expectEqualSlices(u8, list.items, "abcdefg");
1882 }
1883}
1884
1885test "shrink still sets length when resizing is disabled" {1831test "shrink still sets length when resizing is disabled" {
1886 var failing_allocator = testing.FailingAllocator.init(testing.allocator, .{ .resize_fail_index = 0 });1832 var failing_allocator = testing.FailingAllocator.init(testing.allocator, .{ .resize_fail_index = 0 });
1887 const a = failing_allocator.allocator();1833 const a = failing_allocator.allocator();
lib/std/compress/lzma2.zig+9-6
...@@ -15,12 +15,15 @@ pub fn decompress(...@@ -15,12 +15,15 @@ pub fn decompress(
1515
16test {16test {
17 const expected = "Hello\nWorld!\n";17 const expected = "Hello\nWorld!\n";
18 const compressed = &[_]u8{ 0x01, 0x00, 0x05, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x02, 0x00, 0x06, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x0A, 0x00 };18 const compressed = &[_]u8{
19 0x01, 0x00, 0x05, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x02,
20 0x00, 0x06, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x0A, 0x00,
21 };
22 var stream: std.io.FixedBufferStream = .{ .buffer = compressed };
1923
20 const allocator = std.testing.allocator;24 var decomp: std.io.AllocatingWriter = undefined;
21 var decomp = std.ArrayList(u8).init(allocator);25 const decomp_bw = decomp.init(std.testing.allocator);
22 defer decomp.deinit();26 defer decomp.deinit();
23 var stream = std.io.fixedBufferStream(compressed);27 try decompress(std.testing.allocator, stream.reader(), decomp_bw);
24 try decompress(allocator, stream.reader(), decomp.writer());28 try std.testing.expectEqualSlices(u8, expected, decomp.getWritten());
25 try std.testing.expectEqualSlices(u8, expected, decomp.items);
26}29}
lib/std/compress/zstandard/decode/block.zig+3-3
...@@ -631,7 +631,7 @@ pub fn decodeBlock(...@@ -631,7 +631,7 @@ pub fn decodeBlock(
631 var bytes_read: usize = 0;631 var bytes_read: usize = 0;
632 const literals = decodeLiteralsSectionSlice(src[0..block_size], &bytes_read) catch632 const literals = decodeLiteralsSectionSlice(src[0..block_size], &bytes_read) catch
633 return error.MalformedCompressedBlock;633 return error.MalformedCompressedBlock;
634 var fbs = std.io.fixedBufferStream(src[bytes_read..block_size]);634 var fbs: std.io.FixedBufferStream = .{ .buffer = src[bytes_read..block_size] };
635 const fbs_reader = fbs.reader();635 const fbs_reader = fbs.reader();
636 const sequences_header = decodeSequencesHeader(fbs_reader) catch636 const sequences_header = decodeSequencesHeader(fbs_reader) catch
637 return error.MalformedCompressedBlock;637 return error.MalformedCompressedBlock;
...@@ -737,7 +737,7 @@ pub fn decodeBlockRingBuffer(...@@ -737,7 +737,7 @@ pub fn decodeBlockRingBuffer(
737 var bytes_read: usize = 0;737 var bytes_read: usize = 0;
738 const literals = decodeLiteralsSectionSlice(src[0..block_size], &bytes_read) catch738 const literals = decodeLiteralsSectionSlice(src[0..block_size], &bytes_read) catch
739 return error.MalformedCompressedBlock;739 return error.MalformedCompressedBlock;
740 var fbs = std.io.fixedBufferStream(src[bytes_read..block_size]);740 var fbs: std.io.FixedBufferStream = .{ .buffer = src[bytes_read..block_size] };
741 const fbs_reader = fbs.reader();741 const fbs_reader = fbs.reader();
742 const sequences_header = decodeSequencesHeader(fbs_reader) catch742 const sequences_header = decodeSequencesHeader(fbs_reader) catch
743 return error.MalformedCompressedBlock;743 return error.MalformedCompressedBlock;
...@@ -931,7 +931,7 @@ pub fn decodeLiteralsSectionSlice(...@@ -931,7 +931,7 @@ pub fn decodeLiteralsSectionSlice(
931) (error{ MalformedLiteralsHeader, MalformedLiteralsSection, EndOfStream } || huffman.Error)!LiteralsSection {931) (error{ MalformedLiteralsHeader, MalformedLiteralsSection, EndOfStream } || huffman.Error)!LiteralsSection {
932 var bytes_read: usize = 0;932 var bytes_read: usize = 0;
933 const header = header: {933 const header = header: {
934 var fbs = std.io.fixedBufferStream(src);934 var fbs: std.io.FixedBufferStream = .{ .buffer = src };
935 defer bytes_read = fbs.pos;935 defer bytes_read = fbs.pos;
936 break :header decodeLiteralsHeader(fbs.reader()) catch return error.MalformedLiteralsHeader;936 break :header decodeLiteralsHeader(fbs.reader()) catch return error.MalformedLiteralsHeader;
937 };937 };
lib/std/compress/zstandard/decode/huffman.zig+2-2
...@@ -41,7 +41,7 @@ fn decodeFseHuffmanTree(...@@ -41,7 +41,7 @@ fn decodeFseHuffmanTree(
4141
42fn decodeFseHuffmanTreeSlice(src: []const u8, compressed_size: usize, weights: *[256]u4) !usize {42fn decodeFseHuffmanTreeSlice(src: []const u8, compressed_size: usize, weights: *[256]u4) !usize {
43 if (src.len < compressed_size) return error.MalformedHuffmanTree;43 if (src.len < compressed_size) return error.MalformedHuffmanTree;
44 var stream = std.io.fixedBufferStream(src[0..compressed_size]);44 var stream: std.io.FixedBufferStream = .{ .buffer = src[0..compressed_size] };
45 var counting_reader = std.io.countingReader(stream.reader());45 var counting_reader = std.io.countingReader(stream.reader());
46 var bit_reader = readers.bitReader(counting_reader.reader());46 var bit_reader = readers.bitReader(counting_reader.reader());
4747
...@@ -213,7 +213,7 @@ pub fn decodeHuffmanTreeSlice(...@@ -213,7 +213,7 @@ pub fn decodeHuffmanTreeSlice(
213 bytes_read += header;213 bytes_read += header;
214 break :count try decodeFseHuffmanTreeSlice(src[1..], header, &weights);214 break :count try decodeFseHuffmanTreeSlice(src[1..], header, &weights);
215 } else count: {215 } else count: {
216 var fbs = std.io.fixedBufferStream(src[1..]);216 var fbs: std.io.FixedBufferStream = .{ .buffer = src[1..] };
217 defer bytes_read += fbs.pos;217 defer bytes_read += fbs.pos;
218 break :count try decodeDirectHuffmanTree(fbs.reader(), header - 127, &weights);218 break :count try decodeDirectHuffmanTree(fbs.reader(), header - 127, &weights);
219 };219 };
lib/std/compress/zstandard/decompress.zig+4-4
...@@ -186,7 +186,7 @@ pub fn decodeFrame(...@@ -186,7 +186,7 @@ pub fn decodeFrame(
186 DictionaryIdFlagUnsupported,186 DictionaryIdFlagUnsupported,
187 SkippableSizeTooLarge,187 SkippableSizeTooLarge,
188} || FrameError)!ReadWriteCount {188} || FrameError)!ReadWriteCount {
189 var fbs = std.io.fixedBufferStream(src);189 var fbs: std.io.FixedBufferStream = .{ .buffer = src };
190 switch (try decodeFrameType(fbs.reader())) {190 switch (try decodeFrameType(fbs.reader())) {
191 .zstandard => return decodeZstandardFrame(dest, src, verify_checksum),191 .zstandard => return decodeZstandardFrame(dest, src, verify_checksum),
192 .skippable => {192 .skippable => {
...@@ -233,7 +233,7 @@ pub fn decodeFrameArrayList(...@@ -233,7 +233,7 @@ pub fn decodeFrameArrayList(
233 verify_checksum: bool,233 verify_checksum: bool,
234 window_size_max: usize,234 window_size_max: usize,
235) (error{ BadMagic, OutOfMemory, SkippableSizeTooLarge } || FrameContext.Error || FrameError)!usize {235) (error{ BadMagic, OutOfMemory, SkippableSizeTooLarge } || FrameContext.Error || FrameError)!usize {
236 var fbs = std.io.fixedBufferStream(src);236 var fbs: std.io.FixedBufferStream = .{ .buffer = src };
237 const reader = fbs.reader();237 const reader = fbs.reader();
238 const magic = try reader.readInt(u32, .little);238 const magic = try reader.readInt(u32, .little);
239 switch (try frameType(magic)) {239 switch (try frameType(magic)) {
...@@ -303,7 +303,7 @@ pub fn decodeZstandardFrame(...@@ -303,7 +303,7 @@ pub fn decodeZstandardFrame(
303 var consumed_count: usize = 4;303 var consumed_count: usize = 4;
304304
305 var frame_context = context: {305 var frame_context = context: {
306 var fbs = std.io.fixedBufferStream(src[consumed_count..]);306 var fbs: std.io.FixedBufferStream = .{ .buffer = src[consumed_count..] };
307 const source = fbs.reader();307 const source = fbs.reader();
308 const frame_header = try decodeZstandardHeader(source);308 const frame_header = try decodeZstandardHeader(source);
309 consumed_count += fbs.pos;309 consumed_count += fbs.pos;
...@@ -446,7 +446,7 @@ pub fn decodeZstandardFrameArrayList(...@@ -446,7 +446,7 @@ pub fn decodeZstandardFrameArrayList(
446 var consumed_count: usize = 4;446 var consumed_count: usize = 4;
447447
448 var frame_context = context: {448 var frame_context = context: {
449 var fbs = std.io.fixedBufferStream(src[consumed_count..]);449 var fbs: std.io.FixedBufferStream = .{ .buffer = src[consumed_count..] };
450 const source = fbs.reader();450 const source = fbs.reader();
451 const frame_header = try decodeZstandardHeader(source);451 const frame_header = try decodeZstandardHeader(source);
452 consumed_count += fbs.pos;452 consumed_count += fbs.pos;
lib/std/debug.zig+26-30
...@@ -242,50 +242,44 @@ pub fn getSelfDebugInfo() !*SelfInfo {...@@ -242,50 +242,44 @@ pub fn getSelfDebugInfo() !*SelfInfo {
242/// Tries to print a hexadecimal view of the bytes, unbuffered, and ignores any error returned.242/// Tries to print a hexadecimal view of the bytes, unbuffered, and ignores any error returned.
243/// Obtains the stderr mutex while dumping.243/// Obtains the stderr mutex while dumping.
244pub fn dumpHex(bytes: []const u8) void {244pub fn dumpHex(bytes: []const u8) void {
245 lockStdErr();245 var bw = lockStdErr2();
246 defer unlockStdErr();246 defer unlockStdErr();
247 dumpHexFallible(bytes) catch {};247 const ttyconf = std.io.tty.detectConfig(std.io.getStdErr());
248}248 dumpHexFallible(&bw, ttyconf, bytes) catch {};
249
250/// Prints a hexadecimal view of the bytes, unbuffered, returning any error that occurs.
251pub fn dumpHexFallible(bytes: []const u8) !void {
252 const stderr = std.io.getStdErr();
253 const ttyconf = std.io.tty.detectConfig(stderr);
254 const writer = stderr.writer();
255 try dumpHexInternal(bytes, ttyconf, writer);
256}249}
257250
258fn dumpHexInternal(bytes: []const u8, ttyconf: std.io.tty.Config, writer: anytype) !void {251/// Prints a hexadecimal view of the bytes, returning any error that occurs.
252pub fn dumpHexFallible(bw: *std.io.BufferedWriter, ttyconf: std.io.tty.Config, bytes: []const u8) !void {
259 var chunks = mem.window(u8, bytes, 16, 16);253 var chunks = mem.window(u8, bytes, 16, 16);
260 while (chunks.next()) |window| {254 while (chunks.next()) |window| {
261 // 1. Print the address.255 // 1. Print the address.
262 const address = (@intFromPtr(bytes.ptr) + 0x10 * (std.math.divCeil(usize, chunks.index orelse bytes.len, 16) catch unreachable)) - 0x10;256 const address = (@intFromPtr(bytes.ptr) + 0x10 * (std.math.divCeil(usize, chunks.index orelse bytes.len, 16) catch unreachable)) - 0x10;
263 try ttyconf.setColor(writer, .dim);257 try ttyconf.setColor(bw, .dim);
264 // We print the address in lowercase and the bytes in uppercase hexadecimal to distinguish them more.258 // We print the address in lowercase and the bytes in uppercase hexadecimal to distinguish them more.
265 // Also, make sure all lines are aligned by padding the address.259 // Also, make sure all lines are aligned by padding the address.
266 try writer.print("{x:0>[1]} ", .{ address, @sizeOf(usize) * 2 });260 try bw.print("{x:0>[1]} ", .{ address, @sizeOf(usize) * 2 });
267 try ttyconf.setColor(writer, .reset);261 try ttyconf.setColor(bw, .reset);
268262
269 // 2. Print the bytes.263 // 2. Print the bytes.
270 for (window, 0..) |byte, index| {264 for (window, 0..) |byte, index| {
271 try writer.print("{X:0>2} ", .{byte});265 try bw.print("{X:0>2} ", .{byte});
272 if (index == 7) try writer.writeByte(' ');266 if (index == 7) try bw.writeByte(' ');
273 }267 }
274 try writer.writeByte(' ');268 try bw.writeByte(' ');
275 if (window.len < 16) {269 if (window.len < 16) {
276 var missing_columns = (16 - window.len) * 3;270 var missing_columns = (16 - window.len) * 3;
277 if (window.len < 8) missing_columns += 1;271 if (window.len < 8) missing_columns += 1;
278 try writer.splatByteAll(' ', missing_columns);272 try bw.splatByteAll(' ', missing_columns);
279 }273 }
280274
281 // 3. Print the characters.275 // 3. Print the characters.
282 for (window) |byte| {276 for (window) |byte| {
283 if (std.ascii.isPrint(byte)) {277 if (std.ascii.isPrint(byte)) {
284 try writer.writeByte(byte);278 try bw.writeByte(byte);
285 } else {279 } else {
286 // Related: https://github.com/ziglang/zig/issues/7600280 // Related: https://github.com/ziglang/zig/issues/7600
287 if (ttyconf == .windows_api) {281 if (ttyconf == .windows_api) {
288 try writer.writeByte('.');282 try bw.writeByte('.');
289 continue;283 continue;
290 }284 }
291285
...@@ -293,22 +287,24 @@ fn dumpHexInternal(bytes: []const u8, ttyconf: std.io.tty.Config, writer: anytyp...@@ -293,22 +287,24 @@ fn dumpHexInternal(bytes: []const u8, ttyconf: std.io.tty.Config, writer: anytyp
293 // We don't want to do this for all control codes because most control codes apart from287 // We don't want to do this for all control codes because most control codes apart from
294 // the ones that Zig has escape sequences for are likely not very useful to print as symbols.288 // the ones that Zig has escape sequences for are likely not very useful to print as symbols.
295 switch (byte) {289 switch (byte) {
296 '\n' => try writer.writeAll("␊"),290 '\n' => try bw.writeAll("␊"),
297 '\r' => try writer.writeAll("␍"),291 '\r' => try bw.writeAll("␍"),
298 '\t' => try writer.writeAll("␉"),292 '\t' => try bw.writeAll("␉"),
299 else => try writer.writeByte('.'),293 else => try bw.writeByte('.'),
300 }294 }
301 }295 }
302 }296 }
303 try writer.writeByte('\n');297 try bw.writeByte('\n');
304 }298 }
305}299}
306300
307test dumpHexInternal {301test dumpHexFallible {
308 const bytes: []const u8 = &.{ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x01, 0x12, 0x13 };302 const bytes: []const u8 = &.{ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x01, 0x12, 0x13 };
309 var output = std.ArrayList(u8).init(std.testing.allocator);303 var aw: std.io.AllocatingWriter = undefined;
310 defer output.deinit();304 defer aw.deinit();
311 try dumpHexInternal(bytes, .no_color, output.writer());305 var bw = aw.init(std.testing.allocator);
306
307 try dumpHexFallible(&bw, .no_color, bytes);
312 const expected = try std.fmt.allocPrint(std.testing.allocator,308 const expected = try std.fmt.allocPrint(std.testing.allocator,
313 \\{x:0>[2]} 00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF .."3DUfw........309 \\{x:0>[2]} 00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF .."3DUfw........
314 \\{x:0>[2]} 01 12 13 ...310 \\{x:0>[2]} 01 12 13 ...
...@@ -319,7 +315,7 @@ test dumpHexInternal {...@@ -319,7 +315,7 @@ test dumpHexInternal {
319 @sizeOf(usize) * 2,315 @sizeOf(usize) * 2,
320 });316 });
321 defer std.testing.allocator.free(expected);317 defer std.testing.allocator.free(expected);
322 try std.testing.expectEqualStrings(expected, output.items);318 try std.testing.expectEqualStrings(expected, aw.getWritten());
323}319}
324320
325/// Tries to print the current stack trace to stderr, unbuffered, and ignores any error returned.321/// Tries to print the current stack trace to stderr, unbuffered, and ignores any error returned.
lib/std/fs/File.zig+5
...@@ -1496,6 +1496,11 @@ pub fn writeFileAll(self: File, in_file: File, args: WriteFileOptions) WriteFile...@@ -1496,6 +1496,11 @@ pub fn writeFileAll(self: File, in_file: File, args: WriteFileOptions) WriteFile
1496/// Does not try seeking in either of the File parameters.1496/// Does not try seeking in either of the File parameters.
1497/// See `writeFileAll` as an alternative to calling this.1497/// See `writeFileAll` as an alternative to calling this.
1498pub fn writeFileAllUnseekable(self: File, in_file: File, args: WriteFileOptions) WriteFileError!void {1498pub fn writeFileAllUnseekable(self: File, in_file: File, args: WriteFileOptions) WriteFileError!void {
1499 // TODO make `try @errorCast(...)` work
1500 return @errorCast(writeFileAllUnseekableInner(self, in_file, args));
1501}
1502
1503fn writeFileAllUnseekableInner(self: File, in_file: File, args: WriteFileOptions) anyerror!void {
1499 const headers = args.headers_and_trailers[0..args.header_count];1504 const headers = args.headers_and_trailers[0..args.header_count];
1500 const trailers = args.headers_and_trailers[args.header_count..];1505 const trailers = args.headers_and_trailers[args.header_count..];
15011506
lib/std/http/Client.zig+10-14
...@@ -1283,26 +1283,22 @@ pub const basic_authorization = struct {...@@ -1283,26 +1283,22 @@ pub const basic_authorization = struct {
1283 }1283 }
12841284
1285 pub fn valueLengthFromUri(uri: Uri) usize {1285 pub fn valueLengthFromUri(uri: Uri) usize {
1286 var stream = std.io.countingWriter(std.io.null_writer);1286 // TODO don't abuse formatted printing to count percent encoded characters
1287 try stream.writer().print("{user}", .{uri.user orelse Uri.Component.empty});1287 const user_len = std.fmt.count("{fuser}", .{uri.user orelse Uri.Component.empty});
1288 const user_len = stream.bytes_written;1288 const password_len = std.fmt.count("{fpassword}", .{uri.password orelse Uri.Component.empty});
1289 stream.bytes_written = 0;
1290 try stream.writer().print("{password}", .{uri.password orelse Uri.Component.empty});
1291 const password_len = stream.bytes_written;
1292 return valueLength(@intCast(user_len), @intCast(password_len));1289 return valueLength(@intCast(user_len), @intCast(password_len));
1293 }1290 }
12941291
1295 pub fn value(uri: Uri, out: []u8) []u8 {1292 pub fn value(uri: Uri, out: []u8) []u8 {
1296 var buf: [max_user_len + ":".len + max_password_len]u8 = undefined;1293 var buf: [max_user_len + ":".len + max_password_len]u8 = undefined;
1297 var stream = std.io.fixedBufferStream(&buf);1294 var bw: std.io.BufferedWriter = undefined;
1298 stream.writer().print("{user}", .{uri.user orelse Uri.Component.empty}) catch1295 bw.initFixed(&buf);
1299 unreachable;1296 bw.print("{fuser}:{fpassword}", .{
1300 assert(stream.pos <= max_user_len);1297 uri.user orelse Uri.Component.empty,
1301 stream.writer().print(":{password}", .{uri.password orelse Uri.Component.empty}) catch1298 uri.password orelse Uri.Component.empty,
1302 unreachable;1299 }) catch unreachable;
1303
1304 @memcpy(out[0..prefix.len], prefix);1300 @memcpy(out[0..prefix.len], prefix);
1305 const base64 = std.base64.standard.Encoder.encode(out[prefix.len..], stream.getWritten());1301 const base64 = std.base64.standard.Encoder.encode(out[prefix.len..], bw.getWritten());
1306 return out[0 .. prefix.len + base64.len];1302 return out[0 .. prefix.len + base64.len];
1307 }1303 }
1308};1304};
lib/std/io/AllocatingWriter.zig+18-1
...@@ -1,4 +1,3 @@...@@ -1,4 +1,3 @@
1//! TODO rename to AllocatingWriter.
2//! While it is possible to use `std.ArrayList` as the underlying writer when1//! While it is possible to use `std.ArrayList` as the underlying writer when
3//! using `std.io.BufferedWriter` by populating the `std.io.Writer` interface2//! using `std.io.BufferedWriter` by populating the `std.io.Writer` interface
4//! and then using an empty buffer, it means that every use of3//! and then using an empty buffer, it means that every use of
...@@ -41,6 +40,12 @@ pub fn init(aw: *AllocatingWriter, allocator: std.mem.Allocator) *std.io.Buffere...@@ -41,6 +40,12 @@ pub fn init(aw: *AllocatingWriter, allocator: std.mem.Allocator) *std.io.Buffere
41 return &aw.buffered_writer;40 return &aw.buffered_writer;
42}41}
4342
43pub fn deinit(aw: *AllocatingWriter) void {
44 const written = aw.written;
45 aw.allocator.free(written.ptr[0 .. written.len + aw.buffered_writer.buffer.len]);
46 aw.* = undefined;
47}
48
44/// Replaces `array_list` with empty, taking ownership of the memory.49/// Replaces `array_list` with empty, taking ownership of the memory.
45pub fn fromArrayList(50pub fn fromArrayList(
46 aw: *AllocatingWriter,51 aw: *AllocatingWriter,
...@@ -184,3 +189,15 @@ fn writeFile(...@@ -184,3 +189,15 @@ fn writeFile(
184 for (trailers) |bytes| list.appendSliceAssumeCapacity(bytes);189 for (trailers) |bytes| list.appendSliceAssumeCapacity(bytes);
185 return list.items.len - start_len;190 return list.items.len - start_len;
186}191}
192
193test AllocatingWriter {
194 var aw: AllocatingWriter = undefined;
195 const bw = aw.init(std.testing.allocator);
196 defer aw.deinit();
197
198 const x: i32 = 42;
199 const y: i32 = 1234;
200 try bw.print("x: {}\ny: {}\n", .{ x, y });
201
202 try std.testing.expectEqualSlices(u8, "x: 42\ny: 1234\n", aw.getWritten());
203}
lib/std/io/CountingWriter.zig+3
...@@ -1,3 +1,6 @@...@@ -1,3 +1,6 @@
1//! TODO make this more like AllocatingWriter, managing the state of
2//! BufferedWriter both as the output and the input, but with only
3//! one buffer.
1const std = @import("../std.zig");4const std = @import("../std.zig");
2const CountingWriter = @This();5const CountingWriter = @This();
3const assert = std.debug.assert;6const assert = std.debug.assert;
lib/std/testing.zig+26-25
...@@ -390,8 +390,9 @@ pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const...@@ -390,8 +390,9 @@ pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const
390 const actual_window = actual[window_start..@min(actual.len, window_start + max_window_size)];390 const actual_window = actual[window_start..@min(actual.len, window_start + max_window_size)];
391 const actual_truncated = window_start + actual_window.len < actual.len;391 const actual_truncated = window_start + actual_window.len < actual.len;
392392
393 const stderr = std.io.getStdErr();393 var bw = std.debug.lockStdErr2();
394 const ttyconf = std.io.tty.detectConfig(stderr);394 defer std.debug.unlockStdErr();
395 const ttyconf = std.io.tty.detectConfig(std.io.getStdErr());
395 var differ = if (T == u8) BytesDiffer{396 var differ = if (T == u8) BytesDiffer{
396 .expected = expected_window,397 .expected = expected_window,
397 .actual = actual_window,398 .actual = actual_window,
...@@ -415,7 +416,7 @@ pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const...@@ -415,7 +416,7 @@ pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const
415 print("... truncated ...\n", .{});416 print("... truncated ...\n", .{});
416 }417 }
417 }418 }
418 differ.write(stderr.writer()) catch {};419 differ.write(&bw) catch {};
419 if (expected_truncated) {420 if (expected_truncated) {
420 const end_offset = window_start + expected_window.len;421 const end_offset = window_start + expected_window.len;
421 const num_missing_items = expected.len - (window_start + expected_window.len);422 const num_missing_items = expected.len - (window_start + expected_window.len);
...@@ -437,7 +438,7 @@ pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const...@@ -437,7 +438,7 @@ pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const
437 print("... truncated ...\n", .{});438 print("... truncated ...\n", .{});
438 }439 }
439 }440 }
440 differ.write(stderr.writer()) catch {};441 differ.write(&bw) catch {};
441 if (actual_truncated) {442 if (actual_truncated) {
442 const end_offset = window_start + actual_window.len;443 const end_offset = window_start + actual_window.len;
443 const num_missing_items = actual.len - (window_start + actual_window.len);444 const num_missing_items = actual.len - (window_start + actual_window.len);
...@@ -461,17 +462,17 @@ fn SliceDiffer(comptime T: type) type {...@@ -461,17 +462,17 @@ fn SliceDiffer(comptime T: type) type {
461462
462 const Self = @This();463 const Self = @This();
463464
464 pub fn write(self: Self, writer: anytype) !void {465 pub fn write(self: Self, bw: *std.io.BufferedWriter) !void {
465 for (self.expected, 0..) |value, i| {466 for (self.expected, 0..) |value, i| {
466 const full_index = self.start_index + i;467 const full_index = self.start_index + i;
467 const diff = if (i < self.actual.len) !std.meta.eql(self.actual[i], value) else true;468 const diff = if (i < self.actual.len) !std.meta.eql(self.actual[i], value) else true;
468 if (diff) try self.ttyconf.setColor(writer, .red);469 if (diff) try self.ttyconf.setColor(bw, .red);
469 if (@typeInfo(T) == .pointer) {470 if (@typeInfo(T) == .pointer) {
470 try writer.print("[{}]{*}: {any}\n", .{ full_index, value, value });471 try bw.print("[{}]{*}: {any}\n", .{ full_index, value, value });
471 } else {472 } else {
472 try writer.print("[{}]: {any}\n", .{ full_index, value });473 try bw.print("[{}]: {any}\n", .{ full_index, value });
473 }474 }
474 if (diff) try self.ttyconf.setColor(writer, .reset);475 if (diff) try self.ttyconf.setColor(bw, .reset);
475 }476 }
476 }477 }
477 };478 };
...@@ -482,7 +483,7 @@ const BytesDiffer = struct {...@@ -482,7 +483,7 @@ const BytesDiffer = struct {
482 actual: []const u8,483 actual: []const u8,
483 ttyconf: std.io.tty.Config,484 ttyconf: std.io.tty.Config,
484485
485 pub fn write(self: BytesDiffer, writer: anytype) !void {486 pub fn write(self: BytesDiffer, bw: *std.io.BufferedWriter) !void {
486 var expected_iterator = std.mem.window(u8, self.expected, 16, 16);487 var expected_iterator = std.mem.window(u8, self.expected, 16, 16);
487 var row: usize = 0;488 var row: usize = 0;
488 while (expected_iterator.next()) |chunk| {489 while (expected_iterator.next()) |chunk| {
...@@ -492,23 +493,23 @@ const BytesDiffer = struct {...@@ -492,23 +493,23 @@ const BytesDiffer = struct {
492 const absolute_byte_index = col + row * 16;493 const absolute_byte_index = col + row * 16;
493 const diff = if (absolute_byte_index < self.actual.len) self.actual[absolute_byte_index] != byte else true;494 const diff = if (absolute_byte_index < self.actual.len) self.actual[absolute_byte_index] != byte else true;
494 if (diff) diffs.set(col);495 if (diff) diffs.set(col);
495 try self.writeDiff(writer, "{X:0>2} ", .{byte}, diff);496 try self.writeDiff(bw, "{X:0>2} ", .{byte}, diff);
496 if (col == 7) try writer.writeByte(' ');497 if (col == 7) try bw.writeByte(' ');
497 }498 }
498 try writer.writeByte(' ');499 try bw.writeByte(' ');
499 if (chunk.len < 16) {500 if (chunk.len < 16) {
500 var missing_columns = (16 - chunk.len) * 3;501 var missing_columns = (16 - chunk.len) * 3;
501 if (chunk.len < 8) missing_columns += 1;502 if (chunk.len < 8) missing_columns += 1;
502 try writer.writeByteNTimes(' ', missing_columns);503 try bw.splatByteAll(' ', missing_columns);
503 }504 }
504 for (chunk, 0..) |byte, col| {505 for (chunk, 0..) |byte, col| {
505 const diff = diffs.isSet(col);506 const diff = diffs.isSet(col);
506 if (std.ascii.isPrint(byte)) {507 if (std.ascii.isPrint(byte)) {
507 try self.writeDiff(writer, "{c}", .{byte}, diff);508 try self.writeDiff(bw, "{c}", .{byte}, diff);
508 } else {509 } else {
509 // TODO: remove this `if` when https://github.com/ziglang/zig/issues/7600 is fixed510 // TODO: remove this `if` when https://github.com/ziglang/zig/issues/7600 is fixed
510 if (self.ttyconf == .windows_api) {511 if (self.ttyconf == .windows_api) {
511 try self.writeDiff(writer, ".", .{}, diff);512 try self.writeDiff(bw, ".", .{}, diff);
512 continue;513 continue;
513 }514 }
514515
...@@ -516,22 +517,22 @@ const BytesDiffer = struct {...@@ -516,22 +517,22 @@ const BytesDiffer = struct {
516 // We don't want to do this for all control codes because most control codes apart from517 // We don't want to do this for all control codes because most control codes apart from
517 // the ones that Zig has escape sequences for are likely not very useful to print as symbols.518 // the ones that Zig has escape sequences for are likely not very useful to print as symbols.
518 switch (byte) {519 switch (byte) {
519 '\n' => try self.writeDiff(writer, "␊", .{}, diff),520 '\n' => try self.writeDiff(bw, "␊", .{}, diff),
520 '\r' => try self.writeDiff(writer, "␍", .{}, diff),521 '\r' => try self.writeDiff(bw, "␍", .{}, diff),
521 '\t' => try self.writeDiff(writer, "␉", .{}, diff),522 '\t' => try self.writeDiff(bw, "␉", .{}, diff),
522 else => try self.writeDiff(writer, ".", .{}, diff),523 else => try self.writeDiff(bw, ".", .{}, diff),
523 }524 }
524 }525 }
525 }526 }
526 try writer.writeByte('\n');527 try bw.writeByte('\n');
527 row += 1;528 row += 1;
528 }529 }
529 }530 }
530531
531 fn writeDiff(self: BytesDiffer, writer: anytype, comptime fmt: []const u8, args: anytype, diff: bool) !void {532 fn writeDiff(self: BytesDiffer, bw: *std.io.BufferedWriter, comptime fmt: []const u8, args: anytype, diff: bool) !void {
532 if (diff) try self.ttyconf.setColor(writer, .red);533 if (diff) try self.ttyconf.setColor(bw, .red);
533 try writer.print(fmt, args);534 try bw.print(fmt, args);
534 if (diff) try self.ttyconf.setColor(writer, .reset);535 if (diff) try self.ttyconf.setColor(bw, .reset);
535 }536 }
536};537};
537538
lib/std/zig/ErrorBundle.zig+70-63
...@@ -159,21 +159,26 @@ pub const RenderOptions = struct {...@@ -159,21 +159,26 @@ pub const RenderOptions = struct {
159pub fn renderToStdErr(eb: ErrorBundle, options: RenderOptions) void {159pub fn renderToStdErr(eb: ErrorBundle, options: RenderOptions) void {
160 std.debug.lockStdErr();160 std.debug.lockStdErr();
161 defer std.debug.unlockStdErr();161 defer std.debug.unlockStdErr();
162 const stderr = std.io.getStdErr();162 var buffer: [256]u8 = undefined;
163 return renderToWriter(eb, options, stderr.writer()) catch return;163 var bw: std.io.BufferedWriter = .{
164 .unbuffered_writer = std.io.getStdErr().writer(),
165 .buffer = &buffer,
166 };
167 renderToWriter(eb, options, &bw) catch return;
168 bw.flush() catch return;
164}169}
165170
166pub fn renderToWriter(eb: ErrorBundle, options: RenderOptions, writer: anytype) anyerror!void {171pub fn renderToWriter(eb: ErrorBundle, options: RenderOptions, bw: *std.io.BufferedWriter) anyerror!void {
167 if (eb.extra.len == 0) return;172 if (eb.extra.len == 0) return;
168 for (eb.getMessages()) |err_msg| {173 for (eb.getMessages()) |err_msg| {
169 try renderErrorMessageToWriter(eb, options, err_msg, writer, "error", .red, 0);174 try renderErrorMessageToWriter(eb, options, err_msg, bw, "error", .red, 0);
170 }175 }
171176
172 if (options.include_log_text) {177 if (options.include_log_text) {
173 const log_text = eb.getCompileLogOutput();178 const log_text = eb.getCompileLogOutput();
174 if (log_text.len != 0) {179 if (log_text.len != 0) {
175 try writer.writeAll("\nCompile Log Output:\n");180 try bw.writeAll("\nCompile Log Output:\n");
176 try writer.writeAll(log_text);181 try bw.writeAll(log_text);
177 }182 }
178 }183 }
179}184}
...@@ -182,74 +187,74 @@ fn renderErrorMessageToWriter(...@@ -182,74 +187,74 @@ fn renderErrorMessageToWriter(
182 eb: ErrorBundle,187 eb: ErrorBundle,
183 options: RenderOptions,188 options: RenderOptions,
184 err_msg_index: MessageIndex,189 err_msg_index: MessageIndex,
185 stderr: anytype,190 bw: *std.io.BufferedWriter,
186 kind: []const u8,191 kind: []const u8,
187 color: std.io.tty.Color,192 color: std.io.tty.Color,
188 indent: usize,193 indent: usize,
189) anyerror!void {194) anyerror!void {
190 const ttyconf = options.ttyconf;195 const ttyconf = options.ttyconf;
191 var counting_writer = std.io.countingWriter(stderr);196 var counting_writer: std.io.CountingWriter = .{ .child_writer = bw.writer() };
192 const counting_stderr = counting_writer.writer();197 const counting_bw = counting_writer.unbufferedWriter();
193 const err_msg = eb.getErrorMessage(err_msg_index);198 const err_msg = eb.getErrorMessage(err_msg_index);
194 if (err_msg.src_loc != .none) {199 if (err_msg.src_loc != .none) {
195 const src = eb.extraData(SourceLocation, @intFromEnum(err_msg.src_loc));200 const src = eb.extraData(SourceLocation, @intFromEnum(err_msg.src_loc));
196 try counting_stderr.writeByteNTimes(' ', indent);201 try counting_bw.writeByteNTimes(' ', indent);
197 try ttyconf.setColor(stderr, .bold);202 try ttyconf.setColor(bw, .bold);
198 try counting_stderr.print("{s}:{d}:{d}: ", .{203 try counting_bw.print("{s}:{d}:{d}: ", .{
199 eb.nullTerminatedString(src.data.src_path),204 eb.nullTerminatedString(src.data.src_path),
200 src.data.line + 1,205 src.data.line + 1,
201 src.data.column + 1,206 src.data.column + 1,
202 });207 });
203 try ttyconf.setColor(stderr, color);208 try ttyconf.setColor(bw, color);
204 try counting_stderr.writeAll(kind);209 try counting_bw.writeAll(kind);
205 try counting_stderr.writeAll(": ");210 try counting_bw.writeAll(": ");
206 // This is the length of the part before the error message:211 // This is the length of the part before the error message:
207 // e.g. "file.zig:4:5: error: "212 // e.g. "file.zig:4:5: error: "
208 const prefix_len: usize = @intCast(counting_stderr.context.bytes_written);213 const prefix_len: usize = @intCast(counting_bw.context.bytes_written);
209 try ttyconf.setColor(stderr, .reset);214 try ttyconf.setColor(bw, .reset);
210 try ttyconf.setColor(stderr, .bold);215 try ttyconf.setColor(bw, .bold);
211 if (err_msg.count == 1) {216 if (err_msg.count == 1) {
212 try writeMsg(eb, err_msg, stderr, prefix_len);217 try writeMsg(eb, err_msg, bw, prefix_len);
213 try stderr.writeByte('\n');218 try bw.writeByte('\n');
214 } else {219 } else {
215 try writeMsg(eb, err_msg, stderr, prefix_len);220 try writeMsg(eb, err_msg, bw, prefix_len);
216 try ttyconf.setColor(stderr, .dim);221 try ttyconf.setColor(bw, .dim);
217 try stderr.print(" ({d} times)\n", .{err_msg.count});222 try bw.print(" ({d} times)\n", .{err_msg.count});
218 }223 }
219 try ttyconf.setColor(stderr, .reset);224 try ttyconf.setColor(bw, .reset);
220 if (src.data.source_line != 0 and options.include_source_line) {225 if (src.data.source_line != 0 and options.include_source_line) {
221 const line = eb.nullTerminatedString(src.data.source_line);226 const line = eb.nullTerminatedString(src.data.source_line);
222 for (line) |b| switch (b) {227 for (line) |b| switch (b) {
223 '\t' => try stderr.writeByte(' '),228 '\t' => try bw.writeByte(' '),
224 else => try stderr.writeByte(b),229 else => try bw.writeByte(b),
225 };230 };
226 try stderr.writeByte('\n');231 try bw.writeByte('\n');
227 // TODO basic unicode code point monospace width232 // TODO basic unicode code point monospace width
228 const before_caret = src.data.span_main - src.data.span_start;233 const before_caret = src.data.span_main - src.data.span_start;
229 // -1 since span.main includes the caret234 // -1 since span.main includes the caret
230 const after_caret = src.data.span_end -| src.data.span_main -| 1;235 const after_caret = src.data.span_end -| src.data.span_main -| 1;
231 try stderr.writeByteNTimes(' ', src.data.column - before_caret);236 try bw.writeByteNTimes(' ', src.data.column - before_caret);
232 try ttyconf.setColor(stderr, .green);237 try ttyconf.setColor(bw, .green);
233 try stderr.writeByteNTimes('~', before_caret);238 try bw.writeByteNTimes('~', before_caret);
234 try stderr.writeByte('^');239 try bw.writeByte('^');
235 try stderr.writeByteNTimes('~', after_caret);240 try bw.writeByteNTimes('~', after_caret);
236 try stderr.writeByte('\n');241 try bw.writeByte('\n');
237 try ttyconf.setColor(stderr, .reset);242 try ttyconf.setColor(bw, .reset);
238 }243 }
239 for (eb.getNotes(err_msg_index)) |note| {244 for (eb.getNotes(err_msg_index)) |note| {
240 try renderErrorMessageToWriter(eb, options, note, stderr, "note", .cyan, indent);245 try renderErrorMessageToWriter(eb, options, note, bw, "note", .cyan, indent);
241 }246 }
242 if (src.data.reference_trace_len > 0 and options.include_reference_trace) {247 if (src.data.reference_trace_len > 0 and options.include_reference_trace) {
243 try ttyconf.setColor(stderr, .reset);248 try ttyconf.setColor(bw, .reset);
244 try ttyconf.setColor(stderr, .dim);249 try ttyconf.setColor(bw, .dim);
245 try stderr.print("referenced by:\n", .{});250 try bw.print("referenced by:\n", .{});
246 var ref_index = src.end;251 var ref_index = src.end;
247 for (0..src.data.reference_trace_len) |_| {252 for (0..src.data.reference_trace_len) |_| {
248 const ref_trace = eb.extraData(ReferenceTrace, ref_index);253 const ref_trace = eb.extraData(ReferenceTrace, ref_index);
249 ref_index = ref_trace.end;254 ref_index = ref_trace.end;
250 if (ref_trace.data.src_loc != .none) {255 if (ref_trace.data.src_loc != .none) {
251 const ref_src = eb.getSourceLocation(ref_trace.data.src_loc);256 const ref_src = eb.getSourceLocation(ref_trace.data.src_loc);
252 try stderr.print(" {s}: {s}:{d}:{d}\n", .{257 try bw.print(" {s}: {s}:{d}:{d}\n", .{
253 eb.nullTerminatedString(ref_trace.data.decl_name),258 eb.nullTerminatedString(ref_trace.data.decl_name),
254 eb.nullTerminatedString(ref_src.src_path),259 eb.nullTerminatedString(ref_src.src_path),
255 ref_src.line + 1,260 ref_src.line + 1,
...@@ -257,36 +262,36 @@ fn renderErrorMessageToWriter(...@@ -257,36 +262,36 @@ fn renderErrorMessageToWriter(
257 });262 });
258 } else if (ref_trace.data.decl_name != 0) {263 } else if (ref_trace.data.decl_name != 0) {
259 const count = ref_trace.data.decl_name;264 const count = ref_trace.data.decl_name;
260 try stderr.print(265 try bw.print(
261 " {d} reference(s) hidden; use '-freference-trace={d}' to see all references\n",266 " {d} reference(s) hidden; use '-freference-trace={d}' to see all references\n",
262 .{ count, count + src.data.reference_trace_len - 1 },267 .{ count, count + src.data.reference_trace_len - 1 },
263 );268 );
264 } else {269 } else {
265 try stderr.print(270 try bw.print(
266 " remaining reference traces hidden; use '-freference-trace' to see all reference traces\n",271 " remaining reference traces hidden; use '-freference-trace' to see all reference traces\n",
267 .{},272 .{},
268 );273 );
269 }274 }
270 }275 }
271 try ttyconf.setColor(stderr, .reset);276 try ttyconf.setColor(bw, .reset);
272 }277 }
273 } else {278 } else {
274 try ttyconf.setColor(stderr, color);279 try ttyconf.setColor(bw, color);
275 try stderr.writeByteNTimes(' ', indent);280 try bw.writeByteNTimes(' ', indent);
276 try stderr.writeAll(kind);281 try bw.writeAll(kind);
277 try stderr.writeAll(": ");282 try bw.writeAll(": ");
278 try ttyconf.setColor(stderr, .reset);283 try ttyconf.setColor(bw, .reset);
279 const msg = eb.nullTerminatedString(err_msg.msg);284 const msg = eb.nullTerminatedString(err_msg.msg);
280 if (err_msg.count == 1) {285 if (err_msg.count == 1) {
281 try stderr.print("{s}\n", .{msg});286 try bw.print("{s}\n", .{msg});
282 } else {287 } else {
283 try stderr.print("{s}", .{msg});288 try bw.print("{s}", .{msg});
284 try ttyconf.setColor(stderr, .dim);289 try ttyconf.setColor(bw, .dim);
285 try stderr.print(" ({d} times)\n", .{err_msg.count});290 try bw.print(" ({d} times)\n", .{err_msg.count});
286 }291 }
287 try ttyconf.setColor(stderr, .reset);292 try ttyconf.setColor(bw, .reset);
288 for (eb.getNotes(err_msg_index)) |note| {293 for (eb.getNotes(err_msg_index)) |note| {
289 try renderErrorMessageToWriter(eb, options, note, stderr, "note", .cyan, indent + 4);294 try renderErrorMessageToWriter(eb, options, note, bw, "note", .cyan, indent + 4);
290 }295 }
291 }296 }
292}297}
...@@ -295,13 +300,13 @@ fn renderErrorMessageToWriter(...@@ -295,13 +300,13 @@ fn renderErrorMessageToWriter(
295/// to allow for long, good-looking error messages.300/// to allow for long, good-looking error messages.
296///301///
297/// This is used to split the message in `@compileError("hello\nworld")` for example.302/// This is used to split the message in `@compileError("hello\nworld")` for example.
298fn writeMsg(eb: ErrorBundle, err_msg: ErrorMessage, stderr: anytype, indent: usize) !void {303fn writeMsg(eb: ErrorBundle, err_msg: ErrorMessage, bw: *std.io.BufferedWriter, indent: usize) !void {
299 var lines = std.mem.splitScalar(u8, eb.nullTerminatedString(err_msg.msg), '\n');304 var lines = std.mem.splitScalar(u8, eb.nullTerminatedString(err_msg.msg), '\n');
300 while (lines.next()) |line| {305 while (lines.next()) |line| {
301 try stderr.writeAll(line);306 try bw.writeAll(line);
302 if (lines.index == null) break;307 if (lines.index == null) break;
303 try stderr.writeByte('\n');308 try bw.writeByte('\n');
304 try stderr.writeByteNTimes(' ', indent);309 try bw.writeByteNTimes(' ', indent);
305 }310 }
306}311}
307312
...@@ -398,7 +403,7 @@ pub const Wip = struct {...@@ -398,7 +403,7 @@ pub const Wip = struct {
398 pub fn printString(wip: *Wip, comptime fmt: []const u8, args: anytype) Allocator.Error!String {403 pub fn printString(wip: *Wip, comptime fmt: []const u8, args: anytype) Allocator.Error!String {
399 const gpa = wip.gpa;404 const gpa = wip.gpa;
400 const index: String = @intCast(wip.string_bytes.items.len);405 const index: String = @intCast(wip.string_bytes.items.len);
401 try wip.string_bytes.writer(gpa).print(fmt, args);406 try wip.string_bytes.print(gpa, fmt, args);
402 try wip.string_bytes.append(gpa, 0);407 try wip.string_bytes.append(gpa, 0);
403 return index;408 return index;
404 }409 }
...@@ -788,9 +793,10 @@ pub const Wip = struct {...@@ -788,9 +793,10 @@ pub const Wip = struct {
788793
789 const ttyconf: std.io.tty.Config = .no_color;794 const ttyconf: std.io.tty.Config = .no_color;
790795
791 var bundle_buf = std.ArrayList(u8).init(std.testing.allocator);796 var bundle_buf: std.io.AllocatingWriter = undefined;
797 const bundle_bw = bundle_buf.init(std.testing.allocator);
792 defer bundle_buf.deinit();798 defer bundle_buf.deinit();
793 try bundle.renderToWriter(.{ .ttyconf = ttyconf }, bundle_buf.writer());799 try bundle.renderToWriter(.{ .ttyconf = ttyconf }, bundle_bw);
794800
795 var copy = copy: {801 var copy = copy: {
796 var wip: ErrorBundle.Wip = undefined;802 var wip: ErrorBundle.Wip = undefined;
...@@ -803,10 +809,11 @@ pub const Wip = struct {...@@ -803,10 +809,11 @@ pub const Wip = struct {
803 };809 };
804 defer copy.deinit(std.testing.allocator);810 defer copy.deinit(std.testing.allocator);
805811
806 var copy_buf = std.ArrayList(u8).init(std.testing.allocator);812 var copy_buf: std.io.AllocatingWriter = undefined;
813 const copy_bw = copy_buf.init(std.testing.allocator);
807 defer copy_buf.deinit();814 defer copy_buf.deinit();
808 try copy.renderToWriter(.{ .ttyconf = ttyconf }, copy_buf.writer());815 try copy.renderToWriter(.{ .ttyconf = ttyconf }, copy_bw);
809816
810 try std.testing.expectEqualStrings(bundle_buf.items, copy_buf.items);817 try std.testing.expectEqualStrings(bundle_bw.getWritten(), copy_bw.getWritten());
811 }818 }
812};819};