diff --git a/codex/utils/iter.nim b/codex/utils/iter.nim index bdbbf7c9..e695f831 100644 --- a/codex/utils/iter.nim +++ b/codex/utils/iter.nim @@ -103,29 +103,33 @@ proc map*[T, U](iter: Iter[T], fn: Function[T, U]): Iter[U] = ) proc mapFilter*[T, U](iter: Iter[T], mapPredicate: Function[T, Option[U]]): Iter[U] = - var nextUOrErr: Option[Result[U, ref CatchableError]] + var + hasNext = false + nextUOrErr: Result[U, ref CatchableError] proc tryFetch(): void = - nextUOrErr = Result[U, ref CatchableError].none + hasNext = false while not iter.finished: try: let t = iter.next() if u =? mapPredicate(t): - nextUOrErr = some(success(u)) + hasNext = true + nextUOrErr = success(u) break except CatchableError as err: - nextUOrErr = some(U.failure(err)) + hasNext = true + nextUOrErr = U.failure(err) proc genNext(): U {.raises: [CatchableError].} = - # at this point nextUOrErr should always be some(..) - without u =? nextUOrErr.unsafeGet, err: + # at this point hasNext is always true + without u =? nextUOrErr, err: raise err tryFetch() return u proc isFinished(): bool = - nextUOrErr.isNone + not hasNext tryFetch() Iter[U].new(genNext, isFinished) diff --git a/tests/codex/utils/testasynciter.nim b/tests/codex/utils/testasynciter.nim index 2a7e2b8c..d4531f83 100644 --- a/tests/codex/utils/testasynciter.nim +++ b/tests/codex/utils/testasynciter.nim @@ -158,3 +158,21 @@ asyncchecksuite "Test AsyncIter": check: collected == @["0", "1"] iter2.finished + + test "Should not crash with range type": + let + iter1 = AsyncIter[Natural].new(0.Natural..<5.Natural).delayBy(10.millis) + iter2 = await filter[Natural](iter1, + proc (i: Natural): Future[bool] {.async.} = + (i mod 2) == 1 + ) + + var collected: seq[Natural] + + for fut in iter2: + collected.add(await fut) + + check: + collected == @[Natural 1, 3] + + GC_fullCollect() diff --git a/tests/codex/utils/testiter.nim b/tests/codex/utils/testiter.nim index e2806b5a..f2582739 100644 --- a/tests/codex/utils/testiter.nim +++ b/tests/codex/utils/testiter.nim @@ -127,3 +127,13 @@ checksuite "Test Iter": check: collected == @["0", "1", "2"] iter2.finished + + test "Should not crash with range type": + let + iter = Iter.new(0.Natural..<5.Natural) + .filter((i: Natural) => (i mod 2) == 1) + + check: + iter.toSeq() == @[Natural 1, 3] + + GC_fullCollect()