authorgravatar for scorphus@gmail.comPablo Santiago Blum de Aguiar <scorphus@gmail.com> 2022-01-09 17:12:55+01:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-01-24 17:44:26+02:00
log5ba4385971108761ec26830b4afa9aae3eab37f8
tree1e932556b65f8cd20ee3c2d0484c01031f2055a2
parent2fc2d88fc659f456e21d40a11e1d7bdcfa243f53

readUntilDelimiter*: read only if buffer not full

Ref.: #9594

1 files changed, 284 insertions(+), 10 deletions(-)

lib/std/io/reader.zig+284-10
...@@ -107,16 +107,16 @@ pub fn Reader(...@@ -107,16 +107,16 @@ pub fn Reader(
107 ) !void {107 ) !void {
108 array_list.shrinkRetainingCapacity(0);108 array_list.shrinkRetainingCapacity(0);
109 while (true) {109 while (true) {
110 if (array_list.items.len == max_size) {
111 return error.StreamTooLong;
112 }
113
110 var byte: u8 = try self.readByte();114 var byte: u8 = try self.readByte();
111115
112 if (byte == delimiter) {116 if (byte == delimiter) {
113 return;117 return;
114 }118 }
115119
116 if (array_list.items.len == max_size) {
117 return error.StreamTooLong;
118 }
119
120 try array_list.append(byte);120 try array_list.append(byte);
121 }121 }
122 }122 }
...@@ -139,17 +139,20 @@ pub fn Reader(...@@ -139,17 +139,20 @@ pub fn Reader(
139139
140 /// Reads from the stream until specified byte is found. If the buffer is not140 /// Reads from the stream until specified byte is found. If the buffer is not
141 /// large enough to hold the entire contents, `error.StreamTooLong` is returned.141 /// large enough to hold the entire contents, `error.StreamTooLong` is returned.
142 /// If end-of-stream is found, `error.EndOfStream` is returned.
142 /// Returns a slice of the stream data, with ptr equal to `buf.ptr`. The143 /// Returns a slice of the stream data, with ptr equal to `buf.ptr`. The
143 /// delimiter byte is not included in the returned slice.144 /// delimiter byte is written to the output buffer but is not included
145 /// in the returned slice.
144 pub fn readUntilDelimiter(self: Self, buf: []u8, delimiter: u8) ![]u8 {146 pub fn readUntilDelimiter(self: Self, buf: []u8, delimiter: u8) ![]u8 {
145 var index: usize = 0;147 var index: usize = 0;
146 while (true) {148 while (true) {
149 if (index >= buf.len) return error.StreamTooLong;
150
147 const byte = try self.readByte();151 const byte = try self.readByte();
152 buf[index] = byte;
148153
149 if (byte == delimiter) return buf[0..index];154 if (byte == delimiter) return buf[0..index];
150 if (index >= buf.len) return error.StreamTooLong;
151155
152 buf[index] = byte;
153 index += 1;156 index += 1;
154 }157 }
155 }158 }
...@@ -185,10 +188,13 @@ pub fn Reader(...@@ -185,10 +188,13 @@ pub fn Reader(
185 /// If end-of-stream is found, returns the rest of the stream. If this188 /// If end-of-stream is found, returns the rest of the stream. If this
186 /// function is called again after that, returns null.189 /// function is called again after that, returns null.
187 /// Returns a slice of the stream data, with ptr equal to `buf.ptr`. The190 /// Returns a slice of the stream data, with ptr equal to `buf.ptr`. The
188 /// delimiter byte is not included in the returned slice.191 /// delimiter byte is written to the output buffer but is not included
192 /// in the returned slice.
189 pub fn readUntilDelimiterOrEof(self: Self, buf: []u8, delimiter: u8) !?[]u8 {193 pub fn readUntilDelimiterOrEof(self: Self, buf: []u8, delimiter: u8) !?[]u8 {
190 var index: usize = 0;194 var index: usize = 0;
191 while (true) {195 while (true) {
196 if (index >= buf.len) return error.StreamTooLong;
197
192 const byte = self.readByte() catch |err| switch (err) {198 const byte = self.readByte() catch |err| switch (err) {
193 error.EndOfStream => {199 error.EndOfStream => {
194 if (index == 0) {200 if (index == 0) {
...@@ -199,11 +205,10 @@ pub fn Reader(...@@ -199,11 +205,10 @@ pub fn Reader(
199 },205 },
200 else => |e| return e,206 else => |e| return e,
201 };207 };
208 buf[index] = byte;
202209
203 if (byte == delimiter) return buf[0..index];210 if (byte == delimiter) return buf[0..index];
204 if (index >= buf.len) return error.StreamTooLong;
205211
206 buf[index] = byte;
207 index += 1;212 index += 1;
208 }213 }
209 }214 }
...@@ -363,3 +368,272 @@ test "Reader.skipBytes" {...@@ -363,3 +368,272 @@ test "Reader.skipBytes" {
363 try reader.skipBytes(0, .{});368 try reader.skipBytes(0, .{});
364 try testing.expectError(error.EndOfStream, reader.skipBytes(1, .{}));369 try testing.expectError(error.EndOfStream, reader.skipBytes(1, .{}));
365}370}
371
372test "Reader.readUntilDelimiterArrayList returns ArrayLists with bytes read until the delimiter, then EndOfStream" {
373 const a = std.testing.allocator;
374 var list = std.ArrayList(u8).init(a);
375 defer list.deinit();
376
377 const reader = std.io.fixedBufferStream("0000\n1234\n").reader();
378
379 try reader.readUntilDelimiterArrayList(&list, '\n', 5);
380 try std.testing.expectEqualStrings("0000", list.items);
381 try reader.readUntilDelimiterArrayList(&list, '\n', 5);
382 try std.testing.expectEqualStrings("1234", list.items);
383 try std.testing.expectError(error.EndOfStream, reader.readUntilDelimiterArrayList(&list, '\n', 5));
384}
385
386test "Reader.readUntilDelimiterArrayList returns an empty ArrayList" {
387 const a = std.testing.allocator;
388 var list = std.ArrayList(u8).init(a);
389 defer list.deinit();
390
391 const reader = std.io.fixedBufferStream("\n").reader();
392
393 try reader.readUntilDelimiterArrayList(&list, '\n', 5);
394 try std.testing.expectEqualStrings("", list.items);
395}
396
397test "Reader.readUntilDelimiterArrayList returns StreamTooLong, then an ArrayList with bytes read until the delimiter" {
398 const a = std.testing.allocator;
399 var list = std.ArrayList(u8).init(a);
400 defer list.deinit();
401
402 const reader = std.io.fixedBufferStream("1234567\n").reader();
403
404 try std.testing.expectError(error.StreamTooLong, reader.readUntilDelimiterArrayList(&list, '\n', 5));
405 try std.testing.expectEqualStrings("12345", list.items);
406 try reader.readUntilDelimiterArrayList(&list, '\n', 5);
407 try std.testing.expectEqualStrings("67", list.items);
408}
409
410test "Reader.readUntilDelimiterArrayList returns EndOfStream" {
411 const a = std.testing.allocator;
412 var list = std.ArrayList(u8).init(a);
413 defer list.deinit();
414
415 const reader = std.io.fixedBufferStream("1234").reader();
416
417 try std.testing.expectError(error.EndOfStream, reader.readUntilDelimiterArrayList(&list, '\n', 5));
418 try std.testing.expectEqualStrings("1234", list.items);
419}
420
421test "Reader.readUntilDelimiterAlloc returns ArrayLists with bytes read until the delimiter, then EndOfStream" {
422 const a = std.testing.allocator;
423
424 const reader = std.io.fixedBufferStream("0000\n1234\n").reader();
425
426 {
427 var result = try reader.readUntilDelimiterAlloc(a, '\n', 5);
428 defer a.free(result);
429 try std.testing.expectEqualStrings("0000", result);
430 }
431
432 {
433 var result = try reader.readUntilDelimiterAlloc(a, '\n', 5);
434 defer a.free(result);
435 try std.testing.expectEqualStrings("1234", result);
436 }
437
438 try std.testing.expectError(error.EndOfStream, reader.readUntilDelimiterAlloc(a, '\n', 5));
439}
440
441test "Reader.readUntilDelimiterAlloc returns an empty ArrayList" {
442 const a = std.testing.allocator;
443
444 const reader = std.io.fixedBufferStream("\n").reader();
445
446 {
447 var result = try reader.readUntilDelimiterAlloc(a, '\n', 5);
448 defer a.free(result);
449 try std.testing.expectEqualStrings("", result);
450 }
451}
452
453test "Reader.readUntilDelimiterAlloc returns StreamTooLong, then an ArrayList with bytes read until the delimiter" {
454 const a = std.testing.allocator;
455
456 const reader = std.io.fixedBufferStream("1234567\n").reader();
457
458 try std.testing.expectError(error.StreamTooLong, reader.readUntilDelimiterAlloc(a, '\n', 5));
459
460 var result = try reader.readUntilDelimiterAlloc(a, '\n', 5);
461 defer a.free(result);
462 try std.testing.expectEqualStrings("67", result);
463}
464
465test "Reader.readUntilDelimiterAlloc returns EndOfStream" {
466 const a = std.testing.allocator;
467
468 const reader = std.io.fixedBufferStream("1234").reader();
469
470 try std.testing.expectError(error.EndOfStream, reader.readUntilDelimiterAlloc(a, '\n', 5));
471}
472
473test "Reader.readUntilDelimiter returns bytes read until the delimiter" {
474 var buf: [5]u8 = undefined;
475 const reader = std.io.fixedBufferStream("0000\n1234\n").reader();
476 try std.testing.expectEqualStrings("0000", try reader.readUntilDelimiter(&buf, '\n'));
477 try std.testing.expectEqualStrings("1234", try reader.readUntilDelimiter(&buf, '\n'));
478}
479
480test "Reader.readUntilDelimiter returns an empty string" {
481 var buf: [5]u8 = undefined;
482 const reader = std.io.fixedBufferStream("\n").reader();
483 try std.testing.expectEqualStrings("", try reader.readUntilDelimiter(&buf, '\n'));
484}
485
486test "Reader.readUntilDelimiter returns StreamTooLong, then an empty string" {
487 var buf: [5]u8 = undefined;
488 const reader = std.io.fixedBufferStream("12345\n").reader();
489 try std.testing.expectError(error.StreamTooLong, reader.readUntilDelimiter(&buf, '\n'));
490 try std.testing.expectEqualStrings("", try reader.readUntilDelimiter(&buf, '\n'));
491}
492
493test "Reader.readUntilDelimiter returns StreamTooLong, then bytes read until the delimiter" {
494 var buf: [5]u8 = undefined;
495 const reader = std.io.fixedBufferStream("1234567\n").reader();
496 try std.testing.expectError(error.StreamTooLong, reader.readUntilDelimiter(&buf, '\n'));
497 try std.testing.expectEqualStrings("67", try reader.readUntilDelimiter(&buf, '\n'));
498}
499
500test "Reader.readUntilDelimiter returns EndOfStream" {
501 var buf: [5]u8 = undefined;
502 const reader = std.io.fixedBufferStream("").reader();
503 try std.testing.expectError(error.EndOfStream, reader.readUntilDelimiter(&buf, '\n'));
504}
505
506test "Reader.readUntilDelimiter returns bytes read until delimiter, then EndOfStream" {
507 var buf: [5]u8 = undefined;
508 const reader = std.io.fixedBufferStream("1234\n").reader();
509 try std.testing.expectEqualStrings("1234", try reader.readUntilDelimiter(&buf, '\n'));
510 try std.testing.expectError(error.EndOfStream, reader.readUntilDelimiter(&buf, '\n'));
511}
512
513test "Reader.readUntilDelimiter returns EndOfStream" {
514 var buf: [5]u8 = undefined;
515 const reader = std.io.fixedBufferStream("1234").reader();
516 try std.testing.expectError(error.EndOfStream, reader.readUntilDelimiter(&buf, '\n'));
517}
518
519test "Reader.readUntilDelimiter returns StreamTooLong, then EndOfStream" {
520 var buf: [5]u8 = undefined;
521 const reader = std.io.fixedBufferStream("12345").reader();
522 try std.testing.expectError(error.StreamTooLong, reader.readUntilDelimiter(&buf, '\n'));
523 try std.testing.expectError(error.EndOfStream, reader.readUntilDelimiter(&buf, '\n'));
524}
525
526test "Reader.readUntilDelimiter writes all bytes read to the output buffer" {
527 var buf: [5]u8 = undefined;
528 const reader = std.io.fixedBufferStream("0000\n12345").reader();
529 _ = try reader.readUntilDelimiter(&buf, '\n');
530 try std.testing.expectEqualStrings("0000\n", &buf);
531 try std.testing.expectError(error.StreamTooLong, reader.readUntilDelimiter(&buf, '\n'));
532 try std.testing.expectEqualStrings("12345", &buf);
533}
534
535test "Reader.readUntilDelimiterOrEofAlloc returns ArrayLists with bytes read until the delimiter, then EndOfStream" {
536 const a = std.testing.allocator;
537
538 const reader = std.io.fixedBufferStream("0000\n1234\n").reader();
539
540 {
541 var result = (try reader.readUntilDelimiterOrEofAlloc(a, '\n', 5)).?;
542 defer a.free(result);
543 try std.testing.expectEqualStrings("0000", result);
544 }
545
546 {
547 var result = (try reader.readUntilDelimiterOrEofAlloc(a, '\n', 5)).?;
548 defer a.free(result);
549 try std.testing.expectEqualStrings("1234", result);
550 }
551
552 try std.testing.expect((try reader.readUntilDelimiterOrEofAlloc(a, '\n', 5)) == null);
553}
554
555test "Reader.readUntilDelimiterOrEofAlloc returns an empty ArrayList" {
556 const a = std.testing.allocator;
557
558 const reader = std.io.fixedBufferStream("\n").reader();
559
560 {
561 var result = (try reader.readUntilDelimiterOrEofAlloc(a, '\n', 5)).?;
562 defer a.free(result);
563 try std.testing.expectEqualStrings("", result);
564 }
565}
566
567test "Reader.readUntilDelimiterOrEofAlloc returns StreamTooLong, then an ArrayList with bytes read until the delimiter" {
568 const a = std.testing.allocator;
569
570 const reader = std.io.fixedBufferStream("1234567\n").reader();
571
572 try std.testing.expectError(error.StreamTooLong, reader.readUntilDelimiterOrEofAlloc(a, '\n', 5));
573
574 var result = (try reader.readUntilDelimiterOrEofAlloc(a, '\n', 5)).?;
575 defer a.free(result);
576 try std.testing.expectEqualStrings("67", result);
577}
578
579test "Reader.readUntilDelimiterOrEof returns bytes read until the delimiter" {
580 var buf: [5]u8 = undefined;
581 const reader = std.io.fixedBufferStream("0000\n1234\n").reader();
582 try std.testing.expectEqualStrings("0000", (try reader.readUntilDelimiterOrEof(&buf, '\n')).?);
583 try std.testing.expectEqualStrings("1234", (try reader.readUntilDelimiterOrEof(&buf, '\n')).?);
584}
585
586test "Reader.readUntilDelimiterOrEof returns an empty string" {
587 var buf: [5]u8 = undefined;
588 const reader = std.io.fixedBufferStream("\n").reader();
589 try std.testing.expectEqualStrings("", (try reader.readUntilDelimiterOrEof(&buf, '\n')).?);
590}
591
592test "Reader.readUntilDelimiterOrEof returns StreamTooLong, then an empty string" {
593 var buf: [5]u8 = undefined;
594 const reader = std.io.fixedBufferStream("12345\n").reader();
595 try std.testing.expectError(error.StreamTooLong, reader.readUntilDelimiterOrEof(&buf, '\n'));
596 try std.testing.expectEqualStrings("", (try reader.readUntilDelimiterOrEof(&buf, '\n')).?);
597}
598
599test "Reader.readUntilDelimiterOrEof returns StreamTooLong, then bytes read until the delimiter" {
600 var buf: [5]u8 = undefined;
601 const reader = std.io.fixedBufferStream("1234567\n").reader();
602 try std.testing.expectError(error.StreamTooLong, reader.readUntilDelimiterOrEof(&buf, '\n'));
603 try std.testing.expectEqualStrings("67", (try reader.readUntilDelimiterOrEof(&buf, '\n')).?);
604}
605
606test "Reader.readUntilDelimiterOrEof returns null" {
607 var buf: [5]u8 = undefined;
608 const reader = std.io.fixedBufferStream("").reader();
609 try std.testing.expect((try reader.readUntilDelimiterOrEof(&buf, '\n')) == null);
610}
611
612test "Reader.readUntilDelimiterOrEof returns bytes read until delimiter, then null" {
613 var buf: [5]u8 = undefined;
614 const reader = std.io.fixedBufferStream("1234\n").reader();
615 try std.testing.expectEqualStrings("1234", (try reader.readUntilDelimiterOrEof(&buf, '\n')).?);
616 try std.testing.expect((try reader.readUntilDelimiterOrEof(&buf, '\n')) == null);
617}
618
619test "Reader.readUntilDelimiterOrEof returns bytes read until end-of-stream" {
620 var buf: [5]u8 = undefined;
621 const reader = std.io.fixedBufferStream("1234").reader();
622 try std.testing.expectEqualStrings("1234", (try reader.readUntilDelimiterOrEof(&buf, '\n')).?);
623}
624
625test "Reader.readUntilDelimiterOrEof returns StreamTooLong, then bytes read until end-of-stream" {
626 var buf: [5]u8 = undefined;
627 const reader = std.io.fixedBufferStream("1234567").reader();
628 try std.testing.expectError(error.StreamTooLong, reader.readUntilDelimiterOrEof(&buf, '\n'));
629 try std.testing.expectEqualStrings("67", (try reader.readUntilDelimiterOrEof(&buf, '\n')).?);
630}
631
632test "Reader.readUntilDelimiterOrEof writes all bytes read to the output buffer" {
633 var buf: [5]u8 = undefined;
634 const reader = std.io.fixedBufferStream("0000\n12345").reader();
635 _ = try reader.readUntilDelimiterOrEof(&buf, '\n');
636 try std.testing.expectEqualStrings("0000\n", &buf);
637 try std.testing.expectError(error.StreamTooLong, reader.readUntilDelimiterOrEof(&buf, '\n'));
638 try std.testing.expectEqualStrings("12345", &buf);
639}