authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-02-05 07:38:24-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-02-05 07:38:24-05:00
logb7bc259093ccad98cdc5661c493c0bdb4771e899
tree8f7730bdc0e79c240309ec4394b3c3e977d36653
parent893f1088dfe40b0141ac6988a1ae6b165f7cc643

make OutStream and InStream take an error set param


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 them7190 }
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 }
72047209
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 support15/// TODO atomic/multithread support
16var stderr_file: io.File = undefined;16var stderr_file: io.File = undefined;
17var stderr_file_out_stream: io.FileOutStream = undefined;17var stderr_file_out_stream: io.FileOutStream = undefined;
18var stderr_stream: ?&io.OutStream = null;18var stderr_stream: ?&io.OutStream(io.FileOutStream.Error) = null;
19pub fn warn(comptime fmt: []const u8, args: ...) void {19pub 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}
23fn getStderrStream() !&io.OutStream {23fn 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";
140const DIM = "\x1b[2m";140const DIM = "\x1b[2m";
141const RESET = "\x1b[0m";141const RESET = "\x1b[0m";
142142
143pub fn writeStackTrace(stack_trace: &const builtin.StackTrace, out_stream: &io.OutStream, allocator: &mem.Allocator,143pub fn writeStackTrace(stack_trace: &const builtin.StackTrace, out_stream: var, allocator: &mem.Allocator,
144 debug_info: &ElfStackTrace, tty_color: bool) !void144 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}
164164
165pub fn writeCurrentStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator,165pub fn writeCurrentStackTrace(out_stream: var, allocator: &mem.Allocator,
166 debug_info: &ElfStackTrace, tty_color: bool, ignore_frame_count: usize) !void166 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}
181181
182fn printSourceAtAddress(debug_info: &ElfStackTrace, out_stream: &io.OutStream, address: usize) !void {182fn 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};
534534
535fn readStringRaw(allocator: &mem.Allocator, in_stream: &io.InStream) ![]u8 {535fn 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}
551551
552fn readAllocBytes(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) ![]u8 {552fn 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}
558558
559fn parseFormValueBlockLen(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) !FormValue {559fn 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}
563563
564fn parseFormValueBlock(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) !FormValue {564fn 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}
568568
569fn parseFormValueConstant(allocator: &mem.Allocator, in_stream: &io.InStream, signed: bool, size: usize) !FormValue {569fn 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}
575575
576fn parseFormValueDwarfOffsetSize(in_stream: &io.InStream, is_64: bool) !u64 {576fn 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}
580580
581fn parseFormValueTargetAddrSize(in_stream: &io.InStream) !u64 {581fn 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}
586586
587fn parseFormValueRefLen(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) !FormValue {587fn 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}
591591
592fn parseFormValueRef(allocator: &mem.Allocator, in_stream: &io.InStream, comptime T: type) !FormValue {592fn 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}
596596
597const ParseFormValueError = error {};597const ParseFormValueError = error {
598 EndOfStream,
599 Io,
600 BadFd,
601 Unexpected,
602 InvalidDebugInfo,
603 EndOfFile,
604 OutOfMemory,
605};
598606
599fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u64, is_64: bool)607fn parseFormValue(allocator: &mem.Allocator, in_stream: var, form_id: u64, is_64: bool)
600 ParseFormValueError!FormValue608 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);
740748
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);
915923
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}
10161024
1017fn readInitialLength(in_stream: &io.InStream, is_64: &bool) !u64 {1025fn 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}
10271035
1028fn readULeb128(in_stream: &io.InStream) !u64 {1036fn 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;
10311039
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 File61/// Implementation of InStream trait for File
62pub const FileInStream = struct {62pub 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);
6568
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 }
7477
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 File84/// Implementation of OutStream trait for File
82pub const FileOutStream = struct {85pub 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);
8591
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 }
94100
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 }
300306
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 }
342350
343 const WriteError = os.WindowsWriteError || os.PosixWriteError;351 pub const WriteError = os.WindowsWriteError || os.PosixWriteError;
344352
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};
355363
356pub const InStream = struct {364pub fn InStream(comptime Error: type) type {
357 // TODO allow specifying the error set365 return struct {
358 /// Return the number of bytes read. If the number read is smaller than buf.len, it366 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 }
386367
387 /// Allocates enough memory to hold all the contents of the stream. If the allocated368 /// 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();
394372
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);
398378
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 contents381 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);
405384
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 }
408389
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 }
412396
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();
416404
417 try buf.appendByte(byte);405 try self.readAllBuffer(&buf, max_size);
406 return buf.toOwnedSlice();
418 }407 }
419 }
420408
421 /// Allocates enough memory to read until `delimiter`. If the allocated409 /// 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) ![]u8414 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 }
434415
435 /// Returns the number of bytes read. If the number read is smaller than buf.len, it416 while (true) {
436 /// means the stream reached the end. Reaching the end of a stream is not an error417 var byte: u8 = try self.readByte();
437 /// condition.
438 pub fn read(self: &InStream, buffer: []u8) !usize {
439 return self.readFn(self, buffer);
440 }
441418
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 }
447422
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 }
454426
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 }
459430
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 }
463444
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 }
467451
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 }
473457
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 }
482464
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 }
483469
484};470 pub fn readIntLe(self: &Self, comptime T: type) !T {
471 return self.readInt(builtin.Endian.Little, T);
472 }
485473
486pub const OutStream = struct {474 pub fn readIntBe(self: &Self, comptime T: type) !T {
487 // TODO allow specifying the error set475 return self.readInt(builtin.Endian.Big, T);
488 writeFn: fn(self: &OutStream, bytes: []const u8) error!void,476 }
489477
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 }
493483
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}
497494
498 pub fn writeByte(self: &OutStream, byte: u8) !void {495pub 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,
502500
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}
511523
512/// `path` may need to be copied in memory to add a null terminating byte. In this case524/// `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 fixed525/// a fixed size buffer of size `std.os.max_noalloc_path_len` is an attempted solution. If the fixed