| author | |
| committer | |
| log | 383afd19d73c7d98c8d1f7fe9d474b980517372e |
| tree | 48a66ca514f3b3610feb037fa4295fecc61114b1 |
| parent | 4ee25345668ff93f1a4a857436b14fc305f8cee7 |
it's the wrong abstraction and is only a footgun when used this way.7 files changed, 188 insertions(+), 175 deletions(-)
lib/std/fmt.zig+1-1| ... | ... | @@ -856,7 +856,7 @@ pub fn count(comptime fmt: []const u8, args: anytype) usize { |
| 856 | 856 | var buffer: [std.atomic.cache_line]u8 = undefined; |
| 857 | 857 | var bw = std.io.Writer.null.buffered(&buffer); |
| 858 | 858 | bw.print(fmt, args) catch unreachable; |
| 859 | return bw.bytes_written; | |
| 859 | return bw.count; | |
| 860 | 860 | } |
| 861 | 861 | |
| 862 | 862 | pub const AllocPrintError = error{OutOfMemory}; |
lib/std/io/AllocatingWriter.zig+20-10| ... | ... | @@ -27,19 +27,27 @@ const vtable: std.io.Writer.VTable = .{ |
| 27 | 27 | }; |
| 28 | 28 | |
| 29 | 29 | /// Sets the `AllocatingWriter` to an empty state. |
| 30 | pub fn init(aw: *AllocatingWriter, allocator: std.mem.Allocator) *std.io.BufferedWriter { | |
| 30 | pub fn init(aw: *AllocatingWriter, allocator: std.mem.Allocator) void { | |
| 31 | initOwnedSlice(aw, allocator, &.{}); | |
| 32 | } | |
| 33 | ||
| 34 | pub fn initCapacity(aw: *AllocatingWriter, allocator: std.mem.Allocator, capacity: usize) error{OutOfMemory}!void { | |
| 35 | const initial_buffer = try allocator.alloc(u8, capacity); | |
| 36 | initOwnedSlice(aw, allocator, initial_buffer); | |
| 37 | } | |
| 38 | ||
| 39 | pub fn initOwnedSlice(aw: *AllocatingWriter, allocator: std.mem.Allocator, slice: []u8) void { | |
| 31 | 40 | aw.* = .{ |
| 32 | .written = &.{}, | |
| 41 | .written = slice[0..0], | |
| 33 | 42 | .allocator = allocator, |
| 34 | 43 | .buffered_writer = .{ |
| 35 | 44 | .unbuffered_writer = .{ |
| 36 | 45 | .context = aw, |
| 37 | 46 | .vtable = &vtable, |
| 38 | 47 | }, |
| 39 | .buffer = &.{}, | |
| 48 | .buffer = slice, | |
| 40 | 49 | }, |
| 41 | 50 | }; |
| 42 | return &aw.buffered_writer; | |
| 43 | 51 | } |
| 44 | 52 | |
| 45 | 53 | pub fn deinit(aw: *AllocatingWriter) void { |
| ... | ... | @@ -118,7 +126,7 @@ pub fn clearRetainingCapacity(aw: *AllocatingWriter) void { |
| 118 | 126 | aw.written.len = 0; |
| 119 | 127 | } |
| 120 | 128 | |
| 121 | fn writeSplat(context: *anyopaque, data: []const []const u8, splat: usize) anyerror!usize { | |
| 129 | fn writeSplat(context: ?*anyopaque, data: []const []const u8, splat: usize) anyerror!usize { | |
| 122 | 130 | const aw: *AllocatingWriter = @alignCast(@ptrCast(context)); |
| 123 | 131 | const start_len = aw.written.len; |
| 124 | 132 | const bw = &aw.buffered_writer; |
| ... | ... | @@ -150,9 +158,9 @@ fn appendPatternAssumeCapacity(list: *std.ArrayListUnmanaged(u8), pattern: []con |
| 150 | 158 | } |
| 151 | 159 | |
| 152 | 160 | fn writeFile( |
| 153 | context: *anyopaque, | |
| 161 | context: ?*anyopaque, | |
| 154 | 162 | file: std.fs.File, |
| 155 | offset: u64, | |
| 163 | offset: std.io.Writer.Offset, | |
| 156 | 164 | len: std.io.Writer.FileLen, |
| 157 | 165 | headers_and_trailers_full: []const []const u8, |
| 158 | 166 | headers_len_full: usize, |
| ... | ... | @@ -168,13 +176,14 @@ fn writeFile( |
| 168 | 176 | break :b .{ headers_and_trailers_full[1..], headers_len_full - 1 }; |
| 169 | 177 | } else .{ headers_and_trailers_full, headers_len_full }; |
| 170 | 178 | const trailers = headers_and_trailers[headers_len..]; |
| 179 | const pos = offset.toInt() orelse @panic("TODO treat file as stream"); | |
| 171 | 180 | if (len == .entire_file) { |
| 172 | 181 | var new_capacity: usize = list.capacity + std.atomic.cache_line; |
| 173 | 182 | for (headers_and_trailers) |bytes| new_capacity += bytes.len; |
| 174 | 183 | try list.ensureTotalCapacity(gpa, new_capacity); |
| 175 | 184 | for (headers_and_trailers[0..headers_len]) |bytes| list.appendSliceAssumeCapacity(bytes); |
| 176 | 185 | const dest = list.items.ptr[list.items.len..list.capacity]; |
| 177 | const n = try file.pread(dest, offset); | |
| 186 | const n = try file.pread(dest, pos); | |
| 178 | 187 | if (n == 0) { |
| 179 | 188 | new_capacity = list.capacity; |
| 180 | 189 | for (trailers) |bytes| new_capacity += bytes.len; |
| ... | ... | @@ -190,7 +199,7 @@ fn writeFile( |
| 190 | 199 | try list.ensureTotalCapacity(gpa, new_capacity); |
| 191 | 200 | for (headers_and_trailers[0..headers_len]) |bytes| list.appendSliceAssumeCapacity(bytes); |
| 192 | 201 | const dest = list.items.ptr[list.items.len..][0..len.int()]; |
| 193 | const n = try file.pread(dest, offset); | |
| 202 | const n = try file.pread(dest, pos); | |
| 194 | 203 | list.items.len += n; |
| 195 | 204 | if (n < dest.len) { |
| 196 | 205 | return list.items.len - start_len; |
| ... | ... | @@ -201,8 +210,9 @@ fn writeFile( |
| 201 | 210 | |
| 202 | 211 | test AllocatingWriter { |
| 203 | 212 | var aw: AllocatingWriter = undefined; |
| 204 | const bw = aw.init(std.testing.allocator); | |
| 213 | aw.init(std.testing.allocator); | |
| 205 | 214 | defer aw.deinit(); |
| 215 | const bw = &aw.buffered_writer; | |
| 206 | 216 | |
| 207 | 217 | const x: i32 = 42; |
| 208 | 218 | const y: i32 = 1234; |
lib/std/io/BufferedReader.zig+54-51| ... | ... | @@ -74,7 +74,7 @@ pub fn initFixed(br: *BufferedReader, buffer: []const u8) void { |
| 74 | 74 | br.* = .{ |
| 75 | 75 | .seek = 0, |
| 76 | 76 | .storage = .{ |
| 77 | .buffer = .fromOwnedSlice(@constCast(buffer)), | |
| 77 | .buffer = @constCast(buffer), | |
| 78 | 78 | .unbuffered_writer = .{ |
| 79 | 79 | .context = undefined, |
| 80 | 80 | .vtable = &eof_writer, |
| ... | ... | @@ -88,9 +88,10 @@ pub fn initFixed(br: *BufferedReader, buffer: []const u8) void { |
| 88 | 88 | } |
| 89 | 89 | |
| 90 | 90 | pub fn storageBuffer(br: *BufferedReader) []u8 { |
| 91 | assert(br.storage.unbuffered_writer.vtable == &eof_writer); | |
| 91 | const storage = &br.storage; | |
| 92 | assert(storage.unbuffered_writer.vtable == &eof_writer); | |
| 92 | 93 | assert(br.unbuffered_reader.vtable == &eof_reader); |
| 93 | return br.storage.buffer.allocatedSlice(); | |
| 94 | return storage.buffer; | |
| 94 | 95 | } |
| 95 | 96 | |
| 96 | 97 | /// Although `BufferedReader` can easily satisfy the `Reader` interface, it's |
| ... | ... | @@ -108,7 +109,8 @@ pub fn reader(br: *BufferedReader) Reader { |
| 108 | 109 | |
| 109 | 110 | fn passthru_read(ctx: ?*anyopaque, bw: *BufferedWriter, limit: Reader.Limit) anyerror!Reader.RwResult { |
| 110 | 111 | const br: *BufferedReader = @alignCast(@ptrCast(ctx)); |
| 111 | const buffer = br.storage.buffer.items; | |
| 112 | const storage = &br.storage; | |
| 113 | const buffer = storage.buffer[0..storage.end]; | |
| 112 | 114 | const buffered = buffer[br.seek..]; |
| 113 | 115 | const limited = buffered[0..limit.min(buffered.len)]; |
| 114 | 116 | if (limited.len > 0) { |
| ... | ... | @@ -135,7 +137,7 @@ pub fn seekBy(br: *BufferedReader, seek_by: i64) anyerror!void { |
| 135 | 137 | } |
| 136 | 138 | |
| 137 | 139 | pub fn seekBackwardBy(br: *BufferedReader, seek_by: u64) anyerror!void { |
| 138 | if (seek_by > br.storage.buffer.items.len - br.seek) return error.Unseekable; // TODO | |
| 140 | if (seek_by > br.storage.end - br.seek) return error.Unseekable; // TODO | |
| 139 | 141 | br.seek += @abs(seek_by); |
| 140 | 142 | } |
| 141 | 143 | |
| ... | ... | @@ -178,10 +180,10 @@ pub fn peek(br: *BufferedReader, n: usize) anyerror![]u8 { |
| 178 | 180 | /// * `peek` |
| 179 | 181 | /// * `toss` |
| 180 | 182 | pub fn peekAll(br: *BufferedReader, n: usize) anyerror![]u8 { |
| 181 | const list = &br.storage.buffer; | |
| 182 | assert(n <= list.capacity); | |
| 183 | const storage = &br.storage; | |
| 184 | assert(n <= storage.buffer.len); | |
| 183 | 185 | try br.fill(n); |
| 184 | return list.items[br.seek..]; | |
| 186 | return storage.buffer[br.seek..storage.end]; | |
| 185 | 187 | } |
| 186 | 188 | |
| 187 | 189 | /// Skips the next `n` bytes from the stream, advancing the seek position. This |
| ... | ... | @@ -194,7 +196,7 @@ pub fn peekAll(br: *BufferedReader, n: usize) anyerror![]u8 { |
| 194 | 196 | /// * `discard`. |
| 195 | 197 | pub fn toss(br: *BufferedReader, n: usize) void { |
| 196 | 198 | br.seek += n; |
| 197 | assert(br.seek <= br.storage.buffer.items.len); | |
| 199 | assert(br.seek <= br.storage.end); | |
| 198 | 200 | } |
| 199 | 201 | |
| 200 | 202 | /// Equivalent to `peek` + `toss`. |
| ... | ... | @@ -245,22 +247,22 @@ pub fn discard(br: *BufferedReader, n: usize) anyerror!void { |
| 245 | 247 | /// * `toss` |
| 246 | 248 | /// * `discardUntilEnd` |
| 247 | 249 | pub fn discardUpTo(br: *BufferedReader, n: usize) anyerror!usize { |
| 248 | const list = &br.storage.buffer; | |
| 250 | const storage = &br.storage; | |
| 249 | 251 | var remaining = n; |
| 250 | 252 | while (remaining > 0) { |
| 251 | 253 | const proposed_seek = br.seek + remaining; |
| 252 | if (proposed_seek <= list.items.len) { | |
| 254 | if (proposed_seek <= storage.end) { | |
| 253 | 255 | br.seek = proposed_seek; |
| 254 | 256 | return; |
| 255 | 257 | } |
| 256 | remaining -= (list.items.len - br.seek); | |
| 257 | list.items.len = 0; | |
| 258 | remaining -= (storage.end - br.seek); | |
| 259 | storage.end = 0; | |
| 258 | 260 | br.seek = 0; |
| 259 | const result = try br.unbuffered_reader.read(&br.storage, .none); | |
| 261 | const result = try br.unbuffered_reader.read(&storage, .none); | |
| 260 | 262 | result.write_err catch unreachable; |
| 261 | 263 | try result.read_err; |
| 262 | assert(result.len == list.items.len); | |
| 263 | if (remaining <= list.items.len) continue; | |
| 264 | assert(result.len == storage.end); | |
| 265 | if (remaining <= storage.end) continue; | |
| 264 | 266 | if (result.end) return n - remaining; |
| 265 | 267 | } |
| 266 | 268 | } |
| ... | ... | @@ -268,9 +270,9 @@ pub fn discardUpTo(br: *BufferedReader, n: usize) anyerror!usize { |
| 268 | 270 | /// Reads the stream until the end, ignoring all the data. |
| 269 | 271 | /// Returns the number of bytes discarded. |
| 270 | 272 | pub fn discardUntilEnd(br: *BufferedReader) anyerror!usize { |
| 271 | const list = &br.storage.buffer; | |
| 272 | var total: usize = list.items.len; | |
| 273 | list.items.len = 0; | |
| 273 | const storage = &br.storage; | |
| 274 | var total: usize = storage.end; | |
| 275 | storage.end = 0; | |
| 274 | 276 | total += try br.unbuffered_reader.discardUntilEnd(); |
| 275 | 277 | return total; |
| 276 | 278 | } |
| ... | ... | @@ -286,8 +288,8 @@ pub fn discardUntilEnd(br: *BufferedReader) anyerror!usize { |
| 286 | 288 | /// See also: |
| 287 | 289 | /// * `peek` |
| 288 | 290 | pub fn read(br: *BufferedReader, buffer: []u8) anyerror!void { |
| 289 | const list = &br.storage.buffer; | |
| 290 | const in_buffer = list.items; | |
| 291 | const storage = &br.storage; | |
| 292 | const in_buffer = storage.buffer[0..storage.end]; | |
| 291 | 293 | const seek = br.seek; |
| 292 | 294 | const proposed_seek = seek + in_buffer.len; |
| 293 | 295 | if (proposed_seek <= in_buffer.len) { |
| ... | ... | @@ -296,21 +298,21 @@ pub fn read(br: *BufferedReader, buffer: []u8) anyerror!void { |
| 296 | 298 | return; |
| 297 | 299 | } |
| 298 | 300 | @memcpy(buffer[0..in_buffer.len], in_buffer); |
| 299 | list.items.len = 0; | |
| 301 | storage.end = 0; | |
| 300 | 302 | br.seek = 0; |
| 301 | 303 | var i: usize = in_buffer.len; |
| 302 | 304 | while (true) { |
| 303 | const status = try br.unbuffered_reader.read(&br.storage, .none); | |
| 304 | const next_i = i + list.items.len; | |
| 305 | const status = try br.unbuffered_reader.read(storage, .none); | |
| 306 | const next_i = i + storage.end; | |
| 305 | 307 | if (next_i >= buffer.len) { |
| 306 | 308 | const remaining = buffer[i..]; |
| 307 | @memcpy(remaining, list.items[0..remaining.len]); | |
| 309 | @memcpy(remaining, storage.buffer[0..remaining.len]); | |
| 308 | 310 | br.seek = remaining.len; |
| 309 | 311 | return; |
| 310 | 312 | } |
| 311 | 313 | if (status.end) return error.EndOfStream; |
| 312 | @memcpy(buffer[i..next_i], list.items); | |
| 313 | list.items.len = 0; | |
| 314 | @memcpy(buffer[i..next_i], storage.buffer[0..storage.end]); | |
| 315 | storage.end = 0; | |
| 314 | 316 | i = next_i; |
| 315 | 317 | } |
| 316 | 318 | } |
| ... | ... | @@ -347,8 +349,8 @@ pub fn takeDelimiterInclusive(br: *BufferedReader, delimiter: u8) anyerror![]u8 |
| 347 | 349 | } |
| 348 | 350 | |
| 349 | 351 | pub fn peekDelimiterInclusive(br: *BufferedReader, delimiter: u8) anyerror![]u8 { |
| 350 | const list = &br.storage.buffer; | |
| 351 | const buffer = list.items; | |
| 352 | const storage = &br.storage; | |
| 353 | const buffer = storage.buffer[0..storage.end]; | |
| 352 | 354 | const seek = br.seek; |
| 353 | 355 | if (std.mem.indexOfScalarPos(u8, buffer, seek, delimiter)) |end| { |
| 354 | 356 | @branchHint(.likely); |
| ... | ... | @@ -357,15 +359,15 @@ pub fn peekDelimiterInclusive(br: *BufferedReader, delimiter: u8) anyerror![]u8 |
| 357 | 359 | const remainder = buffer[seek..]; |
| 358 | 360 | std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); |
| 359 | 361 | var i = remainder.len; |
| 360 | list.items.len = i; | |
| 362 | storage.end = i; | |
| 361 | 363 | br.seek = 0; |
| 362 | while (i < list.capacity) { | |
| 363 | const status = try br.unbuffered_reader.read(&br.storage, .none); | |
| 364 | if (std.mem.indexOfScalarPos(u8, list.items, i, delimiter)) |end| { | |
| 365 | return list.items[0 .. end + 1]; | |
| 364 | while (i < storage.buffer.len) { | |
| 365 | const status = try br.unbuffered_reader.read(storage, .none); | |
| 366 | if (std.mem.indexOfScalarPos(u8, storage.buffer[0..storage.end], i, delimiter)) |end| { | |
| 367 | return storage.buffer[0 .. end + 1]; | |
| 366 | 368 | } |
| 367 | 369 | if (status.end) return error.EndOfStream; |
| 368 | i = list.items.len; | |
| 370 | i = storage.end; | |
| 369 | 371 | } |
| 370 | 372 | return error.StreamTooLong; |
| 371 | 373 | } |
| ... | ... | @@ -392,8 +394,8 @@ pub fn takeDelimiterConclusive(br: *BufferedReader, delimiter: u8) anyerror![]u8 |
| 392 | 394 | } |
| 393 | 395 | |
| 394 | 396 | pub fn peekDelimiterConclusive(br: *BufferedReader, delimiter: u8) anyerror![]u8 { |
| 395 | const list = &br.storage.buffer; | |
| 396 | const buffer = list.items; | |
| 397 | const storage = &br.storage; | |
| 398 | const buffer = storage.buffer[0..storage.end]; | |
| 397 | 399 | const seek = br.seek; |
| 398 | 400 | if (std.mem.indexOfScalarPos(u8, buffer, seek, delimiter)) |end| { |
| 399 | 401 | @branchHint(.likely); |
| ... | ... | @@ -402,15 +404,15 @@ pub fn peekDelimiterConclusive(br: *BufferedReader, delimiter: u8) anyerror![]u8 |
| 402 | 404 | const remainder = buffer[seek..]; |
| 403 | 405 | std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); |
| 404 | 406 | var i = remainder.len; |
| 405 | list.items.len = i; | |
| 407 | storage.end = i; | |
| 406 | 408 | br.seek = 0; |
| 407 | while (i < list.capacity) { | |
| 408 | const status = try br.unbuffered_reader.read(&br.storage, .none); | |
| 409 | if (std.mem.indexOfScalarPos(u8, list.items, i, delimiter)) |end| { | |
| 410 | return list.items[0 .. end + 1]; | |
| 409 | while (i < storage.buffer.len) { | |
| 410 | const status = try br.unbuffered_reader.read(storage, .none); | |
| 411 | if (std.mem.indexOfScalarPos(u8, storage.buffer[0..storage.end], i, delimiter)) |end| { | |
| 412 | return storage.buffer[0 .. end + 1]; | |
| 411 | 413 | } |
| 412 | if (status.end) return list.items; | |
| 413 | i = list.items.len; | |
| 414 | if (status.end) return storage.buffer[0..storage.end]; | |
| 415 | i = storage.end; | |
| 414 | 416 | } |
| 415 | 417 | return error.StreamTooLong; |
| 416 | 418 | } |
| ... | ... | @@ -490,9 +492,9 @@ pub fn discardDelimiterInclusive(br: *BufferedReader, delimiter: u8) anyerror!vo |
| 490 | 492 | /// |
| 491 | 493 | /// Asserts buffer capacity is at least `n`. |
| 492 | 494 | pub fn fill(br: *BufferedReader, n: usize) anyerror!void { |
| 493 | assert(n <= br.storage.buffer.capacity); | |
| 494 | const list = &br.storage.buffer; | |
| 495 | const buffer = list.items; | |
| 495 | const storage = &br.storage; | |
| 496 | assert(n <= storage.buffer.len); | |
| 497 | const buffer = storage.buffer[0..storage.end]; | |
| 496 | 498 | const seek = br.seek; |
| 497 | 499 | if (seek + n <= buffer.len) { |
| 498 | 500 | @branchHint(.likely); |
| ... | ... | @@ -500,18 +502,19 @@ pub fn fill(br: *BufferedReader, n: usize) anyerror!void { |
| 500 | 502 | } |
| 501 | 503 | const remainder = buffer[seek..]; |
| 502 | 504 | std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); |
| 503 | list.items.len = remainder.len; | |
| 505 | storage.end = remainder.len; | |
| 504 | 506 | br.seek = 0; |
| 505 | 507 | while (true) { |
| 506 | const status = try br.unbuffered_reader.read(&br.storage, .none); | |
| 507 | if (n <= list.items.len) return; | |
| 508 | const status = try br.unbuffered_reader.read(storage, .none); | |
| 509 | if (n <= storage.end) return; | |
| 508 | 510 | if (status.end) return error.EndOfStream; |
| 509 | 511 | } |
| 510 | 512 | } |
| 511 | 513 | |
| 512 | 514 | /// Reads 1 byte from the stream or returns `error.EndOfStream`. |
| 513 | 515 | pub fn takeByte(br: *BufferedReader) anyerror!u8 { |
| 514 | const buffer = br.storage.buffer.items; | |
| 516 | const storage = &br.storage; | |
| 517 | const buffer = storage.buffer[0..storage.end]; | |
| 515 | 518 | const seek = br.seek; |
| 516 | 519 | if (seek >= buffer.len) { |
| 517 | 520 | @branchHint(.unlikely); |
lib/std/io/BufferedWriter.zig+94-98| ... | ... | @@ -6,10 +6,6 @@ const Writer = std.io.Writer; |
| 6 | 6 | const Allocator = std.mem.Allocator; |
| 7 | 7 | const testing = std.testing; |
| 8 | 8 | |
| 9 | /// User-provided storage that must outlive this `BufferedWriter`. | |
| 10 | /// | |
| 11 | /// If this has capacity zero, the writer is unbuffered, and `flush` is a no-op. | |
| 12 | buffer: std.ArrayListUnmanaged(u8), | |
| 13 | 9 | /// Underlying stream to send bytes to. |
| 14 | 10 | /// |
| 15 | 11 | /// A write will only be sent here if it could not fit into `buffer`, or if it |
| ... | ... | @@ -19,10 +15,14 @@ buffer: std.ArrayListUnmanaged(u8), |
| 19 | 15 | /// equals number of bytes provided. This property is exploited by |
| 20 | 16 | /// `std.io.AllocatingWriter` for example. |
| 21 | 17 | unbuffered_writer: Writer, |
| 18 | /// If this has length zero, the writer is unbuffered, and `flush` is a no-op. | |
| 19 | buffer: []u8, | |
| 20 | /// Marks the end of `buffer` - before this are buffered bytes, after this is | |
| 21 | /// undefined. | |
| 22 | end: usize = 0, | |
| 22 | 23 | /// Tracks total number of bytes written to this `BufferedWriter`. This value |
| 23 | /// only increases. In the case of fixed mode, this value always equals | |
| 24 | /// `buffer.items.len`. | |
| 25 | bytes_written: usize = 0, | |
| 24 | /// only increases. In the case of fixed mode, this value always equals `end`. | |
| 25 | count: usize = 0, | |
| 26 | 26 | |
| 27 | 27 | /// Number of slices to store on the stack, when trying to send as many byte |
| 28 | 28 | /// vectors through the underlying write calls as possible. |
| ... | ... | @@ -46,71 +46,72 @@ const fixed_vtable: Writer.VTable = .{ |
| 46 | 46 | .writeFile = Writer.unimplemented_writeFile, |
| 47 | 47 | }; |
| 48 | 48 | |
| 49 | /// Replaces the `BufferedWriter` with a new one that writes to `buffer` and | |
| 50 | /// returns `error.NoSpaceLeft` when it is full. | |
| 49 | /// Replaces the `BufferedWriter` with one that writes to `buffer` and returns | |
| 50 | /// `error.NoSpaceLeft` when it is full. `end` and `count` will always be | |
| 51 | /// equal. | |
| 51 | 52 | pub fn initFixed(bw: *BufferedWriter, buffer: []u8) void { |
| 52 | 53 | bw.* = .{ |
| 53 | 54 | .unbuffered_writer = .{ |
| 54 | 55 | .context = bw, |
| 55 | 56 | .vtable = &fixed_vtable, |
| 56 | 57 | }, |
| 57 | .buffer = .initBuffer(buffer), | |
| 58 | .buffer = buffer, | |
| 58 | 59 | }; |
| 59 | 60 | } |
| 60 | 61 | |
| 61 | 62 | /// This function is available when using `initFixed`. |
| 62 | 63 | pub fn getWritten(bw: *const BufferedWriter) []u8 { |
| 63 | 64 | assert(bw.unbuffered_writer.vtable == &fixed_vtable); |
| 64 | return bw.buffer.items; | |
| 65 | return bw.buffer[0..bw.end]; | |
| 65 | 66 | } |
| 66 | 67 | |
| 67 | 68 | /// This function is available when using `initFixed`. |
| 68 | 69 | pub fn reset(bw: *BufferedWriter) void { |
| 69 | 70 | assert(bw.unbuffered_writer.vtable == &fixed_vtable); |
| 70 | bw.buffer.items.len = 0; | |
| 71 | bw.end = 0; | |
| 72 | bw.count = 0; | |
| 71 | 73 | } |
| 72 | 74 | |
| 73 | 75 | pub fn flush(bw: *BufferedWriter) anyerror!void { |
| 74 | const list = &bw.buffer; | |
| 75 | const send_buffer = list.items; | |
| 76 | const send_buffer = bw.buffer[0..bw.end]; | |
| 76 | 77 | var index: usize = 0; |
| 77 | 78 | while (index < send_buffer.len) index += try bw.unbuffered_writer.writev(&.{send_buffer[index..]}); |
| 78 | list.items.len = 0; | |
| 79 | bw.end = 0; | |
| 79 | 80 | } |
| 80 | 81 | |
| 81 | 82 | pub fn unusedCapacitySlice(bw: *const BufferedWriter) []u8 { |
| 82 | return bw.buffer.unusedCapacitySlice(); | |
| 83 | return bw.buffer[bw.end..]; | |
| 83 | 84 | } |
| 84 | 85 | |
| 86 | /// Asserts the provided buffer has total capacity enough for `minimum_length`. | |
| 85 | 87 | pub fn writableSlice(bw: *BufferedWriter, minimum_length: usize) anyerror![]u8 { |
| 86 | const list = &bw.buffer; | |
| 87 | assert(list.capacity >= minimum_length); | |
| 88 | const cap_slice = list.unusedCapacitySlice(); | |
| 88 | assert(bw.buffer.len >= minimum_length); | |
| 89 | const cap_slice = bw.buffer[bw.end..]; | |
| 89 | 90 | if (cap_slice.len >= minimum_length) { |
| 90 | 91 | @branchHint(.likely); |
| 91 | 92 | return cap_slice; |
| 92 | 93 | } |
| 93 | const buffer = list.items; | |
| 94 | const buffer = bw.buffer[0..bw.end]; | |
| 94 | 95 | const n = try bw.unbuffered_writer.write(buffer); |
| 95 | 96 | if (n == buffer.len) { |
| 96 | 97 | @branchHint(.likely); |
| 97 | list.items.len = 0; | |
| 98 | return list.unusedCapacitySlice(); | |
| 98 | bw.end = 0; | |
| 99 | return bw.buffer; | |
| 99 | 100 | } |
| 100 | 101 | if (n > 0) { |
| 101 | 102 | const remainder = buffer[n..]; |
| 102 | 103 | std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); |
| 103 | list.items.len = remainder.len; | |
| 104 | bw.end = remainder.len; | |
| 104 | 105 | } |
| 105 | return list.unusedCapacitySlice(); | |
| 106 | return bw.buffer[bw.end..]; | |
| 106 | 107 | } |
| 107 | 108 | |
| 108 | 109 | /// After calling `writableSlice`, this function tracks how many bytes were written to it. |
| 109 | 110 | pub fn advance(bw: *BufferedWriter, n: usize) void { |
| 110 | const list = &bw.buffer; | |
| 111 | list.items.len += n; | |
| 112 | assert(list.items.len <= list.capacity); | |
| 113 | bw.bytes_written += n; | |
| 111 | const new_end = bw.end + n; | |
| 112 | assert(new_end <= bw.buffer.len); | |
| 113 | bw.end = new_end; | |
| 114 | bw.count += n; | |
| 114 | 115 | } |
| 115 | 116 | |
| 116 | 117 | /// The `data` parameter is mutable because this function needs to mutate the |
| ... | ... | @@ -139,9 +140,8 @@ pub fn writev(bw: *BufferedWriter, data: []const []const u8) anyerror!usize { |
| 139 | 140 | |
| 140 | 141 | fn passthru_writeSplat(context: ?*anyopaque, data: []const []const u8, splat: usize) anyerror!usize { |
| 141 | 142 | const bw: *BufferedWriter = @alignCast(@ptrCast(context)); |
| 142 | const list = &bw.buffer; | |
| 143 | const buffer = list.allocatedSlice(); | |
| 144 | const start_end = list.items.len; | |
| 143 | const buffer = bw.buffer; | |
| 144 | const start_end = bw.end; | |
| 145 | 145 | |
| 146 | 146 | var buffers: [max_buffers_len][]const u8 = undefined; |
| 147 | 147 | var end = start_end; |
| ... | ... | @@ -153,7 +153,7 @@ fn passthru_writeSplat(context: ?*anyopaque, data: []const []const u8, splat: us |
| 153 | 153 | end = new_end; |
| 154 | 154 | continue; |
| 155 | 155 | } |
| 156 | if (end == 0) return track(&bw.bytes_written, try bw.unbuffered_writer.writeSplat(data, splat)); | |
| 156 | if (end == 0) return track(&bw.count, try bw.unbuffered_writer.writeSplat(data, splat)); | |
| 157 | 157 | buffers[0] = buffer[0..end]; |
| 158 | 158 | const remaining_data = data[i..]; |
| 159 | 159 | const remaining_buffers = buffers[1..]; |
| ... | ... | @@ -168,22 +168,22 @@ fn passthru_writeSplat(context: ?*anyopaque, data: []const []const u8, splat: us |
| 168 | 168 | @branchHint(.unlikely); |
| 169 | 169 | const remainder = buffer[n..end]; |
| 170 | 170 | std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); |
| 171 | list.items.len = remainder.len; | |
| 172 | return track(&bw.bytes_written, end - start_end); | |
| 171 | bw.end = remainder.len; | |
| 172 | return track(&bw.count, end - start_end); | |
| 173 | 173 | } |
| 174 | list.items.len = 0; | |
| 175 | return track(&bw.bytes_written, n - start_end); | |
| 174 | bw.end = 0; | |
| 175 | return track(&bw.count, n - start_end); | |
| 176 | 176 | } |
| 177 | 177 | const n = try bw.unbuffered_writer.writeSplat(send_buffers, 1); |
| 178 | 178 | if (n < end) { |
| 179 | 179 | @branchHint(.unlikely); |
| 180 | 180 | const remainder = buffer[n..end]; |
| 181 | 181 | std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); |
| 182 | list.items.len = remainder.len; | |
| 183 | return track(&bw.bytes_written, end - start_end); | |
| 182 | bw.end = remainder.len; | |
| 183 | return track(&bw.count, end - start_end); | |
| 184 | 184 | } |
| 185 | list.items.len = 0; | |
| 186 | return track(&bw.bytes_written, n - start_end); | |
| 185 | bw.end = 0; | |
| 186 | return track(&bw.count, n - start_end); | |
| 187 | 187 | } |
| 188 | 188 | |
| 189 | 189 | const pattern = data[data.len - 1]; |
| ... | ... | @@ -192,24 +192,24 @@ fn passthru_writeSplat(context: ?*anyopaque, data: []const []const u8, splat: us |
| 192 | 192 | @branchHint(.unlikely); |
| 193 | 193 | // It was added in the loop above; undo it here. |
| 194 | 194 | end -= pattern.len; |
| 195 | list.items.len = end; | |
| 196 | return track(&bw.bytes_written, end - start_end); | |
| 195 | bw.end = end; | |
| 196 | return track(&bw.count, end - start_end); | |
| 197 | 197 | } |
| 198 | 198 | |
| 199 | 199 | const remaining_splat = splat - 1; |
| 200 | 200 | |
| 201 | 201 | switch (pattern.len) { |
| 202 | 202 | 0 => { |
| 203 | list.items.len = end; | |
| 204 | return track(&bw.bytes_written, end - start_end); | |
| 203 | bw.end = end; | |
| 204 | return track(&bw.count, end - start_end); | |
| 205 | 205 | }, |
| 206 | 206 | 1 => { |
| 207 | 207 | const new_end = end + remaining_splat; |
| 208 | 208 | if (new_end <= buffer.len) { |
| 209 | 209 | @branchHint(.likely); |
| 210 | 210 | @memset(buffer[end..new_end], pattern[0]); |
| 211 | list.items.len = new_end; | |
| 212 | return track(&bw.bytes_written, new_end - start_end); | |
| 211 | bw.end = new_end; | |
| 212 | return track(&bw.count, new_end - start_end); | |
| 213 | 213 | } |
| 214 | 214 | buffers[0] = buffer[0..end]; |
| 215 | 215 | buffers[1] = pattern; |
| ... | ... | @@ -218,11 +218,11 @@ fn passthru_writeSplat(context: ?*anyopaque, data: []const []const u8, splat: us |
| 218 | 218 | @branchHint(.unlikely); |
| 219 | 219 | const remainder = buffer[n..end]; |
| 220 | 220 | std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); |
| 221 | list.items.len = remainder.len; | |
| 222 | return track(&bw.bytes_written, end - start_end); | |
| 221 | bw.end = remainder.len; | |
| 222 | return track(&bw.count, end - start_end); | |
| 223 | 223 | } |
| 224 | list.items.len = 0; | |
| 225 | return track(&bw.bytes_written, n - start_end); | |
| 224 | bw.end = 0; | |
| 225 | return track(&bw.count, n - start_end); | |
| 226 | 226 | }, |
| 227 | 227 | else => { |
| 228 | 228 | const new_end = end + pattern.len * remaining_splat; |
| ... | ... | @@ -231,8 +231,8 @@ fn passthru_writeSplat(context: ?*anyopaque, data: []const []const u8, splat: us |
| 231 | 231 | while (end < new_end) : (end += pattern.len) { |
| 232 | 232 | @memcpy(buffer[end..][0..pattern.len], pattern); |
| 233 | 233 | } |
| 234 | list.items.len = new_end; | |
| 235 | return track(&bw.bytes_written, new_end - start_end); | |
| 234 | bw.end = new_end; | |
| 235 | return track(&bw.count, new_end - start_end); | |
| 236 | 236 | } |
| 237 | 237 | buffers[0] = buffer[0..end]; |
| 238 | 238 | buffers[1] = pattern; |
| ... | ... | @@ -241,17 +241,17 @@ fn passthru_writeSplat(context: ?*anyopaque, data: []const []const u8, splat: us |
| 241 | 241 | @branchHint(.unlikely); |
| 242 | 242 | const remainder = buffer[n..end]; |
| 243 | 243 | std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); |
| 244 | list.items.len = remainder.len; | |
| 245 | return track(&bw.bytes_written, end - start_end); | |
| 244 | bw.end = remainder.len; | |
| 245 | return track(&bw.count, end - start_end); | |
| 246 | 246 | } |
| 247 | list.items.len = 0; | |
| 248 | return track(&bw.bytes_written, n - start_end); | |
| 247 | bw.end = 0; | |
| 248 | return track(&bw.count, n - start_end); | |
| 249 | 249 | }, |
| 250 | 250 | } |
| 251 | 251 | } |
| 252 | 252 | |
| 253 | fn track(bytes_written: *usize, n: usize) usize { | |
| 254 | bytes_written.* += n; | |
| 253 | fn track(count: *usize, n: usize) usize { | |
| 254 | count.* += n; | |
| 255 | 255 | return n; |
| 256 | 256 | } |
| 257 | 257 | |
| ... | ... | @@ -260,31 +260,29 @@ fn track(bytes_written: *usize, n: usize) usize { |
| 260 | 260 | /// available buffer has been filled. |
| 261 | 261 | fn fixed_writeSplat(context: ?*anyopaque, data: []const []const u8, splat: usize) anyerror!usize { |
| 262 | 262 | const bw: *BufferedWriter = @alignCast(@ptrCast(context)); |
| 263 | const list = &bw.buffer; | |
| 264 | 263 | for (data) |bytes| { |
| 265 | const dest = list.unusedCapacitySlice(); | |
| 264 | const dest = bw.buffer[bw.end..]; | |
| 266 | 265 | if (dest.len == 0) return error.NoSpaceLeft; |
| 267 | 266 | const len = @min(bytes.len, dest.len); |
| 268 | 267 | @memcpy(dest[0..len], bytes[0..len]); |
| 269 | list.items.len += len; | |
| 270 | bw.bytes_written = list.items.len; | |
| 268 | bw.end += len; | |
| 269 | bw.count = bw.end; | |
| 271 | 270 | } |
| 272 | 271 | const pattern = data[data.len - 1]; |
| 273 | const dest = list.unusedCapacitySlice(); | |
| 272 | const dest = bw.buffer[bw.end..]; | |
| 274 | 273 | switch (pattern.len) { |
| 275 | 274 | 0 => unreachable, |
| 276 | 275 | 1 => @memset(dest, pattern[0]), |
| 277 | 276 | else => for (0..splat - 1) |i| @memcpy(dest[i * pattern.len ..][0..pattern.len], pattern), |
| 278 | 277 | } |
| 279 | list.items.len = list.capacity; | |
| 280 | bw.bytes_written = list.items.len; | |
| 278 | bw.end = bw.buffer.len; | |
| 279 | bw.count = bw.end; | |
| 281 | 280 | return error.NoSpaceLeft; |
| 282 | 281 | } |
| 283 | 282 | |
| 284 | 283 | pub fn write(bw: *BufferedWriter, bytes: []const u8) anyerror!usize { |
| 285 | const list = &bw.buffer; | |
| 286 | const buffer = list.allocatedSlice(); | |
| 287 | const end = list.items.len; | |
| 284 | const buffer = bw.buffer; | |
| 285 | const end = bw.end; | |
| 288 | 286 | const new_end = end + bytes.len; |
| 289 | 287 | if (new_end > buffer.len) { |
| 290 | 288 | var data: [2][]const u8 = .{ buffer[0..end], bytes }; |
| ... | ... | @@ -293,15 +291,15 @@ pub fn write(bw: *BufferedWriter, bytes: []const u8) anyerror!usize { |
| 293 | 291 | @branchHint(.unlikely); |
| 294 | 292 | const remainder = buffer[n..end]; |
| 295 | 293 | std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); |
| 296 | list.items.len = remainder.len; | |
| 294 | bw.end = remainder.len; | |
| 297 | 295 | return 0; |
| 298 | 296 | } |
| 299 | list.items.len = 0; | |
| 300 | return track(&bw.bytes_written, n - end); | |
| 297 | bw.end = 0; | |
| 298 | return track(&bw.count, n - end); | |
| 301 | 299 | } |
| 302 | 300 | @memcpy(buffer[end..new_end], bytes); |
| 303 | list.items.len = new_end; | |
| 304 | return track(&bw.bytes_written, bytes.len); | |
| 301 | bw.end = new_end; | |
| 302 | return track(&bw.count, bytes.len); | |
| 305 | 303 | } |
| 306 | 304 | |
| 307 | 305 | /// Calls `write` as many times as necessary such that all of `bytes` are |
| ... | ... | @@ -316,13 +314,12 @@ pub fn print(bw: *BufferedWriter, comptime format: []const u8, args: anytype) an |
| 316 | 314 | } |
| 317 | 315 | |
| 318 | 316 | pub fn writeByte(bw: *BufferedWriter, byte: u8) anyerror!void { |
| 319 | const list = &bw.buffer; | |
| 320 | const buffer = list.items; | |
| 321 | if (buffer.len < list.capacity) { | |
| 317 | const buffer = bw.buffer[0..bw.end]; | |
| 318 | if (buffer.len < bw.buffer.len) { | |
| 322 | 319 | @branchHint(.likely); |
| 323 | 320 | buffer.ptr[buffer.len] = byte; |
| 324 | list.items.len = buffer.len + 1; | |
| 325 | bw.bytes_written += 1; | |
| 321 | bw.end = buffer.len + 1; | |
| 322 | bw.count += 1; | |
| 326 | 323 | return; |
| 327 | 324 | } |
| 328 | 325 | var buffers: [2][]const u8 = .{ buffer, &.{byte} }; |
| ... | ... | @@ -332,23 +329,23 @@ pub fn writeByte(bw: *BufferedWriter, byte: u8) anyerror!void { |
| 332 | 329 | @branchHint(.unlikely); |
| 333 | 330 | continue; |
| 334 | 331 | } |
| 335 | bw.bytes_written += 1; | |
| 332 | bw.count += 1; | |
| 336 | 333 | if (n >= buffer.len) { |
| 337 | 334 | @branchHint(.likely); |
| 338 | 335 | if (n > buffer.len) { |
| 339 | 336 | @branchHint(.likely); |
| 340 | list.items.len = 0; | |
| 337 | bw.end = 0; | |
| 341 | 338 | return; |
| 342 | 339 | } else { |
| 343 | 340 | buffer[0] = byte; |
| 344 | list.items.len = 1; | |
| 341 | bw.end = 1; | |
| 345 | 342 | return; |
| 346 | 343 | } |
| 347 | 344 | } |
| 348 | 345 | const remainder = buffer[n..]; |
| 349 | 346 | std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); |
| 350 | 347 | buffer[remainder.len] = byte; |
| 351 | list.items.len = remainder.len + 1; | |
| 348 | bw.end = remainder.len + 1; | |
| 352 | 349 | return; |
| 353 | 350 | } |
| 354 | 351 | } |
| ... | ... | @@ -430,13 +427,12 @@ fn passthru_writeFile( |
| 430 | 427 | headers_len: usize, |
| 431 | 428 | ) anyerror!usize { |
| 432 | 429 | const bw: *BufferedWriter = @alignCast(@ptrCast(context)); |
| 433 | const list = &bw.buffer; | |
| 434 | const buffer = list.allocatedSlice(); | |
| 430 | const buffer = bw.buffer; | |
| 435 | 431 | if (buffer.len == 0) return track( |
| 436 | &bw.bytes_written, | |
| 432 | &bw.count, | |
| 437 | 433 | try bw.unbuffered_writer.writeFile(file, offset, len, headers_and_trailers, headers_len), |
| 438 | 434 | ); |
| 439 | const start_end = list.items.len; | |
| 435 | const start_end = bw.end; | |
| 440 | 436 | const headers = headers_and_trailers[0..headers_len]; |
| 441 | 437 | const trailers = headers_and_trailers[headers_len..]; |
| 442 | 438 | var buffers: [max_buffers_len][]const u8 = undefined; |
| ... | ... | @@ -466,11 +462,11 @@ fn passthru_writeFile( |
| 466 | 462 | @branchHint(.unlikely); |
| 467 | 463 | const remainder = buffer[n..end]; |
| 468 | 464 | std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); |
| 469 | list.items.len = remainder.len; | |
| 470 | return track(&bw.bytes_written, end - start_end); | |
| 465 | bw.end = remainder.len; | |
| 466 | return track(&bw.count, end - start_end); | |
| 471 | 467 | } |
| 472 | list.items.len = 0; | |
| 473 | return track(&bw.bytes_written, n - start_end); | |
| 468 | bw.end = 0; | |
| 469 | return track(&bw.count, n - start_end); | |
| 474 | 470 | } |
| 475 | 471 | // Have not made it past the headers yet; must call `writev`. |
| 476 | 472 | const n = try bw.unbuffered_writer.writev(buffers[0 .. buffers_len + 1]); |
| ... | ... | @@ -478,11 +474,11 @@ fn passthru_writeFile( |
| 478 | 474 | @branchHint(.unlikely); |
| 479 | 475 | const remainder = buffer[n..end]; |
| 480 | 476 | std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); |
| 481 | list.items.len = remainder.len; | |
| 482 | return track(&bw.bytes_written, end - start_end); | |
| 477 | bw.end = remainder.len; | |
| 478 | return track(&bw.count, end - start_end); | |
| 483 | 479 | } |
| 484 | list.items.len = 0; | |
| 485 | return track(&bw.bytes_written, n - start_end); | |
| 480 | bw.end = 0; | |
| 481 | return track(&bw.count, n - start_end); | |
| 486 | 482 | } |
| 487 | 483 | // All headers written to buffer. |
| 488 | 484 | buffers[0] = buffer[0..end]; |
| ... | ... | @@ -496,11 +492,11 @@ fn passthru_writeFile( |
| 496 | 492 | @branchHint(.unlikely); |
| 497 | 493 | const remainder = buffer[n..end]; |
| 498 | 494 | std.mem.copyForwards(u8, buffer[0..remainder.len], remainder); |
| 499 | list.items.len = remainder.len; | |
| 500 | return track(&bw.bytes_written, end - start_end); | |
| 495 | bw.end = remainder.len; | |
| 496 | return track(&bw.count, end - start_end); | |
| 501 | 497 | } |
| 502 | list.items.len = 0; | |
| 503 | return track(&bw.bytes_written, n - start_end); | |
| 498 | bw.end = 0; | |
| 499 | return track(&bw.count, n - start_end); | |
| 504 | 500 | } |
| 505 | 501 | |
| 506 | 502 | pub const WriteFileOptions = struct { |
lib/std/io/Writer.zig+1-1| ... | ... | @@ -112,7 +112,7 @@ pub fn unimplemented_writeFile( |
| 112 | 112 | |
| 113 | 113 | pub fn buffered(w: Writer, buffer: []u8) std.io.BufferedWriter { |
| 114 | 114 | return .{ |
| 115 | .buffer = .initBuffer(buffer), | |
| 115 | .buffer = buffer, | |
| 116 | 116 | .unbuffered_writer = w, |
| 117 | 117 | }; |
| 118 | 118 | } |
lib/std/tar/Writer.zig+4-2| ... | ... | @@ -420,7 +420,8 @@ test "write files" { |
| 420 | 420 | const root = "root"; |
| 421 | 421 | |
| 422 | 422 | var output: std.io.AllocatingWriter = undefined; |
| 423 | var wrt: Writer = .{ .underlying_writer = output.init(testing.allocator) }; | |
| 423 | output.init(testing.allocator); | |
| 424 | var wrt: Writer = .{ .underlying_writer = &output.buffered_writer }; | |
| 424 | 425 | defer output.deinit(); |
| 425 | 426 | try wrt.setRoot(root); |
| 426 | 427 | for (files) |file| |
| ... | ... | @@ -456,7 +457,8 @@ test "write files" { |
| 456 | 457 | // without root |
| 457 | 458 | { |
| 458 | 459 | var output: std.io.AllocatingWriter = undefined; |
| 459 | var wrt: Writer = .{ .underlying_writer = output.init(testing.allocator) }; | |
| 460 | output.init(testing.allocator); | |
| 461 | var wrt: Writer = .{ .underlying_writer = &output.buffered_writer }; | |
| 460 | 462 | defer output.deinit(); |
| 461 | 463 | for (files) |file| { |
| 462 | 464 | var content = std.io.fixedBufferStream(file.content); |
lib/std/zon/parse.zig+14-12| ... | ... | @@ -638,10 +638,12 @@ const Parser = struct { |
| 638 | 638 | const pointer = @typeInfo(T).pointer; |
| 639 | 639 | var size_hint = ZonGen.strLitSizeHint(self.ast, ast_node); |
| 640 | 640 | if (pointer.sentinel() != null) size_hint += 1; |
| 641 | const gpa = self.gpa; | |
| 641 | 642 | |
| 642 | var buf: std.ArrayListUnmanaged(u8) = try .initCapacity(self.gpa, size_hint); | |
| 643 | defer buf.deinit(self.gpa); | |
| 644 | switch (try ZonGen.parseStrLit(self.ast, ast_node, buf.writer(self.gpa))) { | |
| 643 | var aw: std.io.AllocatingWriter = undefined; | |
| 644 | try aw.initCapacity(gpa, size_hint); | |
| 645 | defer aw.deinit(); | |
| 646 | switch (try ZonGen.parseStrLit(self.ast, ast_node, &aw.buffered_writer)) { | |
| 645 | 647 | .success => {}, |
| 646 | 648 | .failure => |err| { |
| 647 | 649 | const token = self.ast.nodeMainToken(ast_node); |
| ... | ... | @@ -660,9 +662,9 @@ const Parser = struct { |
| 660 | 662 | } |
| 661 | 663 | |
| 662 | 664 | if (pointer.sentinel() != null) { |
| 663 | return buf.toOwnedSliceSentinel(self.gpa, 0); | |
| 665 | return aw.toOwnedSliceSentinel(gpa, 0); | |
| 664 | 666 | } else { |
| 665 | return buf.toOwnedSlice(self.gpa); | |
| 667 | return aw.toOwnedSlice(gpa); | |
| 666 | 668 | } |
| 667 | 669 | } |
| 668 | 670 | |
| ... | ... | @@ -1064,6 +1066,7 @@ const Parser = struct { |
| 1064 | 1066 | name: []const u8, |
| 1065 | 1067 | ) error{ OutOfMemory, ParseZon } { |
| 1066 | 1068 | @branchHint(.cold); |
| 1069 | const gpa = self.gpa; | |
| 1067 | 1070 | const token = if (field) |f| b: { |
| 1068 | 1071 | var buf: [2]Ast.Node.Index = undefined; |
| 1069 | 1072 | const struct_init = self.ast.fullStructInit(&buf, node.getAstNode(self.zoir)).?; |
| ... | ... | @@ -1081,18 +1084,17 @@ const Parser = struct { |
| 1081 | 1084 | }; |
| 1082 | 1085 | } else b: { |
| 1083 | 1086 | const msg = "supported: "; |
| 1084 | var buf: std.ArrayListUnmanaged(u8) = try .initCapacity(self.gpa, 64); | |
| 1085 | defer buf.deinit(self.gpa); | |
| 1086 | const writer = buf.writer(self.gpa); | |
| 1087 | try writer.writeAll(msg); | |
| 1087 | var buf: std.ArrayListUnmanaged(u8) = try .initCapacity(gpa, 64); | |
| 1088 | defer buf.deinit(gpa); | |
| 1089 | try buf.appendSlice(gpa, msg); | |
| 1088 | 1090 | inline for (info.fields, 0..) |field_info, i| { |
| 1089 | if (i != 0) try writer.writeAll(", "); | |
| 1090 | try writer.print("'{p_}'", .{std.zig.fmtId(field_info.name)}); | |
| 1091 | if (i != 0) try buf.appendSlice(gpa, ", "); | |
| 1092 | try buf.print(gpa, "'{p_}'", .{std.zig.fmtId(field_info.name)}); | |
| 1091 | 1093 | } |
| 1092 | 1094 | break :b .{ |
| 1093 | 1095 | .token = token, |
| 1094 | 1096 | .offset = 0, |
| 1095 | .msg = try buf.toOwnedSlice(self.gpa), | |
| 1097 | .msg = try buf.toOwnedSlice(gpa), | |
| 1096 | 1098 | .owned = true, |
| 1097 | 1099 | }; |
| 1098 | 1100 | }; |