# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/02_prot.ipynb.

# %% auto 0
__all__ = ['NotProtocol', 'OptProtocol', 'SpecType', 'Duckish', 'Hashable', 'Origin', 'Special', 'NotSpecial',
           'NonStrBytesIterable']

# %% ../nbs/02_prot.ipynb 6
#| export


# %% ../nbs/02_prot.ipynb 8
from types import NoneType
from typing import (Any, Self, TypeGuard, Protocol, Iterable, _SpecialForm, Generic, get_origin,)

# %% ../nbs/02_prot.ipynb 10
#| export

# %% ../nbs/02_prot.ipynb 12
#| export

# %% ../nbs/02_prot.ipynb 14
from .cons import DUCK_SPEC_ATTRS, __HASH__
from .type import T

# %% ../nbs/02_prot.ipynb 16
class NotProtocol(Protocol[T]):
    '''A protocol representing a not being a type'''
    def __instancecheck__(cls: type[T], inst: Any) -> TypeGuard[type[T]]: 
        return not isinstance(inst, cls)
    
class OptProtocol(Protocol[T]):
    '''A protocol representing an optional type'''
    def __instancecheck__(cls: type[T], inst: Any) -> TypeGuard[type[T]]: 
        return isinstance(inst, (cls, NoneType))

# %% ../nbs/02_prot.ipynb 18
class SpecType(Protocol[T]):
    '''A protocol representing a duckspec'''
    _attrs: tuple[str, ...] = DUCK_SPEC_ATTRS
    def __instancecheck__(cls: type[T], inst: Any) -> TypeGuard[type[T]]:
        for attr in cls._attrs:
            if not hasattr(inst, attr): return False
        return True

# %% ../nbs/02_prot.ipynb 19
class Duckish(Protocol[T]):
    '''A protocol representing a something that might be like a duck'''
    def __instancecheck__(cls: type[T], inst: Any) -> TypeGuard[type[T]]:
        attrs = ('__duck__', 'duck', '_duck', '__ducktypes__')
        if not any(hasattr(inst, attr) for attr in attrs): return False
        return True

# %% ../nbs/02_prot.ipynb 22
class Hashable(Protocol):
    '''A protocol representing a hashable type'''
    def __hash__(self: Self) -> int: ...
    def __instancecheck__(self: Self, __instance) -> TypeGuard['Hashable']:
        return hasattr(__instance, __HASH__)

# %% ../nbs/02_prot.ipynb 24
class Origin(Hashable, Protocol):
    '''A protocol representing origin typing types'''
    def __hash__(self: Self) -> int:...
    def __instancecheck__(self: Self, __instance) -> TypeGuard['Origin']:
        return hasattr(__instance, __HASH__) and get_origin(__instance)

# %% ../nbs/02_prot.ipynb 26
class Special(Origin, Protocol):
    '''A protocol representing special typing types'''
    def __hash__(self: Self) -> int:...
    def __instancecheck__(self: Self, __instance) -> TypeGuard['Special']:
        origin = super().__instancecheck__(__instance)
        special = isinstance(__instance, _SpecialForm) or __instance in (Generic, Protocol)
        return (origin and special)
    
class NotSpecial(Origin, Protocol):
    '''A protocol representing not special typing types'''
    def __hash__(self: Self) -> int: ...
    def __instancecheck__(self: Self, __instance) -> TypeGuard['NotSpecial']:
        origin = super().__instancecheck__(__instance)
        special = isinstance(__instance, _SpecialForm) or __instance in (Generic, Protocol)
        return (origin and not special)

# %% ../nbs/02_prot.ipynb 28
class NonStrBytesIterable(Protocol):
    '''A protocol representing non-string, non-bytes iterable objects.'''
    def __iter__(self: Self) -> Iterable: ...
    def __instancecheck__(self: Self, __instance) -> TypeGuard['NonStrBytesIterable']:
        return isinstance(__instance, Iterable) and not isinstance(__instance, (str, bytes))
