| ... | ... | @@ -246,18 +246,41 @@ pub fn appendRemaining( |
| 246 | 246 | limit: Limit, |
| 247 | 247 | ) LimitedAllocError!void { |
| 248 | 248 | assert(r.buffer.len != 0); // Needed to detect limit exceeded without losing data. |
| 249 | | var remaining = limit; |
| 250 | | while (remaining.nonzero()) { |
| 251 | | try list.ensureUnusedCapacity(gpa, r.bufferedLen() + 1); |
| 252 | | const dest = remaining.slice(list.unusedCapacitySlice()); |
| 253 | | const n = readVecLimit(r, &.{dest}, .unlimited) catch |err| switch (err) { |
| 254 | | error.EndOfStream => break, |
| 255 | | error.ReadFailed => return error.ReadFailed, |
| 256 | | }; |
| 257 | | list.items.len += n; |
| 258 | | remaining = remaining.subtract(n).?; |
| 249 | const buffer_contents = r.buffer[r.seek..r.end]; |
| 250 | const copy_len = limit.minInt(buffer_contents.len); |
| 251 | try list.appendSlice(gpa, r.buffer[0..copy_len]); |
| 252 | r.seek += copy_len; |
| 253 | if (buffer_contents.len - copy_len != 0) return error.StreamTooLong; |
| 254 | r.seek = 0; |
| 255 | r.end = 0; |
| 256 | var remaining = @intFromEnum(limit) - copy_len; |
| 257 | while (true) { |
| 258 | try list.ensureUnusedCapacity(gpa, 1); |
| 259 | const cap = list.unusedCapacitySlice(); |
| 260 | const dest = cap[0..@min(cap.len, remaining)]; |
| 261 | if (remaining - dest.len == 0) { |
| 262 | // Additionally provides `buffer` to detect end. |
| 263 | const new_remaining = readVecInner(r, &.{}, dest, remaining) catch |err| switch (err) { |
| 264 | error.EndOfStream => { |
| 265 | if (r.bufferedLen() != 0) return error.StreamTooLong; |
| 266 | return; |
| 267 | }, |
| 268 | error.ReadFailed => return error.ReadFailed, |
| 269 | }; |
| 270 | list.items.len += remaining - new_remaining; |
| 271 | remaining = new_remaining; |
| 272 | } else { |
| 273 | // Leave `buffer` empty, appending directly to `list`. |
| 274 | var dest_w: Writer = .fixed(dest); |
| 275 | const n = r.vtable.stream(r, &dest_w, .limited(dest.len)) catch |err| switch (err) { |
| 276 | error.WriteFailed => unreachable, // Prevented by the limit. |
| 277 | error.EndOfStream => return, |
| 278 | error.ReadFailed => return error.ReadFailed, |
| 279 | }; |
| 280 | list.items.len += n; |
| 281 | remaining -= n; |
| 282 | } |
| 259 | 283 | } |
| 260 | | if (r.bufferedLen() != 0) return error.StreamTooLong; |
| 261 | 284 | } |
| 262 | 285 | |
| 263 | 286 | /// Writes bytes from the internally tracked stream position to `data`. |
| ... | ... | @@ -297,60 +320,66 @@ pub fn readVecLimit(r: *Reader, data: []const []u8, limit: Limit) Error!usize { |
| 297 | 320 | // buffer capacity requirements met. |
| 298 | 321 | r.seek = 0; |
| 299 | 322 | r.end = 0; |
| 300 | | const first = buf[copy_len..]; |
| 301 | | const middle = data[i + 1 ..]; |
| 302 | | var wrapper: Writer.VectorWrapper = .{ |
| 303 | | .it = .{ |
| 304 | | .first = first, |
| 305 | | .middle = middle, |
| 306 | | .last = r.buffer, |
| 307 | | }, |
| 308 | | .writer = .{ |
| 309 | | .buffer = if (first.len >= r.buffer.len) first else r.buffer, |
| 310 | | .vtable = Writer.VectorWrapper.vtable, |
| 311 | | }, |
| 312 | | }; |
| 313 | | var n = r.vtable.stream(r, &wrapper.writer, .limited(remaining)) catch |err| switch (err) { |
| 314 | | error.WriteFailed => { |
| 315 | | assert(!wrapper.used); |
| 316 | | if (wrapper.writer.buffer.ptr == first.ptr) { |
| 317 | | remaining -= wrapper.writer.end; |
| 318 | | } else { |
| 319 | | assert(wrapper.writer.end <= r.buffer.len); |
| 320 | | r.end = wrapper.writer.end; |
| 321 | | } |
| 322 | | break; |
| 323 | | }, |
| 324 | | else => |e| return e, |
| 325 | | }; |
| 326 | | if (!wrapper.used) { |
| 323 | remaining = try readVecInner(r, data[i + 1 ..], buf[copy_len..], remaining); |
| 324 | break; |
| 325 | } |
| 326 | return @intFromEnum(limit) - remaining; |
| 327 | } |
| 328 | |
| 329 | fn readVecInner(r: *Reader, middle: []const []u8, first: []u8, remaining: usize) Error!usize { |
| 330 | var wrapper: Writer.VectorWrapper = .{ |
| 331 | .it = .{ |
| 332 | .first = first, |
| 333 | .middle = middle, |
| 334 | .last = r.buffer, |
| 335 | }, |
| 336 | .writer = .{ |
| 337 | .buffer = if (first.len >= r.buffer.len) first else r.buffer, |
| 338 | .vtable = Writer.VectorWrapper.vtable, |
| 339 | }, |
| 340 | }; |
| 341 | // If the limit may pass beyond user buffer into Reader buffer, use |
| 342 | // unlimited, allowing the Reader buffer to fill. |
| 343 | const limit: Limit = l: { |
| 344 | var n: usize = first.len; |
| 345 | for (middle) |m| n += m.len; |
| 346 | break :l if (remaining >= n) .unlimited else .limited(remaining); |
| 347 | }; |
| 348 | var n = r.vtable.stream(r, &wrapper.writer, limit) catch |err| switch (err) { |
| 349 | error.WriteFailed => { |
| 350 | assert(!wrapper.used); |
| 327 | 351 | if (wrapper.writer.buffer.ptr == first.ptr) { |
| 328 | | remaining -= n; |
| 352 | return remaining - wrapper.writer.end; |
| 329 | 353 | } else { |
| 330 | | assert(n <= r.buffer.len); |
| 331 | | r.end = n; |
| 354 | assert(wrapper.writer.end <= r.buffer.len); |
| 355 | r.end = wrapper.writer.end; |
| 356 | return remaining; |
| 332 | 357 | } |
| 333 | | break; |
| 334 | | } |
| 335 | | if (n < first.len) { |
| 336 | | remaining -= n; |
| 337 | | break; |
| 358 | }, |
| 359 | else => |e| return e, |
| 360 | }; |
| 361 | if (!wrapper.used) { |
| 362 | if (wrapper.writer.buffer.ptr == first.ptr) { |
| 363 | return remaining - n; |
| 364 | } else { |
| 365 | assert(n <= r.buffer.len); |
| 366 | r.end = n; |
| 367 | return remaining; |
| 338 | 368 | } |
| 339 | | remaining -= first.len; |
| 340 | | n -= first.len; |
| 341 | | for (middle) |mid| { |
| 342 | | if (n < mid.len) { |
| 343 | | remaining -= n; |
| 344 | | break; |
| 345 | | } |
| 346 | | remaining -= mid.len; |
| 347 | | n -= mid.len; |
| 369 | } |
| 370 | if (n < first.len) return remaining - n; |
| 371 | var result = remaining - first.len; |
| 372 | n -= first.len; |
| 373 | for (middle) |mid| { |
| 374 | if (n < mid.len) { |
| 375 | return result - n; |
| 348 | 376 | } |
| 349 | | assert(n <= r.buffer.len); |
| 350 | | r.end = n; |
| 351 | | break; |
| 377 | result -= mid.len; |
| 378 | n -= mid.len; |
| 352 | 379 | } |
| 353 | | return @intFromEnum(limit) - remaining; |
| 380 | assert(n <= r.buffer.len); |
| 381 | r.end = n; |
| 382 | return result; |
| 354 | 383 | } |
| 355 | 384 | |
| 356 | 385 | pub fn buffered(r: *Reader) []u8 { |