from collections.abc import Callable, Iterable, Sized
from typing import Any, overload

from remedapy.decorator import make_data_last


@overload
def length() -> Callable[[Iterable[Any]], int]: ...


@overload
def length(iterable: Iterable[Any], /) -> int: ...


@make_data_last
def length(iterable: Iterable[Any], /) -> int:
    """
    Determines length of the iterable.

    Parameters
    ----------
    iterable : Iterable[Any]
        Input iterable (positional-only).

    Returns
    -------
    length: int
        Length of the iterable, should not be negative.

    Examples
    --------
    Data first:
    >>> R.length([1, 2, 3])
    3
    >>> R.length((x for x in range(3)))
    3

    Data last:
    >>> R.length()([1, 2, 3])
    3

    """
    if isinstance(iterable, Sized):
        return len(iterable)
    return sum(1 for _ in iterable)
