@@ -481,7 +481,6 @@ pub fn readVecAll(r: *Reader, data: [][]u8) Error!void {
481
481
/// is returned instead.
482
482
///
483
483
/// See also:
484
- /// * `peek`
485
484
/// * `toss`
486
485
pub fn peek (r : * Reader , n : usize ) Error ! []u8 {
487
486
try r .fill (n );
@@ -732,7 +731,7 @@ pub const DelimiterError = error{
732
731
};
733
732
734
733
/// Returns a slice of the next bytes of buffered data from the stream until
735
- /// `sentinel` is found, advancing the seek position.
734
+ /// `sentinel` is found, advancing the seek position past the sentinel .
736
735
///
737
736
/// Returned slice has a sentinel.
738
737
///
@@ -765,7 +764,7 @@ pub fn peekSentinel(r: *Reader, comptime sentinel: u8) DelimiterError![:sentinel
765
764
}
766
765
767
766
/// Returns a slice of the next bytes of buffered data from the stream until
768
- /// `delimiter` is found, advancing the seek position.
767
+ /// `delimiter` is found, advancing the seek position past the delimiter .
769
768
///
770
769
/// Returned slice includes the delimiter as the last byte.
771
770
///
@@ -793,32 +792,42 @@ pub fn takeDelimiterInclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 {
793
792
/// * `peekDelimiterExclusive`
794
793
/// * `takeDelimiterInclusive`
795
794
pub fn peekDelimiterInclusive (r : * Reader , delimiter : u8 ) DelimiterError ! []u8 {
796
- const buffer = r .buffer [0.. r .end ];
797
- const seek = r .seek ;
798
- if (std .mem .indexOfScalarPos (u8 , buffer , seek , delimiter )) | delimiter_index | {
799
- @branchHint (.likely );
800
- return buffer [seek .. delimiter_index + 1 ];
795
+ {
796
+ const contents = r .buffer [0.. r .end ];
797
+ const seek = r .seek ;
798
+ if (std .mem .findScalarPos (u8 , contents , seek , delimiter )) | end | {
799
+ @branchHint (.likely );
800
+ return contents [seek .. end + 1 ];
801
+ }
801
802
}
802
- // TODO take a parameter for max search length rather than relying on buffer capacity
803
- try rebase (r , r .buffer .len );
804
- while (r .buffer .len - r .end != 0 ) {
805
- const existing_buffered_len = r .end - r .seek ;
806
- const end_cap = r .buffer [r .end .. ];
807
- var writer : Writer = .fixed (end_cap );
808
- const n = r .vtable .stream (r , & writer , .limited (end_cap .len )) catch | err | switch (err ) {
809
- error .WriteFailed = > unreachable ,
810
- else = > | e | return e ,
811
- };
812
- r .end += n ;
813
- if (std .mem .indexOfScalarPos (u8 , r .buffer [0.. r .end ], r .seek + existing_buffered_len , delimiter )) | delimiter_index | {
814
- return r .buffer [r .seek .. delimiter_index + 1 ];
803
+ while (true ) {
804
+ const content_len = r .end - r .seek ;
805
+ if (r .buffer .len - content_len == 0 ) break ;
806
+ try fillMore (r );
807
+ const seek = r .seek ;
808
+ const contents = r .buffer [0.. r .end ];
809
+ if (std .mem .findScalarPos (u8 , contents , seek + content_len , delimiter )) | end | {
810
+ return contents [seek .. end + 1 ];
815
811
}
816
812
}
817
- return error .StreamTooLong ;
813
+ // It might or might not be end of stream. There is no more buffer space
814
+ // left to disambiguate. If `StreamTooLong` was added to `RebaseError` then
815
+ // this logic could be replaced by removing the exit condition from the
816
+ // above while loop. That error code would represent when `buffer` capacity
817
+ // is too small for an operation, replacing the current use of asserts.
818
+ var failing_writer = Writer .failing ;
819
+ while (r .vtable .stream (r , & failing_writer , .limited (1 ))) | n | {
820
+ assert (n == 0 );
821
+ } else | err | switch (err ) {
822
+ error .WriteFailed = > return error .StreamTooLong ,
823
+ error .ReadFailed = > | e | return e ,
824
+ error .EndOfStream = > | e | return e ,
825
+ }
818
826
}
819
827
820
828
/// Returns a slice of the next bytes of buffered data from the stream until
821
- /// `delimiter` is found, advancing the seek position up to the delimiter.
829
+ /// `delimiter` is found, advancing the seek position up to (but not past)
830
+ /// the delimiter.
822
831
///
823
832
/// Returned slice excludes the delimiter. End-of-stream is treated equivalent
824
833
/// to a delimiter, unless it would result in a length 0 return value, in which
@@ -832,20 +841,13 @@ pub fn peekDelimiterInclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 {
832
841
/// Invalidates previously returned values from `peek`.
833
842
///
834
843
/// See also:
844
+ /// * `takeDelimiter`
835
845
/// * `takeDelimiterInclusive`
836
846
/// * `peekDelimiterExclusive`
837
847
pub fn takeDelimiterExclusive (r : * Reader , delimiter : u8 ) DelimiterError ! []u8 {
838
- const result = r .peekDelimiterInclusive (delimiter ) catch | err | switch (err ) {
839
- error .EndOfStream = > {
840
- const remaining = r .buffer [r .seek .. r .end ];
841
- if (remaining .len == 0 ) return error .EndOfStream ;
842
- r .toss (remaining .len );
843
- return remaining ;
844
- },
845
- else = > | e | return e ,
846
- };
848
+ const result = try r .peekDelimiterExclusive (delimiter );
847
849
r .toss (result .len );
848
- return result [ 0 .. result . len - 1 ] ;
850
+ return result ;
849
851
}
850
852
851
853
/// Returns a slice of the next bytes of buffered data from the stream until
@@ -866,7 +868,7 @@ pub fn takeDelimiterExclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 {
866
868
/// * `takeDelimiterInclusive`
867
869
/// * `takeDelimiterExclusive`
868
870
pub fn takeDelimiter (r : * Reader , delimiter : u8 ) error { ReadFailed , StreamTooLong }! ? []u8 {
869
- const result = r .peekDelimiterInclusive (delimiter ) catch | err | switch (err ) {
871
+ const inclusive = r .peekDelimiterInclusive (delimiter ) catch | err | switch (err ) {
870
872
error .EndOfStream = > {
871
873
const remaining = r .buffer [r .seek .. r .end ];
872
874
if (remaining .len == 0 ) return null ;
@@ -875,8 +877,8 @@ pub fn takeDelimiter(r: *Reader, delimiter: u8) error{ ReadFailed, StreamTooLong
875
877
},
876
878
else = > | e | return e ,
877
879
};
878
- r .toss (result .len + 1 );
879
- return result [0 .. result .len - 1 ];
880
+ r .toss (inclusive .len );
881
+ return inclusive [0 .. inclusive .len - 1 ];
880
882
}
881
883
882
884
/// Returns a slice of the next bytes of buffered data from the stream until
@@ -1403,6 +1405,9 @@ test peekSentinel {
1403
1405
var r : Reader = .fixed ("ab\n c" );
1404
1406
try testing .expectEqualStrings ("ab" , try r .peekSentinel ('\n ' ));
1405
1407
try testing .expectEqualStrings ("ab" , try r .peekSentinel ('\n ' ));
1408
+ r .toss (3 );
1409
+ try testing .expectError (error .EndOfStream , r .peekSentinel ('\n ' ));
1410
+ try testing .expectEqualStrings ("c" , try r .peek (1 ));
1406
1411
}
1407
1412
1408
1413
test takeDelimiterInclusive {
@@ -1417,22 +1422,52 @@ test peekDelimiterInclusive {
1417
1422
try testing .expectEqualStrings ("ab\n " , try r .peekDelimiterInclusive ('\n ' ));
1418
1423
r .toss (3 );
1419
1424
try testing .expectError (error .EndOfStream , r .peekDelimiterInclusive ('\n ' ));
1425
+ try testing .expectEqualStrings ("c" , try r .peek (1 ));
1420
1426
}
1421
1427
1422
1428
test takeDelimiterExclusive {
1423
1429
var r : Reader = .fixed ("ab\n c" );
1430
+
1424
1431
try testing .expectEqualStrings ("ab" , try r .takeDelimiterExclusive ('\n ' ));
1432
+ try testing .expectEqualStrings ("" , try r .takeDelimiterExclusive ('\n ' ));
1433
+ try testing .expectEqualStrings ("" , try r .takeDelimiterExclusive ('\n ' ));
1434
+ try testing .expectEqualStrings ("\n " , try r .take (1 ));
1435
+
1425
1436
try testing .expectEqualStrings ("c" , try r .takeDelimiterExclusive ('\n ' ));
1426
1437
try testing .expectError (error .EndOfStream , r .takeDelimiterExclusive ('\n ' ));
1427
1438
}
1428
1439
1429
1440
test peekDelimiterExclusive {
1430
1441
var r : Reader = .fixed ("ab\n c" );
1442
+
1431
1443
try testing .expectEqualStrings ("ab" , try r .peekDelimiterExclusive ('\n ' ));
1432
1444
try testing .expectEqualStrings ("ab" , try r .peekDelimiterExclusive ('\n ' ));
1433
- r .toss (3 );
1445
+ r .toss (2 );
1446
+ try testing .expectEqualStrings ("" , try r .peekDelimiterExclusive ('\n ' ));
1447
+ try testing .expectEqualStrings ("\n " , try r .take (1 ));
1448
+
1434
1449
try testing .expectEqualStrings ("c" , try r .peekDelimiterExclusive ('\n ' ));
1435
1450
try testing .expectEqualStrings ("c" , try r .peekDelimiterExclusive ('\n ' ));
1451
+ r .toss (1 );
1452
+ try testing .expectError (error .EndOfStream , r .peekDelimiterExclusive ('\n ' ));
1453
+ }
1454
+
1455
+ test takeDelimiter {
1456
+ var r : Reader = .fixed ("ab\n c\n\n d" );
1457
+ try testing .expectEqualStrings ("ab" , (try r .takeDelimiter ('\n ' )).? );
1458
+ try testing .expectEqualStrings ("c" , (try r .takeDelimiter ('\n ' )).? );
1459
+ try testing .expectEqualStrings ("" , (try r .takeDelimiter ('\n ' )).? );
1460
+ try testing .expectEqualStrings ("d" , (try r .takeDelimiter ('\n ' )).? );
1461
+ try testing .expectEqual (null , try r .takeDelimiter ('\n ' ));
1462
+ try testing .expectEqual (null , try r .takeDelimiter ('\n ' ));
1463
+
1464
+ r = .fixed ("ab\n c\n\n d\n " ); // one trailing newline does not affect behavior
1465
+ try testing .expectEqualStrings ("ab" , (try r .takeDelimiter ('\n ' )).? );
1466
+ try testing .expectEqualStrings ("c" , (try r .takeDelimiter ('\n ' )).? );
1467
+ try testing .expectEqualStrings ("" , (try r .takeDelimiter ('\n ' )).? );
1468
+ try testing .expectEqualStrings ("d" , (try r .takeDelimiter ('\n ' )).? );
1469
+ try testing .expectEqual (null , try r .takeDelimiter ('\n ' ));
1470
+ try testing .expectEqual (null , try r .takeDelimiter ('\n ' ));
1436
1471
}
1437
1472
1438
1473
test streamDelimiter {
0 commit comments