# Path: src/cattr/_compat.py
#     def get_args(cl):
#     def get_origin(cl):
# def has(cls):
# def has_with_generic(cls):
# def fields(type):
# def adapted_fields(cl) -> List[Attribute]:
# def is_hetero_tuple(type: Any) -> bool:
# def is_protocol(type: Any) -> bool:
#     def is_annotated(_):
#     def is_tuple(type):
#     def is_union_type(obj):
#     def is_sequence(type: Any) -> bool:
#     def is_mutable_set(type):
#     def is_frozenset(type):
#     def is_mapping(type):
#     def is_bare(type):
#     def is_counter(type):
#         def is_literal(type) -> bool:
#         def is_literal(_) -> bool:
#     def is_generic(obj):
#     def copy_with(type, args):
#         def is_literal(type) -> bool:
#         def is_literal(_) -> bool:
#     def is_annotated(type) -> bool:
#     def is_tuple(type):
#         def is_union_type(obj):
#         def is_union_type(obj):
#     def is_sequence(type: Any) -> bool:
#     def is_mutable_set(type):
#     def is_frozenset(type):
#     def is_bare(type):
#     def is_mapping(type):
#     def is_counter(type):
#     def is_generic(obj):
#     def copy_with(type, args):
# def is_generic_attrs(type):
# 
# Path: src/cattr/dispatch.py
# class MultiStrategyDispatch:
#     """
#     MultiStrategyDispatch uses a combination of exact-match dispatch,
#     singledispatch, and FunctionDispatch.
#     """
# 
#     __slots__ = (
#         "_direct_dispatch",
#         "_function_dispatch",
#         "_single_dispatch",
#         "_generators",
#         "dispatch",
#     )
# 
#     def __init__(self, fallback_func):
#         self._direct_dispatch = {}
#         self._function_dispatch = FunctionDispatch()
#         self._function_dispatch.register(lambda _: True, fallback_func)
#         self._single_dispatch = singledispatch(_DispatchNotFound)
#         self.dispatch = lru_cache(maxsize=None)(self._dispatch)
# 
#     def _dispatch(self, cl):
#         try:
#             dispatch = self._single_dispatch.dispatch(cl)
#             if dispatch is not _DispatchNotFound:
#                 return dispatch
#         except Exception:
#             pass
# 
#         direct_dispatch = self._direct_dispatch.get(cl)
#         if direct_dispatch is not None:
#             return direct_dispatch
# 
#         return self._function_dispatch.dispatch(cl)
# 
#     def register_cls_list(self, cls_and_handler, direct: bool = False):
#         """Register a class to direct or singledispatch."""
#         for cls, handler in cls_and_handler:
#             if direct:
#                 self._direct_dispatch[cls] = handler
#             else:
#                 self._single_dispatch.register(cls, handler)
#                 self.clear_direct()
#         self.dispatch.cache_clear()
# 
#     def register_func_list(
#         self,
#         func_and_handler: List[
#             Union[
#                 Tuple[Callable[[Any], bool], Any],
#                 Tuple[Callable[[Any], bool], Any, bool],
#             ]
#         ],
#     ):
#         """register a function to determine if the handle
#         should be used for the type
#         """
#         for tup in func_and_handler:
#             if len(tup) == 2:
#                 func, handler = tup
#                 self._function_dispatch.register(func, handler)
#             else:
#                 func, handler, is_gen = tup
#                 self._function_dispatch.register(func, handler, is_generator=is_gen)
#         self.clear_direct()
#         self.dispatch.cache_clear()
# 
#     def clear_direct(self):
#         """Clear the direct dispatch."""
#         self._direct_dispatch.clear()
# 
#     def clear_cache(self):
#         """Clear all caches."""
#         self._direct_dispatch.clear()
#         self.dispatch.cache_clear()
# 
# Path: src/cattr/gen.py



from collections import Counter
from collections.abc import MutableSet as AbcMutableSet
from dataclasses import Field
from enum import Enum
from functools import lru_cache
from typing import Any, Callable, Dict, Optional, Tuple, Type, TypeVar, Union
from attr import Attribute
from attr import has as attrs_has
from attr import resolve_types
from cattrs.errors import IterableValidationError, StructureHandlerNotFoundError
from ._compat import (
    FrozenSetSubscriptable,
    Mapping,
    MutableMapping,
    MutableSequence,
    MutableSet,
    Sequence,
    Set,
    fields,
    get_origin,
    has,
    has_with_generic,
    is_annotated,
    is_bare,
    is_counter,
    is_frozenset,
    is_generic,
    is_generic_attrs,
    is_hetero_tuple,
    is_literal,
    is_mapping,
    is_mutable_set,
    is_protocol,
    is_sequence,
    is_tuple,
    is_union_type,
)
from .disambiguators import create_uniq_field_dis_func
from .dispatch import MultiStrategyDispatch
from .gen import (
    AttributeOverride,
    make_dict_structure_fn,
    make_dict_unstructure_fn,
    make_hetero_tuple_unstructure_fn,
    make_iterable_unstructure_fn,
    make_mapping_structure_fn,
    make_mapping_unstructure_fn,
)




NoneType = type(None)
T = TypeVar("T")
V = TypeVar("V")


class UnstructureStrategy(Enum):
    """`attrs` classes unstructuring strategies."""

    AS_DICT = "asdict"
    AS_TUPLE = "astuple"


def _subclass(typ):
    """a shortcut"""
    return lambda cls: issubclass(cls, typ)


def is_attrs_union(typ):

# Path: src/cattr/_compat.py
#     def get_args(cl):
#     def get_origin(cl):
# def has(cls):
# def has_with_generic(cls):
# def fields(type):
# def adapted_fields(cl) -> List[Attribute]:
# def is_hetero_tuple(type: Any) -> bool:
# def is_protocol(type: Any) -> bool:
#     def is_annotated(_):
#     def is_tuple(type):
#     def is_union_type(obj):
#     def is_sequence(type: Any) -> bool:
#     def is_mutable_set(type):
#     def is_frozenset(type):
#     def is_mapping(type):
#     def is_bare(type):
#     def is_counter(type):
#         def is_literal(type) -> bool:
#         def is_literal(_) -> bool:
#     def is_generic(obj):
#     def copy_with(type, args):
#         def is_literal(type) -> bool:
#         def is_literal(_) -> bool:
#     def is_annotated(type) -> bool:
#     def is_tuple(type):
#         def is_union_type(obj):
#         def is_union_type(obj):
#     def is_sequence(type: Any) -> bool:
#     def is_mutable_set(type):
#     def is_frozenset(type):
#     def is_bare(type):
#     def is_mapping(type):
#     def is_counter(type):
#     def is_generic(obj):
#     def copy_with(type, args):
# def is_generic_attrs(type):
# 
# Path: src/cattr/dispatch.py
# class MultiStrategyDispatch:
#     """
#     MultiStrategyDispatch uses a combination of exact-match dispatch,
#     singledispatch, and FunctionDispatch.
#     """
# 
#     __slots__ = (
#         "_direct_dispatch",
#         "_function_dispatch",
#         "_single_dispatch",
#         "_generators",
#         "dispatch",
#     )
# 
#     def __init__(self, fallback_func):
#         self._direct_dispatch = {}
#         self._function_dispatch = FunctionDispatch()
#         self._function_dispatch.register(lambda _: True, fallback_func)
#         self._single_dispatch = singledispatch(_DispatchNotFound)
#         self.dispatch = lru_cache(maxsize=None)(self._dispatch)
# 
#     def _dispatch(self, cl):
#         try:
#             dispatch = self._single_dispatch.dispatch(cl)
#             if dispatch is not _DispatchNotFound:
#                 return dispatch
#         except Exception:
#             pass
# 
#         direct_dispatch = self._direct_dispatch.get(cl)
#         if direct_dispatch is not None:
#             return direct_dispatch
# 
#         return self._function_dispatch.dispatch(cl)
# 
#     def register_cls_list(self, cls_and_handler, direct: bool = False):
#         """Register a class to direct or singledispatch."""
#         for cls, handler in cls_and_handler:
#             if direct:
#                 self._direct_dispatch[cls] = handler
#             else:
#                 self._single_dispatch.register(cls, handler)
#                 self.clear_direct()
#         self.dispatch.cache_clear()
# 
#     def register_func_list(
#         self,
#         func_and_handler: List[
#             Union[
#                 Tuple[Callable[[Any], bool], Any],
#                 Tuple[Callable[[Any], bool], Any, bool],
#             ]
#         ],
#     ):
#         """register a function to determine if the handle
#         should be used for the type
#         """
#         for tup in func_and_handler:
#             if len(tup) == 2:
#                 func, handler = tup
#                 self._function_dispatch.register(func, handler)
#             else:
#                 func, handler, is_gen = tup
#                 self._function_dispatch.register(func, handler, is_generator=is_gen)
#         self.clear_direct()
#         self.dispatch.cache_clear()
# 
#     def clear_direct(self):
#         """Clear the direct dispatch."""
#         self._direct_dispatch.clear()
# 
#     def clear_cache(self):
#         """Clear all caches."""
#         self._direct_dispatch.clear()
#         self.dispatch.cache_clear()
# 
# Path: src/cattr/gen.py



# Path: src/cattr/converters.py
from collections import Counter
from collections.abc import MutableSet as AbcMutableSet
from dataclasses import Field
from enum import Enum
from functools import lru_cache
from typing import Any, Callable, Dict, Optional, Tuple, Type, TypeVar, Union
from attr import Attribute
from attr import has as attrs_has
from attr import resolve_types
from cattrs.errors import IterableValidationError, StructureHandlerNotFoundError
from ._compat import (
    FrozenSetSubscriptable,
    Mapping,
    MutableMapping,
    MutableSequence,
    MutableSet,
    Sequence,
    Set,
    fields,
    get_origin,
    has,
    has_with_generic,
    is_annotated,
    is_bare,
    is_counter,
    is_frozenset,
    is_generic,
    is_generic_attrs,
    is_hetero_tuple,
    is_literal,
    is_mapping,
    is_mutable_set,
    is_protocol,
    is_sequence,
    is_tuple,
    is_union_type,
)
from .disambiguators import create_uniq_field_dis_func
from .dispatch import MultiStrategyDispatch
from .gen import (
    AttributeOverride,
    make_dict_structure_fn,
    make_dict_unstructure_fn,
    make_hetero_tuple_unstructure_fn,
    make_iterable_unstructure_fn,
    make_mapping_structure_fn,
    make_mapping_unstructure_fn,
)





NoneType = type(None)
T = TypeVar("T")
V = TypeVar("V")


class UnstructureStrategy(Enum):
    """`attrs` classes unstructuring strategies."""

    AS_DICT = "asdict"
    AS_TUPLE = "astuple"


def _subclass(typ):
    """a shortcut"""
    return lambda cls: issubclass(cls, typ)


def is_attrs_union(typ):

    return is_union_type(typ) and all(has(get_origin(e) or e) for e in typ.__args__)