| author | |
| committer | |
| log | ba0e3be5cfa2f60f2f9d2a4eb319408f972796c2 |
| tree | da35c17d0067a463b521163f624f3d109b8050f4 |
| parent | 1ad831a0ef22f354d4e1dd5073456a0683249846 |
| signature |
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 | }; |
| 161 | 172 | ||
| 162 | test "simple Buffer" { | 173 | test "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(); |
| 222 | 222 | ||
| 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); |
| 228 | 228 | ||
| 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 | } |
| 863 | 862 | ||
| 864 | fn readIntFd(fd: i32) !ErrInt { | 863 | fn 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 | } |
| 873 | 871 | ||
| 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 { |
| 55 | var stderr_file: File = undefined; | 55 | var stderr_file: File = undefined; |
| 56 | var stderr_file_out_stream: File.OutStream = undefined; | 56 | var stderr_file_out_stream: File.OutStream = undefined; |
| 57 | 57 | ||
| 58 | var stderr_stream: ?*io.OutStream(File.WriteError) = null; | 58 | var stderr_stream: ?*File.OutStream = null; |
| 59 | var stderr_mutex = std.Mutex.init(); | 59 | var stderr_mutex = std.Mutex.init(); |
| 60 | 60 | ||
| 61 | pub fn warn(comptime fmt: []const u8, args: var) void { | 61 | 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,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 | } |
| 67 | 67 | ||
| 68 | pub fn getStderrStream() *io.OutStream(File.WriteError) { | 68 | pub 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, |
| 409 | 409 | ||
| 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); | ||
| 569 | 570 | ||
| 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 | } |
| 575 | 576 | ||
| 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"); |
| 582 | 583 | ||
| 583 | // Show the matching source code line if possible | 584 | // 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 char | 588 | // The caret already takes one char |
| 588 | const space_needed = @intCast(usize, li.column - 1); | 589 | const space_needed = @intCast(usize, li.column - 1); |
| 589 | 590 | ||
| 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 | }; |
| 610 | 612 | ||
| 611 | /// TODO resources https://github.com/ziglang/zig/issues/4353 | 613 | /// 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. | ||
| 614 | pub fn openSelfDebugInfo(allocator: *mem.Allocator) anyerror!DebugInfo { | 614 | pub 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 | } |
| 629 | 631 | ||
| ... | @@ -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 { |
| 808 | 810 | ||
| 809 | /// TODO resources https://github.com/ziglang/zig/issues/4353 | 811 | /// TODO resources https://github.com/ziglang/zig/issues/4353 |
| 810 | pub fn openElfDebugInfo(allocator: *mem.Allocator, elf_file_path: []const u8) !ModuleDebugInfo { | 812 | pub fn openElfDebugInfo(allocator: *mem.Allocator, elf_file_path: []const u8) !ModuleDebugInfo { |
| 811 | const mapped_mem = try mapWholeFile(elf_file_path); | 813 | noasync { |
| 812 | 814 | 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 | } | ||
| 820 | 853 | ||
| 821 | const debug_info = (try noasync efile.findSection(".debug_info")) orelse | 854 | var di = DW.DwarfInfo{ |
| 822 | return error.MissingDebugInfo; | 855 | .endian = endian, |
| 823 | const debug_abbrev = (try noasync efile.findSection(".debug_abbrev")) orelse | 856 | .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")) orelse | 858 | .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")) orelse | 860 | .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 | }; | ||
| 842 | 862 | ||
| 843 | try noasync DW.openDwarfDebugInfo(&di, allocator); | 863 | try DW.openDwarfDebugInfo(&di, allocator); |
| 844 | 864 | ||
| 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 | } |
| 851 | 872 | ||
| 852 | /// TODO resources https://github.com/ziglang/zig/issues/4353 | 873 | /// 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 | }; |
| 984 | 1005 | ||
| 985 | fn mapWholeFile(path: []const u8) ![]const u8 { | 1006 | fn 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 }); |
| 988 | 1009 | 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); | ||
| 999 | 1010 | ||
| 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 | } |
| 1002 | 1025 | ||
| 1003 | pub const DebugInfo = struct { | 1026 | pub 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; |
| 11 | 11 | ||
| 12 | usingnamespace @import("dwarf_bits.zig"); | 12 | usingnamespace @import("dwarf_bits.zig"); |
| 13 | 13 | ||
| 14 | pub const DwarfSeekableStream = io.SeekableStream(anyerror, anyerror); | ||
| 15 | pub const DwarfInStream = io.InStream(anyerror); | ||
| 16 | |||
| 17 | const PcRange = struct { | 14 | const 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 | }; |
| 241 | 238 | ||
| 242 | fn readInitialLength(comptime E: type, in_stream: *io.InStream(E), is_64: *bool) !u64 { | 239 | fn 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 | } |
| 415 | 412 | ||
| 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; |
| 419 | 418 | ||
| 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 | }; |
| 425 | 424 | ||
| 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)); |
| 430 | 429 | ||
| 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; |
| 433 | 432 | ||
| 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); |
| 435 | 434 | ||
| 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; |
| 438 | 437 | ||
| 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); |
| 441 | 440 | ||
| 442 | try s.seekable_stream.seekTo(compile_unit_pos); | 441 | try seekable.seekTo(compile_unit_pos); |
| 443 | 442 | ||
| 444 | const next_unit_pos = this_unit_offset + next_offset; | 443 | const next_unit_pos = this_unit_offset + next_offset; |
| 445 | 444 | ||
| 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(); |
| 449 | 448 | ||
| 450 | const after_die_offset = try s.seekable_stream.getPos(); | 449 | const after_die_offset = try seekable.getPos(); |
| 451 | 450 | ||
| 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 repeat | 462 | // 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 repeat | 468 | // 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 | } |
| 513 | 512 | ||
| 514 | try s.seekable_stream.seekTo(after_die_offset); | 513 | try seekable.seekTo(after_die_offset); |
| 515 | } | 514 | } |
| 516 | 515 | ||
| 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 | } |
| 520 | 519 | ||
| 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; |
| 524 | 525 | ||
| 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 | }; |
| 530 | 531 | ||
| 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)); |
| 535 | 536 | ||
| 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; |
| 538 | 539 | ||
| 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); |
| 540 | 541 | ||
| 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; |
| 543 | 544 | ||
| 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); |
| 546 | 547 | ||
| 547 | try s.seekable_stream.seekTo(compile_unit_pos); | 548 | try seekable.seekTo(compile_unit_pos); |
| 548 | 549 | ||
| 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; |
| 551 | 552 | ||
| 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; |
| 553 | 554 | ||
| ... | @@ -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(); | ||
| 597 | 600 | ||
| 598 | // All the addresses in the list are relative to the value | 601 | // All the addresses in the list are relative to the value |
| 599 | // specified by DW_AT_low_pc or to some other value encoded | 602 | // 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 | }; |
| 606 | 609 | ||
| 607 | try s.seekable_stream.seekTo(ranges_offset); | 610 | try seekable.seekTo(ranges_offset); |
| 608 | 611 | ||
| 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 | } |
| 647 | 650 | ||
| 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(); | ||
| 650 | 655 | ||
| 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; |
| 664 | 669 | ||
| 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 | } |
| 696 | 701 | ||
| 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(); | ||
| 699 | 706 | ||
| 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); |
| 702 | 709 | ||
| 703 | try s.seekable_stream.seekTo(line_info_offset); | 710 | try seekable.seekTo(line_info_offset); |
| 704 | 711 | ||
| 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)); |
| 711 | 718 | ||
| 712 | const version = try s.stream.readInt(u16, di.endian); | 719 | const version = try in.readInt(u16, di.endian); |
| 713 | // TODO support 3 and 5 | 720 | // 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; |
| 715 | 722 | ||
| 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; |
| 718 | 725 | ||
| 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; |
| 721 | 728 | ||
| 722 | if (version >= 4) { | 729 | if (version >= 4) { |
| 723 | // maximum_operations_per_instruction | 730 | // maximum_operations_per_instruction |
| 724 | _ = try s.stream.readByte(); | 731 | _ = try in.readByte(); |
| 725 | } | 732 | } |
| 726 | 733 | ||
| 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(); |
| 729 | 736 | ||
| 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; |
| 732 | 739 | ||
| 733 | const opcode_base = try s.stream.readByte(); | 740 | const opcode_base = try in.readByte(); |
| 734 | 741 | ||
| 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 | } |
| 744 | 751 | ||
| 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); |
| 755 | 762 | ||
| 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 | } |
| 769 | 776 | ||
| 770 | try s.seekable_stream.seekTo(prog_start_offset); | 777 | try seekable.seekTo(prog_start_offset); |
| 771 | 778 | ||
| 772 | const next_unit_pos = line_info_offset + next_offset; | 779 | const next_unit_pos = line_info_offset + next_offset; |
| 773 | 780 | ||
| 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(); |
| 776 | 783 | ||
| 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) { |
| 333 | pub const SectionHeader = Elf64_Shdr; | 333 | pub const SectionHeader = Elf64_Shdr; |
| 334 | pub const ProgramHeader = Elf64_Phdr; | 334 | pub const ProgramHeader = Elf64_Phdr; |
| 335 | 335 | ||
| 336 | const 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 | |||
| 349 | pub 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 | |||
| 336 | pub const Elf = struct { | 384 | pub 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); |
| 1152 | 1152 | ||
| 1153 | try file.inStream().stream.readNoEof(buf); | 1153 | try file.inStream().readNoEof(buf); |
| 1154 | return buf; | 1154 | return buf; |
| 1155 | } | 1155 | } |
| 1156 | 1156 |
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 | } |
| 77 | 77 | ||
| ... | @@ -496,85 +496,29 @@ pub const File = struct { | ... | @@ -496,85 +496,29 @@ pub const File = struct { |
| 496 | } | 496 | } |
| 497 | } | 497 | } |
| 498 | 498 | ||
| 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 | } |
| 505 | 504 | ||
| 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 | } |
| 512 | 510 | ||
| 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 | } |
| 94 | 94 | ||
| 95 | pub const SeekableStream = @import("io/seekable_stream.zig").SeekableStream; | 95 | pub const SeekableStream = @import("io/seekable_stream.zig").SeekableStream; |
| 96 | pub const SliceSeekableInStream = @import("io/seekable_stream.zig").SliceSeekableInStream; | ||
| 97 | pub const COutStream = @import("io/c_out_stream.zig").COutStream; | ||
| 98 | pub const InStream = @import("io/in_stream.zig").InStream; | 96 | pub const InStream = @import("io/in_stream.zig").InStream; |
| 99 | pub const OutStream = @import("io/out_stream.zig").OutStream; | 97 | pub const OutStream = @import("io/out_stream.zig").OutStream; |
| 98 | pub const FixedBufferInStream = @import("io/fixed_buffer_stream.zig").FixedBufferInStream; | ||
| 99 | pub const BufferedAtomicFile = @import("io/buffered_atomic_file.zig").BufferedAtomicFile; | ||
| 100 | |||
| 101 | pub const BufferedOutStream = @import("io/buffered_out_stream.zig").BufferedOutStream; | ||
| 102 | pub const BufferedOutStreamCustom = @import("io/buffered_out_stream.zig").BufferedOutStreamCustom; | ||
| 103 | pub const bufferedOutStream = @import("io/buffered_out_stream.zig").bufferedOutStream; | ||
| 104 | |||
| 105 | pub const CountingOutStream = @import("io/counting_out_stream.zig").CountingOutStream; | ||
| 106 | |||
| 107 | pub fn fixedBufferStream(bytes: []const u8) FixedBufferInStream { | ||
| 108 | return (FixedBufferInStream{ .bytes = bytes, .pos = 0 }); | ||
| 109 | } | ||
| 110 | |||
| 111 | pub fn cOutStream(c_file: *std.c.FILE) COutStream { | ||
| 112 | return .{ .context = c_file }; | ||
| 113 | } | ||
| 114 | |||
| 115 | pub const COutStream = OutStream(*std.c.FILE, std.fs.File.WriteError, cOutStreamWrite); | ||
| 116 | |||
| 117 | pub 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 | } | ||
| 100 | 136 | ||
| 101 | /// Deprecated; use `std.fs.Dir.writeFile`. | 137 | /// Deprecated; use `std.fs.Dir.writeFile`. |
| 102 | pub fn writeFile(path: []const u8, data: []const u8) !void { | 138 | pub 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 | } |
| 497 | 533 | ||
| 498 | var null_out_stream_state = NullOutStream.init(); | ||
| 499 | pub 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. |
| 502 | pub const NullOutStream = struct { | 535 | pub 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 | }; | ||
| 518 | 536 | ||
| 519 | test "io.NullOutStream" { | 537 | const NullOutStream = OutStream(void, error{}, dummyWrite); |
| 520 | var null_stream = NullOutStream.init(); | 538 | fn 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 | } |
| 524 | 541 | ||
| 525 | /// An OutStream that counts how many bytes has been written to it. | 542 | test "null_out_stream" { |
| 526 | pub 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 | |||
| 553 | test "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 | |||
| 563 | pub fn BufferedOutStream(comptime Error: type) type { | ||
| 564 | return BufferedOutStreamCustom(mem.page_size, Error); | ||
| 565 | } | ||
| 566 | |||
| 567 | pub 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 | } |
| 608 | 545 | ||
| 609 | /// Implementation of OutStream trait for Buffer | ||
| 610 | pub 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 stream | 546 | /// Creates a stream which allows for writing bit fields to another stream |
| 632 | pub fn BitOutStream(endian: builtin.Endian, comptime Error: type) type { | 547 | pub 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 | } |
| 754 | 669 | ||
| 755 | return self.out_stream.writeOnce(buffer); | 670 | return self.out_stream.write(buffer); |
| 756 | } | 671 | } |
| 757 | }; | 672 | }; |
| 758 | } | 673 | } |
| 759 | 674 | ||
| 760 | pub 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 | |||
| 801 | pub const Packing = enum { | 675 | pub const Packing = enum { |
| 802 | /// Pack data to byte alignment | 676 | /// 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 | } |
| 1131 | 1005 | ||
| 1132 | test "import io tests" { | 1006 | test "" { |
| 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 @@ | ||
| 1 | const std = @import("../std.zig"); | ||
| 2 | const mem = std.mem; | ||
| 3 | const fs = std.fs; | ||
| 4 | const File = std.fs.File; | ||
| 5 | |||
| 6 | pub 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 @@ | ||
| 1 | const std = @import("../std.zig"); | ||
| 2 | const io = std.io; | ||
| 3 | |||
| 4 | pub fn BufferedOutStream(comptime OutStreamType: type) type { | ||
| 5 | return BufferedOutStreamCustom(4096, OutStreamType); | ||
| 6 | } | ||
| 7 | |||
| 8 | pub 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 | |||
| 50 | pub 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 @@ | ||
| 1 | const std = @import("../std.zig"); | ||
| 2 | const os = std.os; | ||
| 3 | const OutStream = std.io.OutStream; | ||
| 4 | const 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. | ||
| 9 | pub 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 @@ | ||
| 1 | const std = @import("../std.zig"); | ||
| 2 | const io = std.io; | ||
| 3 | |||
| 4 | /// An OutStream that counts how many bytes has been written to it. | ||
| 5 | pub 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 | |||
| 34 | test "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 @@ | ||
| 1 | const std = @import("../std.zig"); | ||
| 2 | const io = std.io; | ||
| 3 | |||
| 4 | pub 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 @@ |
| 1 | const std = @import("../std.zig"); | 1 | const std = @import("../std.zig"); |
| 2 | const builtin = @import("builtin"); | 2 | const builtin = std.builtin; |
| 3 | const root = @import("root"); | ||
| 4 | const math = std.math; | 3 | const math = std.math; |
| 5 | const assert = std.debug.assert; | 4 | const assert = std.debug.assert; |
| 6 | const mem = std.mem; | 5 | const mem = std.mem; |
| 7 | const Buffer = std.Buffer; | 6 | const Buffer = std.Buffer; |
| 8 | const testing = std.testing; | 7 | const testing = std.testing; |
| 9 | 8 | ||
| 10 | pub const default_stack_size = 1 * 1024 * 1024; | 9 | pub fn InStream( |
| 11 | pub const stack_size: usize = if (@hasDecl(root, "stack_size_std_io_InStream")) | 10 | comptime Context: type, |
| 12 | root.stack_size_std_io_InStream | 11 | comptime ReadError: type, |
| 13 | else | 12 | /// 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. |
| 15 | 14 | /// End of stream is not an error condition. | |
| 16 | pub 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; | ||
| 24 | 19 | ||
| 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, | ||
| 29 | 23 | ||
| 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 | } |
| 43 | 30 | ||
| 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, it | 34 | /// 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 error | 35 | /// 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 { |
| 59 | 46 | ||
| 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 | } |
| 66 | 53 | ||
| 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 returned | 63 | /// 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 the | 103 | /// 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`. The | 147 | /// 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 | } |
| 196 | 183 | ||
| 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 | } |
| 204 | 191 | ||
| 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 | } |
| 209 | 196 | ||
| 210 | /// Reads a native-endian integer | 197 | /// 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 | } |
| 216 | 203 | ||
| 217 | /// Reads a foreign-endian integer | 204 | /// 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 | } |
| 223 | 210 | ||
| 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 | } |
| 229 | 216 | ||
| 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 | } |
| 235 | 222 | ||
| 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 | } |
| 241 | 228 | ||
| 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 | } |
| 249 | 236 | ||
| 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 | } |
| 256 | 243 | ||
| 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 matches | 252 | /// 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 order | 254 | /// 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 @@ |
| 1 | const std = @import("../std.zig"); | 1 | const std = @import("../std.zig"); |
| 2 | const builtin = @import("builtin"); | 2 | const builtin = std.builtin; |
| 3 | const root = @import("root"); | ||
| 4 | const mem = std.mem; | 3 | const mem = std.mem; |
| 5 | 4 | ||
| 6 | pub const default_stack_size = 1 * 1024 * 1024; | 5 | pub fn OutStream( |
| 7 | pub const stack_size: usize = if (@hasDecl(root, "stack_size_std_io_OutStream")) | 6 | comptime Context: type, |
| 8 | root.stack_size_std_io_OutStream | 7 | comptime WriteError: type, |
| 9 | else | 8 | comptime writeFn: fn (context: Context, bytes: []const u8) WriteError!usize, |
| 10 | default_stack_size; | 9 | ) type { |
| 11 | |||
| 12 | pub 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; | ||
| 20 | 15 | ||
| 21 | writeFn: WriteFn, | 16 | pub fn write(self: Self, bytes: []const u8) Error!usize { |
| 22 | 17 | 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 | } |
| 33 | 19 | ||
| 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 | } |
| 40 | 26 | ||
| 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 | } |
| 44 | 30 | ||
| 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 | } |
| 49 | 35 | ||
| 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); |
| 53 | 39 | ||
| 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 | } |
| 61 | 47 | ||
| 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 | } |
| 68 | 55 | ||
| 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 | } |
| 75 | 63 | ||
| 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 | } |
| 81 | 70 | ||
| 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 | } |
| 87 | 77 | ||
| 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 @@ |
| 1 | const std = @import("../std.zig"); | 1 | const std = @import("../std.zig"); |
| 2 | const InStream = std.io.InStream; | 2 | const InStream = std.io.InStream; |
| 3 | 3 | ||
| 4 | pub fn SeekableStream(comptime SeekErrorType: type, comptime GetSeekPosErrorType: type) type { | 4 | pub 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; |
| 9 | 19 | ||
| 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 | } |
| 19 | 23 | ||
| 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 | } |
| 23 | 27 | ||
| 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 | } |
| 27 | 31 | ||
| 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 | |||
| 34 | pub 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 = " ", |
| 32 | 32 | ||
| 33 | stream: *OutStream, | 33 | stream: OutStream, |
| 34 | state_index: usize, | 34 | state_index: usize, |
| 35 | state: [max_depth]State, | 35 | state: [max_depth]State, |
| 36 | 36 | ||
| 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 { |
| 134 | 134 | ||
| 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 | } |
| 140 | 140 | ||
| 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 { |
| 231 | 231 | ||
| 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 | } |
| 240 | 240 |
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 | } |
| 182 | 182 |
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, |
| 634 | 634 | ||
| 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); | ||
| 640 | 636 | ||
| 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 | }; |
| 649 | 644 | ||
| 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 | } |
| 717 | 712 | ||
| 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, |
| 376 | 376 | ||
| 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 | }; |
| 13 | 13 | ||
| 14 | /// Returns whether anything changed | 14 | /// Returns whether anything changed |
| 15 | pub fn render(allocator: *mem.Allocator, stream: var, tree: *ast.Tree) (@TypeOf(stream).Child.Error || Error)!bool { | 15 | pub 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 changed | 16 | // 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); | ||
| 25 | 20 | ||
| 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, |
| 31 | 25 | ||
| 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 | } |
| 47 | 39 | ||
| 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 | }; | ||
| 58 | 52 | ||
| 59 | try renderRoot(allocator, &my_stream.stream, tree); | 53 | try renderRoot(allocator, my_stream_stream, tree); |
| 60 | 54 | ||
| 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 | } |
| 64 | 58 | ||
| 65 | return anything_changed; | 59 | return my_stream.anything_changed; |
| 66 | } | 60 | } |
| 67 | 61 | ||
| 68 | fn renderRoot( | 62 | fn 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); |
| 74 | 68 | ||
| 75 | // render all the line comments at the beginning of the file | 69 | // 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 | } |
| 191 | 185 | ||
| 192 | fn renderExtraNewline(tree: *ast.Tree, stream: var, start_col: *usize, node: *ast.Node) @TypeOf(stream).Child.Error!void { | 186 | fn 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 | } |
| 206 | 200 | ||
| 207 | fn renderTopLevelDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree, indent: usize, start_col: *usize, decl: *ast.Node) (@TypeOf(stream).Child.Error || Error)!void { | 201 | fn 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 | } |
| 210 | 204 | ||
| 211 | fn 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 { | 205 | fn 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 | else | 447 | 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 ..]; |
| 910 | 904 | ||
| 911 | // Null stream for counting the printed length of each expression | 905 | // 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); | ||
| 914 | 907 | ||
| 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( |
| 1336 | 1329 | ||
| 1337 | // TODO: Remove condition after deprecating 'typeOf'. See https://github.com/ziglang/zig/issues/1348 | 1330 | // 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); // @name | 1334 | 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 | } |
| 1512 | 1505 | ||
| 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); |
| 1999 | 1992 | ||
| 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); |
| 2011 | 2004 | ||
| 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(" ("); |
| 2017 | 2010 | ||
| 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); // pub | 2050 | 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); |
| 2130 | 2123 | ||
| 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 | } |
| 2205 | 2198 | ||
| 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..], " ")); |
| 2208 | 2201 | ||
| 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), " ")); |
| 2331 | 2324 | ||
| 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 | } |
| 2387 | 2380 | ||
| ... | @@ -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 | } |
| 2429 | 2422 | ||
| 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. |
| 2432 | const FindByteOutStream = struct { | 2425 | const 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, |
| 2440 | 2428 | ||
| 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 | } |
| 2448 | 2438 | ||
| 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 | }; |
| 2460 | 2453 | ||
| 2461 | fn copyFixingWhitespace(stream: var, slice: []const u8) @TypeOf(stream).Child.Error!void { | 2454 | fn 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 = .{}; |
| 44 | 44 | ||
| ... | @@ -123,7 +123,7 @@ pub const LibCInstallation = struct { | ... | @@ -123,7 +123,7 @@ pub const LibCInstallation = struct { |
| 123 | return self; | 123 | return self; |
| 124 | } | 124 | } |
| 125 | 125 | ||
| 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{ |
| 61 | pub fn cmdTargets( | 61 | pub 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); |
| 94 | 95 | ||
| 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); |
| 98 | 99 | ||
| 99 | try jws.beginObject(); | 100 | try jws.beginObject(); |
| 100 | 101 | ||
| ... | @@ -219,6 +220,6 @@ pub fn cmdTargets( | ... | @@ -219,6 +220,6 @@ pub fn cmdTargets( |
| 219 | 220 | ||
| 220 | try jws.endObject(); | 221 | try jws.endObject(); |
| 221 | 222 | ||
| 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; |
| 18 | const LibCInstallation = @import("libc_installation.zig").LibCInstallation; | 18 | const LibCInstallation = @import("libc_installation.zig").LibCInstallation; |
| 19 | 19 | ||
| 20 | var stderr_file: fs.File = undefined; | 20 | var stderr_file: fs.File = undefined; |
| 21 | var stderr: *io.OutStream(fs.File.WriteError) = undefined; | 21 | var stderr: fs.File.OutStream = undefined; |
| 22 | var stdout: *io.OutStream(fs.File.WriteError) = undefined; | 22 | var stdout: fs.File.OutStream = undefined; |
| 23 | 23 | ||
| 24 | comptime { | 24 | comptime { |
| 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 | } |
| 147 | 147 | ||
| 148 | export fn stage2_render_ast(tree: *ast.Tree, output_file: *FILE) Error { | 148 | export 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 mode | 151 | 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 | } |
| 188 | 188 | ||
| 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(); |
| 192 | 192 | ||
| 193 | const args = args_list.toSliceConst()[2..]; | 193 | const args = args_list.toSliceConst()[2..]; |
| 194 | 194 | ||
| ... | @@ -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 { |
| 238 | 238 | ||
| 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 | } |
| 244 | 244 | ||
| 245 | const stdin_file = io.getStdIn(); | 245 | const stdin_file = io.getStdIn(); |
| 246 | var stdin = stdin_file.inStream(); | 246 | var stdin = stdin_file.inStream(); |
| 247 | 247 | ||
| 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); |
| 250 | 250 | ||
| 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 | } |
| 273 | 273 | ||
| 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 | } |
| 278 | 278 | ||
| ... | @@ -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); |
| 410 | 410 | ||
| 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(); |
| 415 | 415 | ||
| 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 }); |
| 418 | 418 | ||
| 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 warning | 808 | // ABI warning |
| 809 | export fn stage2_libc_parse(stage1_libc: *Stage2LibCInstallation, libc_file_z: [*:0]const u8) Error { | 809 | export 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 warning | 870 | // ABI warning |
| 871 | export fn stage2_libc_render(stage1_libc: *Stage2LibCInstallation, output_file: *FILE) Error { | 871 | export 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 mode | 875 | error.WouldBlock => unreachable, // stage1 opens stuff in exclusively blocking mode |
| 876 | error.SystemResources => return .SystemResources, | 876 | error.SystemResources => return .SystemResources, |