Skip to content

Commit 8aa9c89

Browse files
authored
fix: correctly handle early exit in Scanner iterators (#898)
Both inner and outer `for` must be exited when `yield` returns `false`.
1 parent 5b78011 commit 8aa9c89

File tree

2 files changed

+50
-2
lines changed

2 files changed

+50
-2
lines changed

helper.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,10 @@ func (s *Scanner) scan() iter.Seq[[]string] {
302302
func (s *Scanner) Iter() iter.Seq[string] {
303303
return func(yield func(string) bool) {
304304
for vs := range s.scan() {
305-
for i := 0; i < len(vs) && yield(vs[i]); i++ {
305+
for _, v := range vs {
306+
if !yield(v) {
307+
return
308+
}
306309
}
307310
}
308311
}
@@ -311,7 +314,10 @@ func (s *Scanner) Iter() iter.Seq[string] {
311314
func (s *Scanner) Iter2() iter.Seq2[string, string] {
312315
return func(yield func(string, string) bool) {
313316
for vs := range s.scan() {
314-
for i := 0; i+1 < len(vs) && yield(vs[i], vs[i+1]); i += 2 {
317+
for i := 0; i+1 < len(vs); i += 2 {
318+
if !yield(vs[i], vs[i+1]) {
319+
return
320+
}
315321
}
316322
}
317323
}

helper_test.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1534,6 +1534,27 @@ func TestScannerIter(t *testing.T) {
15341534
}
15351535
})
15361536
}
1537+
1538+
t.Run("early exit", func(t *testing.T) {
1539+
callCount := 0
1540+
entries := []ScanEntry{
1541+
{Elements: []string{"key1"}, Cursor: 10},
1542+
}
1543+
scanner := NewScanner(func(cursor uint64) (ScanEntry, error) {
1544+
if callCount >= len(entries) {
1545+
return ScanEntry{}, errors.New("unexpected call")
1546+
}
1547+
entry := entries[callCount]
1548+
callCount++
1549+
return entry, nil
1550+
})
1551+
for range scanner.Iter() {
1552+
break
1553+
}
1554+
if scanner.Err() != nil {
1555+
t.Errorf("unexpected error: %v", scanner.Err())
1556+
}
1557+
})
15371558
}
15381559

15391560
func TestScannerIter2(t *testing.T) {
@@ -1623,4 +1644,25 @@ func TestScannerIter2(t *testing.T) {
16231644
}
16241645
})
16251646
}
1647+
1648+
t.Run("early exit", func(t *testing.T) {
1649+
callCount := 0
1650+
entries := []ScanEntry{
1651+
{Elements: []string{"field1", "value1"}, Cursor: 10},
1652+
}
1653+
scanner := NewScanner(func(cursor uint64) (ScanEntry, error) {
1654+
if callCount >= len(entries) {
1655+
return ScanEntry{}, errors.New("unexpected call")
1656+
}
1657+
entry := entries[callCount]
1658+
callCount++
1659+
return entry, nil
1660+
})
1661+
for range scanner.Iter2() {
1662+
break
1663+
}
1664+
if scanner.Err() != nil {
1665+
t.Errorf("unexpected error: %v", scanner.Err())
1666+
}
1667+
})
16261668
}

0 commit comments

Comments
 (0)