| author | |
| committer | |
| log | 748158277441343e9b54c56e2b9e0725833a43ce |
| tree | 185638b4b74d36da81e0feb27ae4b00ed4d32944 |
| parent | f5b584cc137b2fb0bdc790f5f9fbba0989e5fbe2 |
Start implementing https://github.com/ziglang/zig/issues/4917 which is to rename instream/outstream to reader/writer. This first change allows code to use Writer/writer instead of OutStream/outStream, but still maintains the old outstream names with "Deprecated" comments.18 files changed, 585 insertions(+), 488 deletions(-)
lib/std/debug.zig+3-3| ... | ... | @@ -53,7 +53,7 @@ pub const LineInfo = struct { |
| 53 | 53 | /// Tries to write to stderr, unbuffered, and ignores any error returned. |
| 54 | 54 | /// Does not append a newline. |
| 55 | 55 | var stderr_file: File = undefined; |
| 56 | var stderr_file_out_stream: File.OutStream = undefined; | |
| 56 | var stderr_file_writer: File.Writer = undefined; | |
| 57 | 57 | |
| 58 | 58 | var stderr_stream: ?*File.OutStream = null; |
| 59 | 59 | var stderr_mutex = std.Mutex.init(); |
| ... | ... | @@ -70,8 +70,8 @@ pub fn getStderrStream() *File.OutStream { |
| 70 | 70 | return st; |
| 71 | 71 | } else { |
| 72 | 72 | stderr_file = io.getStdErr(); |
| 73 | stderr_file_out_stream = stderr_file.outStream(); | |
| 74 | const st = &stderr_file_out_stream; | |
| 73 | stderr_file_writer = stderr_file.outStream(); | |
| 74 | const st = &stderr_file_writer; | |
| 75 | 75 | stderr_stream = st; |
| 76 | 76 | return st; |
| 77 | 77 | } |
lib/std/fs/file.zig+10-2| ... | ... | @@ -648,9 +648,17 @@ pub const File = struct { |
| 648 | 648 | return .{ .context = file }; |
| 649 | 649 | } |
| 650 | 650 | |
| 651 | pub const OutStream = io.OutStream(File, WriteError, write); | |
| 651 | pub const Writer = io.Writer(File, WriteError, write); | |
| 652 | 652 | |
| 653 | pub fn outStream(file: File) OutStream { | |
| 653 | /// Deprecated: use `Writer` | |
| 654 | pub const OutStream = Writer; | |
| 655 | ||
| 656 | pub fn writer(file: File) Writer { | |
| 657 | return .{ .context = file }; | |
| 658 | } | |
| 659 | ||
| 660 | /// Deprecated: use `writer` | |
| 661 | pub fn outStream(file: File) Writer { | |
| 654 | 662 | return .{ .context = file }; |
| 655 | 663 | } |
| 656 | 664 |
lib/std/io.zig+50-23| ... | ... | @@ -102,11 +102,17 @@ pub fn getStdIn() File { |
| 102 | 102 | } |
| 103 | 103 | |
| 104 | 104 | pub const InStream = @import("io/in_stream.zig").InStream; |
| 105 | pub const OutStream = @import("io/out_stream.zig").OutStream; | |
| 105 | pub const Writer = @import("io/writer.zig").Writer; | |
| 106 | /// Deprecated: use `Writer` | |
| 107 | pub const OutStream = Writer; | |
| 106 | 108 | pub const SeekableStream = @import("io/seekable_stream.zig").SeekableStream; |
| 107 | 109 | |
| 108 | pub const BufferedOutStream = @import("io/buffered_out_stream.zig").BufferedOutStream; | |
| 109 | pub const bufferedOutStream = @import("io/buffered_out_stream.zig").bufferedOutStream; | |
| 110 | pub const BufferedWriter = @import("io/buffered_writer.zig").BufferedWriter; | |
| 111 | pub const bufferedWriter = @import("io/buffered_writer.zig").bufferedWriter; | |
| 112 | /// Deprecated: use `BufferedWriter` | |
| 113 | pub const BufferedOutStream = BufferedWriter; | |
| 114 | /// Deprecated: use `bufferedWriter` | |
| 115 | pub const bufferedOutStream = bufferedWriter; | |
| 110 | 116 | |
| 111 | 117 | pub const BufferedInStream = @import("io/buffered_in_stream.zig").BufferedInStream; |
| 112 | 118 | pub const bufferedInStream = @import("io/buffered_in_stream.zig").bufferedInStream; |
| ... | ... | @@ -117,20 +123,36 @@ pub const peekStream = @import("io/peek_stream.zig").peekStream; |
| 117 | 123 | pub const FixedBufferStream = @import("io/fixed_buffer_stream.zig").FixedBufferStream; |
| 118 | 124 | pub const fixedBufferStream = @import("io/fixed_buffer_stream.zig").fixedBufferStream; |
| 119 | 125 | |
| 120 | pub const COutStream = @import("io/c_out_stream.zig").COutStream; | |
| 121 | pub const cOutStream = @import("io/c_out_stream.zig").cOutStream; | |
| 122 | ||
| 123 | pub const CountingOutStream = @import("io/counting_out_stream.zig").CountingOutStream; | |
| 124 | pub const countingOutStream = @import("io/counting_out_stream.zig").countingOutStream; | |
| 125 | ||
| 126 | pub const MultiOutStream = @import("io/multi_out_stream.zig").MultiOutStream; | |
| 127 | pub const multiOutStream = @import("io/multi_out_stream.zig").multiOutStream; | |
| 126 | pub const CWriter = @import("io/c_writer.zig").CWriter; | |
| 127 | pub const cWriter = @import("io/c_writer.zig").cWriter; | |
| 128 | /// Deprecated: use `CWriter` | |
| 129 | pub const COutStream = CWriter; | |
| 130 | /// Deprecated: use `cWriter` | |
| 131 | pub const cOutStream = cWriter; | |
| 132 | ||
| 133 | pub const CountingWriter = @import("io/counting_writer.zig").CountingWriter; | |
| 134 | pub const countingWriter = @import("io/counting_writer.zig").countingWriter; | |
| 135 | /// Deprecated: use `CountingWriter` | |
| 136 | pub const CountingOutStream = CountingWriter; | |
| 137 | /// Deprecated: use `countingWriter` | |
| 138 | pub const countingOutStream = countingWriter; | |
| 139 | ||
| 140 | pub const MultiWriter = @import("io/multi_writer.zig").MultiWriter; | |
| 141 | pub const multiWriter = @import("io/multi_writer.zig").multiWriter; | |
| 142 | /// Deprecated: use `MultiWriter` | |
| 143 | pub const MultiOutStream = MultiWriter; | |
| 144 | /// Deprecated: use `multiWriter` | |
| 145 | pub const multiOutStream = multiWriter; | |
| 128 | 146 | |
| 129 | 147 | pub const BitInStream = @import("io/bit_in_stream.zig").BitInStream; |
| 130 | 148 | pub const bitInStream = @import("io/bit_in_stream.zig").bitInStream; |
| 131 | 149 | |
| 132 | pub const BitOutStream = @import("io/bit_out_stream.zig").BitOutStream; | |
| 133 | pub const bitOutStream = @import("io/bit_out_stream.zig").bitOutStream; | |
| 150 | pub const BitWriter = @import("io/bit_writer.zig").BitWriter; | |
| 151 | pub const bitWriter = @import("io/bit_writer.zig").bitWriter; | |
| 152 | /// Deprecated: use `BitWriter` | |
| 153 | pub const BitOutStream = BitWriter; | |
| 154 | /// Deprecated: use `bitWriter` | |
| 155 | pub const bitOutStream = bitWriter; | |
| 134 | 156 | |
| 135 | 157 | pub const Packing = @import("io/serialization.zig").Packing; |
| 136 | 158 | |
| ... | ... | @@ -144,29 +166,34 @@ pub const BufferedAtomicFile = @import("io/buffered_atomic_file.zig").BufferedAt |
| 144 | 166 | |
| 145 | 167 | pub const StreamSource = @import("io/stream_source.zig").StreamSource; |
| 146 | 168 | |
| 147 | /// An OutStream that doesn't write to anything. | |
| 148 | pub const null_out_stream = @as(NullOutStream, .{ .context = {} }); | |
| 169 | /// A Writer that doesn't write to anything. | |
| 170 | pub const null_writer = @as(NullWriter, .{ .context = {} }); | |
| 171 | ||
| 172 | /// Deprecated: use `null_writer` | |
| 173 | pub const null_out_stream = null_writer; | |
| 149 | 174 | |
| 150 | const NullOutStream = OutStream(void, error{}, dummyWrite); | |
| 175 | const NullWriter = Writer(void, error{}, dummyWrite); | |
| 176 | /// Deprecated: use NullWriter | |
| 177 | const NullOutStream = NullWriter; | |
| 151 | 178 | fn dummyWrite(context: void, data: []const u8) error{}!usize { |
| 152 | 179 | return data.len; |
| 153 | 180 | } |
| 154 | 181 | |
| 155 | test "null_out_stream" { | |
| 156 | null_out_stream.writeAll("yay" ** 10) catch |err| switch (err) {}; | |
| 182 | test "null_writer" { | |
| 183 | null_writer.writeAll("yay" ** 10) catch |err| switch (err) {}; | |
| 157 | 184 | } |
| 158 | 185 | |
| 159 | 186 | test "" { |
| 160 | 187 | _ = @import("io/bit_in_stream.zig"); |
| 161 | _ = @import("io/bit_out_stream.zig"); | |
| 188 | _ = @import("io/bit_writer.zig"); | |
| 162 | 189 | _ = @import("io/buffered_atomic_file.zig"); |
| 163 | 190 | _ = @import("io/buffered_in_stream.zig"); |
| 164 | _ = @import("io/buffered_out_stream.zig"); | |
| 165 | _ = @import("io/c_out_stream.zig"); | |
| 166 | _ = @import("io/counting_out_stream.zig"); | |
| 191 | _ = @import("io/buffered_writer.zig"); | |
| 192 | _ = @import("io/c_writer.zig"); | |
| 193 | _ = @import("io/counting_writer.zig"); | |
| 167 | 194 | _ = @import("io/fixed_buffer_stream.zig"); |
| 168 | 195 | _ = @import("io/in_stream.zig"); |
| 169 | _ = @import("io/out_stream.zig"); | |
| 196 | _ = @import("io/writer.zig"); | |
| 170 | 197 | _ = @import("io/peek_stream.zig"); |
| 171 | 198 | _ = @import("io/seekable_stream.zig"); |
| 172 | 199 | _ = @import("io/serialization.zig"); |
lib/std/io/bit_out_stream.zig+4-196| ... | ... | @@ -1,197 +1,5 @@ |
| 1 | const std = @import("../std.zig"); | |
| 2 | const builtin = std.builtin; | |
| 3 | const io = std.io; | |
| 4 | const testing = std.testing; | |
| 5 | const assert = std.debug.assert; | |
| 6 | const trait = std.meta.trait; | |
| 7 | const meta = std.meta; | |
| 8 | const math = std.math; | |
| 1 | /// Deprecated: use `std.io.bit_writer.BitWriter` | |
| 2 | pub const BitOutStream = @import("./bit_writer.zig").BitWriter; | |
| 9 | 3 | |
| 10 | /// Creates a stream which allows for writing bit fields to another stream | |
| 11 | pub fn BitOutStream(endian: builtin.Endian, comptime OutStreamType: type) type { | |
| 12 | return struct { | |
| 13 | out_stream: OutStreamType, | |
| 14 | bit_buffer: u8, | |
| 15 | bit_count: u4, | |
| 16 | ||
| 17 | pub const Error = OutStreamType.Error; | |
| 18 | pub const OutStream = io.OutStream(*Self, Error, write); | |
| 19 | ||
| 20 | const Self = @This(); | |
| 21 | const u8_bit_count = comptime meta.bitCount(u8); | |
| 22 | const u4_bit_count = comptime meta.bitCount(u4); | |
| 23 | ||
| 24 | pub fn init(out_stream: OutStreamType) Self { | |
| 25 | return Self{ | |
| 26 | .out_stream = out_stream, | |
| 27 | .bit_buffer = 0, | |
| 28 | .bit_count = 0, | |
| 29 | }; | |
| 30 | } | |
| 31 | ||
| 32 | /// Write the specified number of bits to the stream from the least significant bits of | |
| 33 | /// the specified unsigned int value. Bits will only be written to the stream when there | |
| 34 | /// are enough to fill a byte. | |
| 35 | pub fn writeBits(self: *Self, value: var, bits: usize) Error!void { | |
| 36 | if (bits == 0) return; | |
| 37 | ||
| 38 | const U = @TypeOf(value); | |
| 39 | comptime assert(trait.isUnsignedInt(U)); | |
| 40 | ||
| 41 | //by extending the buffer to a minimum of u8 we can cover a number of edge cases | |
| 42 | // related to shifting and casting. | |
| 43 | const u_bit_count = comptime meta.bitCount(U); | |
| 44 | const buf_bit_count = bc: { | |
| 45 | assert(u_bit_count >= bits); | |
| 46 | break :bc if (u_bit_count <= u8_bit_count) u8_bit_count else u_bit_count; | |
| 47 | }; | |
| 48 | const Buf = std.meta.Int(false, buf_bit_count); | |
| 49 | const BufShift = math.Log2Int(Buf); | |
| 50 | ||
| 51 | const buf_value = @intCast(Buf, value); | |
| 52 | ||
| 53 | const high_byte_shift = @intCast(BufShift, buf_bit_count - u8_bit_count); | |
| 54 | var in_buffer = switch (endian) { | |
| 55 | .Big => buf_value << @intCast(BufShift, buf_bit_count - bits), | |
| 56 | .Little => buf_value, | |
| 57 | }; | |
| 58 | var in_bits = bits; | |
| 59 | ||
| 60 | if (self.bit_count > 0) { | |
| 61 | const bits_remaining = u8_bit_count - self.bit_count; | |
| 62 | const n = @intCast(u3, if (bits_remaining > bits) bits else bits_remaining); | |
| 63 | switch (endian) { | |
| 64 | .Big => { | |
| 65 | const shift = @intCast(BufShift, high_byte_shift + self.bit_count); | |
| 66 | const v = @intCast(u8, in_buffer >> shift); | |
| 67 | self.bit_buffer |= v; | |
| 68 | in_buffer <<= n; | |
| 69 | }, | |
| 70 | .Little => { | |
| 71 | const v = @truncate(u8, in_buffer) << @intCast(u3, self.bit_count); | |
| 72 | self.bit_buffer |= v; | |
| 73 | in_buffer >>= n; | |
| 74 | }, | |
| 75 | } | |
| 76 | self.bit_count += n; | |
| 77 | in_bits -= n; | |
| 78 | ||
| 79 | //if we didn't fill the buffer, it's because bits < bits_remaining; | |
| 80 | if (self.bit_count != u8_bit_count) return; | |
| 81 | try self.out_stream.writeByte(self.bit_buffer); | |
| 82 | self.bit_buffer = 0; | |
| 83 | self.bit_count = 0; | |
| 84 | } | |
| 85 | //at this point we know bit_buffer is empty | |
| 86 | ||
| 87 | //copy bytes until we can't fill one anymore, then leave the rest in bit_buffer | |
| 88 | while (in_bits >= u8_bit_count) { | |
| 89 | switch (endian) { | |
| 90 | .Big => { | |
| 91 | const v = @intCast(u8, in_buffer >> high_byte_shift); | |
| 92 | try self.out_stream.writeByte(v); | |
| 93 | in_buffer <<= @intCast(u3, u8_bit_count - 1); | |
| 94 | in_buffer <<= 1; | |
| 95 | }, | |
| 96 | .Little => { | |
| 97 | const v = @truncate(u8, in_buffer); | |
| 98 | try self.out_stream.writeByte(v); | |
| 99 | in_buffer >>= @intCast(u3, u8_bit_count - 1); | |
| 100 | in_buffer >>= 1; | |
| 101 | }, | |
| 102 | } | |
| 103 | in_bits -= u8_bit_count; | |
| 104 | } | |
| 105 | ||
| 106 | if (in_bits > 0) { | |
| 107 | self.bit_count = @intCast(u4, in_bits); | |
| 108 | self.bit_buffer = switch (endian) { | |
| 109 | .Big => @truncate(u8, in_buffer >> high_byte_shift), | |
| 110 | .Little => @truncate(u8, in_buffer), | |
| 111 | }; | |
| 112 | } | |
| 113 | } | |
| 114 | ||
| 115 | /// Flush any remaining bits to the stream. | |
| 116 | pub fn flushBits(self: *Self) Error!void { | |
| 117 | if (self.bit_count == 0) return; | |
| 118 | try self.out_stream.writeByte(self.bit_buffer); | |
| 119 | self.bit_buffer = 0; | |
| 120 | self.bit_count = 0; | |
| 121 | } | |
| 122 | ||
| 123 | pub fn write(self: *Self, buffer: []const u8) Error!usize { | |
| 124 | // TODO: I'm not sure this is a good idea, maybe flushBits should be forced | |
| 125 | if (self.bit_count > 0) { | |
| 126 | for (buffer) |b, i| | |
| 127 | try self.writeBits(b, u8_bit_count); | |
| 128 | return buffer.len; | |
| 129 | } | |
| 130 | ||
| 131 | return self.out_stream.write(buffer); | |
| 132 | } | |
| 133 | ||
| 134 | pub fn outStream(self: *Self) OutStream { | |
| 135 | return .{ .context = self }; | |
| 136 | } | |
| 137 | }; | |
| 138 | } | |
| 139 | ||
| 140 | pub fn bitOutStream( | |
| 141 | comptime endian: builtin.Endian, | |
| 142 | underlying_stream: var, | |
| 143 | ) BitOutStream(endian, @TypeOf(underlying_stream)) { | |
| 144 | return BitOutStream(endian, @TypeOf(underlying_stream)).init(underlying_stream); | |
| 145 | } | |
| 146 | ||
| 147 | test "api coverage" { | |
| 148 | var mem_be = [_]u8{0} ** 2; | |
| 149 | var mem_le = [_]u8{0} ** 2; | |
| 150 | ||
| 151 | var mem_out_be = io.fixedBufferStream(&mem_be); | |
| 152 | var bit_stream_be = bitOutStream(.Big, mem_out_be.outStream()); | |
| 153 | ||
| 154 | try bit_stream_be.writeBits(@as(u2, 1), 1); | |
| 155 | try bit_stream_be.writeBits(@as(u5, 2), 2); | |
| 156 | try bit_stream_be.writeBits(@as(u128, 3), 3); | |
| 157 | try bit_stream_be.writeBits(@as(u8, 4), 4); | |
| 158 | try bit_stream_be.writeBits(@as(u9, 5), 5); | |
| 159 | try bit_stream_be.writeBits(@as(u1, 1), 1); | |
| 160 | ||
| 161 | testing.expect(mem_be[0] == 0b11001101 and mem_be[1] == 0b00001011); | |
| 162 | ||
| 163 | mem_out_be.pos = 0; | |
| 164 | ||
| 165 | try bit_stream_be.writeBits(@as(u15, 0b110011010000101), 15); | |
| 166 | try bit_stream_be.flushBits(); | |
| 167 | testing.expect(mem_be[0] == 0b11001101 and mem_be[1] == 0b00001010); | |
| 168 | ||
| 169 | mem_out_be.pos = 0; | |
| 170 | try bit_stream_be.writeBits(@as(u32, 0b110011010000101), 16); | |
| 171 | testing.expect(mem_be[0] == 0b01100110 and mem_be[1] == 0b10000101); | |
| 172 | ||
| 173 | try bit_stream_be.writeBits(@as(u0, 0), 0); | |
| 174 | ||
| 175 | var mem_out_le = io.fixedBufferStream(&mem_le); | |
| 176 | var bit_stream_le = bitOutStream(.Little, mem_out_le.outStream()); | |
| 177 | ||
| 178 | try bit_stream_le.writeBits(@as(u2, 1), 1); | |
| 179 | try bit_stream_le.writeBits(@as(u5, 2), 2); | |
| 180 | try bit_stream_le.writeBits(@as(u128, 3), 3); | |
| 181 | try bit_stream_le.writeBits(@as(u8, 4), 4); | |
| 182 | try bit_stream_le.writeBits(@as(u9, 5), 5); | |
| 183 | try bit_stream_le.writeBits(@as(u1, 1), 1); | |
| 184 | ||
| 185 | testing.expect(mem_le[0] == 0b00011101 and mem_le[1] == 0b10010101); | |
| 186 | ||
| 187 | mem_out_le.pos = 0; | |
| 188 | try bit_stream_le.writeBits(@as(u15, 0b110011010000101), 15); | |
| 189 | try bit_stream_le.flushBits(); | |
| 190 | testing.expect(mem_le[0] == 0b10000101 and mem_le[1] == 0b01100110); | |
| 191 | ||
| 192 | mem_out_le.pos = 0; | |
| 193 | try bit_stream_le.writeBits(@as(u32, 0b1100110100001011), 16); | |
| 194 | testing.expect(mem_le[0] == 0b00001011 and mem_le[1] == 0b11001101); | |
| 195 | ||
| 196 | try bit_stream_le.writeBits(@as(u0, 0), 0); | |
| 197 | } | |
| 4 | /// Deprecated: use `std.io.bit_writer.bitWriter` | |
| 5 | pub const bitOutStream = @import("./bit_writer.zig").bitWriter; |
lib/std/io/bit_writer.zig created+203| ... | ... | @@ -0,0 +1,203 @@ |
| 1 | const std = @import("../std.zig"); | |
| 2 | const builtin = std.builtin; | |
| 3 | const io = std.io; | |
| 4 | const testing = std.testing; | |
| 5 | const assert = std.debug.assert; | |
| 6 | const trait = std.meta.trait; | |
| 7 | const meta = std.meta; | |
| 8 | const math = std.math; | |
| 9 | ||
| 10 | /// Creates a stream which allows for writing bit fields to another stream | |
| 11 | pub fn BitWriter(endian: builtin.Endian, comptime WriterType: type) type { | |
| 12 | return struct { | |
| 13 | forward_writer: WriterType, | |
| 14 | bit_buffer: u8, | |
| 15 | bit_count: u4, | |
| 16 | ||
| 17 | pub const Error = WriterType.Error; | |
| 18 | pub const Writer = io.Writer(*Self, Error, write); | |
| 19 | /// Deprecated: use `Writer` | |
| 20 | pub const OutStream = io.OutStream(*Self, Error, write); | |
| 21 | ||
| 22 | const Self = @This(); | |
| 23 | const u8_bit_count = comptime meta.bitCount(u8); | |
| 24 | const u4_bit_count = comptime meta.bitCount(u4); | |
| 25 | ||
| 26 | pub fn init(forward_writer: WriterType) Self { | |
| 27 | return Self{ | |
| 28 | .forward_writer = forward_writer, | |
| 29 | .bit_buffer = 0, | |
| 30 | .bit_count = 0, | |
| 31 | }; | |
| 32 | } | |
| 33 | ||
| 34 | /// Write the specified number of bits to the stream from the least significant bits of | |
| 35 | /// the specified unsigned int value. Bits will only be written to the stream when there | |
| 36 | /// are enough to fill a byte. | |
| 37 | pub fn writeBits(self: *Self, value: var, bits: usize) Error!void { | |
| 38 | if (bits == 0) return; | |
| 39 | ||
| 40 | const U = @TypeOf(value); | |
| 41 | comptime assert(trait.isUnsignedInt(U)); | |
| 42 | ||
| 43 | //by extending the buffer to a minimum of u8 we can cover a number of edge cases | |
| 44 | // related to shifting and casting. | |
| 45 | const u_bit_count = comptime meta.bitCount(U); | |
| 46 | const buf_bit_count = bc: { | |
| 47 | assert(u_bit_count >= bits); | |
| 48 | break :bc if (u_bit_count <= u8_bit_count) u8_bit_count else u_bit_count; | |
| 49 | }; | |
| 50 | const Buf = std.meta.Int(false, buf_bit_count); | |
| 51 | const BufShift = math.Log2Int(Buf); | |
| 52 | ||
| 53 | const buf_value = @intCast(Buf, value); | |
| 54 | ||
| 55 | const high_byte_shift = @intCast(BufShift, buf_bit_count - u8_bit_count); | |
| 56 | var in_buffer = switch (endian) { | |
| 57 | .Big => buf_value << @intCast(BufShift, buf_bit_count - bits), | |
| 58 | .Little => buf_value, | |
| 59 | }; | |
| 60 | var in_bits = bits; | |
| 61 | ||
| 62 | if (self.bit_count > 0) { | |
| 63 | const bits_remaining = u8_bit_count - self.bit_count; | |
| 64 | const n = @intCast(u3, if (bits_remaining > bits) bits else bits_remaining); | |
| 65 | switch (endian) { | |
| 66 | .Big => { | |
| 67 | const shift = @intCast(BufShift, high_byte_shift + self.bit_count); | |
| 68 | const v = @intCast(u8, in_buffer >> shift); | |
| 69 | self.bit_buffer |= v; | |
| 70 | in_buffer <<= n; | |
| 71 | }, | |
| 72 | .Little => { | |
| 73 | const v = @truncate(u8, in_buffer) << @intCast(u3, self.bit_count); | |
| 74 | self.bit_buffer |= v; | |
| 75 | in_buffer >>= n; | |
| 76 | }, | |
| 77 | } | |
| 78 | self.bit_count += n; | |
| 79 | in_bits -= n; | |
| 80 | ||
| 81 | //if we didn't fill the buffer, it's because bits < bits_remaining; | |
| 82 | if (self.bit_count != u8_bit_count) return; | |
| 83 | try self.forward_writer.writeByte(self.bit_buffer); | |
| 84 | self.bit_buffer = 0; | |
| 85 | self.bit_count = 0; | |
| 86 | } | |
| 87 | //at this point we know bit_buffer is empty | |
| 88 | ||
| 89 | //copy bytes until we can't fill one anymore, then leave the rest in bit_buffer | |
| 90 | while (in_bits >= u8_bit_count) { | |
| 91 | switch (endian) { | |
| 92 | .Big => { | |
| 93 | const v = @intCast(u8, in_buffer >> high_byte_shift); | |
| 94 | try self.forward_writer.writeByte(v); | |
| 95 | in_buffer <<= @intCast(u3, u8_bit_count - 1); | |
| 96 | in_buffer <<= 1; | |
| 97 | }, | |
| 98 | .Little => { | |
| 99 | const v = @truncate(u8, in_buffer); | |
| 100 | try self.forward_writer.writeByte(v); | |
| 101 | in_buffer >>= @intCast(u3, u8_bit_count - 1); | |
| 102 | in_buffer >>= 1; | |
| 103 | }, | |
| 104 | } | |
| 105 | in_bits -= u8_bit_count; | |
| 106 | } | |
| 107 | ||
| 108 | if (in_bits > 0) { | |
| 109 | self.bit_count = @intCast(u4, in_bits); | |
| 110 | self.bit_buffer = switch (endian) { | |
| 111 | .Big => @truncate(u8, in_buffer >> high_byte_shift), | |
| 112 | .Little => @truncate(u8, in_buffer), | |
| 113 | }; | |
| 114 | } | |
| 115 | } | |
| 116 | ||
| 117 | /// Flush any remaining bits to the stream. | |
| 118 | pub fn flushBits(self: *Self) Error!void { | |
| 119 | if (self.bit_count == 0) return; | |
| 120 | try self.forward_writer.writeByte(self.bit_buffer); | |
| 121 | self.bit_buffer = 0; | |
| 122 | self.bit_count = 0; | |
| 123 | } | |
| 124 | ||
| 125 | pub fn write(self: *Self, buffer: []const u8) Error!usize { | |
| 126 | // TODO: I'm not sure this is a good idea, maybe flushBits should be forced | |
| 127 | if (self.bit_count > 0) { | |
| 128 | for (buffer) |b, i| | |
| 129 | try self.writeBits(b, u8_bit_count); | |
| 130 | return buffer.len; | |
| 131 | } | |
| 132 | ||
| 133 | return self.forward_writer.write(buffer); | |
| 134 | } | |
| 135 | ||
| 136 | pub fn writer(self: *Self) Writer { | |
| 137 | return .{ .context = self }; | |
| 138 | } | |
| 139 | /// Deprecated: use `writer` | |
| 140 | pub fn outStream(self: *Self) OutStream { | |
| 141 | return .{ .context = self }; | |
| 142 | } | |
| 143 | }; | |
| 144 | } | |
| 145 | ||
| 146 | pub fn bitWriter( | |
| 147 | comptime endian: builtin.Endian, | |
| 148 | underlying_stream: var, | |
| 149 | ) BitWriter(endian, @TypeOf(underlying_stream)) { | |
| 150 | return BitWriter(endian, @TypeOf(underlying_stream)).init(underlying_stream); | |
| 151 | } | |
| 152 | ||
| 153 | test "api coverage" { | |
| 154 | var mem_be = [_]u8{0} ** 2; | |
| 155 | var mem_le = [_]u8{0} ** 2; | |
| 156 | ||
| 157 | var mem_out_be = io.fixedBufferStream(&mem_be); | |
| 158 | var bit_stream_be = bitWriter(.Big, mem_out_be.writer()); | |
| 159 | ||
| 160 | try bit_stream_be.writeBits(@as(u2, 1), 1); | |
| 161 | try bit_stream_be.writeBits(@as(u5, 2), 2); | |
| 162 | try bit_stream_be.writeBits(@as(u128, 3), 3); | |
| 163 | try bit_stream_be.writeBits(@as(u8, 4), 4); | |
| 164 | try bit_stream_be.writeBits(@as(u9, 5), 5); | |
| 165 | try bit_stream_be.writeBits(@as(u1, 1), 1); | |
| 166 | ||
| 167 | testing.expect(mem_be[0] == 0b11001101 and mem_be[1] == 0b00001011); | |
| 168 | ||
| 169 | mem_out_be.pos = 0; | |
| 170 | ||
| 171 | try bit_stream_be.writeBits(@as(u15, 0b110011010000101), 15); | |
| 172 | try bit_stream_be.flushBits(); | |
| 173 | testing.expect(mem_be[0] == 0b11001101 and mem_be[1] == 0b00001010); | |
| 174 | ||
| 175 | mem_out_be.pos = 0; | |
| 176 | try bit_stream_be.writeBits(@as(u32, 0b110011010000101), 16); | |
| 177 | testing.expect(mem_be[0] == 0b01100110 and mem_be[1] == 0b10000101); | |
| 178 | ||
| 179 | try bit_stream_be.writeBits(@as(u0, 0), 0); | |
| 180 | ||
| 181 | var mem_out_le = io.fixedBufferStream(&mem_le); | |
| 182 | var bit_stream_le = bitWriter(.Little, mem_out_le.writer()); | |
| 183 | ||
| 184 | try bit_stream_le.writeBits(@as(u2, 1), 1); | |
| 185 | try bit_stream_le.writeBits(@as(u5, 2), 2); | |
| 186 | try bit_stream_le.writeBits(@as(u128, 3), 3); | |
| 187 | try bit_stream_le.writeBits(@as(u8, 4), 4); | |
| 188 | try bit_stream_le.writeBits(@as(u9, 5), 5); | |
| 189 | try bit_stream_le.writeBits(@as(u1, 1), 1); | |
| 190 | ||
| 191 | testing.expect(mem_le[0] == 0b00011101 and mem_le[1] == 0b10010101); | |
| 192 | ||
| 193 | mem_out_le.pos = 0; | |
| 194 | try bit_stream_le.writeBits(@as(u15, 0b110011010000101), 15); | |
| 195 | try bit_stream_le.flushBits(); | |
| 196 | testing.expect(mem_le[0] == 0b10000101 and mem_le[1] == 0b01100110); | |
| 197 | ||
| 198 | mem_out_le.pos = 0; | |
| 199 | try bit_stream_le.writeBits(@as(u32, 0b1100110100001011), 16); | |
| 200 | testing.expect(mem_le[0] == 0b00001011 and mem_le[1] == 0b11001101); | |
| 201 | ||
| 202 | try bit_stream_le.writeBits(@as(u0, 0), 0); | |
| 203 | } |
lib/std/io/buffered_atomic_file.zig+1-1| ... | ... | @@ -34,7 +34,7 @@ pub const BufferedAtomicFile = struct { |
| 34 | 34 | errdefer self.atomic_file.deinit(); |
| 35 | 35 | |
| 36 | 36 | self.file_stream = self.atomic_file.file.outStream(); |
| 37 | self.buffered_stream = .{ .unbuffered_out_stream = self.file_stream }; | |
| 37 | self.buffered_stream = .{ .unbuffered_writer = self.file_stream }; | |
| 38 | 38 | return self; |
| 39 | 39 | } |
| 40 | 40 |
lib/std/io/buffered_out_stream.zig+4-40| ... | ... | @@ -1,41 +1,5 @@ |
| 1 | const std = @import("../std.zig"); | |
| 2 | const io = std.io; | |
| 1 | /// Deprecated: use `std.io.buffered_writer.BufferedWriter` | |
| 2 | pub const BufferedOutStream = @import("./buffered_writer.zig").BufferedWriter; | |
| 3 | 3 | |
| 4 | pub fn BufferedOutStream(comptime buffer_size: usize, comptime OutStreamType: type) type { | |
| 5 | return struct { | |
| 6 | unbuffered_out_stream: OutStreamType, | |
| 7 | fifo: FifoType = FifoType.init(), | |
| 8 | ||
| 9 | pub const Error = OutStreamType.Error; | |
| 10 | pub const OutStream = io.OutStream(*Self, Error, write); | |
| 11 | ||
| 12 | const Self = @This(); | |
| 13 | const FifoType = std.fifo.LinearFifo(u8, std.fifo.LinearFifoBufferType{ .Static = buffer_size }); | |
| 14 | ||
| 15 | pub fn flush(self: *Self) !void { | |
| 16 | while (true) { | |
| 17 | const slice = self.fifo.readableSlice(0); | |
| 18 | if (slice.len == 0) break; | |
| 19 | try self.unbuffered_out_stream.writeAll(slice); | |
| 20 | self.fifo.discard(slice.len); | |
| 21 | } | |
| 22 | } | |
| 23 | ||
| 24 | pub fn outStream(self: *Self) OutStream { | |
| 25 | return .{ .context = self }; | |
| 26 | } | |
| 27 | ||
| 28 | pub fn write(self: *Self, bytes: []const u8) Error!usize { | |
| 29 | if (bytes.len >= self.fifo.writableLength()) { | |
| 30 | try self.flush(); | |
| 31 | return self.unbuffered_out_stream.write(bytes); | |
| 32 | } | |
| 33 | self.fifo.writeAssumeCapacity(bytes); | |
| 34 | return bytes.len; | |
| 35 | } | |
| 36 | }; | |
| 37 | } | |
| 38 | ||
| 39 | pub fn bufferedOutStream(underlying_stream: var) BufferedOutStream(4096, @TypeOf(underlying_stream)) { | |
| 40 | return .{ .unbuffered_out_stream = underlying_stream }; | |
| 41 | } | |
| 4 | /// Deprecated: use `std.io.buffered_writer.bufferedWriter` | |
| 5 | pub const bufferedOutStream = @import("./buffered_writer.zig").bufferedWriter |
lib/std/io/buffered_writer.zig created+48| ... | ... | @@ -0,0 +1,48 @@ |
| 1 | const std = @import("../std.zig"); | |
| 2 | const io = std.io; | |
| 3 | ||
| 4 | pub fn BufferedWriter(comptime buffer_size: usize, comptime WriterType: type) type { | |
| 5 | return struct { | |
| 6 | unbuffered_writer: WriterType, | |
| 7 | fifo: FifoType = FifoType.init(), | |
| 8 | ||
| 9 | pub const Error = WriterType.Error; | |
| 10 | pub const Writer = io.Writer(*Self, Error, write); | |
| 11 | /// Deprecated: use `Writer` | |
| 12 | pub const OutStream = Writer; | |
| 13 | ||
| 14 | const Self = @This(); | |
| 15 | const FifoType = std.fifo.LinearFifo(u8, std.fifo.LinearFifoBufferType{ .Static = buffer_size }); | |
| 16 | ||
| 17 | pub fn flush(self: *Self) !void { | |
| 18 | while (true) { | |
| 19 | const slice = self.fifo.readableSlice(0); | |
| 20 | if (slice.len == 0) break; | |
| 21 | try self.unbuffered_writer.writeAll(slice); | |
| 22 | self.fifo.discard(slice.len); | |
| 23 | } | |
| 24 | } | |
| 25 | ||
| 26 | pub fn writer(self: *Self) Writer { | |
| 27 | return .{ .context = self }; | |
| 28 | } | |
| 29 | ||
| 30 | /// Deprecated: use writer | |
| 31 | pub fn outStream(self: *Self) Writer { | |
| 32 | return .{ .context = self }; | |
| 33 | } | |
| 34 | ||
| 35 | pub fn write(self: *Self, bytes: []const u8) Error!usize { | |
| 36 | if (bytes.len >= self.fifo.writableLength()) { | |
| 37 | try self.flush(); | |
| 38 | return self.unbuffered_writer.write(bytes); | |
| 39 | } | |
| 40 | self.fifo.writeAssumeCapacity(bytes); | |
| 41 | return bytes.len; | |
| 42 | } | |
| 43 | }; | |
| 44 | } | |
| 45 | ||
| 46 | pub fn bufferedWriter(underlying_stream: var) BufferedWriter(4096, @TypeOf(underlying_stream)) { | |
| 47 | return .{ .unbuffered_writer = underlying_stream }; | |
| 48 | } |
lib/std/io/c_out_stream.zig+4-43| ... | ... | @@ -1,44 +1,5 @@ |
| 1 | const std = @import("../std.zig"); | |
| 2 | const builtin = std.builtin; | |
| 3 | const io = std.io; | |
| 4 | const testing = std.testing; | |
| 1 | /// Deprecated: use `std.io.c_writer.CWriter` | |
| 2 | pub const COutStream = @import("./c_writer.zig").CWriter; | |
| 5 | 3 | |
| 6 | pub const COutStream = io.OutStream(*std.c.FILE, std.fs.File.WriteError, cOutStreamWrite); | |
| 7 | ||
| 8 | pub fn cOutStream(c_file: *std.c.FILE) COutStream { | |
| 9 | return .{ .context = c_file }; | |
| 10 | } | |
| 11 | ||
| 12 | fn cOutStreamWrite(c_file: *std.c.FILE, bytes: []const u8) std.fs.File.WriteError!usize { | |
| 13 | const amt_written = std.c.fwrite(bytes.ptr, 1, bytes.len, c_file); | |
| 14 | if (amt_written >= 0) return amt_written; | |
| 15 | switch (std.c._errno().*) { | |
| 16 | 0 => unreachable, | |
| 17 | os.EINVAL => unreachable, | |
| 18 | os.EFAULT => unreachable, | |
| 19 | os.EAGAIN => unreachable, // this is a blocking API | |
| 20 | os.EBADF => unreachable, // always a race condition | |
| 21 | os.EDESTADDRREQ => unreachable, // connect was never called | |
| 22 | os.EDQUOT => return error.DiskQuota, | |
| 23 | os.EFBIG => return error.FileTooBig, | |
| 24 | os.EIO => return error.InputOutput, | |
| 25 | os.ENOSPC => return error.NoSpaceLeft, | |
| 26 | os.EPERM => return error.AccessDenied, | |
| 27 | os.EPIPE => return error.BrokenPipe, | |
| 28 | else => |err| return os.unexpectedErrno(@intCast(usize, err)), | |
| 29 | } | |
| 30 | } | |
| 31 | ||
| 32 | test "" { | |
| 33 | if (!builtin.link_libc) return error.SkipZigTest; | |
| 34 | ||
| 35 | const filename = "tmp_io_test_file.txt"; | |
| 36 | const out_file = std.c.fopen(filename, "w") orelse return error.UnableToOpenTestFile; | |
| 37 | defer { | |
| 38 | _ = std.c.fclose(out_file); | |
| 39 | std.fs.cwd().deleteFileZ(filename) catch {}; | |
| 40 | } | |
| 41 | ||
| 42 | const out_stream = cOutStream(out_file); | |
| 43 | try out_stream.print("hi: {}\n", .{@as(i32, 123)}); | |
| 44 | } | |
| 4 | /// Deprecated: use `std.io.c_writer.cWriter` | |
| 5 | pub const cOutStream = @import("./c_writer.zig").cWriter; |
lib/std/io/c_writer.zig created+44| ... | ... | @@ -0,0 +1,44 @@ |
| 1 | const std = @import("../std.zig"); | |
| 2 | const builtin = std.builtin; | |
| 3 | const io = std.io; | |
| 4 | const testing = std.testing; | |
| 5 | ||
| 6 | pub const CWriter = io.Writer(*std.c.FILE, std.fs.File.WriteError, cWriterWrite); | |
| 7 | ||
| 8 | pub fn cWriter(c_file: *std.c.FILE) CWriter { | |
| 9 | return .{ .context = c_file }; | |
| 10 | } | |
| 11 | ||
| 12 | fn cWriterWrite(c_file: *std.c.FILE, bytes: []const u8) std.fs.File.WriteError!usize { | |
| 13 | const amt_written = std.c.fwrite(bytes.ptr, 1, bytes.len, c_file); | |
| 14 | if (amt_written >= 0) return amt_written; | |
| 15 | switch (std.c._errno().*) { | |
| 16 | 0 => unreachable, | |
| 17 | os.EINVAL => unreachable, | |
| 18 | os.EFAULT => unreachable, | |
| 19 | os.EAGAIN => unreachable, // this is a blocking API | |
| 20 | os.EBADF => unreachable, // always a race condition | |
| 21 | os.EDESTADDRREQ => unreachable, // connect was never called | |
| 22 | os.EDQUOT => return error.DiskQuota, | |
| 23 | os.EFBIG => return error.FileTooBig, | |
| 24 | os.EIO => return error.InputOutput, | |
| 25 | os.ENOSPC => return error.NoSpaceLeft, | |
| 26 | os.EPERM => return error.AccessDenied, | |
| 27 | os.EPIPE => return error.BrokenPipe, | |
| 28 | else => |err| return os.unexpectedErrno(@intCast(usize, err)), | |
| 29 | } | |
| 30 | } | |
| 31 | ||
| 32 | test "" { | |
| 33 | if (!builtin.link_libc) return error.SkipZigTest; | |
| 34 | ||
| 35 | const filename = "tmp_io_test_file.txt"; | |
| 36 | const out_file = std.c.fopen(filename, "w") orelse return error.UnableToOpenTestFile; | |
| 37 | defer { | |
| 38 | _ = std.c.fclose(out_file); | |
| 39 | std.fs.cwd().deleteFileZ(filename) catch {}; | |
| 40 | } | |
| 41 | ||
| 42 | const writer = cWriter(out_file); | |
| 43 | try writer.print("hi: {}\n", .{@as(i32, 123)}); | |
| 44 | } |
lib/std/io/counting_out_stream.zig+4-38| ... | ... | @@ -1,39 +1,5 @@ |
| 1 | const std = @import("../std.zig"); | |
| 2 | const io = std.io; | |
| 3 | const testing = std.testing; | |
| 1 | /// Deprecated: use `std.io.counting_writer.CountingWriter` | |
| 2 | pub const CountingOutStream = @import("./counting_writer.zig").CountingWriter; | |
| 4 | 3 | |
| 5 | /// An OutStream that counts how many bytes has been written to it. | |
| 6 | pub fn CountingOutStream(comptime OutStreamType: type) type { | |
| 7 | return struct { | |
| 8 | bytes_written: u64, | |
| 9 | child_stream: OutStreamType, | |
| 10 | ||
| 11 | pub const Error = OutStreamType.Error; | |
| 12 | pub const OutStream = io.OutStream(*Self, Error, write); | |
| 13 | ||
| 14 | const Self = @This(); | |
| 15 | ||
| 16 | pub fn write(self: *Self, bytes: []const u8) Error!usize { | |
| 17 | const amt = try self.child_stream.write(bytes); | |
| 18 | self.bytes_written += amt; | |
| 19 | return amt; | |
| 20 | } | |
| 21 | ||
| 22 | pub fn outStream(self: *Self) OutStream { | |
| 23 | return .{ .context = self }; | |
| 24 | } | |
| 25 | }; | |
| 26 | } | |
| 27 | ||
| 28 | pub fn countingOutStream(child_stream: var) CountingOutStream(@TypeOf(child_stream)) { | |
| 29 | return .{ .bytes_written = 0, .child_stream = child_stream }; | |
| 30 | } | |
| 31 | ||
| 32 | test "io.CountingOutStream" { | |
| 33 | var counting_stream = countingOutStream(std.io.null_out_stream); | |
| 34 | const stream = counting_stream.outStream(); | |
| 35 | ||
| 36 | const bytes = "yay" ** 100; | |
| 37 | stream.writeAll(bytes) catch unreachable; | |
| 38 | testing.expect(counting_stream.bytes_written == bytes.len); | |
| 39 | } | |
| 4 | /// Deprecated: use `std.io.counting_writer.countingWriter` | |
| 5 | pub const countingOutStream = @import("./counting_writer.zig").countingWriter; |
lib/std/io/counting_writer.zig created+46| ... | ... | @@ -0,0 +1,46 @@ |
| 1 | const std = @import("../std.zig"); | |
| 2 | const io = std.io; | |
| 3 | const testing = std.testing; | |
| 4 | ||
| 5 | /// A Writer that counts how many bytes has been written to it. | |
| 6 | pub fn CountingWriter(comptime WriterType: type) type { | |
| 7 | return struct { | |
| 8 | bytes_written: u64, | |
| 9 | child_stream: WriterType, | |
| 10 | ||
| 11 | pub const Error = WriterType.Error; | |
| 12 | pub const Writer = io.Writer(*Self, Error, write); | |
| 13 | /// Deprecated: use `Writer` | |
| 14 | pub const OutStream = Writer; | |
| 15 | ||
| 16 | const Self = @This(); | |
| 17 | ||
| 18 | pub fn write(self: *Self, bytes: []const u8) Error!usize { | |
| 19 | const amt = try self.child_stream.write(bytes); | |
| 20 | self.bytes_written += amt; | |
| 21 | return amt; | |
| 22 | } | |
| 23 | ||
| 24 | pub fn writer(self: *Self) Writer { | |
| 25 | return .{ .context = self }; | |
| 26 | } | |
| 27 | ||
| 28 | /// Deprecated: use `writer` | |
| 29 | pub fn outStream(self: *Self) OutStream { | |
| 30 | return .{ .context = self }; | |
| 31 | } | |
| 32 | }; | |
| 33 | } | |
| 34 | ||
| 35 | pub fn countingWriter(child_stream: var) CountingWriter(@TypeOf(child_stream)) { | |
| 36 | return .{ .bytes_written = 0, .child_stream = child_stream }; | |
| 37 | } | |
| 38 | ||
| 39 | test "io.CountingWriter" { | |
| 40 | var counting_stream = countingWriter(std.io.null_writer); | |
| 41 | const stream = counting_stream.writer(); | |
| 42 | ||
| 43 | const bytes = "yay" ** 100; | |
| 44 | stream.writeAll(bytes) catch unreachable; | |
| 45 | testing.expect(counting_stream.bytes_written == bytes.len); | |
| 46 | } |
lib/std/io/fixed_buffer_stream.zig+13-6| ... | ... | @@ -18,7 +18,9 @@ pub fn FixedBufferStream(comptime Buffer: type) type { |
| 18 | 18 | pub const GetSeekPosError = error{}; |
| 19 | 19 | |
| 20 | 20 | pub const InStream = io.InStream(*Self, ReadError, read); |
| 21 | pub const OutStream = io.OutStream(*Self, WriteError, write); | |
| 21 | pub const Writer = io.Writer(*Self, WriteError, write); | |
| 22 | /// Deprecated: use `Writer` | |
| 23 | pub const OutStream = Writer; | |
| 22 | 24 | |
| 23 | 25 | pub const SeekableStream = io.SeekableStream( |
| 24 | 26 | *Self, |
| ... | ... | @@ -36,6 +38,11 @@ pub fn FixedBufferStream(comptime Buffer: type) type { |
| 36 | 38 | return .{ .context = self }; |
| 37 | 39 | } |
| 38 | 40 | |
| 41 | pub fn writer(self: *Self) Writer { | |
| 42 | return .{ .context = self }; | |
| 43 | } | |
| 44 | ||
| 45 | /// Deprecated: use `writer` | |
| 39 | 46 | pub fn outStream(self: *Self) OutStream { |
| 40 | 47 | return .{ .context = self }; |
| 41 | 48 | } |
| ... | ... | @@ -126,7 +133,7 @@ fn NonSentinelSpan(comptime T: type) type { |
| 126 | 133 | test "FixedBufferStream output" { |
| 127 | 134 | var buf: [255]u8 = undefined; |
| 128 | 135 | var fbs = fixedBufferStream(&buf); |
| 129 | const stream = fbs.outStream(); | |
| 136 | const stream = fbs.writer(); | |
| 130 | 137 | |
| 131 | 138 | try stream.print("{}{}!", .{ "Hello", "World" }); |
| 132 | 139 | testing.expectEqualSlices(u8, "HelloWorld!", fbs.getWritten()); |
| ... | ... | @@ -136,19 +143,19 @@ test "FixedBufferStream output 2" { |
| 136 | 143 | var buffer: [10]u8 = undefined; |
| 137 | 144 | var fbs = fixedBufferStream(&buffer); |
| 138 | 145 | |
| 139 | try fbs.outStream().writeAll("Hello"); | |
| 146 | try fbs.writer().writeAll("Hello"); | |
| 140 | 147 | testing.expect(mem.eql(u8, fbs.getWritten(), "Hello")); |
| 141 | 148 | |
| 142 | try fbs.outStream().writeAll("world"); | |
| 149 | try fbs.writer().writeAll("world"); | |
| 143 | 150 | testing.expect(mem.eql(u8, fbs.getWritten(), "Helloworld")); |
| 144 | 151 | |
| 145 | testing.expectError(error.NoSpaceLeft, fbs.outStream().writeAll("!")); | |
| 152 | testing.expectError(error.NoSpaceLeft, fbs.writer().writeAll("!")); | |
| 146 | 153 | testing.expect(mem.eql(u8, fbs.getWritten(), "Helloworld")); |
| 147 | 154 | |
| 148 | 155 | fbs.reset(); |
| 149 | 156 | testing.expect(fbs.getWritten().len == 0); |
| 150 | 157 | |
| 151 | testing.expectError(error.NoSpaceLeft, fbs.outStream().writeAll("Hello world!")); | |
| 158 | testing.expectError(error.NoSpaceLeft, fbs.writer().writeAll("Hello world!")); | |
| 152 | 159 | testing.expect(mem.eql(u8, fbs.getWritten(), "Hello worl")); |
| 153 | 160 | } |
| 154 | 161 |
lib/std/io/multi_out_stream.zig+4-50| ... | ... | @@ -1,51 +1,5 @@ |
| 1 | const std = @import("../std.zig"); | |
| 2 | const io = std.io; | |
| 3 | const testing = std.testing; | |
| 1 | /// Deprecated: use `std.io.multi_writer.MultiWriter` | |
| 2 | pub const MultiOutStream = @import("./multi_writer.zig").MultiWriter; | |
| 4 | 3 | |
| 5 | /// Takes a tuple of streams, and constructs a new stream that writes to all of them | |
| 6 | pub fn MultiOutStream(comptime OutStreams: type) type { | |
| 7 | comptime var ErrSet = error{}; | |
| 8 | inline for (@typeInfo(OutStreams).Struct.fields) |field| { | |
| 9 | const StreamType = field.field_type; | |
| 10 | ErrSet = ErrSet || StreamType.Error; | |
| 11 | } | |
| 12 | ||
| 13 | return struct { | |
| 14 | const Self = @This(); | |
| 15 | ||
| 16 | streams: OutStreams, | |
| 17 | ||
| 18 | pub const Error = ErrSet; | |
| 19 | pub const OutStream = io.OutStream(*Self, Error, write); | |
| 20 | pub fn outStream(self: *Self) OutStream { | |
| 21 | return .{ .context = self }; | |
| 22 | } | |
| 23 | ||
| 24 | pub fn write(self: *Self, bytes: []const u8) Error!usize { | |
| 25 | var batch = std.event.Batch(Error!void, self.streams.len, .auto_async).init(); | |
| 26 | comptime var i = 0; | |
| 27 | inline while (i < self.streams.len) : (i += 1) { | |
| 28 | const stream = self.streams[i]; | |
| 29 | // TODO: remove ptrCast: https://github.com/ziglang/zig/issues/5258 | |
| 30 | batch.add(@ptrCast(anyframe->Error!void, &async stream.writeAll(bytes))); | |
| 31 | } | |
| 32 | try batch.wait(); | |
| 33 | return bytes.len; | |
| 34 | } | |
| 35 | }; | |
| 36 | } | |
| 37 | ||
| 38 | pub fn multiOutStream(streams: var) MultiOutStream(@TypeOf(streams)) { | |
| 39 | return .{ .streams = streams }; | |
| 40 | } | |
| 41 | ||
| 42 | test "MultiOutStream" { | |
| 43 | var buf1: [255]u8 = undefined; | |
| 44 | var fbs1 = io.fixedBufferStream(&buf1); | |
| 45 | var buf2: [255]u8 = undefined; | |
| 46 | var fbs2 = io.fixedBufferStream(&buf2); | |
| 47 | var stream = multiOutStream(.{ fbs1.outStream(), fbs2.outStream() }); | |
| 48 | try stream.outStream().print("HI", .{}); | |
| 49 | testing.expectEqualSlices(u8, "HI", fbs1.getWritten()); | |
| 50 | testing.expectEqualSlices(u8, "HI", fbs2.getWritten()); | |
| 51 | } | |
| 4 | /// Deprecated: use `std.io.multi_writer.multiWriter` | |
| 5 | pub const multiOutStream = @import("./multi_writer.zig").multiWriter; |
lib/std/io/multi_writer.zig created+59| ... | ... | @@ -0,0 +1,59 @@ |
| 1 | const std = @import("../std.zig"); | |
| 2 | const io = std.io; | |
| 3 | const testing = std.testing; | |
| 4 | ||
| 5 | /// Takes a tuple of streams, and constructs a new stream that writes to all of them | |
| 6 | pub fn MultiWriter(comptime Writers: type) type { | |
| 7 | comptime var ErrSet = error{}; | |
| 8 | inline for (@typeInfo(Writers).Struct.fields) |field| { | |
| 9 | const StreamType = field.field_type; | |
| 10 | ErrSet = ErrSet || StreamType.Error; | |
| 11 | } | |
| 12 | ||
| 13 | return struct { | |
| 14 | const Self = @This(); | |
| 15 | ||
| 16 | streams: Writers, | |
| 17 | ||
| 18 | pub const Error = ErrSet; | |
| 19 | pub const Writer = io.Writer(*Self, Error, write); | |
| 20 | /// Deprecated: use `Writer` | |
| 21 | pub const OutStream = Writer; | |
| 22 | ||
| 23 | pub fn writer(self: *Self) Writer { | |
| 24 | return .{ .context = self }; | |
| 25 | } | |
| 26 | ||
| 27 | /// Deprecated: use `writer` | |
| 28 | pub fn outStream(self: *Self) OutStream { | |
| 29 | return .{ .context = self }; | |
| 30 | } | |
| 31 | ||
| 32 | pub fn write(self: *Self, bytes: []const u8) Error!usize { | |
| 33 | var batch = std.event.Batch(Error!void, self.streams.len, .auto_async).init(); | |
| 34 | comptime var i = 0; | |
| 35 | inline while (i < self.streams.len) : (i += 1) { | |
| 36 | const stream = self.streams[i]; | |
| 37 | // TODO: remove ptrCast: https://github.com/ziglang/zig/issues/5258 | |
| 38 | batch.add(@ptrCast(anyframe->Error!void, &async stream.writeAll(bytes))); | |
| 39 | } | |
| 40 | try batch.wait(); | |
| 41 | return bytes.len; | |
| 42 | } | |
| 43 | }; | |
| 44 | } | |
| 45 | ||
| 46 | pub fn multiWriter(streams: var) MultiWriter(@TypeOf(streams)) { | |
| 47 | return .{ .streams = streams }; | |
| 48 | } | |
| 49 | ||
| 50 | test "MultiWriter" { | |
| 51 | var buf1: [255]u8 = undefined; | |
| 52 | var fbs1 = io.fixedBufferStream(&buf1); | |
| 53 | var buf2: [255]u8 = undefined; | |
| 54 | var fbs2 = io.fixedBufferStream(&buf2); | |
| 55 | var stream = multiWriter(.{ fbs1.writer(), fbs2.writer() }); | |
| 56 | try stream.writer().print("HI", .{}); | |
| 57 | testing.expectEqualSlices(u8, "HI", fbs1.getWritten()); | |
| 58 | testing.expectEqualSlices(u8, "HI", fbs2.getWritten()); | |
| 59 | } |
lib/std/io/out_stream.zig+2-85| ... | ... | @@ -1,85 +1,2 @@ |
| 1 | const std = @import("../std.zig"); | |
| 2 | const builtin = std.builtin; | |
| 3 | const mem = std.mem; | |
| 4 | ||
| 5 | pub fn OutStream( | |
| 6 | comptime Context: type, | |
| 7 | comptime WriteError: type, | |
| 8 | comptime writeFn: fn (context: Context, bytes: []const u8) WriteError!usize, | |
| 9 | ) type { | |
| 10 | return struct { | |
| 11 | context: Context, | |
| 12 | ||
| 13 | const Self = @This(); | |
| 14 | pub const Error = WriteError; | |
| 15 | ||
| 16 | pub fn write(self: Self, bytes: []const u8) Error!usize { | |
| 17 | return writeFn(self.context, bytes); | |
| 18 | } | |
| 19 | ||
| 20 | pub fn writeAll(self: Self, bytes: []const u8) Error!void { | |
| 21 | var index: usize = 0; | |
| 22 | while (index != bytes.len) { | |
| 23 | index += try self.write(bytes[index..]); | |
| 24 | } | |
| 25 | } | |
| 26 | ||
| 27 | pub fn print(self: Self, comptime format: []const u8, args: var) Error!void { | |
| 28 | return std.fmt.format(self, format, args); | |
| 29 | } | |
| 30 | ||
| 31 | pub fn writeByte(self: Self, byte: u8) Error!void { | |
| 32 | const array = [1]u8{byte}; | |
| 33 | return self.writeAll(&array); | |
| 34 | } | |
| 35 | ||
| 36 | pub fn writeByteNTimes(self: Self, byte: u8, n: usize) Error!void { | |
| 37 | var bytes: [256]u8 = undefined; | |
| 38 | mem.set(u8, bytes[0..], byte); | |
| 39 | ||
| 40 | var remaining: usize = n; | |
| 41 | while (remaining > 0) { | |
| 42 | const to_write = std.math.min(remaining, bytes.len); | |
| 43 | try self.writeAll(bytes[0..to_write]); | |
| 44 | remaining -= to_write; | |
| 45 | } | |
| 46 | } | |
| 47 | ||
| 48 | /// Write a native-endian integer. | |
| 49 | /// TODO audit non-power-of-two int sizes | |
| 50 | pub fn writeIntNative(self: Self, comptime T: type, value: T) Error!void { | |
| 51 | var bytes: [(T.bit_count + 7) / 8]u8 = undefined; | |
| 52 | mem.writeIntNative(T, &bytes, value); | |
| 53 | return self.writeAll(&bytes); | |
| 54 | } | |
| 55 | ||
| 56 | /// Write a foreign-endian integer. | |
| 57 | /// TODO audit non-power-of-two int sizes | |
| 58 | pub fn writeIntForeign(self: Self, comptime T: type, value: T) Error!void { | |
| 59 | var bytes: [(T.bit_count + 7) / 8]u8 = undefined; | |
| 60 | mem.writeIntForeign(T, &bytes, value); | |
| 61 | return self.writeAll(&bytes); | |
| 62 | } | |
| 63 | ||
| 64 | /// TODO audit non-power-of-two int sizes | |
| 65 | pub fn writeIntLittle(self: Self, comptime T: type, value: T) Error!void { | |
| 66 | var bytes: [(T.bit_count + 7) / 8]u8 = undefined; | |
| 67 | mem.writeIntLittle(T, &bytes, value); | |
| 68 | return self.writeAll(&bytes); | |
| 69 | } | |
| 70 | ||
| 71 | /// TODO audit non-power-of-two int sizes | |
| 72 | pub fn writeIntBig(self: Self, comptime T: type, value: T) Error!void { | |
| 73 | var bytes: [(T.bit_count + 7) / 8]u8 = undefined; | |
| 74 | mem.writeIntBig(T, &bytes, value); | |
| 75 | return self.writeAll(&bytes); | |
| 76 | } | |
| 77 | ||
| 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 { | |
| 80 | var bytes: [(T.bit_count + 7) / 8]u8 = undefined; | |
| 81 | mem.writeInt(T, &bytes, value, endian); | |
| 82 | return self.writeAll(&bytes); | |
| 83 | } | |
| 84 | }; | |
| 85 | } | |
| 1 | /// Deprecated: use `std.io.writer.Writer` | |
| 2 | pub const OutStream = @import("./writer.zig").Writer; |
lib/std/io/writer.zig created+85| ... | ... | @@ -0,0 +1,85 @@ |
| 1 | const std = @import("../std.zig"); | |
| 2 | const builtin = std.builtin; | |
| 3 | const mem = std.mem; | |
| 4 | ||
| 5 | pub fn Writer( | |
| 6 | comptime Context: type, | |
| 7 | comptime WriteError: type, | |
| 8 | comptime writeFn: fn (context: Context, bytes: []const u8) WriteError!usize, | |
| 9 | ) type { | |
| 10 | return struct { | |
| 11 | context: Context, | |
| 12 | ||
| 13 | const Self = @This(); | |
| 14 | pub const Error = WriteError; | |
| 15 | ||
| 16 | pub fn write(self: Self, bytes: []const u8) Error!usize { | |
| 17 | return writeFn(self.context, bytes); | |
| 18 | } | |
| 19 | ||
| 20 | pub fn writeAll(self: Self, bytes: []const u8) Error!void { | |
| 21 | var index: usize = 0; | |
| 22 | while (index != bytes.len) { | |
| 23 | index += try self.write(bytes[index..]); | |
| 24 | } | |
| 25 | } | |
| 26 | ||
| 27 | pub fn print(self: Self, comptime format: []const u8, args: var) Error!void { | |
| 28 | return std.fmt.format(self, format, args); | |
| 29 | } | |
| 30 | ||
| 31 | pub fn writeByte(self: Self, byte: u8) Error!void { | |
| 32 | const array = [1]u8{byte}; | |
| 33 | return self.writeAll(&array); | |
| 34 | } | |
| 35 | ||
| 36 | pub fn writeByteNTimes(self: Self, byte: u8, n: usize) Error!void { | |
| 37 | var bytes: [256]u8 = undefined; | |
| 38 | mem.set(u8, bytes[0..], byte); | |
| 39 | ||
| 40 | var remaining: usize = n; | |
| 41 | while (remaining > 0) { | |
| 42 | const to_write = std.math.min(remaining, bytes.len); | |
| 43 | try self.writeAll(bytes[0..to_write]); | |
| 44 | remaining -= to_write; | |
| 45 | } | |
| 46 | } | |
| 47 | ||
| 48 | /// Write a native-endian integer. | |
| 49 | /// TODO audit non-power-of-two int sizes | |
| 50 | pub fn writeIntNative(self: Self, comptime T: type, value: T) Error!void { | |
| 51 | var bytes: [(T.bit_count + 7) / 8]u8 = undefined; | |
| 52 | mem.writeIntNative(T, &bytes, value); | |
| 53 | return self.writeAll(&bytes); | |
| 54 | } | |
| 55 | ||
| 56 | /// Write a foreign-endian integer. | |
| 57 | /// TODO audit non-power-of-two int sizes | |
| 58 | pub fn writeIntForeign(self: Self, comptime T: type, value: T) Error!void { | |
| 59 | var bytes: [(T.bit_count + 7) / 8]u8 = undefined; | |
| 60 | mem.writeIntForeign(T, &bytes, value); | |
| 61 | return self.writeAll(&bytes); | |
| 62 | } | |
| 63 | ||
| 64 | /// TODO audit non-power-of-two int sizes | |
| 65 | pub fn writeIntLittle(self: Self, comptime T: type, value: T) Error!void { | |
| 66 | var bytes: [(T.bit_count + 7) / 8]u8 = undefined; | |
| 67 | mem.writeIntLittle(T, &bytes, value); | |
| 68 | return self.writeAll(&bytes); | |
| 69 | } | |
| 70 | ||
| 71 | /// TODO audit non-power-of-two int sizes | |
| 72 | pub fn writeIntBig(self: Self, comptime T: type, value: T) Error!void { | |
| 73 | var bytes: [(T.bit_count + 7) / 8]u8 = undefined; | |
| 74 | mem.writeIntBig(T, &bytes, value); | |
| 75 | return self.writeAll(&bytes); | |
| 76 | } | |
| 77 | ||
| 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 { | |
| 80 | var bytes: [(T.bit_count + 7) / 8]u8 = undefined; | |
| 81 | mem.writeInt(T, &bytes, value, endian); | |
| 82 | return self.writeAll(&bytes); | |
| 83 | } | |
| 84 | }; | |
| 85 | } |
lib/std/zig/render.zig+1-1| ... | ... | @@ -49,7 +49,7 @@ pub fn render(allocator: *mem.Allocator, stream: var, tree: *ast.Tree) (@TypeOf( |
| 49 | 49 | .source_index = 0, |
| 50 | 50 | .source = tree.source, |
| 51 | 51 | }; |
| 52 | const my_stream_stream: std.io.OutStream(*MyStream, MyStream.StreamError, MyStream.write) = .{ | |
| 52 | const my_stream_stream: std.io.Writer(*MyStream, MyStream.StreamError, MyStream.write) = .{ | |
| 53 | 53 | .context = &my_stream, |
| 54 | 54 | }; |
| 55 | 55 |