# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/01_cons.ipynb.

# %% auto 0
__all__ = ['dunname', 'ALLATTRS', 'PROTOCOL_METHOD_ORDER', 'CALLFNCS', 'ProtocolMethod', 'ProtocolMethodOrder']

# %% ../nbs/01_cons.ipynb 6
from enum import Enum

# %% ../nbs/01_cons.ipynb 8
#| export


# %% ../nbs/01_cons.ipynb 10
#| export


# %% ../nbs/01_cons.ipynb 12
from nchr import NIL
from nlit import STRS, TYPE, TYPES, DTYPE, VALUE, __NAME__, _DEFAULT_
from astr import astr

# %% ../nbs/01_cons.ipynb 14
#| export


# %% ../nbs/01_cons.ipynb 16
dunname = astr(__NAME__, retself=True)
'''Getter for the dunder `__name__` attribute of the given object.''';

ALLATTRS = {TYPE, DTYPE, TYPES}
'''Attributes of which all values in the iterable are to be checked against the type guards.''';

# %% ../nbs/01_cons.ipynb 18
class synonyms(str):
    def __new__(cls, value, *strs: str):
        new = super().__new__(cls, value)
        new._orig = str(value)
        new._strs = (getattr(value, STRS, set()) | set(strs)) - {new._orig, getattr(value, '_orig', '')}
        return new
    
    def __eq__(self, other):
        return super().__eq__(other) or str(other).casefold() in map(str.casefold, self.strs)
    
    
    def startswith(self, __prefix: str | tuple[str, ...]) -> bool:
        return any(str(s).casefold().startswith(str(__prefix).casefold()) for s in self.strs)
    
    
    @property
    def strs(self) -> set[str]:
        return {str(self)} | self._strs
    
    def __hash__(self):
        return super().__hash__()
    
    def __str__(self):
        return str.__str__(self)
    
    def __repr__(self) -> str:
        strs = str(sorted(self._strs)).replace('[', '{').replace(']', '}')
        return f'{self._orig} | {strs}'

# %% ../nbs/01_cons.ipynb 20
# Option 1: try to construct a class from the protocol's `types`
gen = synonyms('gen', 'generator', 'con', 'construct')
'''Try to generate a class from the protocol's `types`.''';

# Option 2: decorate a class
dec = synonyms('dec', 'decorator', 'dec')
'''Use the protocol as a decorator for a class.''';

# Option 3: call `__instancecheck__` / `check(...)` over varadic arguments
ins = synonyms('ins', 'instance', 'inschecks')
'''Call the protocol's `__instancecheck__` method over varadic arguments.''';

# Option 4: create a typeguard function from the protocol's `types`
tfn = synonyms('gfn', 'tfn', 'guard', 'typeguard')
'''Use the progocol's `types` to create a typeguard function.''';

# %% ../nbs/01_cons.ipynb 22
class ProtocolMethod(synonyms, Enum):
    '''Methods for the custom protocol type.
    
    Attributes
    ----------
    generator : str
        Try to generate a class from the protocol's `types`.
        
    decorator : str
        Use the protocol as a decorator for a class.
        
    inschecks : str
        Call the protocol's `__instancecheck__` method over varadic arguments.

    typeguard : str
        Use the progocol's `types` to create a typeguard function.
        
    gen : str
        Alias for `generator`.
        
    con : str
        Alias for `generator`.
        
    construct : str
        Alias for `generator`.
    
    dec : str
        Alias for `decorator`.
        
    ins : str
        Alias for `inschecks`.
        
    gfn : str
        Alias for `typeguard`.
        
    tfn : str
        Alias for `typeguard`.
        
    '''
    # Option 1: try to construct a class from the protocol's `types`
    gen: synonyms = gen
    '''Try to generate a class from the protocol's `types`.''';
    
    # Option 2: decorate a class
    dec: synonyms = dec
    
    # Option 3: call `__instancecheck__` / `check(...)` over varadic arguments
    ins: synonyms = ins
    '''Call the protocol's `__instancecheck__` method over varadic arguments.''';
    
    # Option 4: create a typeguard function from the protocol's `types`
    tfn: synonyms = tfn
    '''Use the progocol's `types` to create a typeguard function.''';
    
    @classmethod
    def _missing_(cls: 'ProtocolMethod', val: str, default = None):
        # Case-Insensitive Search
        for mem in cls:
            if mem.ieq(val): return mem
            
        # Check for default sunder method
        if hasattr(cls, _DEFAULT_): 
            edef = cls._default_()
            try: return cls(edef)
            except: ...
            try: return cls(default)
            except: return default
        
        # Check for startswith
        for mem in cls:
            if mem.startswith(val): return mem
            
        return default
    
    def casefold(self) -> str:
        return str(getattr(self, VALUE, NIL)).casefold()
    
    def ieq(self, val: str) -> bool:
        if self.casefold() == str(val).casefold(): return True
        try: 
            if self == str(val).casefold(): return True
        except: return False
    
    def startswith(self, val: str) -> bool:
        if self.casefold().startswith(str(val).casefold()): return True
        try:
            if self.value.startswith(val) == str(val): True
        except: return False
        
    
    @classmethod
    def idgt(cls) -> tuple['ProtocolMethod', ...]:
        return (ProtocolMethod.ins, ProtocolMethod.dec, ProtocolMethod.gen, ProtocolMethod.tfn)
    
    @classmethod
    def gidt(cls) -> tuple['ProtocolMethod', ...]:
        return (ProtocolMethod.gen, ProtocolMethod.dec, ProtocolMethod.ins, ProtocolMethod.tfn)

# %% ../nbs/01_cons.ipynb 24
class ProtocolMethodOrder(Enum):
    idgt = (ProtocolMethod.ins, ProtocolMethod.dec, ProtocolMethod.gen, ProtocolMethod.tfn)
    '''Options for the overloaded `ProtoType.__call__` method.''';
    gidt = (ProtocolMethod.gen, ProtocolMethod.dec, ProtocolMethod.ins, ProtocolMethod.tfn)

# %% ../nbs/01_cons.ipynb 26
PROTOCOL_METHOD_ORDER = (ProtocolMethod.ins, ProtocolMethod.dec, ProtocolMethod.gen, ProtocolMethod.tfn)
'''Options for the overloaded `ProtoType.__call__` method.''';

CALLFNCS = PROTOCOL_METHOD_ORDER
