@@ -461,6 +461,30 @@ test "stream: ignored limited reader is drained automatically" {
461461 try testing .expectEqual (@as (u32 , 2 ), (try sd .next ()).? .after );
462462}
463463
464+ test "stream: partially read limited reader drains the leftover for the following field" {
465+ const src : WithString = .{ .before = 11 , .name = "hello world" , .after = 22 };
466+ const bytes = try encodeToOwned (src , testing .allocator );
467+ defer testing .allocator .free (bytes );
468+
469+ var reader : std.Io.Reader = .fixed (bytes );
470+ var sd = StreamDecoder (WithString ).init (& reader );
471+
472+ try testing .expectEqual (@as (u32 , 11 ), (try sd .next ()).? .before );
473+
474+ // Read only the first few bytes of the 11-byte string, leaving the rest
475+ // buffered/unread in the limited sub-reader.
476+ {
477+ const limited = (try sd .next ()).? .name ;
478+ var buf : [4 ]u8 = undefined ;
479+ try limited .readSliceAll (& buf );
480+ try testing .expectEqualStrings ("hell" , & buf );
481+ }
482+
483+ // The unread "o world" tail must be drained so the next field decodes.
484+ try testing .expectEqual (@as (u32 , 22 ), (try sd .next ()).? .after );
485+ try testing .expectEqual (@as (? StreamDecoder (WithString ).Event , null ), try sd .next ());
486+ }
487+
464488const Packed = struct {
465489 values : std .ArrayList (u32 ) = .empty ,
466490
@@ -492,6 +516,39 @@ test "stream: packed repeated emits one event per element" {
492516 try testing .expectEqualSlices (u32 , &.{ 1 , 2 , 300 , 40000 , 5 }, collected .items );
493517}
494518
519+ const Unpacked = struct {
520+ values : std .ArrayList (u32 ) = .empty ,
521+
522+ // `.repeated` (not `.packed_repeated`) encodes one individually-tagged
523+ // element per value, which the decoder emits via the non-packed path.
524+ pub const _desc_table = .{
525+ .values = fd (1 , .{ .repeated = .{ .scalar = .uint32 } }),
526+ };
527+
528+ pub fn deinit (self : * @This (), allocator : std .mem .Allocator ) void {
529+ return protobuf .deinit (allocator , self );
530+ }
531+ };
532+
533+ test "stream: unpacked repeated emits one event per individually-tagged element" {
534+ var src : Unpacked = .{};
535+ defer src .deinit (testing .allocator );
536+ try src .values .appendSlice (testing .allocator , &.{ 1 , 2 , 300 , 40000 , 5 });
537+
538+ const bytes = try encodeToOwned (src , testing .allocator );
539+ defer testing .allocator .free (bytes );
540+
541+ var reader : std.Io.Reader = .fixed (bytes );
542+ var sd = StreamDecoder (Unpacked ).init (& reader );
543+
544+ var collected : std .ArrayList (u32 ) = .empty ;
545+ defer collected .deinit (testing .allocator );
546+ while (try sd .next ()) | item | switch (item ) {
547+ .values = > | v | try collected .append (testing .allocator , v ),
548+ };
549+ try testing .expectEqualSlices (u32 , &.{ 1 , 2 , 300 , 40000 , 5 }, collected .items );
550+ }
551+
495552const Inner = struct {
496553 x : i32 = 0 ,
497554 y : i32 = 0 ,
0 commit comments