| author | |
| committer | |
| log | b7bc259093ccad98cdc5661c493c0bdb4771e899 |
| tree | 8f7730bdc0e79c240309ec4394b3c3e977d36653 |
| parent | 893f1088dfe40b0141ac6988a1ae6b165f7cc643 |
3 files changed, 198 insertions(+), 173 deletions(-)
src/ir.cpp+22-17| ... | @@ -7174,32 +7174,37 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod | ... | @@ -7174,32 +7174,37 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod |
| 7174 | return ira->codegen->builtin_types.entry_invalid; | 7174 | return ira->codegen->builtin_types.entry_invalid; |
| 7175 | } | 7175 | } |
| 7176 | if (err_set_type == nullptr) { | 7176 | if (err_set_type == nullptr) { |
| 7177 | err_set_type = cur_type; | 7177 | if (prev_type->id == TypeTableEntryIdErrorUnion) { |
| 7178 | err_set_type = prev_type->data.error_union.err_set_type; | ||
| 7179 | } else { | ||
| 7180 | err_set_type = cur_type; | ||
| 7181 | } | ||
| 7178 | errors = allocate<ErrorTableEntry *>(ira->codegen->errors_by_index.length); | 7182 | errors = allocate<ErrorTableEntry *>(ira->codegen->errors_by_index.length); |
| 7179 | for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) { | 7183 | for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) { |
| 7180 | ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i]; | 7184 | ErrorTableEntry *error_entry = err_set_type->data.error_set.errors[i]; |
| 7181 | errors[error_entry->value] = error_entry; | 7185 | errors[error_entry->value] = error_entry; |
| 7182 | } | 7186 | } |
| 7183 | continue; | 7187 | if (err_set_type == cur_type) { |
| 7184 | } else { | ||
| 7185 | // check if the cur type error set is a subset | ||
| 7186 | bool prev_is_superset = true; | ||
| 7187 | for (uint32_t i = 0; i < cur_type->data.error_set.err_count; i += 1) { | ||
| 7188 | ErrorTableEntry *contained_error_entry = cur_type->data.error_set.errors[i]; | ||
| 7189 | ErrorTableEntry *error_entry = errors[contained_error_entry->value]; | ||
| 7190 | if (error_entry == nullptr) { | ||
| 7191 | prev_is_superset = false; | ||
| 7192 | break; | ||
| 7193 | } | ||
| 7194 | } | ||
| 7195 | if (prev_is_superset) { | ||
| 7196 | continue; | 7188 | continue; |
| 7197 | } | 7189 | } |
| 7198 | // not a subset. invent new error set type, union of both of them | 7190 | } |
| 7199 | err_set_type = get_error_set_union(ira->codegen, errors, err_set_type, cur_type); | 7191 | // check if the cur type error set is a subset |
| 7200 | assert(errors != nullptr); | 7192 | bool prev_is_superset = true; |
| 7193 | for (uint32_t i = 0; i < cur_type->data.error_set.err_count; i += 1) { | ||
| 7194 | ErrorTableEntry *contained_error_entry = cur_type->data.error_set.errors[i]; | ||
| 7195 | ErrorTableEntry *error_entry = errors[contained_error_entry->value]; | ||
| 7196 | if (error_entry == nullptr) { | ||
| 7197 | prev_is_superset = false; | ||
| 7198 | break; | ||
| 7199 | } | ||
| 7200 | } | ||
| 7201 | if (prev_is_superset) { | ||
| 7201 | continue; | 7202 | continue; |
| 7202 | } | 7203 | } |
| 7204 | // not a subset. invent new error set type, union of both of them | ||
| 7205 | err_set_type = get_error_set_union(ira->codegen, errors, err_set_type, cur_type); | ||
| 7206 | assert(errors != nullptr); | ||
| 7207 | continue; | ||
| 7203 | } | 7208 | } |
| 7204 | 7209 | ||
| 7205 | if (prev_type->id == TypeTableEntryIdErrorUnion && cur_type->id == TypeTableEntryIdErrorUnion) { | 7210 | if (prev_type->id == TypeTableEntryIdErrorUnion && cur_type->id == TypeTableEntryIdErrorUnion) { |
std/debug/index.zig+28-20| ... | @@ -15,12 +15,12 @@ pub const FailingAllocator = @import("failing_allocator.zig").FailingAllocator; | ... | @@ -15,12 +15,12 @@ pub const FailingAllocator = @import("failing_allocator.zig").FailingAllocator; |
| 15 | /// TODO atomic/multithread support | 15 | /// TODO atomic/multithread support |
| 16 | var stderr_file: io.File = undefined; | 16 | var stderr_file: io.File = undefined; |
| 17 | var stderr_file_out_stream: io.FileOutStream = undefined; | 17 | var stderr_file_out_stream: io.FileOutStream = undefined; |
| 18 | var stderr_stream: ?&io.OutStream = null; | 18 | var stderr_stream: ?&io.OutStream(io.FileOutStream.Error) = null; |
| 19 | pub fn warn(comptime fmt: []const u8, args: ...) void { | 19 | pub fn warn(comptime fmt: []const u8, args: ...) void { |
| 20 | const stderr = getStderrStream() catch return; | 20 | const stderr = getStderrStream() catch return; |
| 21 | stderr.print(fmt, args) catch return; | 21 | stderr.print(fmt, args) catch return; |
| 22 | } | 22 | } |
| 23 | fn getStderrStream() !&io.OutStream { | 23 | fn getStderrStream() !&io.OutStream(io.FileOutStream.Error) { |
| 24 | if (stderr_stream) |st| { | 24 | if (stderr_stream) |st| { |
| 25 | return st; | 25 | return st; |
| 26 | } else { | 26 | } else { |
| ... | @@ -140,7 +140,7 @@ const WHITE = "\x1b[37;1m"; | ... | @@ -140,7 +140,7 @@ const WHITE = "\x1b[37;1m"; |
| 140 | const DIM = "\x1b[2m"; | 140 | const DIM = "\x1b[2m"; |
| 141 | const RESET = "\x1b[0m"; | 141 | const RESET = "\x1b[0m"; |
| 142 | 142 | ||
| 143 | pub fn writeStackTrace(stack_trace: &const builtin.StackTrace, out_stream: &io.OutStream, allocator: &mem.Allocator, | 143 | pub fn writeStackTrace(stack_trace: &const builtin.StackTrace, out_stream: var, allocator: &mem.Allocator, |
| 144 | debug_info: &ElfStackTrace, tty_color: bool) !void | 144 | debug_info: &ElfStackTrace, tty_color: bool) !void |
| 145 | { | 145 | { |
| 146 | var frame_index: usize = undefined; | 146 | var frame_index: usize = undefined; |
| ... | @@ -162,7 +162,7 @@ pub fn writeStackTrace(stack_trace: &const builtin.StackTrace, out_stream: &io.O | ... | @@ -162,7 +162,7 @@ pub fn writeStackTrace(stack_trace: &const builtin.StackTrace, out_stream: &io.O |
| 162 | } | 162 | } |
| 163 | } | 163 | } |
| 164 | 164 | ||
| 165 | pub fn writeCurrentStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, | 165 | pub fn writeCurrentStackTrace(out_stream: var, allocator: &mem.Allocator, |
| 166 | debug_info: &ElfStackTrace, tty_color: bool, ignore_frame_count: usize) !void | 166 | debug_info: &ElfStackTrace, tty_color: bool, ignore_frame_count: usize) !void |
| 167 | { | 167 | { |
| 168 | var ignored_count: usize = 0; | 168 | var ignored_count: usize = 0; |
| ... | @@ -179,7 +179,7 @@ pub fn writeCurrentStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocat | ... | @@ -179,7 +179,7 @@ pub fn writeCurrentStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocat |
| 179 | } | 179 | } |
| 180 | } | 180 | } |
| 181 | 181 | ||
| 182 | fn printSourceAtAddress(debug_info: &ElfStackTrace, out_stream: &io.OutStream, address: usize) !void { | 182 | fn printSourceAtAddress(debug_info: &ElfStackTrace, out_stream: var, address: usize) !void { |
| 183 | if (builtin.os == builtin.Os.windows) { | 183 | if (builtin.os == builtin.Os.windows) { |
| 184 | return error.UnsupportedDebugInfo; | 184 | return error.UnsupportedDebugInfo; |
| 185 | } | 185 | } |
| ... | @@ -532,7 +532,7 @@ const LineNumberProgram = struct { | ... | @@ -532,7 +532,7 @@ const LineNumberProgram = struct { |
| 532 | } | 532 | } |
| 533 | }; | 533 | }; |
| 534 | 534 | ||
| 535 | fn readStringRaw(allocator: &mem.Allocator, in_stream: &io.InStream) ![]u8 { | 535 | fn readStringRaw(allocator: &mem.Allocator, in_stream: var) ![]u8 { |
| 536 | var buf = ArrayList(u8).init(allocator); | 536 | var buf = ArrayList(u8).init(allocator); |
| 537 | while (true) { | 537 | while (true) { |
| 538 | const byte = try in_stream.readByte(); | 538 | const byte = try in_stream.readByte(); |
| ... | @@ -549,54 +549,62 @@ fn getString(st: &ElfStackTrace, offset: u64) ![]u8 { | ... | @@ -549,54 +549,62 @@ fn getString(st: &ElfStackTrace, offset: u64) ![]u8 { |
| 549 | return st.readString(); | 549 | return st.readString(); |
| 550 | } | 550 | } |
| 551 | 551 | ||
| 552 | fn readAllocBytes(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) ![]u8 { | 552 | fn readAllocBytes(allocator: &mem.Allocator, in_stream: var, size: usize) ![]u8 { |
| 553 | const buf = try global_allocator.alloc(u8, size); | 553 | const buf = try global_allocator.alloc(u8, size); |
| 554 | errdefer global_allocator.free(buf); | 554 | errdefer global_allocator.free(buf); |
| 555 | if ((try in_stream.read(buf)) < size) return error.EndOfFile; | 555 | if ((try in_stream.read(buf)) < size) return error.EndOfFile; |
| 556 | return buf; | 556 | return buf; |
| 557 | } | 557 | } |
| 558 | 558 | ||
| 559 | fn parseFormValueBlockLen(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) !FormValue { | 559 | fn parseFormValueBlockLen(allocator: &mem.Allocator, in_stream: var, size: usize) !FormValue { |
| 560 | const buf = try readAllocBytes(allocator, in_stream, size); | 560 | const buf = try readAllocBytes(allocator, in_stream, size); |
| 561 | return FormValue { .Block = buf }; | 561 | return FormValue { .Block = buf }; |
| 562 | } | 562 | } |
| 563 | 563 | ||
| 564 | fn parseFormValueBlock(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) !FormValue { | 564 | fn parseFormValueBlock(allocator: &mem.Allocator, in_stream: var, size: usize) !FormValue { |
| 565 | const block_len = try in_stream.readVarInt(builtin.Endian.Little, usize, size); | 565 | const block_len = try in_stream.readVarInt(builtin.Endian.Little, usize, size); |
| 566 | return parseFormValueBlockLen(allocator, in_stream, block_len); | 566 | return parseFormValueBlockLen(allocator, in_stream, block_len); |
| 567 | } | 567 | } |
| 568 | 568 | ||
| 569 | fn parseFormValueConstant(allocator: &mem.Allocator, in_stream: &io.InStream, signed: bool, size: usize) !FormValue { | 569 | fn parseFormValueConstant(allocator: &mem.Allocator, in_stream: var, signed: bool, size: usize) !FormValue { |
| 570 | return FormValue { .Const = Constant { | 570 | return FormValue { .Const = Constant { |
| 571 | .signed = signed, | 571 | .signed = signed, |
| 572 | .payload = try readAllocBytes(allocator, in_stream, size), | 572 | .payload = try readAllocBytes(allocator, in_stream, size), |
| 573 | }}; | 573 | }}; |
| 574 | } | 574 | } |
| 575 | 575 | ||
| 576 | fn parseFormValueDwarfOffsetSize(in_stream: &io.InStream, is_64: bool) !u64 { | 576 | fn parseFormValueDwarfOffsetSize(in_stream: var, is_64: bool) !u64 { |
| 577 | return if (is_64) try in_stream.readIntLe(u64) | 577 | return if (is_64) try in_stream.readIntLe(u64) |
| 578 | else u64(try in_stream.readIntLe(u32)) ; | 578 | else u64(try in_stream.readIntLe(u32)) ; |
| 579 | } | 579 | } |
| 580 | 580 | ||
| 581 | fn parseFormValueTargetAddrSize(in_stream: &io.InStream) !u64 { | 581 | fn parseFormValueTargetAddrSize(in_stream: var) !u64 { |
| 582 | return if (@sizeOf(usize) == 4) u64(try in_stream.readIntLe(u32)) | 582 | return if (@sizeOf(usize) == 4) u64(try in_stream.readIntLe(u32)) |
| 583 | else if (@sizeOf(usize) == 8) try in_stream.readIntLe(u64) | 583 | else if (@sizeOf(usize) == 8) try in_stream.readIntLe(u64) |
| 584 | else unreachable; | 584 | else unreachable; |
| 585 | } | 585 | } |
| 586 | 586 | ||
| 587 | fn parseFormValueRefLen(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) !FormValue { | 587 | fn parseFormValueRefLen(allocator: &mem.Allocator, in_stream: var, size: usize) !FormValue { |
| 588 | const buf = try readAllocBytes(allocator, in_stream, size); | 588 | const buf = try readAllocBytes(allocator, in_stream, size); |
| 589 | return FormValue { .Ref = buf }; | 589 | return FormValue { .Ref = buf }; |
| 590 | } | 590 | } |
| 591 | 591 | ||
| 592 | fn parseFormValueRef(allocator: &mem.Allocator, in_stream: &io.InStream, comptime T: type) !FormValue { | 592 | fn parseFormValueRef(allocator: &mem.Allocator, in_stream: var, comptime T: type) !FormValue { |
| 593 | const block_len = try in_stream.readIntLe(T); | 593 | const block_len = try in_stream.readIntLe(T); |
| 594 | return parseFormValueRefLen(allocator, in_stream, block_len); | 594 | return parseFormValueRefLen(allocator, in_stream, block_len); |
| 595 | } | 595 | } |
| 596 | 596 | ||
| 597 | const ParseFormValueError = error {}; | 597 | const ParseFormValueError = error { |
| 598 | EndOfStream, | ||
| 599 | Io, | ||
| 600 | BadFd, | ||
| 601 | Unexpected, | ||
| 602 | InvalidDebugInfo, | ||
| 603 | EndOfFile, | ||
| 604 | OutOfMemory, | ||
| 605 | }; | ||
| 598 | 606 | ||
| 599 | fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u64, is_64: bool) | 607 | fn parseFormValue(allocator: &mem.Allocator, in_stream: var, form_id: u64, is_64: bool) |
| 600 | ParseFormValueError!FormValue | 608 | ParseFormValueError!FormValue |
| 601 | { | 609 | { |
| 602 | return switch (form_id) { | 610 | return switch (form_id) { |
| ... | @@ -739,7 +747,7 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe | ... | @@ -739,7 +747,7 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe |
| 739 | try in_file.seekTo(this_offset); | 747 | try in_file.seekTo(this_offset); |
| 740 | 748 | ||
| 741 | var is_64: bool = undefined; | 749 | var is_64: bool = undefined; |
| 742 | const unit_length = try readInitialLength(in_stream, &is_64); | 750 | const unit_length = try readInitialLength(@typeOf(in_stream.readFn).ReturnType.ErrorSet, in_stream, &is_64); |
| 743 | if (unit_length == 0) | 751 | if (unit_length == 0) |
| 744 | return error.MissingDebugInfo; | 752 | return error.MissingDebugInfo; |
| 745 | const next_offset = unit_length + (if (is_64) usize(12) else usize(4)); | 753 | const next_offset = unit_length + (if (is_64) usize(12) else usize(4)); |
| ... | @@ -914,7 +922,7 @@ fn scanAllCompileUnits(st: &ElfStackTrace) !void { | ... | @@ -914,7 +922,7 @@ fn scanAllCompileUnits(st: &ElfStackTrace) !void { |
| 914 | try st.self_exe_file.seekTo(this_unit_offset); | 922 | try st.self_exe_file.seekTo(this_unit_offset); |
| 915 | 923 | ||
| 916 | var is_64: bool = undefined; | 924 | var is_64: bool = undefined; |
| 917 | const unit_length = try readInitialLength(in_stream, &is_64); | 925 | const unit_length = try readInitialLength(@typeOf(in_stream.readFn).ReturnType.ErrorSet, in_stream, &is_64); |
| 918 | if (unit_length == 0) | 926 | if (unit_length == 0) |
| 919 | return; | 927 | return; |
| 920 | const next_offset = unit_length + (if (is_64) usize(12) else usize(4)); | 928 | const next_offset = unit_length + (if (is_64) usize(12) else usize(4)); |
| ... | @@ -1014,7 +1022,7 @@ fn findCompileUnit(st: &ElfStackTrace, target_address: u64) !&const CompileUnit | ... | @@ -1014,7 +1022,7 @@ fn findCompileUnit(st: &ElfStackTrace, target_address: u64) !&const CompileUnit |
| 1014 | return error.MissingDebugInfo; | 1022 | return error.MissingDebugInfo; |
| 1015 | } | 1023 | } |
| 1016 | 1024 | ||
| 1017 | fn readInitialLength(in_stream: &io.InStream, is_64: &bool) !u64 { | 1025 | fn readInitialLength(comptime E: type, in_stream: &io.InStream(E), is_64: &bool) !u64 { |
| 1018 | const first_32_bits = try in_stream.readIntLe(u32); | 1026 | const first_32_bits = try in_stream.readIntLe(u32); |
| 1019 | *is_64 = (first_32_bits == 0xffffffff); | 1027 | *is_64 = (first_32_bits == 0xffffffff); |
| 1020 | if (*is_64) { | 1028 | if (*is_64) { |
| ... | @@ -1025,7 +1033,7 @@ fn readInitialLength(in_stream: &io.InStream, is_64: &bool) !u64 { | ... | @@ -1025,7 +1033,7 @@ fn readInitialLength(in_stream: &io.InStream, is_64: &bool) !u64 { |
| 1025 | } | 1033 | } |
| 1026 | } | 1034 | } |
| 1027 | 1035 | ||
| 1028 | fn readULeb128(in_stream: &io.InStream) !u64 { | 1036 | fn readULeb128(in_stream: var) !u64 { |
| 1029 | var result: u64 = 0; | 1037 | var result: u64 = 0; |
| 1030 | var shift: usize = 0; | 1038 | var shift: usize = 0; |
| 1031 | 1039 |
std/io.zig+148-136| ... | @@ -61,18 +61,21 @@ pub fn getStdIn() GetStdIoErrs!File { | ... | @@ -61,18 +61,21 @@ pub fn getStdIn() GetStdIoErrs!File { |
| 61 | /// Implementation of InStream trait for File | 61 | /// Implementation of InStream trait for File |
| 62 | pub const FileInStream = struct { | 62 | pub const FileInStream = struct { |
| 63 | file: &File, | 63 | file: &File, |
| 64 | stream: InStream, | 64 | stream: Stream, |
| 65 | |||
| 66 | pub const Error = @typeOf(File.read).ReturnType.ErrorSet; | ||
| 67 | pub const Stream = InStream(Error); | ||
| 65 | 68 | ||
| 66 | pub fn init(file: &File) FileInStream { | 69 | pub fn init(file: &File) FileInStream { |
| 67 | return FileInStream { | 70 | return FileInStream { |
| 68 | .file = file, | 71 | .file = file, |
| 69 | .stream = InStream { | 72 | .stream = Stream { |
| 70 | .readFn = readFn, | 73 | .readFn = readFn, |
| 71 | }, | 74 | }, |
| 72 | }; | 75 | }; |
| 73 | } | 76 | } |
| 74 | 77 | ||
| 75 | fn readFn(in_stream: &InStream, buffer: []u8) !usize { | 78 | fn readFn(in_stream: &Stream, buffer: []u8) Error!usize { |
| 76 | const self = @fieldParentPtr(FileInStream, "stream", in_stream); | 79 | const self = @fieldParentPtr(FileInStream, "stream", in_stream); |
| 77 | return self.file.read(buffer); | 80 | return self.file.read(buffer); |
| 78 | } | 81 | } |
| ... | @@ -81,18 +84,21 @@ pub const FileInStream = struct { | ... | @@ -81,18 +84,21 @@ pub const FileInStream = struct { |
| 81 | /// Implementation of OutStream trait for File | 84 | /// Implementation of OutStream trait for File |
| 82 | pub const FileOutStream = struct { | 85 | pub const FileOutStream = struct { |
| 83 | file: &File, | 86 | file: &File, |
| 84 | stream: OutStream, | 87 | stream: Stream, |
| 88 | |||
| 89 | pub const Error = File.WriteError; | ||
| 90 | pub const Stream = OutStream(Error); | ||
| 85 | 91 | ||
| 86 | pub fn init(file: &File) FileOutStream { | 92 | pub fn init(file: &File) FileOutStream { |
| 87 | return FileOutStream { | 93 | return FileOutStream { |
| 88 | .file = file, | 94 | .file = file, |
| 89 | .stream = OutStream { | 95 | .stream = Stream { |
| 90 | .writeFn = writeFn, | 96 | .writeFn = writeFn, |
| 91 | }, | 97 | }, |
| 92 | }; | 98 | }; |
| 93 | } | 99 | } |
| 94 | 100 | ||
| 95 | fn writeFn(out_stream: &OutStream, bytes: []const u8) !void { | 101 | fn writeFn(out_stream: &Stream, bytes: []const u8) !void { |
| 96 | const self = @fieldParentPtr(FileOutStream, "stream", out_stream); | 102 | const self = @fieldParentPtr(FileOutStream, "stream", out_stream); |
| 97 | return self.file.write(bytes); | 103 | return self.file.write(bytes); |
| 98 | } | 104 | } |
| ... | @@ -298,6 +304,8 @@ pub const File = struct { | ... | @@ -298,6 +304,8 @@ pub const File = struct { |
| 298 | } | 304 | } |
| 299 | } | 305 | } |
| 300 | 306 | ||
| 307 | pub const ReadError = error {}; | ||
| 308 | |||
| 301 | pub fn read(self: &File, buffer: []u8) !usize { | 309 | pub fn read(self: &File, buffer: []u8) !usize { |
| 302 | if (is_posix) { | 310 | if (is_posix) { |
| 303 | var index: usize = 0; | 311 | var index: usize = 0; |
| ... | @@ -340,7 +348,7 @@ pub const File = struct { | ... | @@ -340,7 +348,7 @@ pub const File = struct { |
| 340 | } | 348 | } |
| 341 | } | 349 | } |
| 342 | 350 | ||
| 343 | const WriteError = os.WindowsWriteError || os.PosixWriteError; | 351 | pub const WriteError = os.WindowsWriteError || os.PosixWriteError; |
| 344 | 352 | ||
| 345 | fn write(self: &File, bytes: []const u8) WriteError!void { | 353 | fn write(self: &File, bytes: []const u8) WriteError!void { |
| 346 | if (is_posix) { | 354 | if (is_posix) { |
| ... | @@ -353,161 +361,165 @@ pub const File = struct { | ... | @@ -353,161 +361,165 @@ pub const File = struct { |
| 353 | } | 361 | } |
| 354 | }; | 362 | }; |
| 355 | 363 | ||
| 356 | pub const InStream = struct { | 364 | pub fn InStream(comptime Error: type) type { |
| 357 | // TODO allow specifying the error set | 365 | return struct { |
| 358 | /// Return the number of bytes read. If the number read is smaller than buf.len, it | 366 | const Self = this; |
| 359 | /// means the stream reached the end. Reaching the end of a stream is not an error | ||
| 360 | /// condition. | ||
| 361 | readFn: fn(self: &InStream, buffer: []u8) error!usize, | ||
| 362 | |||
| 363 | /// Replaces `buffer` contents by reading from the stream until it is finished. | ||
| 364 | /// If `buffer.len()` would exceed `max_size`, `error.StreamTooLong` is returned and | ||
| 365 | /// the contents read from the stream are lost. | ||
| 366 | pub fn readAllBuffer(self: &InStream, buffer: &Buffer, max_size: usize) !void { | ||
| 367 | try buffer.resize(0); | ||
| 368 | |||
| 369 | var actual_buf_len: usize = 0; | ||
| 370 | while (true) { | ||
| 371 | const dest_slice = buffer.toSlice()[actual_buf_len..]; | ||
| 372 | const bytes_read = try self.readFn(self, dest_slice); | ||
| 373 | actual_buf_len += bytes_read; | ||
| 374 | |||
| 375 | if (bytes_read != dest_slice.len) { | ||
| 376 | buffer.shrink(actual_buf_len); | ||
| 377 | return; | ||
| 378 | } | ||
| 379 | |||
| 380 | const new_buf_size = math.min(max_size, actual_buf_len + os.page_size); | ||
| 381 | if (new_buf_size == actual_buf_len) | ||
| 382 | return error.StreamTooLong; | ||
| 383 | try buffer.resize(new_buf_size); | ||
| 384 | } | ||
| 385 | } | ||
| 386 | 367 | ||
| 387 | /// Allocates enough memory to hold all the contents of the stream. If the allocated | 368 | /// Return the number of bytes read. If the number read is smaller than buf.len, it |
| 388 | /// memory would be greater than `max_size`, returns `error.StreamTooLong`. | 369 | /// means the stream reached the end. Reaching the end of a stream is not an error |
| 389 | /// Caller owns returned memory. | 370 | /// condition. |
| 390 | /// If this function returns an error, the contents from the stream read so far are lost. | 371 | readFn: fn(self: &Self, buffer: []u8) Error!usize, |
| 391 | pub fn readAllAlloc(self: &InStream, allocator: &mem.Allocator, max_size: usize) ![]u8 { | ||
| 392 | var buf = Buffer.initNull(allocator); | ||
| 393 | defer buf.deinit(); | ||
| 394 | 372 | ||
| 395 | try self.readAllBuffer(&buf, max_size); | 373 | /// Replaces `buffer` contents by reading from the stream until it is finished. |
| 396 | return buf.toOwnedSlice(); | 374 | /// If `buffer.len()` would exceed `max_size`, `error.StreamTooLong` is returned and |
| 397 | } | 375 | /// the contents read from the stream are lost. |
| 376 | pub fn readAllBuffer(self: &Self, buffer: &Buffer, max_size: usize) !void { | ||
| 377 | try buffer.resize(0); | ||
| 398 | 378 | ||
| 399 | /// Replaces `buffer` contents by reading from the stream until `delimiter` is found. | 379 | var actual_buf_len: usize = 0; |
| 400 | /// Does not include the delimiter in the result. | 380 | while (true) { |
| 401 | /// If `buffer.len()` would exceed `max_size`, `error.StreamTooLong` is returned and the contents | 381 | const dest_slice = buffer.toSlice()[actual_buf_len..]; |
| 402 | /// read from the stream so far are lost. | 382 | const bytes_read = try self.readFn(self, dest_slice); |
| 403 | pub fn readUntilDelimiterBuffer(self: &InStream, buffer: &Buffer, delimiter: u8, max_size: usize) !void { | 383 | actual_buf_len += bytes_read; |
| 404 | try buf.resize(0); | ||
| 405 | 384 | ||
| 406 | while (true) { | 385 | if (bytes_read != dest_slice.len) { |
| 407 | var byte: u8 = try self.readByte(); | 386 | buffer.shrink(actual_buf_len); |
| 387 | return; | ||
| 388 | } | ||
| 408 | 389 | ||
| 409 | if (byte == delimiter) { | 390 | const new_buf_size = math.min(max_size, actual_buf_len + os.page_size); |
| 410 | return; | 391 | if (new_buf_size == actual_buf_len) |
| 392 | return error.StreamTooLong; | ||
| 393 | try buffer.resize(new_buf_size); | ||
| 411 | } | 394 | } |
| 395 | } | ||
| 412 | 396 | ||
| 413 | if (buf.len() == max_size) { | 397 | /// Allocates enough memory to hold all the contents of the stream. If the allocated |
| 414 | return error.StreamTooLong; | 398 | /// memory would be greater than `max_size`, returns `error.StreamTooLong`. |
| 415 | } | 399 | /// Caller owns returned memory. |
| 400 | /// If this function returns an error, the contents from the stream read so far are lost. | ||
| 401 | pub fn readAllAlloc(self: &Self, allocator: &mem.Allocator, max_size: usize) ![]u8 { | ||
| 402 | var buf = Buffer.initNull(allocator); | ||
| 403 | defer buf.deinit(); | ||
| 416 | 404 | ||
| 417 | try buf.appendByte(byte); | 405 | try self.readAllBuffer(&buf, max_size); |
| 406 | return buf.toOwnedSlice(); | ||
| 418 | } | 407 | } |
| 419 | } | ||
| 420 | 408 | ||
| 421 | /// Allocates enough memory to read until `delimiter`. If the allocated | 409 | /// Replaces `buffer` contents by reading from the stream until `delimiter` is found. |
| 422 | /// memory would be greater than `max_size`, returns `error.StreamTooLong`. | 410 | /// Does not include the delimiter in the result. |
| 423 | /// Caller owns returned memory. | 411 | /// If `buffer.len()` would exceed `max_size`, `error.StreamTooLong` is returned and the contents |
| 424 | /// If this function returns an error, the contents from the stream read so far are lost. | 412 | /// read from the stream so far are lost. |
| 425 | pub fn readUntilDelimiterAlloc(self: &InStream, allocator: &mem.Allocator, | 413 | pub fn readUntilDelimiterBuffer(self: &Self, buffer: &Buffer, delimiter: u8, max_size: usize) !void { |
| 426 | delimiter: u8, max_size: usize) ![]u8 | 414 | try buf.resize(0); |
| 427 | { | ||
| 428 | var buf = Buffer.initNull(allocator); | ||
| 429 | defer buf.deinit(); | ||
| 430 | |||
| 431 | try self.readUntilDelimiterBuffer(self, &buf, delimiter, max_size); | ||
| 432 | return buf.toOwnedSlice(); | ||
| 433 | } | ||
| 434 | 415 | ||
| 435 | /// Returns the number of bytes read. If the number read is smaller than buf.len, it | 416 | while (true) { |
| 436 | /// means the stream reached the end. Reaching the end of a stream is not an error | 417 | var byte: u8 = try self.readByte(); |
| 437 | /// condition. | ||
| 438 | pub fn read(self: &InStream, buffer: []u8) !usize { | ||
| 439 | return self.readFn(self, buffer); | ||
| 440 | } | ||
| 441 | 418 | ||
| 442 | /// Same as `read` but end of stream returns `error.EndOfStream`. | 419 | if (byte == delimiter) { |
| 443 | pub fn readNoEof(self: &InStream, buf: []u8) !void { | 420 | return; |
| 444 | const amt_read = try self.read(buf); | 421 | } |
| 445 | if (amt_read < buf.len) return error.EndOfStream; | ||
| 446 | } | ||
| 447 | 422 | ||
| 448 | /// Reads 1 byte from the stream or returns `error.EndOfStream`. | 423 | if (buf.len() == max_size) { |
| 449 | pub fn readByte(self: &InStream) !u8 { | 424 | return error.StreamTooLong; |
| 450 | var result: [1]u8 = undefined; | 425 | } |
| 451 | try self.readNoEof(result[0..]); | ||
| 452 | return result[0]; | ||
| 453 | } | ||
| 454 | 426 | ||
| 455 | /// Same as `readByte` except the returned byte is signed. | 427 | try buf.appendByte(byte); |
| 456 | pub fn readByteSigned(self: &InStream) !i8 { | 428 | } |
| 457 | return @bitCast(i8, try self.readByte()); | 429 | } |
| 458 | } | ||
| 459 | 430 | ||
| 460 | pub fn readIntLe(self: &InStream, comptime T: type) !T { | 431 | /// Allocates enough memory to read until `delimiter`. If the allocated |
| 461 | return self.readInt(builtin.Endian.Little, T); | 432 | /// memory would be greater than `max_size`, returns `error.StreamTooLong`. |
| 462 | } | 433 | /// Caller owns returned memory. |
| 434 | /// If this function returns an error, the contents from the stream read so far are lost. | ||
| 435 | pub fn readUntilDelimiterAlloc(self: &Self, allocator: &mem.Allocator, | ||
| 436 | delimiter: u8, max_size: usize) ![]u8 | ||
| 437 | { | ||
| 438 | var buf = Buffer.initNull(allocator); | ||
| 439 | defer buf.deinit(); | ||
| 440 | |||
| 441 | try self.readUntilDelimiterBuffer(self, &buf, delimiter, max_size); | ||
| 442 | return buf.toOwnedSlice(); | ||
| 443 | } | ||
| 463 | 444 | ||
| 464 | pub fn readIntBe(self: &InStream, comptime T: type) !T { | 445 | /// Returns the number of bytes read. If the number read is smaller than buf.len, it |
| 465 | return self.readInt(builtin.Endian.Big, T); | 446 | /// means the stream reached the end. Reaching the end of a stream is not an error |
| 466 | } | 447 | /// condition. |
| 448 | pub fn read(self: &Self, buffer: []u8) !usize { | ||
| 449 | return self.readFn(self, buffer); | ||
| 450 | } | ||
| 467 | 451 | ||
| 468 | pub fn readInt(self: &InStream, endian: builtin.Endian, comptime T: type) !T { | 452 | /// Same as `read` but end of stream returns `error.EndOfStream`. |
| 469 | var bytes: [@sizeOf(T)]u8 = undefined; | 453 | pub fn readNoEof(self: &Self, buf: []u8) !void { |
| 470 | try self.readNoEof(bytes[0..]); | 454 | const amt_read = try self.read(buf); |
| 471 | return mem.readInt(bytes, T, endian); | 455 | if (amt_read < buf.len) return error.EndOfStream; |
| 472 | } | 456 | } |
| 473 | 457 | ||
| 474 | pub fn readVarInt(self: &InStream, endian: builtin.Endian, comptime T: type, size: usize) !T { | 458 | /// Reads 1 byte from the stream or returns `error.EndOfStream`. |
| 475 | assert(size <= @sizeOf(T)); | 459 | pub fn readByte(self: &Self) !u8 { |
| 476 | assert(size <= 8); | 460 | var result: [1]u8 = undefined; |
| 477 | var input_buf: [8]u8 = undefined; | 461 | try self.readNoEof(result[0..]); |
| 478 | const input_slice = input_buf[0..size]; | 462 | return result[0]; |
| 479 | try self.readNoEof(input_slice); | 463 | } |
| 480 | return mem.readInt(input_slice, T, endian); | ||
| 481 | } | ||
| 482 | 464 | ||
| 465 | /// Same as `readByte` except the returned byte is signed. | ||
| 466 | pub fn readByteSigned(self: &Self) !i8 { | ||
| 467 | return @bitCast(i8, try self.readByte()); | ||
| 468 | } | ||
| 483 | 469 | ||
| 484 | }; | 470 | pub fn readIntLe(self: &Self, comptime T: type) !T { |
| 471 | return self.readInt(builtin.Endian.Little, T); | ||
| 472 | } | ||
| 485 | 473 | ||
| 486 | pub const OutStream = struct { | 474 | pub fn readIntBe(self: &Self, comptime T: type) !T { |
| 487 | // TODO allow specifying the error set | 475 | return self.readInt(builtin.Endian.Big, T); |
| 488 | writeFn: fn(self: &OutStream, bytes: []const u8) error!void, | 476 | } |
| 489 | 477 | ||
| 490 | pub fn print(self: &OutStream, comptime format: []const u8, args: ...) !void { | 478 | pub fn readInt(self: &Self, endian: builtin.Endian, comptime T: type) !T { |
| 491 | return std.fmt.format(self, error, self.writeFn, format, args); | 479 | var bytes: [@sizeOf(T)]u8 = undefined; |
| 492 | } | 480 | try self.readNoEof(bytes[0..]); |
| 481 | return mem.readInt(bytes, T, endian); | ||
| 482 | } | ||
| 493 | 483 | ||
| 494 | pub fn write(self: &OutStream, bytes: []const u8) !void { | 484 | pub fn readVarInt(self: &Self, endian: builtin.Endian, comptime T: type, size: usize) !T { |
| 495 | return self.writeFn(self, bytes); | 485 | assert(size <= @sizeOf(T)); |
| 496 | } | 486 | assert(size <= 8); |
| 487 | var input_buf: [8]u8 = undefined; | ||
| 488 | const input_slice = input_buf[0..size]; | ||
| 489 | try self.readNoEof(input_slice); | ||
| 490 | return mem.readInt(input_slice, T, endian); | ||
| 491 | } | ||
| 492 | }; | ||
| 493 | } | ||
| 497 | 494 | ||
| 498 | pub fn writeByte(self: &OutStream, byte: u8) !void { | 495 | pub fn OutStream(comptime Error: type) type { |
| 499 | const slice = (&byte)[0..1]; | 496 | return struct { |
| 500 | return self.writeFn(self, slice); | 497 | const Self = this; |
| 501 | } | 498 | |
| 499 | writeFn: fn(self: &Self, bytes: []const u8) Error!void, | ||
| 502 | 500 | ||
| 503 | pub fn writeByteNTimes(self: &OutStream, byte: u8, n: usize) !void { | 501 | pub fn print(self: &Self, comptime format: []const u8, args: ...) !void { |
| 504 | const slice = (&byte)[0..1]; | 502 | return std.fmt.format(self, error, self.writeFn, format, args); |
| 505 | var i: usize = 0; | ||
| 506 | while (i < n) : (i += 1) { | ||
| 507 | try self.writeFn(self, slice); | ||
| 508 | } | 503 | } |
| 509 | } | 504 | |
| 510 | }; | 505 | pub fn write(self: &Self, bytes: []const u8) !void { |
| 506 | return self.writeFn(self, bytes); | ||
| 507 | } | ||
| 508 | |||
| 509 | pub fn writeByte(self: &Self, byte: u8) !void { | ||
| 510 | const slice = (&byte)[0..1]; | ||
| 511 | return self.writeFn(self, slice); | ||
| 512 | } | ||
| 513 | |||
| 514 | pub fn writeByteNTimes(self: &Self, byte: u8, n: usize) !void { | ||
| 515 | const slice = (&byte)[0..1]; | ||
| 516 | var i: usize = 0; | ||
| 517 | while (i < n) : (i += 1) { | ||
| 518 | try self.writeFn(self, slice); | ||
| 519 | } | ||
| 520 | } | ||
| 521 | }; | ||
| 522 | } | ||
| 511 | 523 | ||
| 512 | /// `path` may need to be copied in memory to add a null terminating byte. In this case | 524 | /// `path` may need to be copied in memory to add a null terminating byte. In this case |
| 513 | /// a fixed size buffer of size `std.os.max_noalloc_path_len` is an attempted solution. If the fixed | 525 | /// a fixed size buffer of size `std.os.max_noalloc_path_len` is an attempted solution. If the fixed |