# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/32_arng.ipynb.

# %% auto 0
__all__ = ['isarng', 'arngchain', 'try2arng', 'arr2arng', 'df2arng', 'asarng', 'arange']

# %% ../nbs/32_arng.ipynb 6
from functools import wraps

# %% ../nbs/32_arng.ipynb 8
from typing import TypeGuard

# %% ../nbs/32_arng.ipynb 10
try: import numpy as np
except ModuleNotFoundError: np = None

# %% ../nbs/32_arng.ipynb 12
from nlit import __DOC__, __NAME__, __MODULE__, __ANNOTATIONS__
from quac import nparray, indexlike, dataframe
from chck import isarr
from sigr import applyfns

# %% ../nbs/32_arng.ipynb 14
from .atyp import P
from .arrs import asnp

# %% ../nbs/32_arng.ipynb 17
def _safe_idx(x): 
    '''try: x.index except: x
    
    Attempts to return the `.index` method of `x`, falling back to `x` itself if unsuccessful.
    
    Parameters
    ----------
    x : Any
        The input object from which to attempt retrieving the `.index` method.
        
    Returns
    -------
    Any
        The `.index` method of `x` if it exists, otherwise `x` itself.
    '''
    try: return x.index
    except: return x

def _safe_len(x):
    '''try: len(x) except: 1
    
    Attempts to return the length of `x`, defaulting to 1 if unsuccessful.
    
    Parameters
    ----------
    x : Any
        The input object from which to attempt measuring the length.
        
    Returns
    -------
    int
        The length of `x` if it is measurable, otherwise 1.
    '''
    try: return len(x)
    except: return 1



# %% ../nbs/32_arng.ipynb 19
def isarng(a) -> TypeGuard[nparray]:
    '''Checks if `a` is a numpy array with elements forming an arithmetic sequence starting at 0 with a step of 1.
    
    Parameters
    ----------
    a : Any
        The input object to check.
        
    Returns
    -------
    bool
        True if `a` is a numpy array with elements forming an arithmetic sequence, otherwise False.
    '''
    return isarr(a) and np.all(np.ediff1d(a) == 1)

# %% ../nbs/32_arng.ipynb 21
def arngchain(x, funcs, *args: P.args, **kwargs: P.kwargs): 
    '''Applies a sequence of functions (`funcs`) to an initial value `x`, 
    optionally stopping when the typeguard function `isarng` returns `True`.
    
    See Also
    --------
    sigr.applyfns
    ''' 
    return applyfns(x, funcs, *args, check=isarng, **kwargs)

# %% ../nbs/32_arng.ipynb 24
def try2arng(a) -> nparray:
    '''Attempts to convert `a` to a numpy array representing an arithmetic range starting at 0.
    
    Parameters
    ----------
    a : Any
        The input object to convert.
        
    Returns
    -------
    np.array
        An arithmetic range numpy array if possible, otherwise `a` itself.
    '''
    if isarng(a): return a
    try:
        arange = np.arange(_safe_len(a))
        return arange
    except: return a

# %% ../nbs/32_arng.ipynb 26
def arr2arng(a: indexlike) -> nparray:
    '''Converts an input array-like to a numpy array representing an arithmetic range starting at 0.
    
    Parameters
    ----------
    a : indexlike
        The array-like object to convert.
        
    Returns
    -------
    np.array
        A numpy array representing an arithmetic range.
    '''
    if isarng(a): return a
    arange = np.arange(len(asnp(a)))
    return arange

# %% ../nbs/32_arng.ipynb 28
def df2arng(df: dataframe) -> nparray:
    '''Converts a DataFrame to a numpy array representing an arithmetic range based on its index.
    
    Parameters
    ----------
    df : dataframe
        The DataFrame to convert.
        
    Returns
    -------
    np.array
        A numpy array representing an arithmetic range based on the DataFrame's index.
    '''
    if isarng(df): return df
    return arr2arng(_safe_idx(df))

# %% ../nbs/32_arng.ipynb 30
def asarng(a, *args: P.args, **kwargs: P.kwargs) -> nparray:
    '''Ensures `a` is represented as a numpy array of an arithmetic range, applying conversions as needed.
    
    Parameters
    ----------
    a : Any
        The input object to convert.
    *args : P.args
        Additional positional arguments for conversion functions.
    **kwargs : P.kwargs
        Additional keyword arguments for conversion functions.
        
    Returns
    -------
    np.array
        A numpy array representing an arithmetic range, or `a` if conversions are unsuccessful.
    '''    
    if isarng(a): return a
    return arngchain(a, (
            df2arng, 
            arr2arng,
            try2arng,            
        ), *args, **kwargs
    )

# %% ../nbs/32_arng.ipynb 32
@wraps(asarng, assigned=(__DOC__, __NAME__, __MODULE__, __ANNOTATIONS__))
def arange(a, *args: P.args, **kwargs: P.kwargs) -> nparray: 
    '''An alias for `asarng`, ensuring `a` is represented as or converted to a numpy array of an arithmetic range.'''
    return asarng(a, *args, **kwargs)
