Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,15 @@ dev = [
"cython==3.0.11",
"types-setuptools==75.8.0.20250110",
]
benchmarks = ["more-itertools==10.6.0"]
docs = ["mkdocs==1.6.1"]

benchmarks = [
"more-itertools==10.6.0",
all = [
{ include-group = "dev" },
{ include-group = "docs" },
{ include-group = "benchmarks" },
]

docs = ["mkdocs==1.6.1"]
all = [{ include-group = "dev" }, { include-group = "docs" }]

[tool.uv]
default-groups = ["dev"]

Expand Down
3 changes: 3 additions & 0 deletions rusty_iterators/core/interface.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,13 @@ cdef class IterInterface:
cpdef object last(self)
cpdef Inspect inspect(self, object f = *)
cpdef Map map(self, object func)
cpdef object max(self)
cpdef object min(self)
cpdef IterInterface moving_window(self, int size, bint use_cache = *)
cpdef object next(self)
cpdef object nth(self, int n)
cpdef Peekable peekable(self)
cpdef object product(self)
cpdef object reduce(self, object func)
cpdef Skip skip(self, int amount)
cpdef StepBy step_by(self, int step)
Expand Down
3 changes: 3 additions & 0 deletions rusty_iterators/core/interface.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ class IterInterface(Generic[T]):
def last(self) -> T: ...
def inspect(self, f: Optional[InspectCallable[T]] = None) -> Inspect[T]: ...
def map(self, func: MapCallable[T, R]) -> Map[R]: ...
def max(self) -> T: ...
def min(self) -> T: ...
@overload
def moving_window(self, size: int, use_cache: Literal[False]) -> CopyMovingWindow[T]: ...
@overload
Expand All @@ -76,6 +78,7 @@ class IterInterface(Generic[T]):
def next(self) -> T: ...
def nth(self, n: int) -> T: ...
def peekable(self) -> Peekable[T]: ...
def product(self) -> T: ...
def reduce(self, func: ReduceCallable[T]) -> T: ...
def skip(self, amount: int) -> Skip[T]: ...
def step_by(self, step: int) -> StepBy[T]: ...
Expand Down
18 changes: 18 additions & 0 deletions rusty_iterators/core/interface.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,15 @@ cdef inline object _aggregate_sum(object acc, object x):
cdef inline object _persist_last_item(object _, object x):
return x

cdef inline object _max(object acc, object x):
return max(acc, x)

cdef inline object _min(object acc, object x):
return min(acc, x)

cdef inline object _product(object acc, object x):
return acc * x

cdef class IterInterface:
def __iter__(self):
return self
Expand Down Expand Up @@ -89,6 +98,12 @@ cdef class IterInterface:
cpdef Map map(self, object func):
return Map(self, func)

cpdef object max(self):
return self.reduce(_max)

cpdef object min(self):
return self.reduce(_min)

cpdef IterInterface moving_window(self, int size, bint use_cache = True):
return CacheMovingWindow(self, size) if use_cache else CopyMovingWindow(self, size)

Expand All @@ -102,6 +117,9 @@ cdef class IterInterface:
cpdef Peekable peekable(self):
return Peekable(self)

cpdef object product(self):
return self.reduce(_product)

cpdef object reduce(self, object func):
cdef object init = self.next()
return self.fold(init, func)
Expand Down
5 changes: 4 additions & 1 deletion tests/types/verify_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,11 @@ def verify_items_iterator_type() -> None:
assert_type(it.reduce(lambda acc, x: acc + x), int)
assert_type(it.nth(5), int)
assert_type(it.last(), int)
assert_type(it.for_each(lambda x: None), None)
assert_type(it.for_each(lambda _: None), None)
assert_type(it.count(), int)
assert_type(it.max(), int)
assert_type(it.min(), int)
assert_type(it.product(), int)


def verify_empty_sequence_iterator_type() -> None:
Expand Down
27 changes: 27 additions & 0 deletions tests/unit/sync/test_iterator.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,30 @@ def test_for_each() -> None:
@pytest.mark.parametrize("arg", ([1, 2, 3], []))
def test_count_iterator_elements(arg: list[int]) -> None:
assert LIter.from_seq(arg).count() == len(arg)


def test_max_returns_the_max_item() -> None:
assert LIter.from_items(1, 2, 3).max() == 3


def test_max_called_on_empty_iterator() -> None:
with pytest.raises(StopIteration):
LIter.from_items().max()


def test_min_returns_the_min_item() -> None:
assert LIter.from_items(1, 2, 3).min() == 1


def test_min_called_on_empty_iterator() -> None:
with pytest.raises(StopIteration):
LIter.from_items().min()


def test_product_returns_the_product_of_items() -> None:
assert LIter.from_items(1, 2, 3).product() == 6


def test_product_called_on_empty_iterator() -> None:
with pytest.raises(StopIteration):
LIter.from_items().product()
2 changes: 2 additions & 0 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.