| ... | @@ -44,6 +44,48 @@ pub fn Readable(T: type, this_kind: enum { _var, _const, _bare }) type { | ... | @@ -44,6 +44,48 @@ pub fn Readable(T: type, this_kind: enum { _var, _const, _bare }) type { |
| 44 | const amt_read = try self.readAll(buf); | 44 | const amt_read = try self.readAll(buf); |
| 45 | if (amt_read < buf.len) return error.EndOfStream; | 45 | if (amt_read < buf.len) return error.EndOfStream; |
| 46 | } | 46 | } |
| | 47 | |
| | 48 | /// Appends to the `std.ArrayList` contents by reading from the stream until end of stream is found. |
| | 49 | /// If the number of bytes appended would exceed `max_append_size`, `error.StreamTooLong` is returned and the `std.ArrayList` has exactly `max_append_size` bytes appended. |
| | 50 | fn readAllArrayList(self: Self, array_list: *std.ArrayList(u8), max_append_size: usize) !void { |
| | 51 | return self.readAllArrayListAligned(null, array_list, max_append_size); |
| | 52 | } |
| | 53 | |
| | 54 | fn readAllArrayListAligned(self: Self, comptime alignment: ?u29, array_list: *std.ArrayListAligned(u8, alignment), max_append_size: usize) !void { |
| | 55 | try array_list.ensureTotalCapacity(@min(max_append_size, 4096)); |
| | 56 | const original_len = array_list.items.len; |
| | 57 | var start_index: usize = original_len; |
| | 58 | while (true) { |
| | 59 | array_list.expandToCapacity(); |
| | 60 | const dest_slice = array_list.items[start_index..]; |
| | 61 | const bytes_read = try self.readAll(dest_slice); |
| | 62 | start_index += bytes_read; |
| | 63 | |
| | 64 | if (start_index - original_len > max_append_size) { |
| | 65 | array_list.shrinkAndFree(original_len + max_append_size); |
| | 66 | return error.StreamTooLong; |
| | 67 | } |
| | 68 | |
| | 69 | if (bytes_read != dest_slice.len) { |
| | 70 | array_list.shrinkAndFree(start_index); |
| | 71 | return; |
| | 72 | } |
| | 73 | |
| | 74 | // This will trigger ArrayList to expand superlinearly at whatever its growth rate is. |
| | 75 | try array_list.ensureTotalCapacity(start_index + 1); |
| | 76 | } |
| | 77 | } |
| | 78 | |
| | 79 | /// Allocates enough memory to hold all the contents of the stream. |
| | 80 | /// If the allocated memory would be greater than `max_size`, returns `error.StreamTooLong`. |
| | 81 | /// Caller owns returned memory. |
| | 82 | /// If this function returns an error, the contents from the stream read so far are lost. |
| | 83 | pub fn readAllAlloc(self: Self, allocator: std.mem.Allocator, max_size: usize) ![]u8 { |
| | 84 | var array_list = std.ArrayList(u8).init(allocator); |
| | 85 | defer array_list.deinit(); |
| | 86 | try self.readAllArrayList(&array_list, max_size); |
| | 87 | return try array_list.toOwnedSlice(); |
| | 88 | } |
| 47 | }; | 89 | }; |
| 48 | } | 90 | } |
| 49 | | 91 | |