authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-03-10 15:27:45-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-03-10 15:32:32-04:00
logba0e3be5cfa2f60f2f9d2a4eb319408f972796c2
treeda35c17d0067a463b521163f624f3d109b8050f4
parent1ad831a0ef22f354d4e1dd5073456a0683249846
signaturelock-open Commit is signed but in an unrecognized format.

(breaking) rework stream abstractions

The main goal here is to make the function pointers comptime, so that we don't have to do the crazy stuff with async function frames. Since InStream, OutStream, and SeekableStream are already generic across error sets, it's not really worse to make them generic across the vtable as well. See #764 for the open issue acknowledging that using generics for these abstractions is a design flaw. See #130 for the efforts to make these abstractions non-generic. This commit also changes the OutStream API so that `write` returns number of bytes written, and `writeAll` is the one that loops until the whole buffer is written.

24 files changed, 752 insertions(+), 776 deletions(-)

lib/std/buffer.zig+11
...@@ -157,6 +157,17 @@ pub const Buffer = struct {...@@ -157,6 +157,17 @@ pub const Buffer = struct {
157 pub fn print(self: *Buffer, comptime fmt: []const u8, args: var) !void {157 pub fn print(self: *Buffer, comptime fmt: []const u8, args: var) !void {
158 return std.fmt.format(self, error{OutOfMemory}, Buffer.append, fmt, args);158 return std.fmt.format(self, error{OutOfMemory}, Buffer.append, fmt, args);
159 }159 }
160
161 pub fn outStream(self: *Buffer) std.io.OutStream(*Buffer, error{OutOfMemory}, appendWrite) {
162 return .{ .context = self };
163 }
164
165 /// Same as `append` except it returns the number of bytes written, which is always the same
166 /// as `m.len`. The purpose of this function existing is to match `std.io.OutStream` API.
167 pub fn appendWrite(self: *Buffer, m: []const u8) !usize {
168 try self.append(m);
169 return m.len;
170 }
160};171};
161172
162test "simple Buffer" {173test "simple Buffer" {
lib/std/child_process.zig+4-6
...@@ -221,9 +221,9 @@ pub const ChildProcess = struct {...@@ -221,9 +221,9 @@ pub const ChildProcess = struct {
221 var stderr_file_in_stream = child.stderr.?.inStream();221 var stderr_file_in_stream = child.stderr.?.inStream();
222222
223 // TODO need to poll to read these streams to prevent a deadlock (or rely on evented I/O).223 // TODO need to poll to read these streams to prevent a deadlock (or rely on evented I/O).
224 const stdout = try stdout_file_in_stream.stream.readAllAlloc(args.allocator, args.max_output_bytes);224 const stdout = try stdout_file_in_stream.readAllAlloc(args.allocator, args.max_output_bytes);
225 errdefer args.allocator.free(stdout);225 errdefer args.allocator.free(stdout);
226 const stderr = try stderr_file_in_stream.stream.readAllAlloc(args.allocator, args.max_output_bytes);226 const stderr = try stderr_file_in_stream.readAllAlloc(args.allocator, args.max_output_bytes);
227 errdefer args.allocator.free(stderr);227 errdefer args.allocator.free(stderr);
228228
229 return ExecResult{229 return ExecResult{
...@@ -857,8 +857,7 @@ fn writeIntFd(fd: i32, value: ErrInt) !void {...@@ -857,8 +857,7 @@ fn writeIntFd(fd: i32, value: ErrInt) !void {
857 .io_mode = .blocking,857 .io_mode = .blocking,
858 .async_block_allowed = File.async_block_allowed_yes,858 .async_block_allowed = File.async_block_allowed_yes,
859 };859 };
860 const stream = &file.outStream().stream;860 file.outStream().writeIntNative(u64, @intCast(u64, value)) catch return error.SystemResources;
861 stream.writeIntNative(u64, @intCast(u64, value)) catch return error.SystemResources;
862}861}
863862
864fn readIntFd(fd: i32) !ErrInt {863fn readIntFd(fd: i32) !ErrInt {
...@@ -867,8 +866,7 @@ fn readIntFd(fd: i32) !ErrInt {...@@ -867,8 +866,7 @@ fn readIntFd(fd: i32) !ErrInt {
867 .io_mode = .blocking,866 .io_mode = .blocking,
868 .async_block_allowed = File.async_block_allowed_yes,867 .async_block_allowed = File.async_block_allowed_yes,
869 };868 };
870 const stream = &file.inStream().stream;869 return @intCast(ErrInt, file.inStream().readIntNative(u64) catch return error.SystemResources);
871 return @intCast(ErrInt, stream.readIntNative(u64) catch return error.SystemResources);
872}870}
873871
874/// Caller must free result.872/// Caller must free result.
lib/std/debug.zig+128-105
...@@ -55,7 +55,7 @@ pub const LineInfo = struct {...@@ -55,7 +55,7 @@ pub const LineInfo = struct {
55var stderr_file: File = undefined;55var stderr_file: File = undefined;
56var stderr_file_out_stream: File.OutStream = undefined;56var stderr_file_out_stream: File.OutStream = undefined;
5757
58var stderr_stream: ?*io.OutStream(File.WriteError) = null;58var stderr_stream: ?*File.OutStream = null;
59var stderr_mutex = std.Mutex.init();59var stderr_mutex = std.Mutex.init();
6060
61pub fn warn(comptime fmt: []const u8, args: var) void {61pub fn warn(comptime fmt: []const u8, args: var) void {
...@@ -65,13 +65,13 @@ pub fn warn(comptime fmt: []const u8, args: var) void {...@@ -65,13 +65,13 @@ pub fn warn(comptime fmt: []const u8, args: var) void {
65 noasync stderr.print(fmt, args) catch return;65 noasync stderr.print(fmt, args) catch return;
66}66}
6767
68pub fn getStderrStream() *io.OutStream(File.WriteError) {68pub fn getStderrStream() *File.OutStream {
69 if (stderr_stream) |st| {69 if (stderr_stream) |st| {
70 return st;70 return st;
71 } else {71 } else {
72 stderr_file = io.getStdErr();72 stderr_file = io.getStdErr();
73 stderr_file_out_stream = stderr_file.outStream();73 stderr_file_out_stream = stderr_file.outStream();
74 const st = &stderr_file_out_stream.stream;74 const st = &stderr_file_out_stream;
75 stderr_stream = st;75 stderr_stream = st;
76 return st;76 return st;
77 }77 }
...@@ -408,15 +408,15 @@ pub const TTY = struct {...@@ -408,15 +408,15 @@ pub const TTY = struct {
408 windows_api,408 windows_api,
409409
410 fn setColor(conf: Config, out_stream: var, color: Color) void {410 fn setColor(conf: Config, out_stream: var, color: Color) void {
411 switch (conf) {411 noasync switch (conf) {
412 .no_color => return,412 .no_color => return,
413 .escape_codes => switch (color) {413 .escape_codes => switch (color) {
414 .Red => noasync out_stream.write(RED) catch return,414 .Red => out_stream.writeAll(RED) catch return,
415 .Green => noasync out_stream.write(GREEN) catch return,415 .Green => out_stream.writeAll(GREEN) catch return,
416 .Cyan => noasync out_stream.write(CYAN) catch return,416 .Cyan => out_stream.writeAll(CYAN) catch return,
417 .White, .Bold => noasync out_stream.write(WHITE) catch return,417 .White, .Bold => out_stream.writeAll(WHITE) catch return,
418 .Dim => noasync out_stream.write(DIM) catch return,418 .Dim => out_stream.writeAll(DIM) catch return,
419 .Reset => noasync out_stream.write(RESET) catch return,419 .Reset => out_stream.writeAll(RESET) catch return,
420 },420 },
421 .windows_api => if (builtin.os.tag == .windows) {421 .windows_api => if (builtin.os.tag == .windows) {
422 const S = struct {422 const S = struct {
...@@ -455,7 +455,7 @@ pub const TTY = struct {...@@ -455,7 +455,7 @@ pub const TTY = struct {
455 } else {455 } else {
456 unreachable;456 unreachable;
457 },457 },
458 }458 };
459 }459 }
460 };460 };
461};461};
...@@ -565,38 +565,40 @@ fn printLineInfo(...@@ -565,38 +565,40 @@ fn printLineInfo(
565 tty_config: TTY.Config,565 tty_config: TTY.Config,
566 comptime printLineFromFile: var,566 comptime printLineFromFile: var,
567) !void {567) !void {
568 tty_config.setColor(out_stream, .White);568 noasync {
569 tty_config.setColor(out_stream, .White);
569570
570 if (line_info) |*li| {571 if (line_info) |*li| {
571 try noasync out_stream.print("{}:{}:{}", .{ li.file_name, li.line, li.column });572 try out_stream.print("{}:{}:{}", .{ li.file_name, li.line, li.column });
572 } else {573 } else {
573 try noasync out_stream.write("???:?:?");574 try out_stream.writeAll("???:?:?");
574 }575 }
575576
576 tty_config.setColor(out_stream, .Reset);577 tty_config.setColor(out_stream, .Reset);
577 try noasync out_stream.write(": ");578 try out_stream.writeAll(": ");
578 tty_config.setColor(out_stream, .Dim);579 tty_config.setColor(out_stream, .Dim);
579 try noasync out_stream.print("0x{x} in {} ({})", .{ address, symbol_name, compile_unit_name });580 try out_stream.print("0x{x} in {} ({})", .{ address, symbol_name, compile_unit_name });
580 tty_config.setColor(out_stream, .Reset);581 tty_config.setColor(out_stream, .Reset);
581 try noasync out_stream.write("\n");582 try out_stream.writeAll("\n");
582583
583 // Show the matching source code line if possible584 // Show the matching source code line if possible
584 if (line_info) |li| {585 if (line_info) |li| {
585 if (noasync printLineFromFile(out_stream, li)) {586 if (printLineFromFile(out_stream, li)) {
586 if (li.column > 0) {587 if (li.column > 0) {
587 // The caret already takes one char588 // The caret already takes one char
588 const space_needed = @intCast(usize, li.column - 1);589 const space_needed = @intCast(usize, li.column - 1);
589590
590 try noasync out_stream.writeByteNTimes(' ', space_needed);591 try out_stream.writeByteNTimes(' ', space_needed);
591 tty_config.setColor(out_stream, .Green);592 tty_config.setColor(out_stream, .Green);
592 try noasync out_stream.write("^");593 try out_stream.writeAll("^");
593 tty_config.setColor(out_stream, .Reset);594 tty_config.setColor(out_stream, .Reset);
595 }
596 try out_stream.writeAll("\n");
597 } else |err| switch (err) {
598 error.EndOfFile, error.FileNotFound => {},
599 error.BadPathName => {},
600 else => return err,
594 }601 }
595 try noasync out_stream.write("\n");
596 } else |err| switch (err) {
597 error.EndOfFile, error.FileNotFound => {},
598 error.BadPathName => {},
599 else => return err,
600 }602 }
601 }603 }
602}604}
...@@ -609,21 +611,21 @@ pub const OpenSelfDebugInfoError = error{...@@ -609,21 +611,21 @@ pub const OpenSelfDebugInfoError = error{
609};611};
610612
611/// TODO resources https://github.com/ziglang/zig/issues/4353613/// TODO resources https://github.com/ziglang/zig/issues/4353
612/// TODO once https://github.com/ziglang/zig/issues/3157 is fully implemented,
613/// make this `noasync fn` and remove the individual noasync calls.
614pub fn openSelfDebugInfo(allocator: *mem.Allocator) anyerror!DebugInfo {614pub fn openSelfDebugInfo(allocator: *mem.Allocator) anyerror!DebugInfo {
615 if (builtin.strip_debug_info)615 noasync {
616 return error.MissingDebugInfo;616 if (builtin.strip_debug_info)
617 if (@hasDecl(root, "os") and @hasDecl(root.os, "debug") and @hasDecl(root.os.debug, "openSelfDebugInfo")) {617 return error.MissingDebugInfo;
618 return noasync root.os.debug.openSelfDebugInfo(allocator);618 if (@hasDecl(root, "os") and @hasDecl(root.os, "debug") and @hasDecl(root.os.debug, "openSelfDebugInfo")) {
619 }619 return root.os.debug.openSelfDebugInfo(allocator);
620 switch (builtin.os.tag) {620 }
621 .linux,621 switch (builtin.os.tag) {
622 .freebsd,622 .linux,
623 .macosx,623 .freebsd,
624 .windows,624 .macosx,
625 => return DebugInfo.init(allocator),625 .windows,
626 else => @compileError("openSelfDebugInfo unsupported for this platform"),626 => return DebugInfo.init(allocator),
627 else => @compileError("openSelfDebugInfo unsupported for this platform"),
628 }
627 }629 }
628}630}
629631
...@@ -808,45 +810,64 @@ fn chopSlice(ptr: []const u8, offset: u64, size: u64) ![]const u8 {...@@ -808,45 +810,64 @@ fn chopSlice(ptr: []const u8, offset: u64, size: u64) ![]const u8 {
808810
809/// TODO resources https://github.com/ziglang/zig/issues/4353811/// TODO resources https://github.com/ziglang/zig/issues/4353
810pub fn openElfDebugInfo(allocator: *mem.Allocator, elf_file_path: []const u8) !ModuleDebugInfo {812pub fn openElfDebugInfo(allocator: *mem.Allocator, elf_file_path: []const u8) !ModuleDebugInfo {
811 const mapped_mem = try mapWholeFile(elf_file_path);813 noasync {
812814 const mapped_mem = try mapWholeFile(elf_file_path);
813 var seekable_stream = io.SliceSeekableInStream.init(mapped_mem);815 const hdr = @ptrCast(*const elf.Ehdr, &mapped_mem[0]);
814 var efile = try noasync elf.Elf.openStream(816 if (!mem.eql(u8, hdr.e_ident[0..4], "\x7fELF")) return error.InvalidElfMagic;
815 allocator,817 if (hdr.e_ident[elf.EI_VERSION] != 1) return error.InvalidElfVersion;
816 @ptrCast(*DW.DwarfSeekableStream, &seekable_stream.seekable_stream),818
817 @ptrCast(*DW.DwarfInStream, &seekable_stream.stream),819 const endian: builtin.Endian = switch (hdr.e_ident[elf.EI_DATA]) {
818 );820 elf.ELFDATA2LSB => .Little,
819 defer noasync efile.close();821 elf.ELFDATA2MSB => .Big,
822 else => return error.InvalidElfEndian,
823 };
824 assert(endian == std.builtin.endian); // this is our own debug info
825
826 const shoff = hdr.e_shoff;
827 const str_section_off = shoff + @as(u64, hdr.e_shentsize) * @as(u64, hdr.e_shstrndx);
828 const header_strings = mapped_mem[str_section_off..str_section_off + hdr.e_shentsize];
829 const shdrs = @ptrCast([*]const elf.Shdr, @alignCast(@alignOf(elf.Shdr), &mapped_mem[shoff]))[0..hdr.e_shnum];
830
831 var opt_debug_info: ?[]const u8 = null;
832 var opt_debug_abbrev: ?[]const u8 = null;
833 var opt_debug_str: ?[]const u8 = null;
834 var opt_debug_line: ?[]const u8 = null;
835 var opt_debug_ranges: ?[]const u8 = null;
836
837 for (shdrs) |*shdr| {
838 if (shdr.sh_type == elf.SHT_NULL) continue;
839
840 const name = std.mem.span(@ptrCast([*:0]const u8, header_strings[shdr.sh_name..].ptr));
841 if (mem.eql(u8, name, ".debug_info")) {
842 opt_debug_info = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);
843 } else if (mem.eql(u8, name, ".debug_abbrev")) {
844 opt_debug_abbrev = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);
845 } else if (mem.eql(u8, name, ".debug_str")) {
846 opt_debug_str = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);
847 } else if (mem.eql(u8, name, ".debug_line")) {
848 opt_debug_line = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);
849 } else if (mem.eql(u8, name, ".debug_ranges")) {
850 opt_debug_ranges = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);
851 }
852 }
820853
821 const debug_info = (try noasync efile.findSection(".debug_info")) orelse854 var di = DW.DwarfInfo{
822 return error.MissingDebugInfo;855 .endian = endian,
823 const debug_abbrev = (try noasync efile.findSection(".debug_abbrev")) orelse856 .debug_info = opt_debug_info orelse return error.MissingDebugInfo,
824 return error.MissingDebugInfo;857 .debug_abbrev = opt_debug_abbrev orelse return error.MissingDebugInfo,
825 const debug_str = (try noasync efile.findSection(".debug_str")) orelse858 .debug_str = opt_debug_str orelse return error.MissingDebugInfo,
826 return error.MissingDebugInfo;859 .debug_line = opt_debug_line orelse return error.MissingDebugInfo,
827 const debug_line = (try noasync efile.findSection(".debug_line")) orelse860 .debug_ranges = opt_debug_ranges,
828 return error.MissingDebugInfo;861 };
829 const opt_debug_ranges = try noasync efile.findSection(".debug_ranges");
830
831 var di = DW.DwarfInfo{
832 .endian = efile.endian,
833 .debug_info = try chopSlice(mapped_mem, debug_info.sh_offset, debug_info.sh_size),
834 .debug_abbrev = try chopSlice(mapped_mem, debug_abbrev.sh_offset, debug_abbrev.sh_size),
835 .debug_str = try chopSlice(mapped_mem, debug_str.sh_offset, debug_str.sh_size),
836 .debug_line = try chopSlice(mapped_mem, debug_line.sh_offset, debug_line.sh_size),
837 .debug_ranges = if (opt_debug_ranges) |debug_ranges|
838 try chopSlice(mapped_mem, debug_ranges.sh_offset, debug_ranges.sh_size)
839 else
840 null,
841 };
842862
843 try noasync DW.openDwarfDebugInfo(&di, allocator);863 try DW.openDwarfDebugInfo(&di, allocator);
844864
845 return ModuleDebugInfo{865 return ModuleDebugInfo{
846 .base_address = undefined,866 .base_address = undefined,
847 .dwarf = di,867 .dwarf = di,
848 .mapped_memory = mapped_mem,868 .mapped_memory = mapped_mem,
849 };869 };
870 }
850}871}
851872
852/// TODO resources https://github.com/ziglang/zig/issues/4353873/// TODO resources https://github.com/ziglang/zig/issues/4353
...@@ -982,22 +1003,24 @@ const MachoSymbol = struct {...@@ -982,22 +1003,24 @@ const MachoSymbol = struct {
982 }1003 }
983};1004};
9841005
985fn mapWholeFile(path: []const u8) ![]const u8 {1006fn mapWholeFile(path: []const u8) ![]align(mem.page_size) const u8 {
986 const file = try noasync fs.openFileAbsolute(path, .{ .always_blocking = true });1007 noasync {
987 defer noasync file.close();1008 const file = try fs.openFileAbsolute(path, .{ .always_blocking = true });
9881009 defer file.close();
989 const file_len = try math.cast(usize, try file.getEndPos());
990 const mapped_mem = try os.mmap(
991 null,
992 file_len,
993 os.PROT_READ,
994 os.MAP_SHARED,
995 file.handle,
996 0,
997 );
998 errdefer os.munmap(mapped_mem);
9991010
1000 return mapped_mem;1011 const file_len = try math.cast(usize, try file.getEndPos());
1012 const mapped_mem = try os.mmap(
1013 null,
1014 file_len,
1015 os.PROT_READ,
1016 os.MAP_SHARED,
1017 file.handle,
1018 0,
1019 );
1020 errdefer os.munmap(mapped_mem);
1021
1022 return mapped_mem;
1023 }
1001}1024}
10021025
1003pub const DebugInfo = struct {1026pub const DebugInfo = struct {
lib/std/dwarf.zig+84-77
...@@ -11,9 +11,6 @@ const ArrayList = std.ArrayList;...@@ -11,9 +11,6 @@ const ArrayList = std.ArrayList;
1111
12usingnamespace @import("dwarf_bits.zig");12usingnamespace @import("dwarf_bits.zig");
1313
14pub const DwarfSeekableStream = io.SeekableStream(anyerror, anyerror);
15pub const DwarfInStream = io.InStream(anyerror);
16
17const PcRange = struct {14const PcRange = struct {
18 start: u64,15 start: u64,
19 end: u64,16 end: u64,
...@@ -239,7 +236,7 @@ const LineNumberProgram = struct {...@@ -239,7 +236,7 @@ const LineNumberProgram = struct {
239 }236 }
240};237};
241238
242fn readInitialLength(comptime E: type, in_stream: *io.InStream(E), is_64: *bool) !u64 {239fn readInitialLength(in_stream: var, is_64: *bool) !u64 {
243 const first_32_bits = try in_stream.readIntLittle(u32);240 const first_32_bits = try in_stream.readIntLittle(u32);
244 is_64.* = (first_32_bits == 0xffffffff);241 is_64.* = (first_32_bits == 0xffffffff);
245 if (is_64.*) {242 if (is_64.*) {
...@@ -414,40 +411,42 @@ pub const DwarfInfo = struct {...@@ -414,40 +411,42 @@ pub const DwarfInfo = struct {
414 }411 }
415412
416 fn scanAllFunctions(di: *DwarfInfo) !void {413 fn scanAllFunctions(di: *DwarfInfo) !void {
417 var s = io.SliceSeekableInStream.init(di.debug_info);414 var stream = io.fixedBufferStream(di.debug_info);
415 const in = &stream.inStream();
416 const seekable = &stream.seekableStream();
418 var this_unit_offset: u64 = 0;417 var this_unit_offset: u64 = 0;
419418
420 while (this_unit_offset < try s.seekable_stream.getEndPos()) {419 while (this_unit_offset < try seekable.getEndPos()) {
421 s.seekable_stream.seekTo(this_unit_offset) catch |err| switch (err) {420 seekable.seekTo(this_unit_offset) catch |err| switch (err) {
422 error.EndOfStream => unreachable,421 error.EndOfStream => unreachable,
423 else => return err,422 else => return err,
424 };423 };
425424
426 var is_64: bool = undefined;425 var is_64: bool = undefined;
427 const unit_length = try readInitialLength(@TypeOf(s.stream.readFn).ReturnType.ErrorSet, &s.stream, &is_64);426 const unit_length = try readInitialLength(in, &is_64);
428 if (unit_length == 0) return;427 if (unit_length == 0) return;
429 const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));428 const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));
430429
431 const version = try s.stream.readInt(u16, di.endian);430 const version = try in.readInt(u16, di.endian);
432 if (version < 2 or version > 5) return error.InvalidDebugInfo;431 if (version < 2 or version > 5) return error.InvalidDebugInfo;
433432
434 const debug_abbrev_offset = if (is_64) try s.stream.readInt(u64, di.endian) else try s.stream.readInt(u32, di.endian);433 const debug_abbrev_offset = if (is_64) try in.readInt(u64, di.endian) else try in.readInt(u32, di.endian);
435434
436 const address_size = try s.stream.readByte();435 const address_size = try in.readByte();
437 if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;436 if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
438437
439 const compile_unit_pos = try s.seekable_stream.getPos();438 const compile_unit_pos = try seekable.getPos();
440 const abbrev_table = try di.getAbbrevTable(debug_abbrev_offset);439 const abbrev_table = try di.getAbbrevTable(debug_abbrev_offset);
441440
442 try s.seekable_stream.seekTo(compile_unit_pos);441 try seekable.seekTo(compile_unit_pos);
443442
444 const next_unit_pos = this_unit_offset + next_offset;443 const next_unit_pos = this_unit_offset + next_offset;
445444
446 while ((try s.seekable_stream.getPos()) < next_unit_pos) {445 while ((try seekable.getPos()) < next_unit_pos) {
447 const die_obj = (try di.parseDie(&s.stream, abbrev_table, is_64)) orelse continue;446 const die_obj = (try di.parseDie(in, abbrev_table, is_64)) orelse continue;
448 defer die_obj.attrs.deinit();447 defer die_obj.attrs.deinit();
449448
450 const after_die_offset = try s.seekable_stream.getPos();449 const after_die_offset = try seekable.getPos();
451450
452 switch (die_obj.tag_id) {451 switch (die_obj.tag_id) {
453 TAG_subprogram, TAG_inlined_subroutine, TAG_subroutine, TAG_entry_point => {452 TAG_subprogram, TAG_inlined_subroutine, TAG_subroutine, TAG_entry_point => {
...@@ -463,14 +462,14 @@ pub const DwarfInfo = struct {...@@ -463,14 +462,14 @@ pub const DwarfInfo = struct {
463 // Follow the DIE it points to and repeat462 // Follow the DIE it points to and repeat
464 const ref_offset = try this_die_obj.getAttrRef(AT_abstract_origin);463 const ref_offset = try this_die_obj.getAttrRef(AT_abstract_origin);
465 if (ref_offset > next_offset) return error.InvalidDebugInfo;464 if (ref_offset > next_offset) return error.InvalidDebugInfo;
466 try s.seekable_stream.seekTo(this_unit_offset + ref_offset);465 try seekable.seekTo(this_unit_offset + ref_offset);
467 this_die_obj = (try di.parseDie(&s.stream, abbrev_table, is_64)) orelse return error.InvalidDebugInfo;466 this_die_obj = (try di.parseDie(in, abbrev_table, is_64)) orelse return error.InvalidDebugInfo;
468 } else if (this_die_obj.getAttr(AT_specification)) |ref| {467 } else if (this_die_obj.getAttr(AT_specification)) |ref| {
469 // Follow the DIE it points to and repeat468 // Follow the DIE it points to and repeat
470 const ref_offset = try this_die_obj.getAttrRef(AT_specification);469 const ref_offset = try this_die_obj.getAttrRef(AT_specification);
471 if (ref_offset > next_offset) return error.InvalidDebugInfo;470 if (ref_offset > next_offset) return error.InvalidDebugInfo;
472 try s.seekable_stream.seekTo(this_unit_offset + ref_offset);471 try seekable.seekTo(this_unit_offset + ref_offset);
473 this_die_obj = (try di.parseDie(&s.stream, abbrev_table, is_64)) orelse return error.InvalidDebugInfo;472 this_die_obj = (try di.parseDie(in, abbrev_table, is_64)) orelse return error.InvalidDebugInfo;
474 } else {473 } else {
475 break :x null;474 break :x null;
476 }475 }
...@@ -511,7 +510,7 @@ pub const DwarfInfo = struct {...@@ -511,7 +510,7 @@ pub const DwarfInfo = struct {
511 else => {},510 else => {},
512 }511 }
513512
514 try s.seekable_stream.seekTo(after_die_offset);513 try seekable.seekTo(after_die_offset);
515 }514 }
516515
517 this_unit_offset += next_offset;516 this_unit_offset += next_offset;
...@@ -519,35 +518,37 @@ pub const DwarfInfo = struct {...@@ -519,35 +518,37 @@ pub const DwarfInfo = struct {
519 }518 }
520519
521 fn scanAllCompileUnits(di: *DwarfInfo) !void {520 fn scanAllCompileUnits(di: *DwarfInfo) !void {
522 var s = io.SliceSeekableInStream.init(di.debug_info);521 var stream = io.fixedBufferStream(di.debug_info);
522 const in = &stream.inStream();
523 const seekable = &stream.seekableStream();
523 var this_unit_offset: u64 = 0;524 var this_unit_offset: u64 = 0;
524525
525 while (this_unit_offset < try s.seekable_stream.getEndPos()) {526 while (this_unit_offset < try seekable.getEndPos()) {
526 s.seekable_stream.seekTo(this_unit_offset) catch |err| switch (err) {527 seekable.seekTo(this_unit_offset) catch |err| switch (err) {
527 error.EndOfStream => unreachable,528 error.EndOfStream => unreachable,
528 else => return err,529 else => return err,
529 };530 };
530531
531 var is_64: bool = undefined;532 var is_64: bool = undefined;
532 const unit_length = try readInitialLength(@TypeOf(s.stream.readFn).ReturnType.ErrorSet, &s.stream, &is_64);533 const unit_length = try readInitialLength(in, &is_64);
533 if (unit_length == 0) return;534 if (unit_length == 0) return;
534 const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));535 const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));
535536
536 const version = try s.stream.readInt(u16, di.endian);537 const version = try in.readInt(u16, di.endian);
537 if (version < 2 or version > 5) return error.InvalidDebugInfo;538 if (version < 2 or version > 5) return error.InvalidDebugInfo;
538539
539 const debug_abbrev_offset = if (is_64) try s.stream.readInt(u64, di.endian) else try s.stream.readInt(u32, di.endian);540 const debug_abbrev_offset = if (is_64) try in.readInt(u64, di.endian) else try in.readInt(u32, di.endian);
540541
541 const address_size = try s.stream.readByte();542 const address_size = try in.readByte();
542 if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;543 if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
543544
544 const compile_unit_pos = try s.seekable_stream.getPos();545 const compile_unit_pos = try seekable.getPos();
545 const abbrev_table = try di.getAbbrevTable(debug_abbrev_offset);546 const abbrev_table = try di.getAbbrevTable(debug_abbrev_offset);
546547
547 try s.seekable_stream.seekTo(compile_unit_pos);548 try seekable.seekTo(compile_unit_pos);
548549
549 const compile_unit_die = try di.allocator().create(Die);550 const compile_unit_die = try di.allocator().create(Die);
550 compile_unit_die.* = (try di.parseDie(&s.stream, abbrev_table, is_64)) orelse return error.InvalidDebugInfo;551 compile_unit_die.* = (try di.parseDie(in, abbrev_table, is_64)) orelse return error.InvalidDebugInfo;
551552
552 if (compile_unit_die.tag_id != TAG_compile_unit) return error.InvalidDebugInfo;553 if (compile_unit_die.tag_id != TAG_compile_unit) return error.InvalidDebugInfo;
553554
...@@ -593,7 +594,9 @@ pub const DwarfInfo = struct {...@@ -593,7 +594,9 @@ pub const DwarfInfo = struct {
593 }594 }
594 if (di.debug_ranges) |debug_ranges| {595 if (di.debug_ranges) |debug_ranges| {
595 if (compile_unit.die.getAttrSecOffset(AT_ranges)) |ranges_offset| {596 if (compile_unit.die.getAttrSecOffset(AT_ranges)) |ranges_offset| {
596 var s = io.SliceSeekableInStream.init(debug_ranges);597 var stream = io.fixedBufferStream(debug_ranges);
598 const in = &stream.inStream();
599 const seekable = &stream.seekableStream();
597600
598 // All the addresses in the list are relative to the value601 // All the addresses in the list are relative to the value
599 // specified by DW_AT_low_pc or to some other value encoded602 // specified by DW_AT_low_pc or to some other value encoded
...@@ -604,11 +607,11 @@ pub const DwarfInfo = struct {...@@ -604,11 +607,11 @@ pub const DwarfInfo = struct {
604 else => return err,607 else => return err,
605 };608 };
606609
607 try s.seekable_stream.seekTo(ranges_offset);610 try seekable.seekTo(ranges_offset);
608611
609 while (true) {612 while (true) {
610 const begin_addr = try s.stream.readIntLittle(usize);613 const begin_addr = try in.readIntLittle(usize);
611 const end_addr = try s.stream.readIntLittle(usize);614 const end_addr = try in.readIntLittle(usize);
612 if (begin_addr == 0 and end_addr == 0) {615 if (begin_addr == 0 and end_addr == 0) {
613 break;616 break;
614 }617 }
...@@ -646,25 +649,27 @@ pub const DwarfInfo = struct {...@@ -646,25 +649,27 @@ pub const DwarfInfo = struct {
646 }649 }
647650
648 fn parseAbbrevTable(di: *DwarfInfo, offset: u64) !AbbrevTable {651 fn parseAbbrevTable(di: *DwarfInfo, offset: u64) !AbbrevTable {
649 var s = io.SliceSeekableInStream.init(di.debug_abbrev);652 var stream = io.fixedBufferStream(di.debug_abbrev);
653 const in = &stream.inStream();
654 const seekable = &stream.seekableStream();
650655
651 try s.seekable_stream.seekTo(offset);656 try seekable.seekTo(offset);
652 var result = AbbrevTable.init(di.allocator());657 var result = AbbrevTable.init(di.allocator());
653 errdefer result.deinit();658 errdefer result.deinit();
654 while (true) {659 while (true) {
655 const abbrev_code = try leb.readULEB128(u64, &s.stream);660 const abbrev_code = try leb.readULEB128(u64, in);
656 if (abbrev_code == 0) return result;661 if (abbrev_code == 0) return result;
657 try result.append(AbbrevTableEntry{662 try result.append(AbbrevTableEntry{
658 .abbrev_code = abbrev_code,663 .abbrev_code = abbrev_code,
659 .tag_id = try leb.readULEB128(u64, &s.stream),664 .tag_id = try leb.readULEB128(u64, in),
660 .has_children = (try s.stream.readByte()) == CHILDREN_yes,665 .has_children = (try in.readByte()) == CHILDREN_yes,
661 .attrs = ArrayList(AbbrevAttr).init(di.allocator()),666 .attrs = ArrayList(AbbrevAttr).init(di.allocator()),
662 });667 });
663 const attrs = &result.items[result.len - 1].attrs;668 const attrs = &result.items[result.len - 1].attrs;
664669
665 while (true) {670 while (true) {
666 const attr_id = try leb.readULEB128(u64, &s.stream);671 const attr_id = try leb.readULEB128(u64, in);
667 const form_id = try leb.readULEB128(u64, &s.stream);672 const form_id = try leb.readULEB128(u64, in);
668 if (attr_id == 0 and form_id == 0) break;673 if (attr_id == 0 and form_id == 0) break;
669 try attrs.append(AbbrevAttr{674 try attrs.append(AbbrevAttr{
670 .attr_id = attr_id,675 .attr_id = attr_id,
...@@ -695,42 +700,44 @@ pub const DwarfInfo = struct {...@@ -695,42 +700,44 @@ pub const DwarfInfo = struct {
695 }700 }
696701
697 fn getLineNumberInfo(di: *DwarfInfo, compile_unit: CompileUnit, target_address: usize) !debug.LineInfo {702 fn getLineNumberInfo(di: *DwarfInfo, compile_unit: CompileUnit, target_address: usize) !debug.LineInfo {
698 var s = io.SliceSeekableInStream.init(di.debug_line);703 var stream = io.fixedBufferStream(di.debug_line);
704 const in = &stream.inStream();
705 const seekable = &stream.seekableStream();
699706
700 const compile_unit_cwd = try compile_unit.die.getAttrString(di, AT_comp_dir);707 const compile_unit_cwd = try compile_unit.die.getAttrString(di, AT_comp_dir);
701 const line_info_offset = try compile_unit.die.getAttrSecOffset(AT_stmt_list);708 const line_info_offset = try compile_unit.die.getAttrSecOffset(AT_stmt_list);
702709
703 try s.seekable_stream.seekTo(line_info_offset);710 try seekable.seekTo(line_info_offset);
704711
705 var is_64: bool = undefined;712 var is_64: bool = undefined;
706 const unit_length = try readInitialLength(@TypeOf(s.stream.readFn).ReturnType.ErrorSet, &s.stream, &is_64);713 const unit_length = try readInitialLength(in, &is_64);
707 if (unit_length == 0) {714 if (unit_length == 0) {
708 return error.MissingDebugInfo;715 return error.MissingDebugInfo;
709 }716 }
710 const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));717 const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));
711718
712 const version = try s.stream.readInt(u16, di.endian);719 const version = try in.readInt(u16, di.endian);
713 // TODO support 3 and 5720 // TODO support 3 and 5
714 if (version != 2 and version != 4) return error.InvalidDebugInfo;721 if (version != 2 and version != 4) return error.InvalidDebugInfo;
715722
716 const prologue_length = if (is_64) try s.stream.readInt(u64, di.endian) else try s.stream.readInt(u32, di.endian);723 const prologue_length = if (is_64) try in.readInt(u64, di.endian) else try in.readInt(u32, di.endian);
717 const prog_start_offset = (try s.seekable_stream.getPos()) + prologue_length;724 const prog_start_offset = (try seekable.getPos()) + prologue_length;
718725
719 const minimum_instruction_length = try s.stream.readByte();726 const minimum_instruction_length = try in.readByte();
720 if (minimum_instruction_length == 0) return error.InvalidDebugInfo;727 if (minimum_instruction_length == 0) return error.InvalidDebugInfo;
721728
722 if (version >= 4) {729 if (version >= 4) {
723 // maximum_operations_per_instruction730 // maximum_operations_per_instruction
724 _ = try s.stream.readByte();731 _ = try in.readByte();
725 }732 }
726733
727 const default_is_stmt = (try s.stream.readByte()) != 0;734 const default_is_stmt = (try in.readByte()) != 0;
728 const line_base = try s.stream.readByteSigned();735 const line_base = try in.readByteSigned();
729736
730 const line_range = try s.stream.readByte();737 const line_range = try in.readByte();
731 if (line_range == 0) return error.InvalidDebugInfo;738 if (line_range == 0) return error.InvalidDebugInfo;
732739
733 const opcode_base = try s.stream.readByte();740 const opcode_base = try in.readByte();
734741
735 const standard_opcode_lengths = try di.allocator().alloc(u8, opcode_base - 1);742 const standard_opcode_lengths = try di.allocator().alloc(u8, opcode_base - 1);
736 defer di.allocator().free(standard_opcode_lengths);743 defer di.allocator().free(standard_opcode_lengths);
...@@ -738,14 +745,14 @@ pub const DwarfInfo = struct {...@@ -738,14 +745,14 @@ pub const DwarfInfo = struct {
738 {745 {
739 var i: usize = 0;746 var i: usize = 0;
740 while (i < opcode_base - 1) : (i += 1) {747 while (i < opcode_base - 1) : (i += 1) {
741 standard_opcode_lengths[i] = try s.stream.readByte();748 standard_opcode_lengths[i] = try in.readByte();
742 }749 }
743 }750 }
744751
745 var include_directories = ArrayList([]const u8).init(di.allocator());752 var include_directories = ArrayList([]const u8).init(di.allocator());
746 try include_directories.append(compile_unit_cwd);753 try include_directories.append(compile_unit_cwd);
747 while (true) {754 while (true) {
748 const dir = try s.stream.readUntilDelimiterAlloc(di.allocator(), 0, math.maxInt(usize));755 const dir = try in.readUntilDelimiterAlloc(di.allocator(), 0, math.maxInt(usize));
749 if (dir.len == 0) break;756 if (dir.len == 0) break;
750 try include_directories.append(dir);757 try include_directories.append(dir);
751 }758 }
...@@ -754,11 +761,11 @@ pub const DwarfInfo = struct {...@@ -754,11 +761,11 @@ pub const DwarfInfo = struct {
754 var prog = LineNumberProgram.init(default_is_stmt, include_directories.toSliceConst(), &file_entries, target_address);761 var prog = LineNumberProgram.init(default_is_stmt, include_directories.toSliceConst(), &file_entries, target_address);
755762
756 while (true) {763 while (true) {
757 const file_name = try s.stream.readUntilDelimiterAlloc(di.allocator(), 0, math.maxInt(usize));764 const file_name = try in.readUntilDelimiterAlloc(di.allocator(), 0, math.maxInt(usize));
758 if (file_name.len == 0) break;765 if (file_name.len == 0) break;
759 const dir_index = try leb.readULEB128(usize, &s.stream);766 const dir_index = try leb.readULEB128(usize, in);
760 const mtime = try leb.readULEB128(usize, &s.stream);767 const mtime = try leb.readULEB128(usize, in);
761 const len_bytes = try leb.readULEB128(usize, &s.stream);768 const len_bytes = try leb.readULEB128(usize, in);
762 try file_entries.append(FileEntry{769 try file_entries.append(FileEntry{
763 .file_name = file_name,770 .file_name = file_name,
764 .dir_index = dir_index,771 .dir_index = dir_index,
...@@ -767,17 +774,17 @@ pub const DwarfInfo = struct {...@@ -767,17 +774,17 @@ pub const DwarfInfo = struct {
767 });774 });
768 }775 }
769776
770 try s.seekable_stream.seekTo(prog_start_offset);777 try seekable.seekTo(prog_start_offset);
771778
772 const next_unit_pos = line_info_offset + next_offset;779 const next_unit_pos = line_info_offset + next_offset;
773780
774 while ((try s.seekable_stream.getPos()) < next_unit_pos) {781 while ((try seekable.getPos()) < next_unit_pos) {
775 const opcode = try s.stream.readByte();782 const opcode = try in.readByte();
776783
777 if (opcode == LNS_extended_op) {784 if (opcode == LNS_extended_op) {
778 const op_size = try leb.readULEB128(u64, &s.stream);785 const op_size = try leb.readULEB128(u64, in);
779 if (op_size < 1) return error.InvalidDebugInfo;786 if (op_size < 1) return error.InvalidDebugInfo;
780 var sub_op = try s.stream.readByte();787 var sub_op = try in.readByte();
781 switch (sub_op) {788 switch (sub_op) {
782 LNE_end_sequence => {789 LNE_end_sequence => {
783 prog.end_sequence = true;790 prog.end_sequence = true;
...@@ -785,14 +792,14 @@ pub const DwarfInfo = struct {...@@ -785,14 +792,14 @@ pub const DwarfInfo = struct {
785 prog.reset();792 prog.reset();
786 },793 },
787 LNE_set_address => {794 LNE_set_address => {
788 const addr = try s.stream.readInt(usize, di.endian);795 const addr = try in.readInt(usize, di.endian);
789 prog.address = addr;796 prog.address = addr;
790 },797 },
791 LNE_define_file => {798 LNE_define_file => {
792 const file_name = try s.stream.readUntilDelimiterAlloc(di.allocator(), 0, math.maxInt(usize));799 const file_name = try in.readUntilDelimiterAlloc(di.allocator(), 0, math.maxInt(usize));
793 const dir_index = try leb.readULEB128(usize, &s.stream);800 const dir_index = try leb.readULEB128(usize, in);
794 const mtime = try leb.readULEB128(usize, &s.stream);801 const mtime = try leb.readULEB128(usize, in);
795 const len_bytes = try leb.readULEB128(usize, &s.stream);802 const len_bytes = try leb.readULEB128(usize, in);
796 try file_entries.append(FileEntry{803 try file_entries.append(FileEntry{
797 .file_name = file_name,804 .file_name = file_name,
798 .dir_index = dir_index,805 .dir_index = dir_index,
...@@ -802,7 +809,7 @@ pub const DwarfInfo = struct {...@@ -802,7 +809,7 @@ pub const DwarfInfo = struct {
802 },809 },
803 else => {810 else => {
804 const fwd_amt = math.cast(isize, op_size - 1) catch return error.InvalidDebugInfo;811 const fwd_amt = math.cast(isize, op_size - 1) catch return error.InvalidDebugInfo;
805 try s.seekable_stream.seekBy(fwd_amt);812 try seekable.seekBy(fwd_amt);
806 },813 },
807 }814 }
808 } else if (opcode >= opcode_base) {815 } else if (opcode >= opcode_base) {
...@@ -821,19 +828,19 @@ pub const DwarfInfo = struct {...@@ -821,19 +828,19 @@ pub const DwarfInfo = struct {
821 prog.basic_block = false;828 prog.basic_block = false;
822 },829 },
823 LNS_advance_pc => {830 LNS_advance_pc => {
824 const arg = try leb.readULEB128(usize, &s.stream);831 const arg = try leb.readULEB128(usize, in);
825 prog.address += arg * minimum_instruction_length;832 prog.address += arg * minimum_instruction_length;
826 },833 },
827 LNS_advance_line => {834 LNS_advance_line => {
828 const arg = try leb.readILEB128(i64, &s.stream);835 const arg = try leb.readILEB128(i64, in);
829 prog.line += arg;836 prog.line += arg;
830 },837 },
831 LNS_set_file => {838 LNS_set_file => {
832 const arg = try leb.readULEB128(usize, &s.stream);839 const arg = try leb.readULEB128(usize, in);
833 prog.file = arg;840 prog.file = arg;
834 },841 },
835 LNS_set_column => {842 LNS_set_column => {
836 const arg = try leb.readULEB128(u64, &s.stream);843 const arg = try leb.readULEB128(u64, in);
837 prog.column = arg;844 prog.column = arg;
838 },845 },
839 LNS_negate_stmt => {846 LNS_negate_stmt => {
...@@ -847,14 +854,14 @@ pub const DwarfInfo = struct {...@@ -847,14 +854,14 @@ pub const DwarfInfo = struct {
847 prog.address += inc_addr;854 prog.address += inc_addr;
848 },855 },
849 LNS_fixed_advance_pc => {856 LNS_fixed_advance_pc => {
850 const arg = try s.stream.readInt(u16, di.endian);857 const arg = try in.readInt(u16, di.endian);
851 prog.address += arg;858 prog.address += arg;
852 },859 },
853 LNS_set_prologue_end => {},860 LNS_set_prologue_end => {},
854 else => {861 else => {
855 if (opcode - 1 >= standard_opcode_lengths.len) return error.InvalidDebugInfo;862 if (opcode - 1 >= standard_opcode_lengths.len) return error.InvalidDebugInfo;
856 const len_bytes = standard_opcode_lengths[opcode - 1];863 const len_bytes = standard_opcode_lengths[opcode - 1];
857 try s.seekable_stream.seekBy(len_bytes);864 try seekable.seekBy(len_bytes);
858 },865 },
859 }866 }
860 }867 }
lib/std/elf.zig+48
...@@ -333,6 +333,54 @@ pub const ET = extern enum(u16) {...@@ -333,6 +333,54 @@ pub const ET = extern enum(u16) {
333pub const SectionHeader = Elf64_Shdr;333pub const SectionHeader = Elf64_Shdr;
334pub const ProgramHeader = Elf64_Phdr;334pub const ProgramHeader = Elf64_Phdr;
335335
336const Header = struct {
337 endian: builtin.Endian,
338 is_64: bool,
339 entry: u64,
340 phoff: u64,
341 shoff: u64,
342 phentsize: u16,
343 phnum: u16,
344 shentsize: u16,
345 shnum: u16,
346 shstrndx: u16,
347};
348
349pub fn readHeader(in_stream: var) !Header {
350 var hdr_buf: [@sizeOf(Elf64_Ehdr)]u8 align(@alignOf(Elf64_Ehdr)) = undefined;
351 try in_stream.readAll(&hdr_buf);
352 const hdr32 = @ptrCast(*elf.Elf32_Ehdr, &hdr_buf);
353 const hdr64 = @ptrCast(*elf.Elf64_Ehdr, &hdr_buf);
354 if (!mem.eql(u8, hdr32.e_ident[0..4], "\x7fELF")) return error.InvalidElfMagic;
355 if (hdr32.e_ident[EI_VERSION] != 1) return error.InvalidElfVersion;
356
357 const endian = switch (hdr32.e_ident[elf.EI_DATA]) {
358 ELFDATA2LSB => .Little,
359 ELFDATA2MSB => .Big,
360 else => return error.InvalidElfEndian,
361 };
362 const need_bswap = endian != std.builtin.endian;
363
364 const is_64 = switch (hdr32.e_ident[EI_CLASS]) {
365 ELFCLASS32 => false,
366 ELFCLASS64 => true,
367 else => return error.InvalidElfClass,
368 };
369
370 return @as(Header, .{
371 .endian = endian,
372 .is_64 = is_64,
373 .entry = int(is_64, need_bswap, hdr32.e_entry, hdr64.e_entry),
374 .phoff = int(is_64, need_bswap, hdr32.e_phoff, hdr64.e_phoff),
375 .shoff = int(is_64, need_bswap, hdr32.e_shoff, hdr64.e_shoff),
376 .phentsize = int(is_64, need_bswap, hdr32.e_phentsize, hdr64.e_phentsize),
377 .phnum = int(is_64, need_bswap, hdr32.e_phnum, hdr64.e_phnum),
378 .shentsize = int(is_64, need_bswap, hdr32.e_shentsize, hdr64.e_shentsize),
379 .shnum = int(is_64, need_bswap, hdr32.e_shnum, hdr64.e_shnum),
380 .shstrndx = int(is_64, need_bswap, hdr32.e_shstrndx, hdr64.e_shstrndx),
381 });
382}
383
336pub const Elf = struct {384pub const Elf = struct {
337 seekable_stream: *io.SeekableStream(anyerror, anyerror),385 seekable_stream: *io.SeekableStream(anyerror, anyerror),
338 in_stream: *io.InStream(anyerror),386 in_stream: *io.InStream(anyerror),
lib/std/fs.zig+1-1
...@@ -1150,7 +1150,7 @@ pub const Dir = struct {...@@ -1150,7 +1150,7 @@ pub const Dir = struct {
1150 const buf = try allocator.alignedAlloc(u8, A, size);1150 const buf = try allocator.alignedAlloc(u8, A, size);
1151 errdefer allocator.free(buf);1151 errdefer allocator.free(buf);
11521152
1153 try file.inStream().stream.readNoEof(buf);1153 try file.inStream().readNoEof(buf);
1154 return buf;1154 return buf;
1155 }1155 }
11561156
lib/std/fs/file.zig+19-75
...@@ -71,7 +71,7 @@ pub const File = struct {...@@ -71,7 +71,7 @@ pub const File = struct {
71 if (need_async_thread and self.io_mode == .blocking and !self.async_block_allowed) {71 if (need_async_thread and self.io_mode == .blocking and !self.async_block_allowed) {
72 std.event.Loop.instance.?.close(self.handle);72 std.event.Loop.instance.?.close(self.handle);
73 } else {73 } else {
74 return os.close(self.handle);74 os.close(self.handle);
75 }75 }
76 }76 }
7777
...@@ -496,85 +496,29 @@ pub const File = struct {...@@ -496,85 +496,29 @@ pub const File = struct {
496 }496 }
497 }497 }
498498
499 pub fn inStream(file: File) InStream {499 pub const InStream = io.InStream(File, ReadError, read);
500 return InStream{500
501 .file = file,501 pub fn inStream(file: File) io.InStream(File, ReadError, read) {
502 .stream = InStream.Stream{ .readFn = InStream.readFn },502 return .{ .context = file };
503 };
504 }503 }
505504
505 pub const OutStream = io.OutStream(File, WriteError, write);
506
506 pub fn outStream(file: File) OutStream {507 pub fn outStream(file: File) OutStream {
507 return OutStream{508 return .{ .context = file };
508 .file = file,
509 .stream = OutStream.Stream{ .writeFn = OutStream.writeFn },
510 };
511 }509 }
512510
511 pub const SeekableStream = io.SeekableStream(
512 File,
513 SeekError,
514 GetPosError,
515 seekTo,
516 seekBy,
517 getPos,
518 getEndPos,
519 );
520
513 pub fn seekableStream(file: File) SeekableStream {521 pub fn seekableStream(file: File) SeekableStream {
514 return SeekableStream{522 return .{ .context = file };
515 .file = file,
516 .stream = SeekableStream.Stream{
517 .seekToFn = SeekableStream.seekToFn,
518 .seekByFn = SeekableStream.seekByFn,
519 .getPosFn = SeekableStream.getPosFn,
520 .getEndPosFn = SeekableStream.getEndPosFn,
521 },
522 };
523 }523 }
524
525 /// Implementation of io.InStream trait for File
526 pub const InStream = struct {
527 file: File,
528 stream: Stream,
529
530 pub const Error = ReadError;
531 pub const Stream = io.InStream(Error);
532
533 fn readFn(in_stream: *Stream, buffer: []u8) Error!usize {
534 const self = @fieldParentPtr(InStream, "stream", in_stream);
535 return self.file.read(buffer);
536 }
537 };
538
539 /// Implementation of io.OutStream trait for File
540 pub const OutStream = struct {
541 file: File,
542 stream: Stream,
543
544 pub const Error = WriteError;
545 pub const Stream = io.OutStream(Error);
546
547 fn writeFn(out_stream: *Stream, bytes: []const u8) Error!usize {
548 const self = @fieldParentPtr(OutStream, "stream", out_stream);
549 return self.file.write(bytes);
550 }
551 };
552
553 /// Implementation of io.SeekableStream trait for File
554 pub const SeekableStream = struct {
555 file: File,
556 stream: Stream,
557
558 pub const Stream = io.SeekableStream(SeekError, GetPosError);
559
560 pub fn seekToFn(seekable_stream: *Stream, pos: u64) SeekError!void {
561 const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream);
562 return self.file.seekTo(pos);
563 }
564
565 pub fn seekByFn(seekable_stream: *Stream, amt: i64) SeekError!void {
566 const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream);
567 return self.file.seekBy(amt);
568 }
569
570 pub fn getEndPosFn(seekable_stream: *Stream) GetPosError!u64 {
571 const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream);
572 return self.file.getEndPos();
573 }
574
575 pub fn getPosFn(seekable_stream: *Stream) GetPosError!u64 {
576 const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream);
577 return self.file.getPos();
578 }
579 };
580};524};
lib/std/io.zig+47-172
...@@ -93,10 +93,46 @@ pub fn getStdIn() File {...@@ -93,10 +93,46 @@ pub fn getStdIn() File {
93}93}
9494
95pub const SeekableStream = @import("io/seekable_stream.zig").SeekableStream;95pub const SeekableStream = @import("io/seekable_stream.zig").SeekableStream;
96pub const SliceSeekableInStream = @import("io/seekable_stream.zig").SliceSeekableInStream;
97pub const COutStream = @import("io/c_out_stream.zig").COutStream;
98pub const InStream = @import("io/in_stream.zig").InStream;96pub const InStream = @import("io/in_stream.zig").InStream;
99pub const OutStream = @import("io/out_stream.zig").OutStream;97pub const OutStream = @import("io/out_stream.zig").OutStream;
98pub const FixedBufferInStream = @import("io/fixed_buffer_stream.zig").FixedBufferInStream;
99pub const BufferedAtomicFile = @import("io/buffered_atomic_file.zig").BufferedAtomicFile;
100
101pub const BufferedOutStream = @import("io/buffered_out_stream.zig").BufferedOutStream;
102pub const BufferedOutStreamCustom = @import("io/buffered_out_stream.zig").BufferedOutStreamCustom;
103pub const bufferedOutStream = @import("io/buffered_out_stream.zig").bufferedOutStream;
104
105pub const CountingOutStream = @import("io/counting_out_stream.zig").CountingOutStream;
106
107pub fn fixedBufferStream(bytes: []const u8) FixedBufferInStream {
108 return (FixedBufferInStream{ .bytes = bytes, .pos = 0 });
109}
110
111pub fn cOutStream(c_file: *std.c.FILE) COutStream {
112 return .{ .context = c_file };
113}
114
115pub const COutStream = OutStream(*std.c.FILE, std.fs.File.WriteError, cOutStreamWrite);
116
117pub fn cOutStreamWrite(c_file: *std.c.FILE, bytes: []const u8) std.fs.File.WriteError!usize {
118 const amt_written = std.c.fwrite(bytes.ptr, 1, bytes.len, c_file);
119 if (amt_written >= 0) return amt_written;
120 switch (std.c._errno().*) {
121 0 => unreachable,
122 os.EINVAL => unreachable,
123 os.EFAULT => unreachable,
124 os.EAGAIN => unreachable, // this is a blocking API
125 os.EBADF => unreachable, // always a race condition
126 os.EDESTADDRREQ => unreachable, // connect was never called
127 os.EDQUOT => return error.DiskQuota,
128 os.EFBIG => return error.FileTooBig,
129 os.EIO => return error.InputOutput,
130 os.ENOSPC => return error.NoSpaceLeft,
131 os.EPERM => return error.AccessDenied,
132 os.EPIPE => return error.BrokenPipe,
133 else => |err| return os.unexpectedErrno(@intCast(usize, err)),
134 }
135}
100136
101/// Deprecated; use `std.fs.Dir.writeFile`.137/// Deprecated; use `std.fs.Dir.writeFile`.
102pub fn writeFile(path: []const u8, data: []const u8) !void {138pub fn writeFile(path: []const u8, data: []const u8) !void {
...@@ -495,139 +531,18 @@ test "io.SliceOutStream" {...@@ -495,139 +531,18 @@ test "io.SliceOutStream" {
495 testing.expectEqualSlices(u8, "HelloWorld!", slice_stream.getWritten());531 testing.expectEqualSlices(u8, "HelloWorld!", slice_stream.getWritten());
496}532}
497533
498var null_out_stream_state = NullOutStream.init();
499pub const null_out_stream = &null_out_stream_state.stream;
500
501/// An OutStream that doesn't write to anything.534/// An OutStream that doesn't write to anything.
502pub const NullOutStream = struct {535pub const null_out_stream = @as(NullOutStream, .{ .context = {} });
503 pub const Error = error{};
504 pub const Stream = OutStream(Error);
505
506 stream: Stream,
507
508 pub fn init() NullOutStream {
509 return NullOutStream{
510 .stream = Stream{ .writeFn = writeFn },
511 };
512 }
513
514 fn writeFn(out_stream: *Stream, bytes: []const u8) Error!usize {
515 return bytes.len;
516 }
517};
518536
519test "io.NullOutStream" {537const NullOutStream = OutStream(void, error{}, dummyWrite);
520 var null_stream = NullOutStream.init();538fn dummyWrite(context: void, data: []const u8) error{}!usize {
521 const stream = &null_stream.stream;539 return data.len;
522 stream.write("yay" ** 10000) catch unreachable;
523}540}
524541
525/// An OutStream that counts how many bytes has been written to it.542test "null_out_stream" {
526pub fn CountingOutStream(comptime OutStreamError: type) type {543 null_out_stream.writeAll("yay" ** 1000) catch |err| switch (err) {};
527 return struct {
528 const Self = @This();
529 pub const Stream = OutStream(Error);
530 pub const Error = OutStreamError;
531
532 stream: Stream,
533 bytes_written: u64,
534 child_stream: *Stream,
535
536 pub fn init(child_stream: *Stream) Self {
537 return Self{
538 .stream = Stream{ .writeFn = writeFn },
539 .bytes_written = 0,
540 .child_stream = child_stream,
541 };
542 }
543
544 fn writeFn(out_stream: *Stream, bytes: []const u8) OutStreamError!usize {
545 const self = @fieldParentPtr(Self, "stream", out_stream);
546 try self.child_stream.write(bytes);
547 self.bytes_written += bytes.len;
548 return bytes.len;
549 }
550 };
551}
552
553test "io.CountingOutStream" {
554 var null_stream = NullOutStream.init();
555 var counting_stream = CountingOutStream(NullOutStream.Error).init(&null_stream.stream);
556 const stream = &counting_stream.stream;
557
558 const bytes = "yay" ** 10000;
559 stream.write(bytes) catch unreachable;
560 testing.expect(counting_stream.bytes_written == bytes.len);
561}
562
563pub fn BufferedOutStream(comptime Error: type) type {
564 return BufferedOutStreamCustom(mem.page_size, Error);
565}
566
567pub fn BufferedOutStreamCustom(comptime buffer_size: usize, comptime OutStreamError: type) type {
568 return struct {
569 const Self = @This();
570 pub const Stream = OutStream(Error);
571 pub const Error = OutStreamError;
572
573 stream: Stream,
574
575 unbuffered_out_stream: *Stream,
576
577 const FifoType = std.fifo.LinearFifo(u8, std.fifo.LinearFifoBufferType{ .Static = buffer_size });
578 fifo: FifoType,
579
580 pub fn init(unbuffered_out_stream: *Stream) Self {
581 return Self{
582 .unbuffered_out_stream = unbuffered_out_stream,
583 .fifo = FifoType.init(),
584 .stream = Stream{ .writeFn = writeFn },
585 };
586 }
587
588 pub fn flush(self: *Self) !void {
589 while (true) {
590 const slice = self.fifo.readableSlice(0);
591 if (slice.len == 0) break;
592 try self.unbuffered_out_stream.write(slice);
593 self.fifo.discard(slice.len);
594 }
595 }
596
597 fn writeFn(out_stream: *Stream, bytes: []const u8) Error!usize {
598 const self = @fieldParentPtr(Self, "stream", out_stream);
599 if (bytes.len >= self.fifo.writableLength()) {
600 try self.flush();
601 return self.unbuffered_out_stream.writeOnce(bytes);
602 }
603 self.fifo.writeAssumeCapacity(bytes);
604 return bytes.len;
605 }
606 };
607}544}
608545
609/// Implementation of OutStream trait for Buffer
610pub const BufferOutStream = struct {
611 buffer: *Buffer,
612 stream: Stream,
613
614 pub const Error = error{OutOfMemory};
615 pub const Stream = OutStream(Error);
616
617 pub fn init(buffer: *Buffer) BufferOutStream {
618 return BufferOutStream{
619 .buffer = buffer,
620 .stream = Stream{ .writeFn = writeFn },
621 };
622 }
623
624 fn writeFn(out_stream: *Stream, bytes: []const u8) !usize {
625 const self = @fieldParentPtr(BufferOutStream, "stream", out_stream);
626 try self.buffer.append(bytes);
627 return bytes.len;
628 }
629};
630
631/// Creates a stream which allows for writing bit fields to another stream546/// Creates a stream which allows for writing bit fields to another stream
632pub fn BitOutStream(endian: builtin.Endian, comptime Error: type) type {547pub fn BitOutStream(endian: builtin.Endian, comptime Error: type) type {
633 return struct {548 return struct {
...@@ -752,52 +667,11 @@ pub fn BitOutStream(endian: builtin.Endian, comptime Error: type) type {...@@ -752,52 +667,11 @@ pub fn BitOutStream(endian: builtin.Endian, comptime Error: type) type {
752 return buffer.len;667 return buffer.len;
753 }668 }
754669
755 return self.out_stream.writeOnce(buffer);670 return self.out_stream.write(buffer);
756 }671 }
757 };672 };
758}673}
759674
760pub const BufferedAtomicFile = struct {
761 atomic_file: fs.AtomicFile,
762 file_stream: File.OutStream,
763 buffered_stream: BufferedOutStream(File.WriteError),
764 allocator: *mem.Allocator,
765
766 pub fn create(allocator: *mem.Allocator, dest_path: []const u8) !*BufferedAtomicFile {
767 // TODO with well defined copy elision we don't need this allocation
768 var self = try allocator.create(BufferedAtomicFile);
769 self.* = BufferedAtomicFile{
770 .atomic_file = undefined,
771 .file_stream = undefined,
772 .buffered_stream = undefined,
773 .allocator = allocator,
774 };
775 errdefer allocator.destroy(self);
776
777 self.atomic_file = try fs.AtomicFile.init(dest_path, File.default_mode);
778 errdefer self.atomic_file.deinit();
779
780 self.file_stream = self.atomic_file.file.outStream();
781 self.buffered_stream = BufferedOutStream(File.WriteError).init(&self.file_stream.stream);
782 return self;
783 }
784
785 /// always call destroy, even after successful finish()
786 pub fn destroy(self: *BufferedAtomicFile) void {
787 self.atomic_file.deinit();
788 self.allocator.destroy(self);
789 }
790
791 pub fn finish(self: *BufferedAtomicFile) !void {
792 try self.buffered_stream.flush();
793 try self.atomic_file.finish();
794 }
795
796 pub fn stream(self: *BufferedAtomicFile) *OutStream(File.WriteError) {
797 return &self.buffered_stream.stream;
798 }
799};
800
801pub const Packing = enum {675pub const Packing = enum {
802 /// Pack data to byte alignment676 /// Pack data to byte alignment
803 Byte,677 Byte,
...@@ -1129,8 +1003,9 @@ pub fn Serializer(comptime endian: builtin.Endian, comptime packing: Packing, co...@@ -1129,8 +1003,9 @@ pub fn Serializer(comptime endian: builtin.Endian, comptime packing: Packing, co
1129 };1003 };
1130}1004}
11311005
1132test "import io tests" {1006test "" {
1133 comptime {1007 comptime {
1134 _ = @import("io/test.zig");1008 _ = @import("io/test.zig");
1135 }1009 }
1010 std.meta.refAllDecls(@This());
1136}1011}
lib/std/io/buffered_atomic_file.zig created+50
...@@ -0,0 +1,50 @@
1const std = @import("../std.zig");
2const mem = std.mem;
3const fs = std.fs;
4const File = std.fs.File;
5
6pub const BufferedAtomicFile = struct {
7 atomic_file: fs.AtomicFile,
8 file_stream: File.OutStream,
9 buffered_stream: BufferedOutStream,
10 allocator: *mem.Allocator,
11
12 pub const buffer_size = 4096;
13 pub const BufferedOutStream = std.io.BufferedOutStreamCustom(buffer_size, File.OutStream);
14 pub const OutStream = std.io.OutStream(*BufferedOutStream, BufferedOutStream.Error, BufferedOutStream.write);
15
16 /// TODO when https://github.com/ziglang/zig/issues/2761 is solved
17 /// this API will not need an allocator
18 pub fn create(allocator: *mem.Allocator, dest_path: []const u8) !*BufferedAtomicFile {
19 var self = try allocator.create(BufferedAtomicFile);
20 self.* = BufferedAtomicFile{
21 .atomic_file = undefined,
22 .file_stream = undefined,
23 .buffered_stream = undefined,
24 .allocator = allocator,
25 };
26 errdefer allocator.destroy(self);
27
28 self.atomic_file = try fs.AtomicFile.init(dest_path, File.default_mode);
29 errdefer self.atomic_file.deinit();
30
31 self.file_stream = self.atomic_file.file.outStream();
32 self.buffered_stream = std.io.bufferedOutStream(buffer_size, self.file_stream);
33 return self;
34 }
35
36 /// always call destroy, even after successful finish()
37 pub fn destroy(self: *BufferedAtomicFile) void {
38 self.atomic_file.deinit();
39 self.allocator.destroy(self);
40 }
41
42 pub fn finish(self: *BufferedAtomicFile) !void {
43 try self.buffered_stream.flush();
44 try self.atomic_file.finish();
45 }
46
47 pub fn stream(self: *BufferedAtomicFile) OutStream {
48 return .{ .context = &self.buffered_stream };
49 }
50};
lib/std/io/buffered_out_stream.zig created+56
...@@ -0,0 +1,56 @@
1const std = @import("../std.zig");
2const io = std.io;
3
4pub fn BufferedOutStream(comptime OutStreamType: type) type {
5 return BufferedOutStreamCustom(4096, OutStreamType);
6}
7
8pub fn BufferedOutStreamCustom(comptime buffer_size: usize, comptime OutStreamType: type) type {
9 return struct {
10 unbuffered_out_stream: OutStreamType,
11 fifo: FifoType,
12
13 pub const Error = OutStreamType.Error;
14 pub const OutStream = io.OutStream(*Self, Error, write);
15
16 const Self = @This();
17 const FifoType = std.fifo.LinearFifo(u8, std.fifo.LinearFifoBufferType{ .Static = buffer_size });
18
19 pub fn init(unbuffered_out_stream: OutStreamType) Self {
20 return Self{
21 .unbuffered_out_stream = unbuffered_out_stream,
22 .fifo = FifoType.init(),
23 };
24 }
25
26 pub fn flush(self: *Self) !void {
27 while (true) {
28 const slice = self.fifo.readableSlice(0);
29 if (slice.len == 0) break;
30 try self.unbuffered_out_stream.writeAll(slice);
31 self.fifo.discard(slice.len);
32 }
33 }
34
35 pub fn outStream(self: *Self) OutStream {
36 return .{ .context = self };
37 }
38
39 pub fn write(self: *Self, bytes: []const u8) Error!usize {
40 if (bytes.len >= self.fifo.writableLength()) {
41 try self.flush();
42 return self.unbuffered_out_stream.write(bytes);
43 }
44 self.fifo.writeAssumeCapacity(bytes);
45 return bytes.len;
46 }
47 };
48}
49
50pub fn bufferedOutStream(
51 comptime buffer_size: usize,
52 underlying_stream: var,
53) BufferedOutStreamCustom(buffer_size, @TypeOf(underlying_stream)) {
54 return BufferedOutStreamCustom(buffer_size, @TypeOf(underlying_stream)).init(underlying_stream);
55}
56
lib/std/io/c_out_stream.zig deleted-43
...@@ -1,43 +0,0 @@
1const std = @import("../std.zig");
2const os = std.os;
3const OutStream = std.io.OutStream;
4const builtin = @import("builtin");
5
6/// TODO make a proposal to make `std.fs.File` use *FILE when linking libc and this just becomes
7/// std.io.FileOutStream because std.fs.File.write would do this when linking
8/// libc.
9pub const COutStream = struct {
10 pub const Error = std.fs.File.WriteError;
11 pub const Stream = OutStream(Error);
12
13 stream: Stream,
14 c_file: *std.c.FILE,
15
16 pub fn init(c_file: *std.c.FILE) COutStream {
17 return COutStream{
18 .c_file = c_file,
19 .stream = Stream{ .writeFn = writeFn },
20 };
21 }
22
23 fn writeFn(out_stream: *Stream, bytes: []const u8) Error!usize {
24 const self = @fieldParentPtr(COutStream, "stream", out_stream);
25 const amt_written = std.c.fwrite(bytes.ptr, 1, bytes.len, self.c_file);
26 if (amt_written >= 0) return amt_written;
27 switch (std.c._errno().*) {
28 0 => unreachable,
29 os.EINVAL => unreachable,
30 os.EFAULT => unreachable,
31 os.EAGAIN => unreachable, // this is a blocking API
32 os.EBADF => unreachable, // always a race condition
33 os.EDESTADDRREQ => unreachable, // connect was never called
34 os.EDQUOT => return error.DiskQuota,
35 os.EFBIG => return error.FileTooBig,
36 os.EIO => return error.InputOutput,
37 os.ENOSPC => return error.NoSpaceLeft,
38 os.EPERM => return error.AccessDenied,
39 os.EPIPE => return error.BrokenPipe,
40 else => |err| return os.unexpectedErrno(@intCast(usize, err)),
41 }
42 }
43};
lib/std/io/counting_out_stream.zig created+42
...@@ -0,0 +1,42 @@
1const std = @import("../std.zig");
2const io = std.io;
3
4/// An OutStream that counts how many bytes has been written to it.
5pub fn CountingOutStream(comptime OutStreamType: type) type {
6 return struct {
7 bytes_written: u64,
8 child_stream: OutStreamType,
9
10 pub const Error = OutStreamType.Error;
11 pub const OutStream = io.OutStream(*Self, Error, write);
12
13 const Self = @This();
14
15 pub fn init(child_stream: OutStreamType) Self {
16 return Self{
17 .bytes_written = 0,
18 .child_stream = child_stream,
19 };
20 }
21
22 pub fn write(self: *Self, bytes: []const u8) Error!usize {
23 const amt = try self.child_stream.write(bytes);
24 self.bytes_written += amt;
25 return amt;
26 }
27
28 pub fn outStream(self: *Self) OutStream {
29 return .{ .context = self };
30 }
31 };
32}
33
34test "io.CountingOutStream" {
35 var counting_stream = CountingOutStream(NullOutStream.Error).init(std.io.null_out_stream);
36 const stream = &counting_stream.stream;
37
38 const bytes = "yay" ** 10000;
39 stream.write(bytes) catch unreachable;
40 testing.expect(counting_stream.bytes_written == bytes.len);
41}
42
lib/std/io/fixed_buffer_stream.zig created+66
...@@ -0,0 +1,66 @@
1const std = @import("../std.zig");
2const io = std.io;
3
4pub const FixedBufferInStream = struct {
5 bytes: []const u8,
6 pos: usize,
7
8 pub const SeekError = error{EndOfStream};
9 pub const GetSeekPosError = error{};
10
11 pub const InStream = io.InStream(*FixedBufferInStream, error{}, read);
12
13 pub fn inStream(self: *FixedBufferInStream) InStream {
14 return .{ .context = self };
15 }
16
17 pub const SeekableStream = io.SeekableStream(
18 *FixedBufferInStream,
19 SeekError,
20 GetSeekPosError,
21 seekTo,
22 seekBy,
23 getPos,
24 getEndPos,
25 );
26
27 pub fn seekableStream(self: *FixedBufferInStream) SeekableStream {
28 return .{ .context = self };
29 }
30
31 pub fn read(self: *FixedBufferInStream, dest: []u8) error{}!usize {
32 const size = std.math.min(dest.len, self.bytes.len - self.pos);
33 const end = self.pos + size;
34
35 std.mem.copy(u8, dest[0..size], self.bytes[self.pos..end]);
36 self.pos = end;
37
38 return size;
39 }
40
41 pub fn seekTo(self: *FixedBufferInStream, pos: u64) SeekError!void {
42 const usize_pos = std.math.cast(usize, pos) catch return error.EndOfStream;
43 if (usize_pos > self.bytes.len) return error.EndOfStream;
44 self.pos = usize_pos;
45 }
46
47 pub fn seekBy(self: *FixedBufferInStream, amt: i64) SeekError!void {
48 if (amt < 0) {
49 const abs_amt = std.math.cast(usize, -amt) catch return error.EndOfStream;
50 if (abs_amt > self.pos) return error.EndOfStream;
51 self.pos -= abs_amt;
52 } else {
53 const usize_amt = std.math.cast(usize, amt) catch return error.EndOfStream;
54 if (self.pos + usize_amt > self.bytes.len) return error.EndOfStream;
55 self.pos += usize_amt;
56 }
57 }
58
59 pub fn getEndPos(self: *FixedBufferInStream) GetSeekPosError!u64 {
60 return self.bytes.len;
61 }
62
63 pub fn getPos(self: *FixedBufferInStream) GetSeekPosError!u64 {
64 return self.pos;
65 }
66};
lib/std/io/in_stream.zig+34-47
...@@ -1,44 +1,31 @@...@@ -1,44 +1,31 @@
1const std = @import("../std.zig");1const std = @import("../std.zig");
2const builtin = @import("builtin");2const builtin = std.builtin;
3const root = @import("root");
4const math = std.math;3const math = std.math;
5const assert = std.debug.assert;4const assert = std.debug.assert;
6const mem = std.mem;5const mem = std.mem;
7const Buffer = std.Buffer;6const Buffer = std.Buffer;
8const testing = std.testing;7const testing = std.testing;
98
10pub const default_stack_size = 1 * 1024 * 1024;9pub fn InStream(
11pub const stack_size: usize = if (@hasDecl(root, "stack_size_std_io_InStream"))10 comptime Context: type,
12 root.stack_size_std_io_InStream11 comptime ReadError: type,
13else12 /// Returns the number of bytes read. It may be less than buffer.len.
14 default_stack_size;13 /// If the number of bytes read is 0, it means end of stream.
1514 /// End of stream is not an error condition.
16pub fn InStream(comptime ReadError: type) type {15 comptime readFn: fn (context: Context, buffer: []u8) ReadError!usize,
16) type {
17 return struct {17 return struct {
18 const Self = @This();
19 pub const Error = ReadError;18 pub const Error = ReadError;
20 pub const ReadFn = if (std.io.is_async)
21 async fn (self: *Self, buffer: []u8) Error!usize
22 else
23 fn (self: *Self, buffer: []u8) Error!usize;
2419
25 /// Returns the number of bytes read. It may be less than buffer.len.20 context: Context,
26 /// If the number of bytes read is 0, it means end of stream.21
27 /// End of stream is not an error condition.22 const Self = @This();
28 readFn: ReadFn,
2923
30 /// Returns the number of bytes read. It may be less than buffer.len.24 /// Returns the number of bytes read. It may be less than buffer.len.
31 /// If the number of bytes read is 0, it means end of stream.25 /// If the number of bytes read is 0, it means end of stream.
32 /// End of stream is not an error condition.26 /// End of stream is not an error condition.
33 pub fn read(self: *Self, buffer: []u8) Error!usize {27 pub fn read(self: Self, buffer: []u8) Error!usize {
34 if (std.io.is_async) {28 return readFn(self.context, buffer);
35 // Let's not be writing 0xaa in safe modes for upwards of 4 MiB for every stream read.
36 @setRuntimeSafety(false);
37 var stack_frame: [stack_size]u8 align(std.Target.stack_align) = undefined;
38 return await @asyncCall(&stack_frame, {}, self.readFn, self, buffer);
39 } else {
40 return self.readFn(self, buffer);
41 }
42 }29 }
4330
44 /// Deprecated: use `readAll`.31 /// Deprecated: use `readAll`.
...@@ -47,7 +34,7 @@ pub fn InStream(comptime ReadError: type) type {...@@ -47,7 +34,7 @@ pub fn InStream(comptime ReadError: type) type {
47 /// Returns the number of bytes read. If the number read is smaller than buf.len, it34 /// Returns the number of bytes read. If the number read is smaller than buf.len, it
48 /// means the stream reached the end. Reaching the end of a stream is not an error35 /// means the stream reached the end. Reaching the end of a stream is not an error
49 /// condition.36 /// condition.
50 pub fn readAll(self: *Self, buffer: []u8) Error!usize {37 pub fn readAll(self: Self, buffer: []u8) Error!usize {
51 var index: usize = 0;38 var index: usize = 0;
52 while (index != buffer.len) {39 while (index != buffer.len) {
53 const amt = try self.read(buffer[index..]);40 const amt = try self.read(buffer[index..]);
...@@ -59,13 +46,13 @@ pub fn InStream(comptime ReadError: type) type {...@@ -59,13 +46,13 @@ pub fn InStream(comptime ReadError: type) type {
5946
60 /// Returns the number of bytes read. If the number read would be smaller than buf.len,47 /// Returns the number of bytes read. If the number read would be smaller than buf.len,
61 /// error.EndOfStream is returned instead.48 /// error.EndOfStream is returned instead.
62 pub fn readNoEof(self: *Self, buf: []u8) !void {49 pub fn readNoEof(self: Self, buf: []u8) !void {
63 const amt_read = try self.readAll(buf);50 const amt_read = try self.readAll(buf);
64 if (amt_read < buf.len) return error.EndOfStream;51 if (amt_read < buf.len) return error.EndOfStream;
65 }52 }
6653
67 /// Deprecated: use `readAllArrayList`.54 /// Deprecated: use `readAllArrayList`.
68 pub fn readAllBuffer(self: *Self, buffer: *Buffer, max_size: usize) !void {55 pub fn readAllBuffer(self: Self, buffer: *Buffer, max_size: usize) !void {
69 buffer.list.shrink(0);56 buffer.list.shrink(0);
70 try self.readAllArrayList(&buffer.list, max_size);57 try self.readAllArrayList(&buffer.list, max_size);
71 errdefer buffer.shrink(0);58 errdefer buffer.shrink(0);
...@@ -75,7 +62,7 @@ pub fn InStream(comptime ReadError: type) type {...@@ -75,7 +62,7 @@ pub fn InStream(comptime ReadError: type) type {
75 /// Appends to the `std.ArrayList` contents by reading from the stream until end of stream is found.62 /// Appends to the `std.ArrayList` contents by reading from the stream until end of stream is found.
76 /// If the number of bytes appended would exceed `max_append_size`, `error.StreamTooLong` is returned63 /// If the number of bytes appended would exceed `max_append_size`, `error.StreamTooLong` is returned
77 /// and the `std.ArrayList` has exactly `max_append_size` bytes appended.64 /// and the `std.ArrayList` has exactly `max_append_size` bytes appended.
78 pub fn readAllArrayList(self: *Self, array_list: *std.ArrayList(u8), max_append_size: usize) !void {65 pub fn readAllArrayList(self: Self, array_list: *std.ArrayList(u8), max_append_size: usize) !void {
79 try array_list.ensureCapacity(math.min(max_append_size, 4096));66 try array_list.ensureCapacity(math.min(max_append_size, 4096));
80 const original_len = array_list.len;67 const original_len = array_list.len;
81 var start_index: usize = original_len;68 var start_index: usize = original_len;
...@@ -104,7 +91,7 @@ pub fn InStream(comptime ReadError: type) type {...@@ -104,7 +91,7 @@ pub fn InStream(comptime ReadError: type) type {
104 /// memory would be greater than `max_size`, returns `error.StreamTooLong`.91 /// memory would be greater than `max_size`, returns `error.StreamTooLong`.
105 /// Caller owns returned memory.92 /// Caller owns returned memory.
106 /// If this function returns an error, the contents from the stream read so far are lost.93 /// If this function returns an error, the contents from the stream read so far are lost.
107 pub fn readAllAlloc(self: *Self, allocator: *mem.Allocator, max_size: usize) ![]u8 {94 pub fn readAllAlloc(self: Self, allocator: *mem.Allocator, max_size: usize) ![]u8 {
108 var array_list = std.ArrayList(u8).init(allocator);95 var array_list = std.ArrayList(u8).init(allocator);
109 defer array_list.deinit();96 defer array_list.deinit();
110 try self.readAllArrayList(&array_list, max_size);97 try self.readAllArrayList(&array_list, max_size);
...@@ -116,7 +103,7 @@ pub fn InStream(comptime ReadError: type) type {...@@ -116,7 +103,7 @@ pub fn InStream(comptime ReadError: type) type {
116 /// If the `std.ArrayList` length would exceed `max_size`, `error.StreamTooLong` is returned and the103 /// If the `std.ArrayList` length would exceed `max_size`, `error.StreamTooLong` is returned and the
117 /// `std.ArrayList` is populated with `max_size` bytes from the stream.104 /// `std.ArrayList` is populated with `max_size` bytes from the stream.
118 pub fn readUntilDelimiterArrayList(105 pub fn readUntilDelimiterArrayList(
119 self: *Self,106 self: Self,
120 array_list: *std.ArrayList(u8),107 array_list: *std.ArrayList(u8),
121 delimiter: u8,108 delimiter: u8,
122 max_size: usize,109 max_size: usize,
...@@ -142,7 +129,7 @@ pub fn InStream(comptime ReadError: type) type {...@@ -142,7 +129,7 @@ pub fn InStream(comptime ReadError: type) type {
142 /// Caller owns returned memory.129 /// Caller owns returned memory.
143 /// If this function returns an error, the contents from the stream read so far are lost.130 /// If this function returns an error, the contents from the stream read so far are lost.
144 pub fn readUntilDelimiterAlloc(131 pub fn readUntilDelimiterAlloc(
145 self: *Self,132 self: Self,
146 allocator: *mem.Allocator,133 allocator: *mem.Allocator,
147 delimiter: u8,134 delimiter: u8,
148 max_size: usize,135 max_size: usize,
...@@ -159,7 +146,7 @@ pub fn InStream(comptime ReadError: type) type {...@@ -159,7 +146,7 @@ pub fn InStream(comptime ReadError: type) type {
159 /// function is called again after that, returns null.146 /// function is called again after that, returns null.
160 /// Returns a slice of the stream data, with ptr equal to `buf.ptr`. The147 /// Returns a slice of the stream data, with ptr equal to `buf.ptr`. The
161 /// delimiter byte is not included in the returned slice.148 /// delimiter byte is not included in the returned slice.
162 pub fn readUntilDelimiterOrEof(self: *Self, buf: []u8, delimiter: u8) !?[]u8 {149 pub fn readUntilDelimiterOrEof(self: Self, buf: []u8, delimiter: u8) !?[]u8 {
163 var index: usize = 0;150 var index: usize = 0;
164 while (true) {151 while (true) {
165 const byte = self.readByte() catch |err| switch (err) {152 const byte = self.readByte() catch |err| switch (err) {
...@@ -184,7 +171,7 @@ pub fn InStream(comptime ReadError: type) type {...@@ -184,7 +171,7 @@ pub fn InStream(comptime ReadError: type) type {
184 /// Reads from the stream until specified byte is found, discarding all data,171 /// Reads from the stream until specified byte is found, discarding all data,
185 /// including the delimiter.172 /// including the delimiter.
186 /// If end-of-stream is found, this function succeeds.173 /// If end-of-stream is found, this function succeeds.
187 pub fn skipUntilDelimiterOrEof(self: *Self, delimiter: u8) !void {174 pub fn skipUntilDelimiterOrEof(self: Self, delimiter: u8) !void {
188 while (true) {175 while (true) {
189 const byte = self.readByte() catch |err| switch (err) {176 const byte = self.readByte() catch |err| switch (err) {
190 error.EndOfStream => return,177 error.EndOfStream => return,
...@@ -195,7 +182,7 @@ pub fn InStream(comptime ReadError: type) type {...@@ -195,7 +182,7 @@ pub fn InStream(comptime ReadError: type) type {
195 }182 }
196183
197 /// Reads 1 byte from the stream or returns `error.EndOfStream`.184 /// Reads 1 byte from the stream or returns `error.EndOfStream`.
198 pub fn readByte(self: *Self) !u8 {185 pub fn readByte(self: Self) !u8 {
199 var result: [1]u8 = undefined;186 var result: [1]u8 = undefined;
200 const amt_read = try self.read(result[0..]);187 const amt_read = try self.read(result[0..]);
201 if (amt_read < 1) return error.EndOfStream;188 if (amt_read < 1) return error.EndOfStream;
...@@ -203,43 +190,43 @@ pub fn InStream(comptime ReadError: type) type {...@@ -203,43 +190,43 @@ pub fn InStream(comptime ReadError: type) type {
203 }190 }
204191
205 /// Same as `readByte` except the returned byte is signed.192 /// Same as `readByte` except the returned byte is signed.
206 pub fn readByteSigned(self: *Self) !i8 {193 pub fn readByteSigned(self: Self) !i8 {
207 return @bitCast(i8, try self.readByte());194 return @bitCast(i8, try self.readByte());
208 }195 }
209196
210 /// Reads a native-endian integer197 /// Reads a native-endian integer
211 pub fn readIntNative(self: *Self, comptime T: type) !T {198 pub fn readIntNative(self: Self, comptime T: type) !T {
212 var bytes: [(T.bit_count + 7) / 8]u8 = undefined;199 var bytes: [(T.bit_count + 7) / 8]u8 = undefined;
213 try self.readNoEof(bytes[0..]);200 try self.readNoEof(bytes[0..]);
214 return mem.readIntNative(T, &bytes);201 return mem.readIntNative(T, &bytes);
215 }202 }
216203
217 /// Reads a foreign-endian integer204 /// Reads a foreign-endian integer
218 pub fn readIntForeign(self: *Self, comptime T: type) !T {205 pub fn readIntForeign(self: Self, comptime T: type) !T {
219 var bytes: [(T.bit_count + 7) / 8]u8 = undefined;206 var bytes: [(T.bit_count + 7) / 8]u8 = undefined;
220 try self.readNoEof(bytes[0..]);207 try self.readNoEof(bytes[0..]);
221 return mem.readIntForeign(T, &bytes);208 return mem.readIntForeign(T, &bytes);
222 }209 }
223210
224 pub fn readIntLittle(self: *Self, comptime T: type) !T {211 pub fn readIntLittle(self: Self, comptime T: type) !T {
225 var bytes: [(T.bit_count + 7) / 8]u8 = undefined;212 var bytes: [(T.bit_count + 7) / 8]u8 = undefined;
226 try self.readNoEof(bytes[0..]);213 try self.readNoEof(bytes[0..]);
227 return mem.readIntLittle(T, &bytes);214 return mem.readIntLittle(T, &bytes);
228 }215 }
229216
230 pub fn readIntBig(self: *Self, comptime T: type) !T {217 pub fn readIntBig(self: Self, comptime T: type) !T {
231 var bytes: [(T.bit_count + 7) / 8]u8 = undefined;218 var bytes: [(T.bit_count + 7) / 8]u8 = undefined;
232 try self.readNoEof(bytes[0..]);219 try self.readNoEof(bytes[0..]);
233 return mem.readIntBig(T, &bytes);220 return mem.readIntBig(T, &bytes);
234 }221 }
235222
236 pub fn readInt(self: *Self, comptime T: type, endian: builtin.Endian) !T {223 pub fn readInt(self: Self, comptime T: type, endian: builtin.Endian) !T {
237 var bytes: [(T.bit_count + 7) / 8]u8 = undefined;224 var bytes: [(T.bit_count + 7) / 8]u8 = undefined;
238 try self.readNoEof(bytes[0..]);225 try self.readNoEof(bytes[0..]);
239 return mem.readInt(T, &bytes, endian);226 return mem.readInt(T, &bytes, endian);
240 }227 }
241228
242 pub fn readVarInt(self: *Self, comptime ReturnType: type, endian: builtin.Endian, size: usize) !ReturnType {229 pub fn readVarInt(self: Self, comptime ReturnType: type, endian: builtin.Endian, size: usize) !ReturnType {
243 assert(size <= @sizeOf(ReturnType));230 assert(size <= @sizeOf(ReturnType));
244 var bytes_buf: [@sizeOf(ReturnType)]u8 = undefined;231 var bytes_buf: [@sizeOf(ReturnType)]u8 = undefined;
245 const bytes = bytes_buf[0..size];232 const bytes = bytes_buf[0..size];
...@@ -247,14 +234,14 @@ pub fn InStream(comptime ReadError: type) type {...@@ -247,14 +234,14 @@ pub fn InStream(comptime ReadError: type) type {
247 return mem.readVarInt(ReturnType, bytes, endian);234 return mem.readVarInt(ReturnType, bytes, endian);
248 }235 }
249236
250 pub fn skipBytes(self: *Self, num_bytes: u64) !void {237 pub fn skipBytes(self: Self, num_bytes: u64) !void {
251 var i: u64 = 0;238 var i: u64 = 0;
252 while (i < num_bytes) : (i += 1) {239 while (i < num_bytes) : (i += 1) {
253 _ = try self.readByte();240 _ = try self.readByte();
254 }241 }
255 }242 }
256243
257 pub fn readStruct(self: *Self, comptime T: type) !T {244 pub fn readStruct(self: Self, comptime T: type) !T {
258 // Only extern and packed structs have defined in-memory layout.245 // Only extern and packed structs have defined in-memory layout.
259 comptime assert(@typeInfo(T).Struct.layout != builtin.TypeInfo.ContainerLayout.Auto);246 comptime assert(@typeInfo(T).Struct.layout != builtin.TypeInfo.ContainerLayout.Auto);
260 var res: [1]T = undefined;247 var res: [1]T = undefined;
...@@ -265,7 +252,7 @@ pub fn InStream(comptime ReadError: type) type {...@@ -265,7 +252,7 @@ pub fn InStream(comptime ReadError: type) type {
265 /// Reads an integer with the same size as the given enum's tag type. If the integer matches252 /// Reads an integer with the same size as the given enum's tag type. If the integer matches
266 /// an enum tag, casts the integer to the enum tag and returns it. Otherwise, returns an error.253 /// an enum tag, casts the integer to the enum tag and returns it. Otherwise, returns an error.
267 /// TODO optimization taking advantage of most fields being in order254 /// TODO optimization taking advantage of most fields being in order
268 pub fn readEnum(self: *Self, comptime Enum: type, endian: builtin.Endian) !Enum {255 pub fn readEnum(self: Self, comptime Enum: type, endian: builtin.Endian) !Enum {
269 const E = error{256 const E = error{
270 /// An integer was read, but it did not match any of the tags in the supplied enum.257 /// An integer was read, but it did not match any of the tags in the supplied enum.
271 InvalidValue,258 InvalidValue,
lib/std/io/out_stream.zig+33-42
...@@ -1,94 +1,85 @@...@@ -1,94 +1,85 @@
1const std = @import("../std.zig");1const std = @import("../std.zig");
2const builtin = @import("builtin");2const builtin = std.builtin;
3const root = @import("root");
4const mem = std.mem;3const mem = std.mem;
54
6pub const default_stack_size = 1 * 1024 * 1024;5pub fn OutStream(
7pub const stack_size: usize = if (@hasDecl(root, "stack_size_std_io_OutStream"))6 comptime Context: type,
8 root.stack_size_std_io_OutStream7 comptime WriteError: type,
9else8 comptime writeFn: fn (context: Context, bytes: []const u8) WriteError!usize,
10 default_stack_size;9) type {
11
12pub fn OutStream(comptime WriteError: type) type {
13 return struct {10 return struct {
11 context: Context,
12
14 const Self = @This();13 const Self = @This();
15 pub const Error = WriteError;14 pub const Error = WriteError;
16 pub const WriteFn = if (std.io.is_async)
17 async fn (self: *Self, bytes: []const u8) Error!usize
18 else
19 fn (self: *Self, bytes: []const u8) Error!usize;
2015
21 writeFn: WriteFn,16 pub fn write(self: Self, bytes: []const u8) Error!usize {
2217 return writeFn(self.context, bytes);
23 pub fn writeOnce(self: *Self, bytes: []const u8) Error!usize {
24 if (std.io.is_async) {
25 // Let's not be writing 0xaa in safe modes for upwards of 4 MiB for every stream write.
26 @setRuntimeSafety(false);
27 var stack_frame: [stack_size]u8 align(std.Target.stack_align) = undefined;
28 return await @asyncCall(&stack_frame, {}, self.writeFn, self, bytes);
29 } else {
30 return self.writeFn(self, bytes);
31 }
32 }18 }
3319
34 pub fn write(self: *Self, bytes: []const u8) Error!void {20 pub fn writeAll(self: Self, bytes: []const u8) Error!void {
35 var index: usize = 0;21 var index: usize = 0;
36 while (index != bytes.len) {22 while (index != bytes.len) {
37 index += try self.writeOnce(bytes[index..]);23 index += try self.write(bytes[index..]);
38 }24 }
39 }25 }
4026
41 pub fn print(self: *Self, comptime format: []const u8, args: var) Error!void {27 pub fn print(self: Self, comptime format: []const u8, args: var) Error!void {
42 return std.fmt.format(self, Error, write, format, args);28 return std.fmt.format(self, Error, writeAll, format, args);
43 }29 }
4430
45 pub fn writeByte(self: *Self, byte: u8) Error!void {31 pub fn writeByte(self: Self, byte: u8) Error!void {
46 const array = [1]u8{byte};32 const array = [1]u8{byte};
47 return self.write(&array);33 return self.writeAll(&array);
48 }34 }
4935
50 pub fn writeByteNTimes(self: *Self, byte: u8, n: usize) Error!void {36 pub fn writeByteNTimes(self: Self, byte: u8, n: usize) Error!void {
51 var bytes: [256]u8 = undefined;37 var bytes: [256]u8 = undefined;
52 mem.set(u8, bytes[0..], byte);38 mem.set(u8, bytes[0..], byte);
5339
54 var remaining: usize = n;40 var remaining: usize = n;
55 while (remaining > 0) {41 while (remaining > 0) {
56 const to_write = std.math.min(remaining, bytes.len);42 const to_write = std.math.min(remaining, bytes.len);
57 try self.write(bytes[0..to_write]);43 try self.writeAll(bytes[0..to_write]);
58 remaining -= to_write;44 remaining -= to_write;
59 }45 }
60 }46 }
6147
62 /// Write a native-endian integer.48 /// Write a native-endian integer.
63 pub fn writeIntNative(self: *Self, comptime T: type, value: T) Error!void {49 /// TODO audit non-power-of-two int sizes
50 pub fn writeIntNative(self: Self, comptime T: type, value: T) Error!void {
64 var bytes: [(T.bit_count + 7) / 8]u8 = undefined;51 var bytes: [(T.bit_count + 7) / 8]u8 = undefined;
65 mem.writeIntNative(T, &bytes, value);52 mem.writeIntNative(T, &bytes, value);
66 return self.write(&bytes);53 return self.writeAll(&bytes);
67 }54 }
6855
69 /// Write a foreign-endian integer.56 /// Write a foreign-endian integer.
70 pub fn writeIntForeign(self: *Self, comptime T: type, value: T) Error!void {57 /// TODO audit non-power-of-two int sizes
58 pub fn writeIntForeign(self: Self, comptime T: type, value: T) Error!void {
71 var bytes: [(T.bit_count + 7) / 8]u8 = undefined;59 var bytes: [(T.bit_count + 7) / 8]u8 = undefined;
72 mem.writeIntForeign(T, &bytes, value);60 mem.writeIntForeign(T, &bytes, value);
73 return self.write(&bytes);61 return self.writeAll(&bytes);
74 }62 }
7563
76 pub fn writeIntLittle(self: *Self, comptime T: type, value: T) Error!void {64 /// TODO audit non-power-of-two int sizes
65 pub fn writeIntLittle(self: Self, comptime T: type, value: T) Error!void {
77 var bytes: [(T.bit_count + 7) / 8]u8 = undefined;66 var bytes: [(T.bit_count + 7) / 8]u8 = undefined;
78 mem.writeIntLittle(T, &bytes, value);67 mem.writeIntLittle(T, &bytes, value);
79 return self.write(&bytes);68 return self.writeAll(&bytes);
80 }69 }
8170
82 pub fn writeIntBig(self: *Self, comptime T: type, value: T) Error!void {71 /// TODO audit non-power-of-two int sizes
72 pub fn writeIntBig(self: Self, comptime T: type, value: T) Error!void {
83 var bytes: [(T.bit_count + 7) / 8]u8 = undefined;73 var bytes: [(T.bit_count + 7) / 8]u8 = undefined;
84 mem.writeIntBig(T, &bytes, value);74 mem.writeIntBig(T, &bytes, value);
85 return self.write(&bytes);75 return self.writeAll(&bytes);
86 }76 }
8777
88 pub fn writeInt(self: *Self, comptime T: type, value: T, endian: builtin.Endian) Error!void {78 /// TODO audit non-power-of-two int sizes
79 pub fn writeInt(self: Self, comptime T: type, value: T, endian: builtin.Endian) Error!void {
89 var bytes: [(T.bit_count + 7) / 8]u8 = undefined;80 var bytes: [(T.bit_count + 7) / 8]u8 = undefined;
90 mem.writeInt(T, &bytes, value, endian);81 mem.writeInt(T, &bytes, value, endian);
91 return self.write(&bytes);82 return self.writeAll(&bytes);
92 }83 }
93 };84 };
94}85}
lib/std/io/seekable_stream.zig+19-86
...@@ -1,103 +1,36 @@...@@ -1,103 +1,36 @@
1const std = @import("../std.zig");1const std = @import("../std.zig");
2const InStream = std.io.InStream;2const InStream = std.io.InStream;
33
4pub fn SeekableStream(comptime SeekErrorType: type, comptime GetSeekPosErrorType: type) type {4pub fn SeekableStream(
5 comptime Context: type,
6 comptime SeekErrorType: type,
7 comptime GetSeekPosErrorType: type,
8 comptime seekToFn: fn (context: Context, pos: u64) SeekErrorType!void,
9 comptime seekByFn: fn (context: Context, pos: i64) SeekErrorType!void,
10 comptime getPosFn: fn (context: Context) GetSeekPosErrorType!u64,
11 comptime getEndPosFn: fn (context: Context) GetSeekPosErrorType!u64,
12) type {
5 return struct {13 return struct {
14 context: Context,
15
6 const Self = @This();16 const Self = @This();
7 pub const SeekError = SeekErrorType;17 pub const SeekError = SeekErrorType;
8 pub const GetSeekPosError = GetSeekPosErrorType;18 pub const GetSeekPosError = GetSeekPosErrorType;
919
10 seekToFn: fn (self: *Self, pos: u64) SeekError!void,20 pub fn seekTo(self: Self, pos: u64) SeekError!void {
11 seekByFn: fn (self: *Self, pos: i64) SeekError!void,21 return seekToFn(self.context, pos);
12
13 getPosFn: fn (self: *Self) GetSeekPosError!u64,
14 getEndPosFn: fn (self: *Self) GetSeekPosError!u64,
15
16 pub fn seekTo(self: *Self, pos: u64) SeekError!void {
17 return self.seekToFn(self, pos);
18 }22 }
1923
20 pub fn seekBy(self: *Self, amt: i64) SeekError!void {24 pub fn seekBy(self: Self, amt: i64) SeekError!void {
21 return self.seekByFn(self, amt);25 return seekByFn(self.context, amt);
22 }26 }
2327
24 pub fn getEndPos(self: *Self) GetSeekPosError!u64 {28 pub fn getEndPos(self: Self) GetSeekPosError!u64 {
25 return self.getEndPosFn(self);29 return getEndPosFn(self.context);
26 }30 }
2731
28 pub fn getPos(self: *Self) GetSeekPosError!u64 {32 pub fn getPos(self: Self) GetSeekPosError!u64 {
29 return self.getPosFn(self);33 return getPosFn(self.context);
30 }34 }
31 };35 };
32}36}
33
34pub const SliceSeekableInStream = struct {
35 const Self = @This();
36 pub const Error = error{};
37 pub const SeekError = error{EndOfStream};
38 pub const GetSeekPosError = error{};
39 pub const Stream = InStream(Error);
40 pub const SeekableInStream = SeekableStream(SeekError, GetSeekPosError);
41
42 stream: Stream,
43 seekable_stream: SeekableInStream,
44
45 pos: usize,
46 slice: []const u8,
47
48 pub fn init(slice: []const u8) Self {
49 return Self{
50 .slice = slice,
51 .pos = 0,
52 .stream = Stream{ .readFn = readFn },
53 .seekable_stream = SeekableInStream{
54 .seekToFn = seekToFn,
55 .seekByFn = seekByFn,
56 .getEndPosFn = getEndPosFn,
57 .getPosFn = getPosFn,
58 },
59 };
60 }
61
62 fn readFn(in_stream: *Stream, dest: []u8) Error!usize {
63 const self = @fieldParentPtr(Self, "stream", in_stream);
64 const size = std.math.min(dest.len, self.slice.len - self.pos);
65 const end = self.pos + size;
66
67 std.mem.copy(u8, dest[0..size], self.slice[self.pos..end]);
68 self.pos = end;
69
70 return size;
71 }
72
73 fn seekToFn(in_stream: *SeekableInStream, pos: u64) SeekError!void {
74 const self = @fieldParentPtr(Self, "seekable_stream", in_stream);
75 const usize_pos = @intCast(usize, pos);
76 if (usize_pos > self.slice.len) return error.EndOfStream;
77 self.pos = usize_pos;
78 }
79
80 fn seekByFn(in_stream: *SeekableInStream, amt: i64) SeekError!void {
81 const self = @fieldParentPtr(Self, "seekable_stream", in_stream);
82
83 if (amt < 0) {
84 const abs_amt = @intCast(usize, -amt);
85 if (abs_amt > self.pos) return error.EndOfStream;
86 self.pos -= abs_amt;
87 } else {
88 const usize_amt = @intCast(usize, amt);
89 if (self.pos + usize_amt > self.slice.len) return error.EndOfStream;
90 self.pos += usize_amt;
91 }
92 }
93
94 fn getEndPosFn(in_stream: *SeekableInStream) GetSeekPosError!u64 {
95 const self = @fieldParentPtr(Self, "seekable_stream", in_stream);
96 return @intCast(u64, self.slice.len);
97 }
98
99 fn getPosFn(in_stream: *SeekableInStream) GetSeekPosError!u64 {
100 const self = @fieldParentPtr(Self, "seekable_stream", in_stream);
101 return @intCast(u64, self.pos);
102 }
103};
lib/std/json/write_stream.zig+16-16
...@@ -30,11 +30,11 @@ pub fn WriteStream(comptime OutStream: type, comptime max_depth: usize) type {...@@ -30,11 +30,11 @@ pub fn WriteStream(comptime OutStream: type, comptime max_depth: usize) type {
30 /// The string used as spacing.30 /// The string used as spacing.
31 space: []const u8 = " ",31 space: []const u8 = " ",
3232
33 stream: *OutStream,33 stream: OutStream,
34 state_index: usize,34 state_index: usize,
35 state: [max_depth]State,35 state: [max_depth]State,
3636
37 pub fn init(stream: *OutStream) Self {37 pub fn init(stream: OutStream) Self {
38 var self = Self{38 var self = Self{
39 .stream = stream,39 .stream = stream,
40 .state_index = 1,40 .state_index = 1,
...@@ -90,8 +90,8 @@ pub fn WriteStream(comptime OutStream: type, comptime max_depth: usize) type {...@@ -90,8 +90,8 @@ pub fn WriteStream(comptime OutStream: type, comptime max_depth: usize) type {
90 self.pushState(.Value);90 self.pushState(.Value);
91 try self.indent();91 try self.indent();
92 try self.writeEscapedString(name);92 try self.writeEscapedString(name);
93 try self.stream.write(":");93 try self.stream.writeAll(":");
94 try self.stream.write(self.space);94 try self.stream.writeAll(self.space);
95 },95 },
96 }96 }
97 }97 }
...@@ -134,16 +134,16 @@ pub fn WriteStream(comptime OutStream: type, comptime max_depth: usize) type {...@@ -134,16 +134,16 @@ pub fn WriteStream(comptime OutStream: type, comptime max_depth: usize) type {
134134
135 pub fn emitNull(self: *Self) !void {135 pub fn emitNull(self: *Self) !void {
136 assert(self.state[self.state_index] == State.Value);136 assert(self.state[self.state_index] == State.Value);
137 try self.stream.write("null");137 try self.stream.writeAll("null");
138 self.popState();138 self.popState();
139 }139 }
140140
141 pub fn emitBool(self: *Self, value: bool) !void {141 pub fn emitBool(self: *Self, value: bool) !void {
142 assert(self.state[self.state_index] == State.Value);142 assert(self.state[self.state_index] == State.Value);
143 if (value) {143 if (value) {
144 try self.stream.write("true");144 try self.stream.writeAll("true");
145 } else {145 } else {
146 try self.stream.write("false");146 try self.stream.writeAll("false");
147 }147 }
148 self.popState();148 self.popState();
149 }149 }
...@@ -188,13 +188,13 @@ pub fn WriteStream(comptime OutStream: type, comptime max_depth: usize) type {...@@ -188,13 +188,13 @@ pub fn WriteStream(comptime OutStream: type, comptime max_depth: usize) type {
188 try self.stream.writeByte('"');188 try self.stream.writeByte('"');
189 for (string) |s| {189 for (string) |s| {
190 switch (s) {190 switch (s) {
191 '"' => try self.stream.write("\\\""),191 '"' => try self.stream.writeAll("\\\""),
192 '\t' => try self.stream.write("\\t"),192 '\t' => try self.stream.writeAll("\\t"),
193 '\r' => try self.stream.write("\\r"),193 '\r' => try self.stream.writeAll("\\r"),
194 '\n' => try self.stream.write("\\n"),194 '\n' => try self.stream.writeAll("\\n"),
195 8 => try self.stream.write("\\b"),195 8 => try self.stream.writeAll("\\b"),
196 12 => try self.stream.write("\\f"),196 12 => try self.stream.writeAll("\\f"),
197 '\\' => try self.stream.write("\\\\"),197 '\\' => try self.stream.writeAll("\\\\"),
198 else => try self.stream.writeByte(s),198 else => try self.stream.writeByte(s),
199 }199 }
200 }200 }
...@@ -231,10 +231,10 @@ pub fn WriteStream(comptime OutStream: type, comptime max_depth: usize) type {...@@ -231,10 +231,10 @@ pub fn WriteStream(comptime OutStream: type, comptime max_depth: usize) type {
231231
232 fn indent(self: *Self) !void {232 fn indent(self: *Self) !void {
233 assert(self.state_index >= 1);233 assert(self.state_index >= 1);
234 try self.stream.write(self.newline);234 try self.stream.writeAll(self.newline);
235 var i: usize = 0;235 var i: usize = 0;
236 while (i < self.state_index - 1) : (i += 1) {236 while (i < self.state_index - 1) : (i += 1) {
237 try self.stream.write(self.one_indent);237 try self.stream.writeAll(self.one_indent);
238 }238 }
239 }239 }
240240
lib/std/os.zig+1-1
...@@ -176,7 +176,7 @@ fn getRandomBytesDevURandom(buf: []u8) !void {...@@ -176,7 +176,7 @@ fn getRandomBytesDevURandom(buf: []u8) !void {
176 .io_mode = .blocking,176 .io_mode = .blocking,
177 .async_block_allowed = std.fs.File.async_block_allowed_yes,177 .async_block_allowed = std.fs.File.async_block_allowed_yes,
178 };178 };
179 const stream = &file.inStream().stream;179 const stream = file.inStream();
180 stream.readNoEof(buf) catch return error.Unexpected;180 stream.readNoEof(buf) catch return error.Unexpected;
181}181}
182182
lib/std/pdb.zig+2-8
...@@ -632,11 +632,7 @@ const MsfStream = struct {...@@ -632,11 +632,7 @@ const MsfStream = struct {
632 blocks: []u32 = undefined,632 blocks: []u32 = undefined,
633 block_size: u32 = undefined,633 block_size: u32 = undefined,
634634
635 /// Implementation of InStream trait for Pdb.MsfStream
636 stream: Stream = undefined,
637
638 pub const Error = @TypeOf(read).ReturnType.ErrorSet;635 pub const Error = @TypeOf(read).ReturnType.ErrorSet;
639 pub const Stream = io.InStream(Error);
640636
641 fn init(block_size: u32, file: File, blocks: []u32) MsfStream {637 fn init(block_size: u32, file: File, blocks: []u32) MsfStream {
642 const stream = MsfStream{638 const stream = MsfStream{
...@@ -644,7 +640,6 @@ const MsfStream = struct {...@@ -644,7 +640,6 @@ const MsfStream = struct {
644 .pos = 0,640 .pos = 0,
645 .blocks = blocks,641 .blocks = blocks,
646 .block_size = block_size,642 .block_size = block_size,
647 .stream = Stream{ .readFn = readFn },
648 };643 };
649644
650 return stream;645 return stream;
...@@ -715,8 +710,7 @@ const MsfStream = struct {...@@ -715,8 +710,7 @@ const MsfStream = struct {
715 return block * self.block_size + offset;710 return block * self.block_size + offset;
716 }711 }
717712
718 fn readFn(in_stream: *Stream, buffer: []u8) Error!usize {713 fn inStream(self: *MsfStream) std.io.InStream(*MsfStream, Error, read) {
719 const self = @fieldParentPtr(MsfStream, "stream", in_stream);714 return .{ .context = self };
720 return self.read(buffer);
721 }715 }
722};716};
lib/std/zig/ast.zig+1-1
...@@ -375,7 +375,7 @@ pub const Error = union(enum) {...@@ -375,7 +375,7 @@ pub const Error = union(enum) {
375 token: TokenIndex,375 token: TokenIndex,
376376
377 pub fn render(self: *const ThisError, tokens: *Tree.TokenList, stream: var) !void {377 pub fn render(self: *const ThisError, tokens: *Tree.TokenList, stream: var) !void {
378 return stream.write(msg);378 return stream.writeAll(msg);
379 }379 }
380 };380 };
381 }381 }
lib/std/zig/render.zig+66-73
...@@ -12,64 +12,58 @@ pub const Error = error{...@@ -12,64 +12,58 @@ pub const Error = error{
12};12};
1313
14/// Returns whether anything changed14/// Returns whether anything changed
15pub fn render(allocator: *mem.Allocator, stream: var, tree: *ast.Tree) (@TypeOf(stream).Child.Error || Error)!bool {15pub fn render(allocator: *mem.Allocator, stream: var, tree: *ast.Tree) (@TypeOf(stream).Error || Error)!bool {
16 comptime assert(@typeInfo(@TypeOf(stream)) == .Pointer);
17
18 var anything_changed: bool = false;
19
20 // make a passthrough stream that checks whether something changed16 // make a passthrough stream that checks whether something changed
21 const MyStream = struct {17 const MyStream = struct {
22 const MyStream = @This();18 const MyStream = @This();
23 const StreamError = @TypeOf(stream).Child.Error;19 const StreamError = @TypeOf(stream).Error;
24 const Stream = std.io.OutStream(StreamError);
2520
26 anything_changed_ptr: *bool,
27 child_stream: @TypeOf(stream),21 child_stream: @TypeOf(stream),
28 stream: Stream,22 anything_changed: bool,
29 source_index: usize,23 source_index: usize,
30 source: []const u8,24 source: []const u8,
3125
32 fn write(iface_stream: *Stream, bytes: []const u8) StreamError!usize {26 fn write(self: *MyStream, bytes: []const u8) StreamError!usize {
33 const self = @fieldParentPtr(MyStream, "stream", iface_stream);27 if (!self.anything_changed) {
34
35 if (!self.anything_changed_ptr.*) {
36 const end = self.source_index + bytes.len;28 const end = self.source_index + bytes.len;
37 if (end > self.source.len) {29 if (end > self.source.len) {
38 self.anything_changed_ptr.* = true;30 self.anything_changed = true;
39 } else {31 } else {
40 const src_slice = self.source[self.source_index..end];32 const src_slice = self.source[self.source_index..end];
41 self.source_index += bytes.len;33 self.source_index += bytes.len;
42 if (!mem.eql(u8, bytes, src_slice)) {34 if (!mem.eql(u8, bytes, src_slice)) {
43 self.anything_changed_ptr.* = true;35 self.anything_changed = true;
44 }36 }
45 }37 }
46 }38 }
4739
48 return self.child_stream.writeOnce(bytes);40 return self.child_stream.write(bytes);
49 }41 }
50 };42 };
51 var my_stream = MyStream{43 var my_stream = MyStream{
52 .stream = MyStream.Stream{ .writeFn = MyStream.write },
53 .child_stream = stream,44 .child_stream = stream,
54 .anything_changed_ptr = &anything_changed,45 .anything_changed = false,
55 .source_index = 0,46 .source_index = 0,
56 .source = tree.source,47 .source = tree.source,
57 };48 };
49 const my_stream_stream: std.io.OutStream(*MyStream, MyStream.StreamError, MyStream.write) = .{
50 .context = &my_stream,
51 };
5852
59 try renderRoot(allocator, &my_stream.stream, tree);53 try renderRoot(allocator, my_stream_stream, tree);
6054
61 if (!anything_changed and my_stream.source_index != my_stream.source.len) {55 if (my_stream.source_index != my_stream.source.len) {
62 anything_changed = true;56 my_stream.anything_changed = true;
63 }57 }
6458
65 return anything_changed;59 return my_stream.anything_changed;
66}60}
6761
68fn renderRoot(62fn renderRoot(
69 allocator: *mem.Allocator,63 allocator: *mem.Allocator,
70 stream: var,64 stream: var,
71 tree: *ast.Tree,65 tree: *ast.Tree,
72) (@TypeOf(stream).Child.Error || Error)!void {66) (@TypeOf(stream).Error || Error)!void {
73 var tok_it = tree.tokens.iterator(0);67 var tok_it = tree.tokens.iterator(0);
7468
75 // render all the line comments at the beginning of the file69 // render all the line comments at the beginning of the file
...@@ -189,7 +183,7 @@ fn renderRoot(...@@ -189,7 +183,7 @@ fn renderRoot(
189 }183 }
190}184}
191185
192fn renderExtraNewline(tree: *ast.Tree, stream: var, start_col: *usize, node: *ast.Node) @TypeOf(stream).Child.Error!void {186fn renderExtraNewline(tree: *ast.Tree, stream: var, start_col: *usize, node: *ast.Node) @TypeOf(stream).Error!void {
193 const first_token = node.firstToken();187 const first_token = node.firstToken();
194 var prev_token = first_token;188 var prev_token = first_token;
195 if (prev_token == 0) return;189 if (prev_token == 0) return;
...@@ -204,11 +198,11 @@ fn renderExtraNewline(tree: *ast.Tree, stream: var, start_col: *usize, node: *as...@@ -204,11 +198,11 @@ fn renderExtraNewline(tree: *ast.Tree, stream: var, start_col: *usize, node: *as
204 }198 }
205}199}
206200
207fn renderTopLevelDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree, indent: usize, start_col: *usize, decl: *ast.Node) (@TypeOf(stream).Child.Error || Error)!void {201fn renderTopLevelDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree, indent: usize, start_col: *usize, decl: *ast.Node) (@TypeOf(stream).Error || Error)!void {
208 try renderContainerDecl(allocator, stream, tree, indent, start_col, decl, .Newline);202 try renderContainerDecl(allocator, stream, tree, indent, start_col, decl, .Newline);
209}203}
210204
211fn renderContainerDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree, indent: usize, start_col: *usize, decl: *ast.Node, space: Space) (@TypeOf(stream).Child.Error || Error)!void {205fn renderContainerDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree, indent: usize, start_col: *usize, decl: *ast.Node, space: Space) (@TypeOf(stream).Error || Error)!void {
212 switch (decl.id) {206 switch (decl.id) {
213 .FnProto => {207 .FnProto => {
214 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", decl);208 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", decl);
...@@ -343,7 +337,7 @@ fn renderExpression(...@@ -343,7 +337,7 @@ fn renderExpression(
343 start_col: *usize,337 start_col: *usize,
344 base: *ast.Node,338 base: *ast.Node,
345 space: Space,339 space: Space,
346) (@TypeOf(stream).Child.Error || Error)!void {340) (@TypeOf(stream).Error || Error)!void {
347 switch (base.id) {341 switch (base.id) {
348 .Identifier => {342 .Identifier => {
349 const identifier = @fieldParentPtr(ast.Node.Identifier, "base", base);343 const identifier = @fieldParentPtr(ast.Node.Identifier, "base", base);
...@@ -449,9 +443,9 @@ fn renderExpression(...@@ -449,9 +443,9 @@ fn renderExpression(
449 switch (op_tok_id) {443 switch (op_tok_id) {
450 .Asterisk, .AsteriskAsterisk => try stream.writeByte('*'),444 .Asterisk, .AsteriskAsterisk => try stream.writeByte('*'),
451 .LBracket => if (tree.tokens.at(prefix_op_node.op_token + 2).id == .Identifier)445 .LBracket => if (tree.tokens.at(prefix_op_node.op_token + 2).id == .Identifier)
452 try stream.write("[*c")446 try stream.writeAll("[*c")
453 else447 else
454 try stream.write("[*"),448 try stream.writeAll("[*"),
455 else => unreachable,449 else => unreachable,
456 }450 }
457 if (ptr_info.sentinel) |sentinel| {451 if (ptr_info.sentinel) |sentinel| {
...@@ -757,7 +751,7 @@ fn renderExpression(...@@ -757,7 +751,7 @@ fn renderExpression(
757 while (it.next()) |field_init| {751 while (it.next()) |field_init| {
758 var find_stream = FindByteOutStream.init('\n');752 var find_stream = FindByteOutStream.init('\n');
759 var dummy_col: usize = 0;753 var dummy_col: usize = 0;
760 try renderExpression(allocator, &find_stream.stream, tree, 0, &dummy_col, field_init.*, Space.None);754 try renderExpression(allocator, find_stream.outStream(), tree, 0, &dummy_col, field_init.*, Space.None);
761 if (find_stream.byte_found) break :blk false;755 if (find_stream.byte_found) break :blk false;
762 }756 }
763 break :blk true;757 break :blk true;
...@@ -909,8 +903,7 @@ fn renderExpression(...@@ -909,8 +903,7 @@ fn renderExpression(
909 var column_widths = widths[widths.len - row_size ..];903 var column_widths = widths[widths.len - row_size ..];
910904
911 // Null stream for counting the printed length of each expression905 // Null stream for counting the printed length of each expression
912 var null_stream = std.io.NullOutStream.init();906 var counting_stream = std.io.CountingOutStream(@TypeOf(std.io.null_out_stream)).init(std.io.null_out_stream);
913 var counting_stream = std.io.CountingOutStream(std.io.NullOutStream.Error).init(&null_stream.stream);
914907
915 var it = exprs.iterator(0);908 var it = exprs.iterator(0);
916 var i: usize = 0;909 var i: usize = 0;
...@@ -918,7 +911,7 @@ fn renderExpression(...@@ -918,7 +911,7 @@ fn renderExpression(
918 while (it.next()) |expr| : (i += 1) {911 while (it.next()) |expr| : (i += 1) {
919 counting_stream.bytes_written = 0;912 counting_stream.bytes_written = 0;
920 var dummy_col: usize = 0;913 var dummy_col: usize = 0;
921 try renderExpression(allocator, &counting_stream.stream, tree, indent, &dummy_col, expr.*, Space.None);914 try renderExpression(allocator, counting_stream.outStream(), tree, indent, &dummy_col, expr.*, Space.None);
922 const width = @intCast(usize, counting_stream.bytes_written);915 const width = @intCast(usize, counting_stream.bytes_written);
923 const col = i % row_size;916 const col = i % row_size;
924 column_widths[col] = std.math.max(column_widths[col], width);917 column_widths[col] = std.math.max(column_widths[col], width);
...@@ -1336,7 +1329,7 @@ fn renderExpression(...@@ -1336,7 +1329,7 @@ fn renderExpression(
13361329
1337 // TODO: Remove condition after deprecating 'typeOf'. See https://github.com/ziglang/zig/issues/13481330 // TODO: Remove condition after deprecating 'typeOf'. See https://github.com/ziglang/zig/issues/1348
1338 if (mem.eql(u8, tree.tokenSlicePtr(tree.tokens.at(builtin_call.builtin_token)), "@typeOf")) {1331 if (mem.eql(u8, tree.tokenSlicePtr(tree.tokens.at(builtin_call.builtin_token)), "@typeOf")) {
1339 try stream.write("@TypeOf");1332 try stream.writeAll("@TypeOf");
1340 } else {1333 } else {
1341 try renderToken(tree, stream, builtin_call.builtin_token, indent, start_col, Space.None); // @name1334 try renderToken(tree, stream, builtin_call.builtin_token, indent, start_col, Space.None); // @name
1342 }1335 }
...@@ -1505,9 +1498,9 @@ fn renderExpression(...@@ -1505,9 +1498,9 @@ fn renderExpression(
1505 try renderExpression(allocator, stream, tree, indent, start_col, callconv_expr, Space.None);1498 try renderExpression(allocator, stream, tree, indent, start_col, callconv_expr, Space.None);
1506 try renderToken(tree, stream, callconv_rparen, indent, start_col, Space.Space); // )1499 try renderToken(tree, stream, callconv_rparen, indent, start_col, Space.Space); // )
1507 } else if (cc_rewrite_str) |str| {1500 } else if (cc_rewrite_str) |str| {
1508 try stream.write("callconv(");1501 try stream.writeAll("callconv(");
1509 try stream.write(mem.toSliceConst(u8, str));1502 try stream.writeAll(mem.toSliceConst(u8, str));
1510 try stream.write(") ");1503 try stream.writeAll(") ");
1511 }1504 }
15121505
1513 switch (fn_proto.return_type) {1506 switch (fn_proto.return_type) {
...@@ -1997,11 +1990,11 @@ fn renderExpression(...@@ -1997,11 +1990,11 @@ fn renderExpression(
1997 .AsmInput => {1990 .AsmInput => {
1998 const asm_input = @fieldParentPtr(ast.Node.AsmInput, "base", base);1991 const asm_input = @fieldParentPtr(ast.Node.AsmInput, "base", base);
19991992
2000 try stream.write("[");1993 try stream.writeAll("[");
2001 try renderExpression(allocator, stream, tree, indent, start_col, asm_input.symbolic_name, Space.None);1994 try renderExpression(allocator, stream, tree, indent, start_col, asm_input.symbolic_name, Space.None);
2002 try stream.write("] ");1995 try stream.writeAll("] ");
2003 try renderExpression(allocator, stream, tree, indent, start_col, asm_input.constraint, Space.None);1996 try renderExpression(allocator, stream, tree, indent, start_col, asm_input.constraint, Space.None);
2004 try stream.write(" (");1997 try stream.writeAll(" (");
2005 try renderExpression(allocator, stream, tree, indent, start_col, asm_input.expr, Space.None);1998 try renderExpression(allocator, stream, tree, indent, start_col, asm_input.expr, Space.None);
2006 return renderToken(tree, stream, asm_input.lastToken(), indent, start_col, space); // )1999 return renderToken(tree, stream, asm_input.lastToken(), indent, start_col, space); // )
2007 },2000 },
...@@ -2009,18 +2002,18 @@ fn renderExpression(...@@ -2009,18 +2002,18 @@ fn renderExpression(
2009 .AsmOutput => {2002 .AsmOutput => {
2010 const asm_output = @fieldParentPtr(ast.Node.AsmOutput, "base", base);2003 const asm_output = @fieldParentPtr(ast.Node.AsmOutput, "base", base);
20112004
2012 try stream.write("[");2005 try stream.writeAll("[");
2013 try renderExpression(allocator, stream, tree, indent, start_col, asm_output.symbolic_name, Space.None);2006 try renderExpression(allocator, stream, tree, indent, start_col, asm_output.symbolic_name, Space.None);
2014 try stream.write("] ");2007 try stream.writeAll("] ");
2015 try renderExpression(allocator, stream, tree, indent, start_col, asm_output.constraint, Space.None);2008 try renderExpression(allocator, stream, tree, indent, start_col, asm_output.constraint, Space.None);
2016 try stream.write(" (");2009 try stream.writeAll(" (");
20172010
2018 switch (asm_output.kind) {2011 switch (asm_output.kind) {
2019 ast.Node.AsmOutput.Kind.Variable => |variable_name| {2012 ast.Node.AsmOutput.Kind.Variable => |variable_name| {
2020 try renderExpression(allocator, stream, tree, indent, start_col, &variable_name.base, Space.None);2013 try renderExpression(allocator, stream, tree, indent, start_col, &variable_name.base, Space.None);
2021 },2014 },
2022 ast.Node.AsmOutput.Kind.Return => |return_type| {2015 ast.Node.AsmOutput.Kind.Return => |return_type| {
2023 try stream.write("-> ");2016 try stream.writeAll("-> ");
2024 try renderExpression(allocator, stream, tree, indent, start_col, return_type, Space.None);2017 try renderExpression(allocator, stream, tree, indent, start_col, return_type, Space.None);
2025 },2018 },
2026 }2019 }
...@@ -2052,7 +2045,7 @@ fn renderVarDecl(...@@ -2052,7 +2045,7 @@ fn renderVarDecl(
2052 indent: usize,2045 indent: usize,
2053 start_col: *usize,2046 start_col: *usize,
2054 var_decl: *ast.Node.VarDecl,2047 var_decl: *ast.Node.VarDecl,
2055) (@TypeOf(stream).Child.Error || Error)!void {2048) (@TypeOf(stream).Error || Error)!void {
2056 if (var_decl.visib_token) |visib_token| {2049 if (var_decl.visib_token) |visib_token| {
2057 try renderToken(tree, stream, visib_token, indent, start_col, Space.Space); // pub2050 try renderToken(tree, stream, visib_token, indent, start_col, Space.Space); // pub
2058 }2051 }
...@@ -2125,7 +2118,7 @@ fn renderParamDecl(...@@ -2125,7 +2118,7 @@ fn renderParamDecl(
2125 start_col: *usize,2118 start_col: *usize,
2126 base: *ast.Node,2119 base: *ast.Node,
2127 space: Space,2120 space: Space,
2128) (@TypeOf(stream).Child.Error || Error)!void {2121) (@TypeOf(stream).Error || Error)!void {
2129 const param_decl = @fieldParentPtr(ast.Node.ParamDecl, "base", base);2122 const param_decl = @fieldParentPtr(ast.Node.ParamDecl, "base", base);
21302123
2131 try renderDocComments(tree, stream, param_decl, indent, start_col);2124 try renderDocComments(tree, stream, param_decl, indent, start_col);
...@@ -2154,7 +2147,7 @@ fn renderStatement(...@@ -2154,7 +2147,7 @@ fn renderStatement(
2154 indent: usize,2147 indent: usize,
2155 start_col: *usize,2148 start_col: *usize,
2156 base: *ast.Node,2149 base: *ast.Node,
2157) (@TypeOf(stream).Child.Error || Error)!void {2150) (@TypeOf(stream).Error || Error)!void {
2158 switch (base.id) {2151 switch (base.id) {
2159 .VarDecl => {2152 .VarDecl => {
2160 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", base);2153 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", base);
...@@ -2193,7 +2186,7 @@ fn renderTokenOffset(...@@ -2193,7 +2186,7 @@ fn renderTokenOffset(
2193 start_col: *usize,2186 start_col: *usize,
2194 space: Space,2187 space: Space,
2195 token_skip_bytes: usize,2188 token_skip_bytes: usize,
2196) (@TypeOf(stream).Child.Error || Error)!void {2189) (@TypeOf(stream).Error || Error)!void {
2197 if (space == Space.BlockStart) {2190 if (space == Space.BlockStart) {
2198 if (start_col.* < indent + indent_delta)2191 if (start_col.* < indent + indent_delta)
2199 return renderToken(tree, stream, token_index, indent, start_col, Space.Space);2192 return renderToken(tree, stream, token_index, indent, start_col, Space.Space);
...@@ -2204,7 +2197,7 @@ fn renderTokenOffset(...@@ -2204,7 +2197,7 @@ fn renderTokenOffset(
2204 }2197 }
22052198
2206 var token = tree.tokens.at(token_index);2199 var token = tree.tokens.at(token_index);
2207 try stream.write(mem.trimRight(u8, tree.tokenSlicePtr(token)[token_skip_bytes..], " "));2200 try stream.writeAll(mem.trimRight(u8, tree.tokenSlicePtr(token)[token_skip_bytes..], " "));
22082201
2209 if (space == Space.NoComment)2202 if (space == Space.NoComment)
2210 return;2203 return;
...@@ -2214,15 +2207,15 @@ fn renderTokenOffset(...@@ -2214,15 +2207,15 @@ fn renderTokenOffset(
2214 if (space == Space.Comma) switch (next_token.id) {2207 if (space == Space.Comma) switch (next_token.id) {
2215 .Comma => return renderToken(tree, stream, token_index + 1, indent, start_col, Space.Newline),2208 .Comma => return renderToken(tree, stream, token_index + 1, indent, start_col, Space.Newline),
2216 .LineComment => {2209 .LineComment => {
2217 try stream.write(", ");2210 try stream.writeAll(", ");
2218 return renderToken(tree, stream, token_index + 1, indent, start_col, Space.Newline);2211 return renderToken(tree, stream, token_index + 1, indent, start_col, Space.Newline);
2219 },2212 },
2220 else => {2213 else => {
2221 if (token_index + 2 < tree.tokens.len and tree.tokens.at(token_index + 2).id == .MultilineStringLiteralLine) {2214 if (token_index + 2 < tree.tokens.len and tree.tokens.at(token_index + 2).id == .MultilineStringLiteralLine) {
2222 try stream.write(",");2215 try stream.writeAll(",");
2223 return;2216 return;
2224 } else {2217 } else {
2225 try stream.write(",\n");2218 try stream.writeAll(",\n");
2226 start_col.* = 0;2219 start_col.* = 0;
2227 return;2220 return;
2228 }2221 }
...@@ -2246,7 +2239,7 @@ fn renderTokenOffset(...@@ -2246,7 +2239,7 @@ fn renderTokenOffset(
2246 if (next_token.id == .MultilineStringLiteralLine) {2239 if (next_token.id == .MultilineStringLiteralLine) {
2247 return;2240 return;
2248 } else {2241 } else {
2249 try stream.write("\n");2242 try stream.writeAll("\n");
2250 start_col.* = 0;2243 start_col.* = 0;
2251 return;2244 return;
2252 }2245 }
...@@ -2309,7 +2302,7 @@ fn renderTokenOffset(...@@ -2309,7 +2302,7 @@ fn renderTokenOffset(
2309 if (next_token.id == .MultilineStringLiteralLine) {2302 if (next_token.id == .MultilineStringLiteralLine) {
2310 return;2303 return;
2311 } else {2304 } else {
2312 try stream.write("\n");2305 try stream.writeAll("\n");
2313 start_col.* = 0;2306 start_col.* = 0;
2314 return;2307 return;
2315 }2308 }
...@@ -2327,7 +2320,7 @@ fn renderTokenOffset(...@@ -2327,7 +2320,7 @@ fn renderTokenOffset(
2327 const newline_count = if (loc.line == 1) @as(u8, 1) else @as(u8, 2);2320 const newline_count = if (loc.line == 1) @as(u8, 1) else @as(u8, 2);
2328 try stream.writeByteNTimes('\n', newline_count);2321 try stream.writeByteNTimes('\n', newline_count);
2329 try stream.writeByteNTimes(' ', indent);2322 try stream.writeByteNTimes(' ', indent);
2330 try stream.write(mem.trimRight(u8, tree.tokenSlicePtr(next_token), " "));2323 try stream.writeAll(mem.trimRight(u8, tree.tokenSlicePtr(next_token), " "));
23312324
2332 offset += 1;2325 offset += 1;
2333 token = next_token;2326 token = next_token;
...@@ -2338,7 +2331,7 @@ fn renderTokenOffset(...@@ -2338,7 +2331,7 @@ fn renderTokenOffset(
2338 if (next_token.id == .MultilineStringLiteralLine) {2331 if (next_token.id == .MultilineStringLiteralLine) {
2339 return;2332 return;
2340 } else {2333 } else {
2341 try stream.write("\n");2334 try stream.writeAll("\n");
2342 start_col.* = 0;2335 start_col.* = 0;
2343 return;2336 return;
2344 }2337 }
...@@ -2381,7 +2374,7 @@ fn renderToken(...@@ -2381,7 +2374,7 @@ fn renderToken(
2381 indent: usize,2374 indent: usize,
2382 start_col: *usize,2375 start_col: *usize,
2383 space: Space,2376 space: Space,
2384) (@TypeOf(stream).Child.Error || Error)!void {2377) (@TypeOf(stream).Error || Error)!void {
2385 return renderTokenOffset(tree, stream, token_index, indent, start_col, space, 0);2378 return renderTokenOffset(tree, stream, token_index, indent, start_col, space, 0);
2386}2379}
23872380
...@@ -2391,7 +2384,7 @@ fn renderDocComments(...@@ -2391,7 +2384,7 @@ fn renderDocComments(
2391 node: var,2384 node: var,
2392 indent: usize,2385 indent: usize,
2393 start_col: *usize,2386 start_col: *usize,
2394) (@TypeOf(stream).Child.Error || Error)!void {2387) (@TypeOf(stream).Error || Error)!void {
2395 const comment = node.doc_comments orelse return;2388 const comment = node.doc_comments orelse return;
2396 var it = comment.lines.iterator(0);2389 var it = comment.lines.iterator(0);
2397 const first_token = node.firstToken();2390 const first_token = node.firstToken();
...@@ -2401,7 +2394,7 @@ fn renderDocComments(...@@ -2401,7 +2394,7 @@ fn renderDocComments(
2401 try stream.writeByteNTimes(' ', indent);2394 try stream.writeByteNTimes(' ', indent);
2402 } else {2395 } else {
2403 try renderToken(tree, stream, line_token_index.*, indent, start_col, Space.NoComment);2396 try renderToken(tree, stream, line_token_index.*, indent, start_col, Space.NoComment);
2404 try stream.write("\n");2397 try stream.writeAll("\n");
2405 try stream.writeByteNTimes(' ', indent);2398 try stream.writeByteNTimes(' ', indent);
2406 }2399 }
2407 }2400 }
...@@ -2427,27 +2420,23 @@ fn nodeCausesSliceOpSpace(base: *ast.Node) bool {...@@ -2427,27 +2420,23 @@ fn nodeCausesSliceOpSpace(base: *ast.Node) bool {
2427 };2420 };
2428}2421}
24292422
2430// An OutStream that returns whether the given character has been written to it.2423/// A `std.io.OutStream` that returns whether the given character has been written to it.
2431// The contents are not written to anything.2424/// The contents are not written to anything.
2432const FindByteOutStream = struct {2425const FindByteOutStream = struct {
2433 const Self = FindByteOutStream;
2434 pub const Error = error{};
2435 pub const Stream = std.io.OutStream(Error);
2436
2437 stream: Stream,
2438 byte_found: bool,2426 byte_found: bool,
2439 byte: u8,2427 byte: u8,
24402428
2441 pub fn init(byte: u8) Self {2429 pub const Error = error{};
2442 return Self{2430 pub const OutStream = std.io.OutStream(*FindByteOutStream, Error, write);
2443 .stream = Stream{ .writeFn = writeFn },2431
2432 pub fn init(byte: u8) FindByteOutStream {
2433 return FindByteOutStream{
2444 .byte = byte,2434 .byte = byte,
2445 .byte_found = false,2435 .byte_found = false,
2446 };2436 };
2447 }2437 }
24482438
2449 fn writeFn(out_stream: *Stream, bytes: []const u8) Error!usize {2439 pub fn write(self: *FindByteOutStream, bytes: []const u8) Error!usize {
2450 const self = @fieldParentPtr(Self, "stream", out_stream);
2451 if (self.byte_found) return bytes.len;2440 if (self.byte_found) return bytes.len;
2452 self.byte_found = blk: {2441 self.byte_found = blk: {
2453 for (bytes) |b|2442 for (bytes) |b|
...@@ -2456,11 +2445,15 @@ const FindByteOutStream = struct {...@@ -2456,11 +2445,15 @@ const FindByteOutStream = struct {
2456 };2445 };
2457 return bytes.len;2446 return bytes.len;
2458 }2447 }
2448
2449 pub fn outStream(self: *FindByteOutStream) OutStream {
2450 return .{ .context = self };
2451 }
2459};2452};
24602453
2461fn copyFixingWhitespace(stream: var, slice: []const u8) @TypeOf(stream).Child.Error!void {2454fn copyFixingWhitespace(stream: var, slice: []const u8) @TypeOf(stream).Error!void {
2462 for (slice) |byte| switch (byte) {2455 for (slice) |byte| switch (byte) {
2463 '\t' => try stream.write(" "),2456 '\t' => try stream.writeAll(" "),
2464 '\r' => {},2457 '\r' => {},
2465 else => try stream.writeByte(byte),2458 else => try stream.writeByte(byte),
2466 };2459 };
src-self-hosted/libc_installation.zig+2-2
...@@ -38,7 +38,7 @@ pub const LibCInstallation = struct {...@@ -38,7 +38,7 @@ pub const LibCInstallation = struct {
38 pub fn parse(38 pub fn parse(
39 allocator: *Allocator,39 allocator: *Allocator,
40 libc_file: []const u8,40 libc_file: []const u8,
41 stderr: *std.io.OutStream(fs.File.WriteError),41 stderr: var,
42 ) !LibCInstallation {42 ) !LibCInstallation {
43 var self: LibCInstallation = .{};43 var self: LibCInstallation = .{};
4444
...@@ -123,7 +123,7 @@ pub const LibCInstallation = struct {...@@ -123,7 +123,7 @@ pub const LibCInstallation = struct {
123 return self;123 return self;
124 }124 }
125125
126 pub fn render(self: LibCInstallation, out: *std.io.OutStream(fs.File.WriteError)) !void {126 pub fn render(self: LibCInstallation, out: var) !void {
127 @setEvalBranchQuota(4000);127 @setEvalBranchQuota(4000);
128 const include_dir = self.include_dir orelse "";128 const include_dir = self.include_dir orelse "";
129 const sys_include_dir = self.sys_include_dir orelse "";129 const sys_include_dir = self.sys_include_dir orelse "";
src-self-hosted/print_targets.zig+7-6
...@@ -52,7 +52,7 @@ const available_libcs = [_][]const u8{...@@ -52,7 +52,7 @@ const available_libcs = [_][]const u8{
52 "sparc-linux-gnu",52 "sparc-linux-gnu",
53 "sparcv9-linux-gnu",53 "sparcv9-linux-gnu",
54 "wasm32-freestanding-musl",54 "wasm32-freestanding-musl",
55 "x86_64-linux-gnu (native)",55 "x86_64-linux-gnu",
56 "x86_64-linux-gnux32",56 "x86_64-linux-gnux32",
57 "x86_64-linux-musl",57 "x86_64-linux-musl",
58 "x86_64-windows-gnu",58 "x86_64-windows-gnu",
...@@ -61,7 +61,8 @@ const available_libcs = [_][]const u8{...@@ -61,7 +61,8 @@ const available_libcs = [_][]const u8{
61pub fn cmdTargets(61pub fn cmdTargets(
62 allocator: *Allocator,62 allocator: *Allocator,
63 args: []const []const u8,63 args: []const []const u8,
64 stdout: *io.OutStream(fs.File.WriteError),64 /// Output stream
65 stdout: var,
65 native_target: Target,66 native_target: Target,
66) !void {67) !void {
67 const available_glibcs = blk: {68 const available_glibcs = blk: {
...@@ -92,9 +93,9 @@ pub fn cmdTargets(...@@ -92,9 +93,9 @@ pub fn cmdTargets(
92 };93 };
93 defer allocator.free(available_glibcs);94 defer allocator.free(available_glibcs);
9495
95 const BOS = io.BufferedOutStream(fs.File.WriteError);96 var bos = io.bufferedOutStream(4096, stdout);
96 var bos = BOS.init(stdout);97 const bos_stream = bos.outStream();
97 var jws = std.json.WriteStream(BOS.Stream, 6).init(&bos.stream);98 var jws = std.json.WriteStream(@TypeOf(bos_stream), 6).init(bos_stream);
9899
99 try jws.beginObject();100 try jws.beginObject();
100101
...@@ -219,6 +220,6 @@ pub fn cmdTargets(...@@ -219,6 +220,6 @@ pub fn cmdTargets(
219220
220 try jws.endObject();221 try jws.endObject();
221222
222 try bos.stream.writeByte('\n');223 try bos_stream.writeByte('\n');
223 return bos.flush();224 return bos.flush();
224}225}
src-self-hosted/stage2.zig+15-15
...@@ -18,8 +18,8 @@ const assert = std.debug.assert;...@@ -18,8 +18,8 @@ const assert = std.debug.assert;
18const LibCInstallation = @import("libc_installation.zig").LibCInstallation;18const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
1919
20var stderr_file: fs.File = undefined;20var stderr_file: fs.File = undefined;
21var stderr: *io.OutStream(fs.File.WriteError) = undefined;21var stderr: fs.File.OutStream = undefined;
22var stdout: *io.OutStream(fs.File.WriteError) = undefined;22var stdout: fs.File.OutStream = undefined;
2323
24comptime {24comptime {
25 _ = @import("dep_tokenizer.zig");25 _ = @import("dep_tokenizer.zig");
...@@ -146,7 +146,7 @@ export fn stage2_free_clang_errors(errors_ptr: [*]translate_c.ClangErrMsg, error...@@ -146,7 +146,7 @@ export fn stage2_free_clang_errors(errors_ptr: [*]translate_c.ClangErrMsg, error
146}146}
147147
148export fn stage2_render_ast(tree: *ast.Tree, output_file: *FILE) Error {148export fn stage2_render_ast(tree: *ast.Tree, output_file: *FILE) Error {
149 const c_out_stream = &std.io.COutStream.init(output_file).stream;149 const c_out_stream = std.io.cOutStream(output_file);
150 _ = std.zig.render(std.heap.c_allocator, c_out_stream, tree) catch |e| switch (e) {150 _ = std.zig.render(std.heap.c_allocator, c_out_stream, tree) catch |e| switch (e) {
151 error.WouldBlock => unreachable, // stage1 opens stuff in exclusively blocking mode151 error.WouldBlock => unreachable, // stage1 opens stuff in exclusively blocking mode
152 error.SystemResources => return .SystemResources,152 error.SystemResources => return .SystemResources,
...@@ -186,9 +186,9 @@ fn fmtMain(argc: c_int, argv: [*]const [*:0]const u8) !void {...@@ -186,9 +186,9 @@ fn fmtMain(argc: c_int, argv: [*]const [*:0]const u8) !void {
186 try args_list.append(mem.toSliceConst(u8, argv[arg_i]));186 try args_list.append(mem.toSliceConst(u8, argv[arg_i]));
187 }187 }
188188
189 stdout = &std.io.getStdOut().outStream().stream;189 stdout = std.io.getStdOut().outStream();
190 stderr_file = std.io.getStdErr();190 stderr_file = std.io.getStdErr();
191 stderr = &stderr_file.outStream().stream;191 stderr = stderr_file.outStream();
192192
193 const args = args_list.toSliceConst()[2..];193 const args = args_list.toSliceConst()[2..];
194194
...@@ -203,11 +203,11 @@ fn fmtMain(argc: c_int, argv: [*]const [*:0]const u8) !void {...@@ -203,11 +203,11 @@ fn fmtMain(argc: c_int, argv: [*]const [*:0]const u8) !void {
203 const arg = args[i];203 const arg = args[i];
204 if (mem.startsWith(u8, arg, "-")) {204 if (mem.startsWith(u8, arg, "-")) {
205 if (mem.eql(u8, arg, "--help")) {205 if (mem.eql(u8, arg, "--help")) {
206 try stdout.write(self_hosted_main.usage_fmt);206 try stdout.writeAll(self_hosted_main.usage_fmt);
207 process.exit(0);207 process.exit(0);
208 } else if (mem.eql(u8, arg, "--color")) {208 } else if (mem.eql(u8, arg, "--color")) {
209 if (i + 1 >= args.len) {209 if (i + 1 >= args.len) {
210 try stderr.write("expected [auto|on|off] after --color\n");210 try stderr.writeAll("expected [auto|on|off] after --color\n");
211 process.exit(1);211 process.exit(1);
212 }212 }
213 i += 1;213 i += 1;
...@@ -238,14 +238,14 @@ fn fmtMain(argc: c_int, argv: [*]const [*:0]const u8) !void {...@@ -238,14 +238,14 @@ fn fmtMain(argc: c_int, argv: [*]const [*:0]const u8) !void {
238238
239 if (stdin_flag) {239 if (stdin_flag) {
240 if (input_files.len != 0) {240 if (input_files.len != 0) {
241 try stderr.write("cannot use --stdin with positional arguments\n");241 try stderr.writeAll("cannot use --stdin with positional arguments\n");
242 process.exit(1);242 process.exit(1);
243 }243 }
244244
245 const stdin_file = io.getStdIn();245 const stdin_file = io.getStdIn();
246 var stdin = stdin_file.inStream();246 var stdin = stdin_file.inStream();
247247
248 const source_code = try stdin.stream.readAllAlloc(allocator, self_hosted_main.max_src_size);248 const source_code = try stdin.readAllAlloc(allocator, self_hosted_main.max_src_size);
249 defer allocator.free(source_code);249 defer allocator.free(source_code);
250250
251 const tree = std.zig.parse(allocator, source_code) catch |err| {251 const tree = std.zig.parse(allocator, source_code) catch |err| {
...@@ -272,7 +272,7 @@ fn fmtMain(argc: c_int, argv: [*]const [*:0]const u8) !void {...@@ -272,7 +272,7 @@ fn fmtMain(argc: c_int, argv: [*]const [*:0]const u8) !void {
272 }272 }
273273
274 if (input_files.len == 0) {274 if (input_files.len == 0) {
275 try stderr.write("expected at least one source file argument\n");275 try stderr.writeAll("expected at least one source file argument\n");
276 process.exit(1);276 process.exit(1);
277 }277 }
278278
...@@ -409,11 +409,11 @@ fn printErrMsgToFile(...@@ -409,11 +409,11 @@ fn printErrMsgToFile(
409 const end_loc = tree.tokenLocationPtr(first_token.end, last_token);409 const end_loc = tree.tokenLocationPtr(first_token.end, last_token);
410410
411 var text_buf = try std.Buffer.initSize(allocator, 0);411 var text_buf = try std.Buffer.initSize(allocator, 0);
412 var out_stream = &std.io.BufferOutStream.init(&text_buf).stream;412 const out_stream = &text_buf.outStream();
413 try parse_error.render(&tree.tokens, out_stream);413 try parse_error.render(&tree.tokens, out_stream);
414 const text = text_buf.toOwnedSlice();414 const text = text_buf.toOwnedSlice();
415415
416 const stream = &file.outStream().stream;416 const stream = &file.outStream();
417 try stream.print("{}:{}:{}: error: {}\n", .{ path, start_loc.line + 1, start_loc.column + 1, text });417 try stream.print("{}:{}:{}: error: {}\n", .{ path, start_loc.line + 1, start_loc.column + 1, text });
418418
419 if (!color_on) return;419 if (!color_on) return;
...@@ -641,7 +641,7 @@ fn cmdTargets(zig_triple: [*:0]const u8) !void {...@@ -641,7 +641,7 @@ fn cmdTargets(zig_triple: [*:0]const u8) !void {
641 return @import("print_targets.zig").cmdTargets(641 return @import("print_targets.zig").cmdTargets(
642 std.heap.c_allocator,642 std.heap.c_allocator,
643 &[0][]u8{},643 &[0][]u8{},
644 &std.io.getStdOut().outStream().stream,644 std.io.getStdOut().outStream(),
645 target,645 target,
646 );646 );
647}647}
...@@ -808,7 +808,7 @@ const Stage2LibCInstallation = extern struct {...@@ -808,7 +808,7 @@ const Stage2LibCInstallation = extern struct {
808// ABI warning808// ABI warning
809export fn stage2_libc_parse(stage1_libc: *Stage2LibCInstallation, libc_file_z: [*:0]const u8) Error {809export fn stage2_libc_parse(stage1_libc: *Stage2LibCInstallation, libc_file_z: [*:0]const u8) Error {
810 stderr_file = std.io.getStdErr();810 stderr_file = std.io.getStdErr();
811 stderr = &stderr_file.outStream().stream;811 stderr = stderr_file.outStream();
812 const libc_file = mem.toSliceConst(u8, libc_file_z);812 const libc_file = mem.toSliceConst(u8, libc_file_z);
813 var libc = LibCInstallation.parse(std.heap.c_allocator, libc_file, stderr) catch |err| switch (err) {813 var libc = LibCInstallation.parse(std.heap.c_allocator, libc_file, stderr) catch |err| switch (err) {
814 error.ParseError => return .SemanticAnalyzeFail,814 error.ParseError => return .SemanticAnalyzeFail,
...@@ -870,7 +870,7 @@ export fn stage2_libc_find_native(stage1_libc: *Stage2LibCInstallation) Error {...@@ -870,7 +870,7 @@ export fn stage2_libc_find_native(stage1_libc: *Stage2LibCInstallation) Error {
870// ABI warning870// ABI warning
871export fn stage2_libc_render(stage1_libc: *Stage2LibCInstallation, output_file: *FILE) Error {871export fn stage2_libc_render(stage1_libc: *Stage2LibCInstallation, output_file: *FILE) Error {
872 var libc = stage1_libc.toStage2();872 var libc = stage1_libc.toStage2();
873 const c_out_stream = &std.io.COutStream.init(output_file).stream;873 const c_out_stream = std.io.cOutStream(output_file);
874 libc.render(c_out_stream) catch |err| switch (err) {874 libc.render(c_out_stream) catch |err| switch (err) {
875 error.WouldBlock => unreachable, // stage1 opens stuff in exclusively blocking mode875 error.WouldBlock => unreachable, // stage1 opens stuff in exclusively blocking mode
876 error.SystemResources => return .SystemResources,876 error.SystemResources => return .SystemResources,