mirror of
https://github.com/ziglang/zig.git
synced 2025-12-24 07:03:11 +00:00
std ArrayList unit tests passing
This commit is contained in:
parent
221b194f28
commit
fced9467e8
@ -1242,7 +1242,7 @@ const MachODumper = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parseRebaseInfo(ctx: ObjectContext, data: []const u8, rebases: *std.ArrayList(u64)) !void {
|
fn parseRebaseInfo(ctx: ObjectContext, data: []const u8, rebases: *std.ArrayList(u64)) !void {
|
||||||
var stream = std.io.fixedBufferStream(data);
|
var stream: std.io.FixedBufferStream = .{ .buffer = data };
|
||||||
var creader = std.io.countingReader(stream.reader());
|
var creader = std.io.countingReader(stream.reader());
|
||||||
const reader = creader.reader();
|
const reader = creader.reader();
|
||||||
|
|
||||||
@ -1354,7 +1354,7 @@ const MachODumper = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parseBindInfo(ctx: ObjectContext, data: []const u8, bindings: *std.ArrayList(Binding)) !void {
|
fn parseBindInfo(ctx: ObjectContext, data: []const u8, bindings: *std.ArrayList(Binding)) !void {
|
||||||
var stream = std.io.fixedBufferStream(data);
|
var stream: std.io.FixedBufferStream = .{ .buffer = data };
|
||||||
var creader = std.io.countingReader(stream.reader());
|
var creader = std.io.countingReader(stream.reader());
|
||||||
const reader = creader.reader();
|
const reader = creader.reader();
|
||||||
|
|
||||||
@ -1487,8 +1487,8 @@ const MachODumper = struct {
|
|||||||
data: []const u8,
|
data: []const u8,
|
||||||
pos: usize = 0,
|
pos: usize = 0,
|
||||||
|
|
||||||
fn getStream(it: *TrieIterator) std.io.FixedBufferStream([]const u8) {
|
fn getStream(it: *TrieIterator) std.io.FixedBufferStream {
|
||||||
return std.io.fixedBufferStream(it.data[it.pos..]);
|
return .{ .buffer = it.data[it.pos..] };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn readUleb128(it: *TrieIterator) !u64 {
|
fn readUleb128(it: *TrieIterator) !u64 {
|
||||||
@ -1748,7 +1748,7 @@ const ElfDumper = struct {
|
|||||||
|
|
||||||
fn parseAndDumpArchive(step: *Step, check: Check, bytes: []const u8) ![]const u8 {
|
fn parseAndDumpArchive(step: *Step, check: Check, bytes: []const u8) ![]const u8 {
|
||||||
const gpa = step.owner.allocator;
|
const gpa = step.owner.allocator;
|
||||||
var stream = std.io.fixedBufferStream(bytes);
|
var stream: std.io.FixedBufferStream = .{ .buffer = bytes };
|
||||||
const reader = stream.reader();
|
const reader = stream.reader();
|
||||||
|
|
||||||
const magic = try reader.readBytesNoEof(elf.ARMAG.len);
|
const magic = try reader.readBytesNoEof(elf.ARMAG.len);
|
||||||
@ -1805,8 +1805,8 @@ const ElfDumper = struct {
|
|||||||
try ctx.objects.append(gpa, .{ .name = name, .off = stream.pos, .len = size });
|
try ctx.objects.append(gpa, .{ .name = name, .off = stream.pos, .len = size });
|
||||||
}
|
}
|
||||||
|
|
||||||
var output = std.ArrayList(u8).init(gpa);
|
var output: std.io.AllocatingWriter = undefined;
|
||||||
const writer = output.writer();
|
const writer = output.init(gpa);
|
||||||
|
|
||||||
switch (check.kind) {
|
switch (check.kind) {
|
||||||
.archive_symtab => if (ctx.symtab.items.len > 0) {
|
.archive_symtab => if (ctx.symtab.items.len > 0) {
|
||||||
@ -1829,7 +1829,7 @@ const ElfDumper = struct {
|
|||||||
objects: std.ArrayListUnmanaged(struct { name: []const u8, off: usize, len: usize }) = .empty,
|
objects: std.ArrayListUnmanaged(struct { name: []const u8, off: usize, len: usize }) = .empty,
|
||||||
|
|
||||||
fn parseSymtab(ctx: *ArchiveContext, raw: []const u8, ptr_width: enum { p32, p64 }) !void {
|
fn parseSymtab(ctx: *ArchiveContext, raw: []const u8, ptr_width: enum { p32, p64 }) !void {
|
||||||
var stream = std.io.fixedBufferStream(raw);
|
var stream: std.io.FixedBufferStream = .{ .buffer = raw };
|
||||||
const reader = stream.reader();
|
const reader = stream.reader();
|
||||||
const num = switch (ptr_width) {
|
const num = switch (ptr_width) {
|
||||||
.p32 => try reader.readInt(u32, .big),
|
.p32 => try reader.readInt(u32, .big),
|
||||||
@ -1914,7 +1914,7 @@ const ElfDumper = struct {
|
|||||||
|
|
||||||
fn parseAndDumpObject(step: *Step, check: Check, bytes: []const u8) ![]const u8 {
|
fn parseAndDumpObject(step: *Step, check: Check, bytes: []const u8) ![]const u8 {
|
||||||
const gpa = step.owner.allocator;
|
const gpa = step.owner.allocator;
|
||||||
var stream = std.io.fixedBufferStream(bytes);
|
var stream: std.io.FixedBufferStream = .{ .buffer = bytes };
|
||||||
const reader = stream.reader();
|
const reader = stream.reader();
|
||||||
|
|
||||||
const hdr = try reader.readStruct(elf.Elf64_Ehdr);
|
const hdr = try reader.readStruct(elf.Elf64_Ehdr);
|
||||||
@ -2419,7 +2419,7 @@ const WasmDumper = struct {
|
|||||||
|
|
||||||
fn parseAndDump(step: *Step, check: Check, bytes: []const u8) ![]const u8 {
|
fn parseAndDump(step: *Step, check: Check, bytes: []const u8) ![]const u8 {
|
||||||
const gpa = step.owner.allocator;
|
const gpa = step.owner.allocator;
|
||||||
var fbs = std.io.fixedBufferStream(bytes);
|
var fbs: std.io.FixedBufferStream = .{ .buffer = bytes };
|
||||||
const reader = fbs.reader();
|
const reader = fbs.reader();
|
||||||
|
|
||||||
const buf = try reader.readBytesNoEof(8);
|
const buf = try reader.readBytesNoEof(8);
|
||||||
@ -2472,7 +2472,7 @@ const WasmDumper = struct {
|
|||||||
data: []const u8,
|
data: []const u8,
|
||||||
bw: *std.io.BufferedWriter,
|
bw: *std.io.BufferedWriter,
|
||||||
) !void {
|
) !void {
|
||||||
var fbs = std.io.fixedBufferStream(data);
|
var fbs: std.io.FixedBufferStream = .{ .buffer = data };
|
||||||
const reader = fbs.reader();
|
const reader = fbs.reader();
|
||||||
|
|
||||||
try bw.print(
|
try bw.print(
|
||||||
@ -2524,7 +2524,7 @@ const WasmDumper = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parseSection(step: *Step, section: std.wasm.Section, data: []const u8, entries: u32, bw: *std.io.BufferedWriter) !void {
|
fn parseSection(step: *Step, section: std.wasm.Section, data: []const u8, entries: u32, bw: *std.io.BufferedWriter) !void {
|
||||||
var fbs = std.io.fixedBufferStream(data);
|
var fbs: std.io.FixedBufferStream = .{ .buffer = data };
|
||||||
const reader = fbs.reader();
|
const reader = fbs.reader();
|
||||||
|
|
||||||
switch (section) {
|
switch (section) {
|
||||||
|
|||||||
@ -1964,20 +1964,24 @@ fn addFlag(args: *ArrayList([]const u8), comptime name: []const u8, opt: ?bool)
|
|||||||
fn checkCompileErrors(compile: *Compile) !void {
|
fn checkCompileErrors(compile: *Compile) !void {
|
||||||
// Clear this field so that it does not get printed by the build runner.
|
// Clear this field so that it does not get printed by the build runner.
|
||||||
const actual_eb = compile.step.result_error_bundle;
|
const actual_eb = compile.step.result_error_bundle;
|
||||||
compile.step.result_error_bundle = std.zig.ErrorBundle.empty;
|
compile.step.result_error_bundle = .empty;
|
||||||
|
|
||||||
const arena = compile.step.owner.allocator;
|
const arena = compile.step.owner.allocator;
|
||||||
|
|
||||||
var actual_errors_list = std.ArrayList(u8).init(arena);
|
const actual_errors = ae: {
|
||||||
try actual_eb.renderToWriter(.{
|
var aw: std.io.AllocatingWriter = undefined;
|
||||||
.ttyconf = .no_color,
|
const bw = aw.init(arena);
|
||||||
.include_reference_trace = false,
|
defer aw.deinit();
|
||||||
.include_source_line = false,
|
try actual_eb.renderToWriter(.{
|
||||||
}, actual_errors_list.writer());
|
.ttyconf = .no_color,
|
||||||
const actual_errors = try actual_errors_list.toOwnedSlice();
|
.include_reference_trace = false,
|
||||||
|
.include_source_line = false,
|
||||||
|
}, bw);
|
||||||
|
break :ae try aw.toOwnedSlice();
|
||||||
|
};
|
||||||
|
|
||||||
// Render the expected lines into a string that we can compare verbatim.
|
// Render the expected lines into a string that we can compare verbatim.
|
||||||
var expected_generated = std.ArrayList(u8).init(arena);
|
var expected_generated: std.ArrayListUnmanaged(u8) = .empty;
|
||||||
const expect_errors = compile.expect_errors.?;
|
const expect_errors = compile.expect_errors.?;
|
||||||
|
|
||||||
var actual_line_it = mem.splitScalar(u8, actual_errors, '\n');
|
var actual_line_it = mem.splitScalar(u8, actual_errors, '\n');
|
||||||
|
|||||||
@ -34,7 +34,7 @@ pub const Component = union(enum) {
|
|||||||
return switch (component) {
|
return switch (component) {
|
||||||
.raw => |raw| raw,
|
.raw => |raw| raw,
|
||||||
.percent_encoded => |percent_encoded| if (std.mem.indexOfScalar(u8, percent_encoded, '%')) |_|
|
.percent_encoded => |percent_encoded| if (std.mem.indexOfScalar(u8, percent_encoded, '%')) |_|
|
||||||
try std.fmt.allocPrint(arena, "{raw}", .{component})
|
try std.fmt.allocPrint(arena, "{fraw}", .{component})
|
||||||
else
|
else
|
||||||
percent_encoded,
|
percent_encoded,
|
||||||
};
|
};
|
||||||
@ -44,8 +44,8 @@ pub const Component = union(enum) {
|
|||||||
component: Component,
|
component: Component,
|
||||||
comptime fmt_str: []const u8,
|
comptime fmt_str: []const u8,
|
||||||
_: std.fmt.FormatOptions,
|
_: std.fmt.FormatOptions,
|
||||||
writer: anytype,
|
writer: *std.io.BufferedWriter,
|
||||||
) @TypeOf(writer).Error!void {
|
) anyerror!void {
|
||||||
if (fmt_str.len == 0) {
|
if (fmt_str.len == 0) {
|
||||||
try writer.print("std.Uri.Component{{ .{s} = \"{}\" }}", .{
|
try writer.print("std.Uri.Component{{ .{s} = \"{}\" }}", .{
|
||||||
@tagName(component),
|
@tagName(component),
|
||||||
@ -97,10 +97,10 @@ pub const Component = union(enum) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn percentEncode(
|
pub fn percentEncode(
|
||||||
writer: anytype,
|
writer: *std.io.BufferedWriter,
|
||||||
raw: []const u8,
|
raw: []const u8,
|
||||||
comptime isValidChar: fn (u8) bool,
|
comptime isValidChar: fn (u8) bool,
|
||||||
) @TypeOf(writer).Error!void {
|
) anyerror!void {
|
||||||
var start: usize = 0;
|
var start: usize = 0;
|
||||||
for (raw, 0..) |char, index| {
|
for (raw, 0..) |char, index| {
|
||||||
if (isValidChar(char)) continue;
|
if (isValidChar(char)) continue;
|
||||||
@ -822,7 +822,7 @@ test "URI percent decoding" {
|
|||||||
const expected = "\\ö/ äöß ~~.adas-https://canvas:123/#ads&&sad";
|
const expected = "\\ö/ äöß ~~.adas-https://canvas:123/#ads&&sad";
|
||||||
var input = "%5C%C3%B6%2F%20%C3%A4%C3%B6%C3%9F%20~~.adas-https%3A%2F%2Fcanvas%3A123%2F%23ads%26%26sad".*;
|
var input = "%5C%C3%B6%2F%20%C3%A4%C3%B6%C3%9F%20~~.adas-https%3A%2F%2Fcanvas%3A123%2F%23ads%26%26sad".*;
|
||||||
|
|
||||||
try std.testing.expectFmt(expected, "{raw}", .{Component{ .percent_encoded = &input }});
|
try std.testing.expectFmt(expected, "{fraw}", .{Component{ .percent_encoded = &input }});
|
||||||
|
|
||||||
var output: [expected.len]u8 = undefined;
|
var output: [expected.len]u8 = undefined;
|
||||||
try std.testing.expectEqualStrings(percentDecodeBackwards(&output, &input), expected);
|
try std.testing.expectEqualStrings(percentDecodeBackwards(&output, &input), expected);
|
||||||
@ -834,7 +834,7 @@ test "URI percent decoding" {
|
|||||||
const expected = "/abc%";
|
const expected = "/abc%";
|
||||||
var input = expected.*;
|
var input = expected.*;
|
||||||
|
|
||||||
try std.testing.expectFmt(expected, "{raw}", .{Component{ .percent_encoded = &input }});
|
try std.testing.expectFmt(expected, "{fraw}", .{Component{ .percent_encoded = &input }});
|
||||||
|
|
||||||
var output: [expected.len]u8 = undefined;
|
var output: [expected.len]u8 = undefined;
|
||||||
try std.testing.expectEqualStrings(percentDecodeBackwards(&output, &input), expected);
|
try std.testing.expectEqualStrings(percentDecodeBackwards(&output, &input), expected);
|
||||||
|
|||||||
@ -1828,60 +1828,6 @@ test "ArrayList(T) of struct T" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test "ArrayList(u8) implements writer" {
|
|
||||||
const a = testing.allocator;
|
|
||||||
|
|
||||||
{
|
|
||||||
var buffer = ArrayList(u8).init(a);
|
|
||||||
defer buffer.deinit();
|
|
||||||
|
|
||||||
const x: i32 = 42;
|
|
||||||
const y: i32 = 1234;
|
|
||||||
try buffer.writer().print("x: {}\ny: {}\n", .{ x, y });
|
|
||||||
|
|
||||||
try testing.expectEqualSlices(u8, "x: 42\ny: 1234\n", buffer.items);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
var list = ArrayListAligned(u8, .@"2").init(a);
|
|
||||||
defer list.deinit();
|
|
||||||
|
|
||||||
const writer = list.writer();
|
|
||||||
try writer.writeAll("a");
|
|
||||||
try writer.writeAll("bc");
|
|
||||||
try writer.writeAll("d");
|
|
||||||
try writer.writeAll("efg");
|
|
||||||
|
|
||||||
try testing.expectEqualSlices(u8, list.items, "abcdefg");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
test "ArrayListUnmanaged(u8) implements writer" {
|
|
||||||
const a = testing.allocator;
|
|
||||||
|
|
||||||
{
|
|
||||||
var buffer: ArrayListUnmanaged(u8) = .empty;
|
|
||||||
defer buffer.deinit(a);
|
|
||||||
|
|
||||||
const x: i32 = 42;
|
|
||||||
const y: i32 = 1234;
|
|
||||||
try buffer.writer(a).print("x: {}\ny: {}\n", .{ x, y });
|
|
||||||
|
|
||||||
try testing.expectEqualSlices(u8, "x: 42\ny: 1234\n", buffer.items);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
var list: ArrayListAlignedUnmanaged(u8, .@"2") = .empty;
|
|
||||||
defer list.deinit(a);
|
|
||||||
|
|
||||||
const writer = list.writer(a);
|
|
||||||
try writer.writeAll("a");
|
|
||||||
try writer.writeAll("bc");
|
|
||||||
try writer.writeAll("d");
|
|
||||||
try writer.writeAll("efg");
|
|
||||||
|
|
||||||
try testing.expectEqualSlices(u8, list.items, "abcdefg");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
test "shrink still sets length when resizing is disabled" {
|
test "shrink still sets length when resizing is disabled" {
|
||||||
var failing_allocator = testing.FailingAllocator.init(testing.allocator, .{ .resize_fail_index = 0 });
|
var failing_allocator = testing.FailingAllocator.init(testing.allocator, .{ .resize_fail_index = 0 });
|
||||||
const a = failing_allocator.allocator();
|
const a = failing_allocator.allocator();
|
||||||
|
|||||||
@ -15,12 +15,15 @@ pub fn decompress(
|
|||||||
|
|
||||||
test {
|
test {
|
||||||
const expected = "Hello\nWorld!\n";
|
const expected = "Hello\nWorld!\n";
|
||||||
const compressed = &[_]u8{ 0x01, 0x00, 0x05, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x02, 0x00, 0x06, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x0A, 0x00 };
|
const compressed = &[_]u8{
|
||||||
|
0x01, 0x00, 0x05, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x02,
|
||||||
|
0x00, 0x06, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x0A, 0x00,
|
||||||
|
};
|
||||||
|
var stream: std.io.FixedBufferStream = .{ .buffer = compressed };
|
||||||
|
|
||||||
const allocator = std.testing.allocator;
|
var decomp: std.io.AllocatingWriter = undefined;
|
||||||
var decomp = std.ArrayList(u8).init(allocator);
|
const decomp_bw = decomp.init(std.testing.allocator);
|
||||||
defer decomp.deinit();
|
defer decomp.deinit();
|
||||||
var stream = std.io.fixedBufferStream(compressed);
|
try decompress(std.testing.allocator, stream.reader(), decomp_bw);
|
||||||
try decompress(allocator, stream.reader(), decomp.writer());
|
try std.testing.expectEqualSlices(u8, expected, decomp.getWritten());
|
||||||
try std.testing.expectEqualSlices(u8, expected, decomp.items);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -631,7 +631,7 @@ pub fn decodeBlock(
|
|||||||
var bytes_read: usize = 0;
|
var bytes_read: usize = 0;
|
||||||
const literals = decodeLiteralsSectionSlice(src[0..block_size], &bytes_read) catch
|
const literals = decodeLiteralsSectionSlice(src[0..block_size], &bytes_read) catch
|
||||||
return error.MalformedCompressedBlock;
|
return error.MalformedCompressedBlock;
|
||||||
var fbs = std.io.fixedBufferStream(src[bytes_read..block_size]);
|
var fbs: std.io.FixedBufferStream = .{ .buffer = src[bytes_read..block_size] };
|
||||||
const fbs_reader = fbs.reader();
|
const fbs_reader = fbs.reader();
|
||||||
const sequences_header = decodeSequencesHeader(fbs_reader) catch
|
const sequences_header = decodeSequencesHeader(fbs_reader) catch
|
||||||
return error.MalformedCompressedBlock;
|
return error.MalformedCompressedBlock;
|
||||||
@ -737,7 +737,7 @@ pub fn decodeBlockRingBuffer(
|
|||||||
var bytes_read: usize = 0;
|
var bytes_read: usize = 0;
|
||||||
const literals = decodeLiteralsSectionSlice(src[0..block_size], &bytes_read) catch
|
const literals = decodeLiteralsSectionSlice(src[0..block_size], &bytes_read) catch
|
||||||
return error.MalformedCompressedBlock;
|
return error.MalformedCompressedBlock;
|
||||||
var fbs = std.io.fixedBufferStream(src[bytes_read..block_size]);
|
var fbs: std.io.FixedBufferStream = .{ .buffer = src[bytes_read..block_size] };
|
||||||
const fbs_reader = fbs.reader();
|
const fbs_reader = fbs.reader();
|
||||||
const sequences_header = decodeSequencesHeader(fbs_reader) catch
|
const sequences_header = decodeSequencesHeader(fbs_reader) catch
|
||||||
return error.MalformedCompressedBlock;
|
return error.MalformedCompressedBlock;
|
||||||
@ -931,7 +931,7 @@ pub fn decodeLiteralsSectionSlice(
|
|||||||
) (error{ MalformedLiteralsHeader, MalformedLiteralsSection, EndOfStream } || huffman.Error)!LiteralsSection {
|
) (error{ MalformedLiteralsHeader, MalformedLiteralsSection, EndOfStream } || huffman.Error)!LiteralsSection {
|
||||||
var bytes_read: usize = 0;
|
var bytes_read: usize = 0;
|
||||||
const header = header: {
|
const header = header: {
|
||||||
var fbs = std.io.fixedBufferStream(src);
|
var fbs: std.io.FixedBufferStream = .{ .buffer = src };
|
||||||
defer bytes_read = fbs.pos;
|
defer bytes_read = fbs.pos;
|
||||||
break :header decodeLiteralsHeader(fbs.reader()) catch return error.MalformedLiteralsHeader;
|
break :header decodeLiteralsHeader(fbs.reader()) catch return error.MalformedLiteralsHeader;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -41,7 +41,7 @@ fn decodeFseHuffmanTree(
|
|||||||
|
|
||||||
fn decodeFseHuffmanTreeSlice(src: []const u8, compressed_size: usize, weights: *[256]u4) !usize {
|
fn decodeFseHuffmanTreeSlice(src: []const u8, compressed_size: usize, weights: *[256]u4) !usize {
|
||||||
if (src.len < compressed_size) return error.MalformedHuffmanTree;
|
if (src.len < compressed_size) return error.MalformedHuffmanTree;
|
||||||
var stream = std.io.fixedBufferStream(src[0..compressed_size]);
|
var stream: std.io.FixedBufferStream = .{ .buffer = src[0..compressed_size] };
|
||||||
var counting_reader = std.io.countingReader(stream.reader());
|
var counting_reader = std.io.countingReader(stream.reader());
|
||||||
var bit_reader = readers.bitReader(counting_reader.reader());
|
var bit_reader = readers.bitReader(counting_reader.reader());
|
||||||
|
|
||||||
@ -213,7 +213,7 @@ pub fn decodeHuffmanTreeSlice(
|
|||||||
bytes_read += header;
|
bytes_read += header;
|
||||||
break :count try decodeFseHuffmanTreeSlice(src[1..], header, &weights);
|
break :count try decodeFseHuffmanTreeSlice(src[1..], header, &weights);
|
||||||
} else count: {
|
} else count: {
|
||||||
var fbs = std.io.fixedBufferStream(src[1..]);
|
var fbs: std.io.FixedBufferStream = .{ .buffer = src[1..] };
|
||||||
defer bytes_read += fbs.pos;
|
defer bytes_read += fbs.pos;
|
||||||
break :count try decodeDirectHuffmanTree(fbs.reader(), header - 127, &weights);
|
break :count try decodeDirectHuffmanTree(fbs.reader(), header - 127, &weights);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -186,7 +186,7 @@ pub fn decodeFrame(
|
|||||||
DictionaryIdFlagUnsupported,
|
DictionaryIdFlagUnsupported,
|
||||||
SkippableSizeTooLarge,
|
SkippableSizeTooLarge,
|
||||||
} || FrameError)!ReadWriteCount {
|
} || FrameError)!ReadWriteCount {
|
||||||
var fbs = std.io.fixedBufferStream(src);
|
var fbs: std.io.FixedBufferStream = .{ .buffer = src };
|
||||||
switch (try decodeFrameType(fbs.reader())) {
|
switch (try decodeFrameType(fbs.reader())) {
|
||||||
.zstandard => return decodeZstandardFrame(dest, src, verify_checksum),
|
.zstandard => return decodeZstandardFrame(dest, src, verify_checksum),
|
||||||
.skippable => {
|
.skippable => {
|
||||||
@ -233,7 +233,7 @@ pub fn decodeFrameArrayList(
|
|||||||
verify_checksum: bool,
|
verify_checksum: bool,
|
||||||
window_size_max: usize,
|
window_size_max: usize,
|
||||||
) (error{ BadMagic, OutOfMemory, SkippableSizeTooLarge } || FrameContext.Error || FrameError)!usize {
|
) (error{ BadMagic, OutOfMemory, SkippableSizeTooLarge } || FrameContext.Error || FrameError)!usize {
|
||||||
var fbs = std.io.fixedBufferStream(src);
|
var fbs: std.io.FixedBufferStream = .{ .buffer = src };
|
||||||
const reader = fbs.reader();
|
const reader = fbs.reader();
|
||||||
const magic = try reader.readInt(u32, .little);
|
const magic = try reader.readInt(u32, .little);
|
||||||
switch (try frameType(magic)) {
|
switch (try frameType(magic)) {
|
||||||
@ -303,7 +303,7 @@ pub fn decodeZstandardFrame(
|
|||||||
var consumed_count: usize = 4;
|
var consumed_count: usize = 4;
|
||||||
|
|
||||||
var frame_context = context: {
|
var frame_context = context: {
|
||||||
var fbs = std.io.fixedBufferStream(src[consumed_count..]);
|
var fbs: std.io.FixedBufferStream = .{ .buffer = src[consumed_count..] };
|
||||||
const source = fbs.reader();
|
const source = fbs.reader();
|
||||||
const frame_header = try decodeZstandardHeader(source);
|
const frame_header = try decodeZstandardHeader(source);
|
||||||
consumed_count += fbs.pos;
|
consumed_count += fbs.pos;
|
||||||
@ -446,7 +446,7 @@ pub fn decodeZstandardFrameArrayList(
|
|||||||
var consumed_count: usize = 4;
|
var consumed_count: usize = 4;
|
||||||
|
|
||||||
var frame_context = context: {
|
var frame_context = context: {
|
||||||
var fbs = std.io.fixedBufferStream(src[consumed_count..]);
|
var fbs: std.io.FixedBufferStream = .{ .buffer = src[consumed_count..] };
|
||||||
const source = fbs.reader();
|
const source = fbs.reader();
|
||||||
const frame_header = try decodeZstandardHeader(source);
|
const frame_header = try decodeZstandardHeader(source);
|
||||||
consumed_count += fbs.pos;
|
consumed_count += fbs.pos;
|
||||||
|
|||||||
@ -242,50 +242,44 @@ pub fn getSelfDebugInfo() !*SelfInfo {
|
|||||||
/// Tries to print a hexadecimal view of the bytes, unbuffered, and ignores any error returned.
|
/// Tries to print a hexadecimal view of the bytes, unbuffered, and ignores any error returned.
|
||||||
/// Obtains the stderr mutex while dumping.
|
/// Obtains the stderr mutex while dumping.
|
||||||
pub fn dumpHex(bytes: []const u8) void {
|
pub fn dumpHex(bytes: []const u8) void {
|
||||||
lockStdErr();
|
var bw = lockStdErr2();
|
||||||
defer unlockStdErr();
|
defer unlockStdErr();
|
||||||
dumpHexFallible(bytes) catch {};
|
const ttyconf = std.io.tty.detectConfig(std.io.getStdErr());
|
||||||
|
dumpHexFallible(&bw, ttyconf, bytes) catch {};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prints a hexadecimal view of the bytes, unbuffered, returning any error that occurs.
|
/// Prints a hexadecimal view of the bytes, returning any error that occurs.
|
||||||
pub fn dumpHexFallible(bytes: []const u8) !void {
|
pub fn dumpHexFallible(bw: *std.io.BufferedWriter, ttyconf: std.io.tty.Config, bytes: []const u8) !void {
|
||||||
const stderr = std.io.getStdErr();
|
|
||||||
const ttyconf = std.io.tty.detectConfig(stderr);
|
|
||||||
const writer = stderr.writer();
|
|
||||||
try dumpHexInternal(bytes, ttyconf, writer);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn dumpHexInternal(bytes: []const u8, ttyconf: std.io.tty.Config, writer: anytype) !void {
|
|
||||||
var chunks = mem.window(u8, bytes, 16, 16);
|
var chunks = mem.window(u8, bytes, 16, 16);
|
||||||
while (chunks.next()) |window| {
|
while (chunks.next()) |window| {
|
||||||
// 1. Print the address.
|
// 1. Print the address.
|
||||||
const address = (@intFromPtr(bytes.ptr) + 0x10 * (std.math.divCeil(usize, chunks.index orelse bytes.len, 16) catch unreachable)) - 0x10;
|
const address = (@intFromPtr(bytes.ptr) + 0x10 * (std.math.divCeil(usize, chunks.index orelse bytes.len, 16) catch unreachable)) - 0x10;
|
||||||
try ttyconf.setColor(writer, .dim);
|
try ttyconf.setColor(bw, .dim);
|
||||||
// We print the address in lowercase and the bytes in uppercase hexadecimal to distinguish them more.
|
// We print the address in lowercase and the bytes in uppercase hexadecimal to distinguish them more.
|
||||||
// Also, make sure all lines are aligned by padding the address.
|
// Also, make sure all lines are aligned by padding the address.
|
||||||
try writer.print("{x:0>[1]} ", .{ address, @sizeOf(usize) * 2 });
|
try bw.print("{x:0>[1]} ", .{ address, @sizeOf(usize) * 2 });
|
||||||
try ttyconf.setColor(writer, .reset);
|
try ttyconf.setColor(bw, .reset);
|
||||||
|
|
||||||
// 2. Print the bytes.
|
// 2. Print the bytes.
|
||||||
for (window, 0..) |byte, index| {
|
for (window, 0..) |byte, index| {
|
||||||
try writer.print("{X:0>2} ", .{byte});
|
try bw.print("{X:0>2} ", .{byte});
|
||||||
if (index == 7) try writer.writeByte(' ');
|
if (index == 7) try bw.writeByte(' ');
|
||||||
}
|
}
|
||||||
try writer.writeByte(' ');
|
try bw.writeByte(' ');
|
||||||
if (window.len < 16) {
|
if (window.len < 16) {
|
||||||
var missing_columns = (16 - window.len) * 3;
|
var missing_columns = (16 - window.len) * 3;
|
||||||
if (window.len < 8) missing_columns += 1;
|
if (window.len < 8) missing_columns += 1;
|
||||||
try writer.splatByteAll(' ', missing_columns);
|
try bw.splatByteAll(' ', missing_columns);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Print the characters.
|
// 3. Print the characters.
|
||||||
for (window) |byte| {
|
for (window) |byte| {
|
||||||
if (std.ascii.isPrint(byte)) {
|
if (std.ascii.isPrint(byte)) {
|
||||||
try writer.writeByte(byte);
|
try bw.writeByte(byte);
|
||||||
} else {
|
} else {
|
||||||
// Related: https://github.com/ziglang/zig/issues/7600
|
// Related: https://github.com/ziglang/zig/issues/7600
|
||||||
if (ttyconf == .windows_api) {
|
if (ttyconf == .windows_api) {
|
||||||
try writer.writeByte('.');
|
try bw.writeByte('.');
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -293,22 +287,24 @@ fn dumpHexInternal(bytes: []const u8, ttyconf: std.io.tty.Config, writer: anytyp
|
|||||||
// We don't want to do this for all control codes because most control codes apart from
|
// We don't want to do this for all control codes because most control codes apart from
|
||||||
// the ones that Zig has escape sequences for are likely not very useful to print as symbols.
|
// the ones that Zig has escape sequences for are likely not very useful to print as symbols.
|
||||||
switch (byte) {
|
switch (byte) {
|
||||||
'\n' => try writer.writeAll("␊"),
|
'\n' => try bw.writeAll("␊"),
|
||||||
'\r' => try writer.writeAll("␍"),
|
'\r' => try bw.writeAll("␍"),
|
||||||
'\t' => try writer.writeAll("␉"),
|
'\t' => try bw.writeAll("␉"),
|
||||||
else => try writer.writeByte('.'),
|
else => try bw.writeByte('.'),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try writer.writeByte('\n');
|
try bw.writeByte('\n');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test dumpHexInternal {
|
test dumpHexFallible {
|
||||||
const bytes: []const u8 = &.{ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x01, 0x12, 0x13 };
|
const bytes: []const u8 = &.{ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x01, 0x12, 0x13 };
|
||||||
var output = std.ArrayList(u8).init(std.testing.allocator);
|
var aw: std.io.AllocatingWriter = undefined;
|
||||||
defer output.deinit();
|
defer aw.deinit();
|
||||||
try dumpHexInternal(bytes, .no_color, output.writer());
|
var bw = aw.init(std.testing.allocator);
|
||||||
|
|
||||||
|
try dumpHexFallible(&bw, .no_color, bytes);
|
||||||
const expected = try std.fmt.allocPrint(std.testing.allocator,
|
const expected = try std.fmt.allocPrint(std.testing.allocator,
|
||||||
\\{x:0>[2]} 00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF .."3DUfw........
|
\\{x:0>[2]} 00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF .."3DUfw........
|
||||||
\\{x:0>[2]} 01 12 13 ...
|
\\{x:0>[2]} 01 12 13 ...
|
||||||
@ -319,7 +315,7 @@ test dumpHexInternal {
|
|||||||
@sizeOf(usize) * 2,
|
@sizeOf(usize) * 2,
|
||||||
});
|
});
|
||||||
defer std.testing.allocator.free(expected);
|
defer std.testing.allocator.free(expected);
|
||||||
try std.testing.expectEqualStrings(expected, output.items);
|
try std.testing.expectEqualStrings(expected, aw.getWritten());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to print the current stack trace to stderr, unbuffered, and ignores any error returned.
|
/// Tries to print the current stack trace to stderr, unbuffered, and ignores any error returned.
|
||||||
|
|||||||
@ -1496,6 +1496,11 @@ pub fn writeFileAll(self: File, in_file: File, args: WriteFileOptions) WriteFile
|
|||||||
/// Does not try seeking in either of the File parameters.
|
/// Does not try seeking in either of the File parameters.
|
||||||
/// See `writeFileAll` as an alternative to calling this.
|
/// See `writeFileAll` as an alternative to calling this.
|
||||||
pub fn writeFileAllUnseekable(self: File, in_file: File, args: WriteFileOptions) WriteFileError!void {
|
pub fn writeFileAllUnseekable(self: File, in_file: File, args: WriteFileOptions) WriteFileError!void {
|
||||||
|
// TODO make `try @errorCast(...)` work
|
||||||
|
return @errorCast(writeFileAllUnseekableInner(self, in_file, args));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn writeFileAllUnseekableInner(self: File, in_file: File, args: WriteFileOptions) anyerror!void {
|
||||||
const headers = args.headers_and_trailers[0..args.header_count];
|
const headers = args.headers_and_trailers[0..args.header_count];
|
||||||
const trailers = args.headers_and_trailers[args.header_count..];
|
const trailers = args.headers_and_trailers[args.header_count..];
|
||||||
|
|
||||||
|
|||||||
@ -1283,26 +1283,22 @@ pub const basic_authorization = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn valueLengthFromUri(uri: Uri) usize {
|
pub fn valueLengthFromUri(uri: Uri) usize {
|
||||||
var stream = std.io.countingWriter(std.io.null_writer);
|
// TODO don't abuse formatted printing to count percent encoded characters
|
||||||
try stream.writer().print("{user}", .{uri.user orelse Uri.Component.empty});
|
const user_len = std.fmt.count("{fuser}", .{uri.user orelse Uri.Component.empty});
|
||||||
const user_len = stream.bytes_written;
|
const password_len = std.fmt.count("{fpassword}", .{uri.password orelse Uri.Component.empty});
|
||||||
stream.bytes_written = 0;
|
|
||||||
try stream.writer().print("{password}", .{uri.password orelse Uri.Component.empty});
|
|
||||||
const password_len = stream.bytes_written;
|
|
||||||
return valueLength(@intCast(user_len), @intCast(password_len));
|
return valueLength(@intCast(user_len), @intCast(password_len));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn value(uri: Uri, out: []u8) []u8 {
|
pub fn value(uri: Uri, out: []u8) []u8 {
|
||||||
var buf: [max_user_len + ":".len + max_password_len]u8 = undefined;
|
var buf: [max_user_len + ":".len + max_password_len]u8 = undefined;
|
||||||
var stream = std.io.fixedBufferStream(&buf);
|
var bw: std.io.BufferedWriter = undefined;
|
||||||
stream.writer().print("{user}", .{uri.user orelse Uri.Component.empty}) catch
|
bw.initFixed(&buf);
|
||||||
unreachable;
|
bw.print("{fuser}:{fpassword}", .{
|
||||||
assert(stream.pos <= max_user_len);
|
uri.user orelse Uri.Component.empty,
|
||||||
stream.writer().print(":{password}", .{uri.password orelse Uri.Component.empty}) catch
|
uri.password orelse Uri.Component.empty,
|
||||||
unreachable;
|
}) catch unreachable;
|
||||||
|
|
||||||
@memcpy(out[0..prefix.len], prefix);
|
@memcpy(out[0..prefix.len], prefix);
|
||||||
const base64 = std.base64.standard.Encoder.encode(out[prefix.len..], stream.getWritten());
|
const base64 = std.base64.standard.Encoder.encode(out[prefix.len..], bw.getWritten());
|
||||||
return out[0 .. prefix.len + base64.len];
|
return out[0 .. prefix.len + base64.len];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
//! TODO rename to AllocatingWriter.
|
|
||||||
//! While it is possible to use `std.ArrayList` as the underlying writer when
|
//! While it is possible to use `std.ArrayList` as the underlying writer when
|
||||||
//! using `std.io.BufferedWriter` by populating the `std.io.Writer` interface
|
//! using `std.io.BufferedWriter` by populating the `std.io.Writer` interface
|
||||||
//! and then using an empty buffer, it means that every use of
|
//! 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
|
|||||||
return &aw.buffered_writer;
|
return &aw.buffered_writer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn deinit(aw: *AllocatingWriter) void {
|
||||||
|
const written = aw.written;
|
||||||
|
aw.allocator.free(written.ptr[0 .. written.len + aw.buffered_writer.buffer.len]);
|
||||||
|
aw.* = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
/// Replaces `array_list` with empty, taking ownership of the memory.
|
/// Replaces `array_list` with empty, taking ownership of the memory.
|
||||||
pub fn fromArrayList(
|
pub fn fromArrayList(
|
||||||
aw: *AllocatingWriter,
|
aw: *AllocatingWriter,
|
||||||
@ -184,3 +189,15 @@ fn writeFile(
|
|||||||
for (trailers) |bytes| list.appendSliceAssumeCapacity(bytes);
|
for (trailers) |bytes| list.appendSliceAssumeCapacity(bytes);
|
||||||
return list.items.len - start_len;
|
return list.items.len - start_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test AllocatingWriter {
|
||||||
|
var aw: AllocatingWriter = undefined;
|
||||||
|
const bw = aw.init(std.testing.allocator);
|
||||||
|
defer aw.deinit();
|
||||||
|
|
||||||
|
const x: i32 = 42;
|
||||||
|
const y: i32 = 1234;
|
||||||
|
try bw.print("x: {}\ny: {}\n", .{ x, y });
|
||||||
|
|
||||||
|
try std.testing.expectEqualSlices(u8, "x: 42\ny: 1234\n", aw.getWritten());
|
||||||
|
}
|
||||||
|
|||||||
@ -1,3 +1,6 @@
|
|||||||
|
//! TODO make this more like AllocatingWriter, managing the state of
|
||||||
|
//! BufferedWriter both as the output and the input, but with only
|
||||||
|
//! one buffer.
|
||||||
const std = @import("../std.zig");
|
const std = @import("../std.zig");
|
||||||
const CountingWriter = @This();
|
const CountingWriter = @This();
|
||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
|
|||||||
@ -390,8 +390,9 @@ pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const
|
|||||||
const actual_window = actual[window_start..@min(actual.len, window_start + max_window_size)];
|
const actual_window = actual[window_start..@min(actual.len, window_start + max_window_size)];
|
||||||
const actual_truncated = window_start + actual_window.len < actual.len;
|
const actual_truncated = window_start + actual_window.len < actual.len;
|
||||||
|
|
||||||
const stderr = std.io.getStdErr();
|
var bw = std.debug.lockStdErr2();
|
||||||
const ttyconf = std.io.tty.detectConfig(stderr);
|
defer std.debug.unlockStdErr();
|
||||||
|
const ttyconf = std.io.tty.detectConfig(std.io.getStdErr());
|
||||||
var differ = if (T == u8) BytesDiffer{
|
var differ = if (T == u8) BytesDiffer{
|
||||||
.expected = expected_window,
|
.expected = expected_window,
|
||||||
.actual = actual_window,
|
.actual = actual_window,
|
||||||
@ -415,7 +416,7 @@ pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const
|
|||||||
print("... truncated ...\n", .{});
|
print("... truncated ...\n", .{});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
differ.write(stderr.writer()) catch {};
|
differ.write(&bw) catch {};
|
||||||
if (expected_truncated) {
|
if (expected_truncated) {
|
||||||
const end_offset = window_start + expected_window.len;
|
const end_offset = window_start + expected_window.len;
|
||||||
const num_missing_items = expected.len - (window_start + expected_window.len);
|
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
|
|||||||
print("... truncated ...\n", .{});
|
print("... truncated ...\n", .{});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
differ.write(stderr.writer()) catch {};
|
differ.write(&bw) catch {};
|
||||||
if (actual_truncated) {
|
if (actual_truncated) {
|
||||||
const end_offset = window_start + actual_window.len;
|
const end_offset = window_start + actual_window.len;
|
||||||
const num_missing_items = actual.len - (window_start + actual_window.len);
|
const num_missing_items = actual.len - (window_start + actual_window.len);
|
||||||
@ -461,17 +462,17 @@ fn SliceDiffer(comptime T: type) type {
|
|||||||
|
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
||||||
pub fn write(self: Self, writer: anytype) !void {
|
pub fn write(self: Self, bw: *std.io.BufferedWriter) !void {
|
||||||
for (self.expected, 0..) |value, i| {
|
for (self.expected, 0..) |value, i| {
|
||||||
const full_index = self.start_index + i;
|
const full_index = self.start_index + i;
|
||||||
const diff = if (i < self.actual.len) !std.meta.eql(self.actual[i], value) else true;
|
const diff = if (i < self.actual.len) !std.meta.eql(self.actual[i], value) else true;
|
||||||
if (diff) try self.ttyconf.setColor(writer, .red);
|
if (diff) try self.ttyconf.setColor(bw, .red);
|
||||||
if (@typeInfo(T) == .pointer) {
|
if (@typeInfo(T) == .pointer) {
|
||||||
try writer.print("[{}]{*}: {any}\n", .{ full_index, value, value });
|
try bw.print("[{}]{*}: {any}\n", .{ full_index, value, value });
|
||||||
} else {
|
} else {
|
||||||
try writer.print("[{}]: {any}\n", .{ full_index, value });
|
try bw.print("[{}]: {any}\n", .{ full_index, value });
|
||||||
}
|
}
|
||||||
if (diff) try self.ttyconf.setColor(writer, .reset);
|
if (diff) try self.ttyconf.setColor(bw, .reset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -482,7 +483,7 @@ const BytesDiffer = struct {
|
|||||||
actual: []const u8,
|
actual: []const u8,
|
||||||
ttyconf: std.io.tty.Config,
|
ttyconf: std.io.tty.Config,
|
||||||
|
|
||||||
pub fn write(self: BytesDiffer, writer: anytype) !void {
|
pub fn write(self: BytesDiffer, bw: *std.io.BufferedWriter) !void {
|
||||||
var expected_iterator = std.mem.window(u8, self.expected, 16, 16);
|
var expected_iterator = std.mem.window(u8, self.expected, 16, 16);
|
||||||
var row: usize = 0;
|
var row: usize = 0;
|
||||||
while (expected_iterator.next()) |chunk| {
|
while (expected_iterator.next()) |chunk| {
|
||||||
@ -492,23 +493,23 @@ const BytesDiffer = struct {
|
|||||||
const absolute_byte_index = col + row * 16;
|
const absolute_byte_index = col + row * 16;
|
||||||
const diff = if (absolute_byte_index < self.actual.len) self.actual[absolute_byte_index] != byte else true;
|
const diff = if (absolute_byte_index < self.actual.len) self.actual[absolute_byte_index] != byte else true;
|
||||||
if (diff) diffs.set(col);
|
if (diff) diffs.set(col);
|
||||||
try self.writeDiff(writer, "{X:0>2} ", .{byte}, diff);
|
try self.writeDiff(bw, "{X:0>2} ", .{byte}, diff);
|
||||||
if (col == 7) try writer.writeByte(' ');
|
if (col == 7) try bw.writeByte(' ');
|
||||||
}
|
}
|
||||||
try writer.writeByte(' ');
|
try bw.writeByte(' ');
|
||||||
if (chunk.len < 16) {
|
if (chunk.len < 16) {
|
||||||
var missing_columns = (16 - chunk.len) * 3;
|
var missing_columns = (16 - chunk.len) * 3;
|
||||||
if (chunk.len < 8) missing_columns += 1;
|
if (chunk.len < 8) missing_columns += 1;
|
||||||
try writer.writeByteNTimes(' ', missing_columns);
|
try bw.splatByteAll(' ', missing_columns);
|
||||||
}
|
}
|
||||||
for (chunk, 0..) |byte, col| {
|
for (chunk, 0..) |byte, col| {
|
||||||
const diff = diffs.isSet(col);
|
const diff = diffs.isSet(col);
|
||||||
if (std.ascii.isPrint(byte)) {
|
if (std.ascii.isPrint(byte)) {
|
||||||
try self.writeDiff(writer, "{c}", .{byte}, diff);
|
try self.writeDiff(bw, "{c}", .{byte}, diff);
|
||||||
} else {
|
} else {
|
||||||
// TODO: remove this `if` when https://github.com/ziglang/zig/issues/7600 is fixed
|
// TODO: remove this `if` when https://github.com/ziglang/zig/issues/7600 is fixed
|
||||||
if (self.ttyconf == .windows_api) {
|
if (self.ttyconf == .windows_api) {
|
||||||
try self.writeDiff(writer, ".", .{}, diff);
|
try self.writeDiff(bw, ".", .{}, diff);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -516,22 +517,22 @@ const BytesDiffer = struct {
|
|||||||
// We don't want to do this for all control codes because most control codes apart from
|
// We don't want to do this for all control codes because most control codes apart from
|
||||||
// the ones that Zig has escape sequences for are likely not very useful to print as symbols.
|
// the ones that Zig has escape sequences for are likely not very useful to print as symbols.
|
||||||
switch (byte) {
|
switch (byte) {
|
||||||
'\n' => try self.writeDiff(writer, "␊", .{}, diff),
|
'\n' => try self.writeDiff(bw, "␊", .{}, diff),
|
||||||
'\r' => try self.writeDiff(writer, "␍", .{}, diff),
|
'\r' => try self.writeDiff(bw, "␍", .{}, diff),
|
||||||
'\t' => try self.writeDiff(writer, "␉", .{}, diff),
|
'\t' => try self.writeDiff(bw, "␉", .{}, diff),
|
||||||
else => try self.writeDiff(writer, ".", .{}, diff),
|
else => try self.writeDiff(bw, ".", .{}, diff),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try writer.writeByte('\n');
|
try bw.writeByte('\n');
|
||||||
row += 1;
|
row += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn writeDiff(self: BytesDiffer, writer: anytype, comptime fmt: []const u8, args: anytype, diff: bool) !void {
|
fn writeDiff(self: BytesDiffer, bw: *std.io.BufferedWriter, comptime fmt: []const u8, args: anytype, diff: bool) !void {
|
||||||
if (diff) try self.ttyconf.setColor(writer, .red);
|
if (diff) try self.ttyconf.setColor(bw, .red);
|
||||||
try writer.print(fmt, args);
|
try bw.print(fmt, args);
|
||||||
if (diff) try self.ttyconf.setColor(writer, .reset);
|
if (diff) try self.ttyconf.setColor(bw, .reset);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -159,21 +159,26 @@ pub const RenderOptions = struct {
|
|||||||
pub fn renderToStdErr(eb: ErrorBundle, options: RenderOptions) void {
|
pub fn renderToStdErr(eb: ErrorBundle, options: RenderOptions) void {
|
||||||
std.debug.lockStdErr();
|
std.debug.lockStdErr();
|
||||||
defer std.debug.unlockStdErr();
|
defer std.debug.unlockStdErr();
|
||||||
const stderr = std.io.getStdErr();
|
var buffer: [256]u8 = undefined;
|
||||||
return renderToWriter(eb, options, stderr.writer()) catch return;
|
var bw: std.io.BufferedWriter = .{
|
||||||
|
.unbuffered_writer = std.io.getStdErr().writer(),
|
||||||
|
.buffer = &buffer,
|
||||||
|
};
|
||||||
|
renderToWriter(eb, options, &bw) catch return;
|
||||||
|
bw.flush() catch return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn renderToWriter(eb: ErrorBundle, options: RenderOptions, writer: anytype) anyerror!void {
|
pub fn renderToWriter(eb: ErrorBundle, options: RenderOptions, bw: *std.io.BufferedWriter) anyerror!void {
|
||||||
if (eb.extra.len == 0) return;
|
if (eb.extra.len == 0) return;
|
||||||
for (eb.getMessages()) |err_msg| {
|
for (eb.getMessages()) |err_msg| {
|
||||||
try renderErrorMessageToWriter(eb, options, err_msg, writer, "error", .red, 0);
|
try renderErrorMessageToWriter(eb, options, err_msg, bw, "error", .red, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.include_log_text) {
|
if (options.include_log_text) {
|
||||||
const log_text = eb.getCompileLogOutput();
|
const log_text = eb.getCompileLogOutput();
|
||||||
if (log_text.len != 0) {
|
if (log_text.len != 0) {
|
||||||
try writer.writeAll("\nCompile Log Output:\n");
|
try bw.writeAll("\nCompile Log Output:\n");
|
||||||
try writer.writeAll(log_text);
|
try bw.writeAll(log_text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -182,74 +187,74 @@ fn renderErrorMessageToWriter(
|
|||||||
eb: ErrorBundle,
|
eb: ErrorBundle,
|
||||||
options: RenderOptions,
|
options: RenderOptions,
|
||||||
err_msg_index: MessageIndex,
|
err_msg_index: MessageIndex,
|
||||||
stderr: anytype,
|
bw: *std.io.BufferedWriter,
|
||||||
kind: []const u8,
|
kind: []const u8,
|
||||||
color: std.io.tty.Color,
|
color: std.io.tty.Color,
|
||||||
indent: usize,
|
indent: usize,
|
||||||
) anyerror!void {
|
) anyerror!void {
|
||||||
const ttyconf = options.ttyconf;
|
const ttyconf = options.ttyconf;
|
||||||
var counting_writer = std.io.countingWriter(stderr);
|
var counting_writer: std.io.CountingWriter = .{ .child_writer = bw.writer() };
|
||||||
const counting_stderr = counting_writer.writer();
|
const counting_bw = counting_writer.unbufferedWriter();
|
||||||
const err_msg = eb.getErrorMessage(err_msg_index);
|
const err_msg = eb.getErrorMessage(err_msg_index);
|
||||||
if (err_msg.src_loc != .none) {
|
if (err_msg.src_loc != .none) {
|
||||||
const src = eb.extraData(SourceLocation, @intFromEnum(err_msg.src_loc));
|
const src = eb.extraData(SourceLocation, @intFromEnum(err_msg.src_loc));
|
||||||
try counting_stderr.writeByteNTimes(' ', indent);
|
try counting_bw.writeByteNTimes(' ', indent);
|
||||||
try ttyconf.setColor(stderr, .bold);
|
try ttyconf.setColor(bw, .bold);
|
||||||
try counting_stderr.print("{s}:{d}:{d}: ", .{
|
try counting_bw.print("{s}:{d}:{d}: ", .{
|
||||||
eb.nullTerminatedString(src.data.src_path),
|
eb.nullTerminatedString(src.data.src_path),
|
||||||
src.data.line + 1,
|
src.data.line + 1,
|
||||||
src.data.column + 1,
|
src.data.column + 1,
|
||||||
});
|
});
|
||||||
try ttyconf.setColor(stderr, color);
|
try ttyconf.setColor(bw, color);
|
||||||
try counting_stderr.writeAll(kind);
|
try counting_bw.writeAll(kind);
|
||||||
try counting_stderr.writeAll(": ");
|
try counting_bw.writeAll(": ");
|
||||||
// This is the length of the part before the error message:
|
// This is the length of the part before the error message:
|
||||||
// e.g. "file.zig:4:5: error: "
|
// e.g. "file.zig:4:5: error: "
|
||||||
const prefix_len: usize = @intCast(counting_stderr.context.bytes_written);
|
const prefix_len: usize = @intCast(counting_bw.context.bytes_written);
|
||||||
try ttyconf.setColor(stderr, .reset);
|
try ttyconf.setColor(bw, .reset);
|
||||||
try ttyconf.setColor(stderr, .bold);
|
try ttyconf.setColor(bw, .bold);
|
||||||
if (err_msg.count == 1) {
|
if (err_msg.count == 1) {
|
||||||
try writeMsg(eb, err_msg, stderr, prefix_len);
|
try writeMsg(eb, err_msg, bw, prefix_len);
|
||||||
try stderr.writeByte('\n');
|
try bw.writeByte('\n');
|
||||||
} else {
|
} else {
|
||||||
try writeMsg(eb, err_msg, stderr, prefix_len);
|
try writeMsg(eb, err_msg, bw, prefix_len);
|
||||||
try ttyconf.setColor(stderr, .dim);
|
try ttyconf.setColor(bw, .dim);
|
||||||
try stderr.print(" ({d} times)\n", .{err_msg.count});
|
try bw.print(" ({d} times)\n", .{err_msg.count});
|
||||||
}
|
}
|
||||||
try ttyconf.setColor(stderr, .reset);
|
try ttyconf.setColor(bw, .reset);
|
||||||
if (src.data.source_line != 0 and options.include_source_line) {
|
if (src.data.source_line != 0 and options.include_source_line) {
|
||||||
const line = eb.nullTerminatedString(src.data.source_line);
|
const line = eb.nullTerminatedString(src.data.source_line);
|
||||||
for (line) |b| switch (b) {
|
for (line) |b| switch (b) {
|
||||||
'\t' => try stderr.writeByte(' '),
|
'\t' => try bw.writeByte(' '),
|
||||||
else => try stderr.writeByte(b),
|
else => try bw.writeByte(b),
|
||||||
};
|
};
|
||||||
try stderr.writeByte('\n');
|
try bw.writeByte('\n');
|
||||||
// TODO basic unicode code point monospace width
|
// TODO basic unicode code point monospace width
|
||||||
const before_caret = src.data.span_main - src.data.span_start;
|
const before_caret = src.data.span_main - src.data.span_start;
|
||||||
// -1 since span.main includes the caret
|
// -1 since span.main includes the caret
|
||||||
const after_caret = src.data.span_end -| src.data.span_main -| 1;
|
const after_caret = src.data.span_end -| src.data.span_main -| 1;
|
||||||
try stderr.writeByteNTimes(' ', src.data.column - before_caret);
|
try bw.writeByteNTimes(' ', src.data.column - before_caret);
|
||||||
try ttyconf.setColor(stderr, .green);
|
try ttyconf.setColor(bw, .green);
|
||||||
try stderr.writeByteNTimes('~', before_caret);
|
try bw.writeByteNTimes('~', before_caret);
|
||||||
try stderr.writeByte('^');
|
try bw.writeByte('^');
|
||||||
try stderr.writeByteNTimes('~', after_caret);
|
try bw.writeByteNTimes('~', after_caret);
|
||||||
try stderr.writeByte('\n');
|
try bw.writeByte('\n');
|
||||||
try ttyconf.setColor(stderr, .reset);
|
try ttyconf.setColor(bw, .reset);
|
||||||
}
|
}
|
||||||
for (eb.getNotes(err_msg_index)) |note| {
|
for (eb.getNotes(err_msg_index)) |note| {
|
||||||
try renderErrorMessageToWriter(eb, options, note, stderr, "note", .cyan, indent);
|
try renderErrorMessageToWriter(eb, options, note, bw, "note", .cyan, indent);
|
||||||
}
|
}
|
||||||
if (src.data.reference_trace_len > 0 and options.include_reference_trace) {
|
if (src.data.reference_trace_len > 0 and options.include_reference_trace) {
|
||||||
try ttyconf.setColor(stderr, .reset);
|
try ttyconf.setColor(bw, .reset);
|
||||||
try ttyconf.setColor(stderr, .dim);
|
try ttyconf.setColor(bw, .dim);
|
||||||
try stderr.print("referenced by:\n", .{});
|
try bw.print("referenced by:\n", .{});
|
||||||
var ref_index = src.end;
|
var ref_index = src.end;
|
||||||
for (0..src.data.reference_trace_len) |_| {
|
for (0..src.data.reference_trace_len) |_| {
|
||||||
const ref_trace = eb.extraData(ReferenceTrace, ref_index);
|
const ref_trace = eb.extraData(ReferenceTrace, ref_index);
|
||||||
ref_index = ref_trace.end;
|
ref_index = ref_trace.end;
|
||||||
if (ref_trace.data.src_loc != .none) {
|
if (ref_trace.data.src_loc != .none) {
|
||||||
const ref_src = eb.getSourceLocation(ref_trace.data.src_loc);
|
const ref_src = eb.getSourceLocation(ref_trace.data.src_loc);
|
||||||
try stderr.print(" {s}: {s}:{d}:{d}\n", .{
|
try bw.print(" {s}: {s}:{d}:{d}\n", .{
|
||||||
eb.nullTerminatedString(ref_trace.data.decl_name),
|
eb.nullTerminatedString(ref_trace.data.decl_name),
|
||||||
eb.nullTerminatedString(ref_src.src_path),
|
eb.nullTerminatedString(ref_src.src_path),
|
||||||
ref_src.line + 1,
|
ref_src.line + 1,
|
||||||
@ -257,36 +262,36 @@ fn renderErrorMessageToWriter(
|
|||||||
});
|
});
|
||||||
} else if (ref_trace.data.decl_name != 0) {
|
} else if (ref_trace.data.decl_name != 0) {
|
||||||
const count = ref_trace.data.decl_name;
|
const count = ref_trace.data.decl_name;
|
||||||
try stderr.print(
|
try bw.print(
|
||||||
" {d} reference(s) hidden; use '-freference-trace={d}' to see all references\n",
|
" {d} reference(s) hidden; use '-freference-trace={d}' to see all references\n",
|
||||||
.{ count, count + src.data.reference_trace_len - 1 },
|
.{ count, count + src.data.reference_trace_len - 1 },
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
try stderr.print(
|
try bw.print(
|
||||||
" remaining reference traces hidden; use '-freference-trace' to see all reference traces\n",
|
" remaining reference traces hidden; use '-freference-trace' to see all reference traces\n",
|
||||||
.{},
|
.{},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try ttyconf.setColor(stderr, .reset);
|
try ttyconf.setColor(bw, .reset);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
try ttyconf.setColor(stderr, color);
|
try ttyconf.setColor(bw, color);
|
||||||
try stderr.writeByteNTimes(' ', indent);
|
try bw.writeByteNTimes(' ', indent);
|
||||||
try stderr.writeAll(kind);
|
try bw.writeAll(kind);
|
||||||
try stderr.writeAll(": ");
|
try bw.writeAll(": ");
|
||||||
try ttyconf.setColor(stderr, .reset);
|
try ttyconf.setColor(bw, .reset);
|
||||||
const msg = eb.nullTerminatedString(err_msg.msg);
|
const msg = eb.nullTerminatedString(err_msg.msg);
|
||||||
if (err_msg.count == 1) {
|
if (err_msg.count == 1) {
|
||||||
try stderr.print("{s}\n", .{msg});
|
try bw.print("{s}\n", .{msg});
|
||||||
} else {
|
} else {
|
||||||
try stderr.print("{s}", .{msg});
|
try bw.print("{s}", .{msg});
|
||||||
try ttyconf.setColor(stderr, .dim);
|
try ttyconf.setColor(bw, .dim);
|
||||||
try stderr.print(" ({d} times)\n", .{err_msg.count});
|
try bw.print(" ({d} times)\n", .{err_msg.count});
|
||||||
}
|
}
|
||||||
try ttyconf.setColor(stderr, .reset);
|
try ttyconf.setColor(bw, .reset);
|
||||||
for (eb.getNotes(err_msg_index)) |note| {
|
for (eb.getNotes(err_msg_index)) |note| {
|
||||||
try renderErrorMessageToWriter(eb, options, note, stderr, "note", .cyan, indent + 4);
|
try renderErrorMessageToWriter(eb, options, note, bw, "note", .cyan, indent + 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -295,13 +300,13 @@ fn renderErrorMessageToWriter(
|
|||||||
/// to allow for long, good-looking error messages.
|
/// to allow for long, good-looking error messages.
|
||||||
///
|
///
|
||||||
/// This is used to split the message in `@compileError("hello\nworld")` for example.
|
/// This is used to split the message in `@compileError("hello\nworld")` for example.
|
||||||
fn writeMsg(eb: ErrorBundle, err_msg: ErrorMessage, stderr: anytype, indent: usize) !void {
|
fn writeMsg(eb: ErrorBundle, err_msg: ErrorMessage, bw: *std.io.BufferedWriter, indent: usize) !void {
|
||||||
var lines = std.mem.splitScalar(u8, eb.nullTerminatedString(err_msg.msg), '\n');
|
var lines = std.mem.splitScalar(u8, eb.nullTerminatedString(err_msg.msg), '\n');
|
||||||
while (lines.next()) |line| {
|
while (lines.next()) |line| {
|
||||||
try stderr.writeAll(line);
|
try bw.writeAll(line);
|
||||||
if (lines.index == null) break;
|
if (lines.index == null) break;
|
||||||
try stderr.writeByte('\n');
|
try bw.writeByte('\n');
|
||||||
try stderr.writeByteNTimes(' ', indent);
|
try bw.writeByteNTimes(' ', indent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -398,7 +403,7 @@ pub const Wip = struct {
|
|||||||
pub fn printString(wip: *Wip, comptime fmt: []const u8, args: anytype) Allocator.Error!String {
|
pub fn printString(wip: *Wip, comptime fmt: []const u8, args: anytype) Allocator.Error!String {
|
||||||
const gpa = wip.gpa;
|
const gpa = wip.gpa;
|
||||||
const index: String = @intCast(wip.string_bytes.items.len);
|
const index: String = @intCast(wip.string_bytes.items.len);
|
||||||
try wip.string_bytes.writer(gpa).print(fmt, args);
|
try wip.string_bytes.print(gpa, fmt, args);
|
||||||
try wip.string_bytes.append(gpa, 0);
|
try wip.string_bytes.append(gpa, 0);
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
@ -788,9 +793,10 @@ pub const Wip = struct {
|
|||||||
|
|
||||||
const ttyconf: std.io.tty.Config = .no_color;
|
const ttyconf: std.io.tty.Config = .no_color;
|
||||||
|
|
||||||
var bundle_buf = std.ArrayList(u8).init(std.testing.allocator);
|
var bundle_buf: std.io.AllocatingWriter = undefined;
|
||||||
|
const bundle_bw = bundle_buf.init(std.testing.allocator);
|
||||||
defer bundle_buf.deinit();
|
defer bundle_buf.deinit();
|
||||||
try bundle.renderToWriter(.{ .ttyconf = ttyconf }, bundle_buf.writer());
|
try bundle.renderToWriter(.{ .ttyconf = ttyconf }, bundle_bw);
|
||||||
|
|
||||||
var copy = copy: {
|
var copy = copy: {
|
||||||
var wip: ErrorBundle.Wip = undefined;
|
var wip: ErrorBundle.Wip = undefined;
|
||||||
@ -803,10 +809,11 @@ pub const Wip = struct {
|
|||||||
};
|
};
|
||||||
defer copy.deinit(std.testing.allocator);
|
defer copy.deinit(std.testing.allocator);
|
||||||
|
|
||||||
var copy_buf = std.ArrayList(u8).init(std.testing.allocator);
|
var copy_buf: std.io.AllocatingWriter = undefined;
|
||||||
|
const copy_bw = copy_buf.init(std.testing.allocator);
|
||||||
defer copy_buf.deinit();
|
defer copy_buf.deinit();
|
||||||
try copy.renderToWriter(.{ .ttyconf = ttyconf }, copy_buf.writer());
|
try copy.renderToWriter(.{ .ttyconf = ttyconf }, copy_bw);
|
||||||
|
|
||||||
try std.testing.expectEqualStrings(bundle_buf.items, copy_buf.items);
|
try std.testing.expectEqualStrings(bundle_bw.getWritten(), copy_bw.getWritten());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user