from typing import Type
from typing import Callable
import operator
from typing import Tuple
import pickle


def _decode_type(
    cls: Type,
    header: dict,
    frames: list,
    is_valid_class: Callable[[Type, Type], bool] = operator.is_,
) -> Tuple[dict, list, Type]:
    """Decode metadata-encoded type and check validity

    Parameters
    ----------
    cls : type
        class performing deserialization
    header : dict
        metadata for deserialization
    frames : list
        buffers containing data for deserialization
    is_valid_class : Callable
        function to call to check if the encoded class type is valid for
        serialization by `cls` (default is to check type equality), called
        as `is_valid_class(decoded_class, cls)`.

    Returns
    -------
    tuple
        Tuple of validated headers, frames, and the decoded class
        constructor.

    Raises
    ------
    AssertionError
        if the number of frames doesn't match the count encoded in the
        headers, or `is_valid_class` is not true.
    """
    assert header["frame_count"] == len(frames), (
        f"Deserialization expected {header['frame_count']} frames, "
        f"but received {len(frames)}."
    )
    klass = pickle.loads(header["type-serialized"])
    assert is_valid_class(
        klass, cls
    ), f"Header-encoded {klass=} does not match decoding {cls=}."
    return header, frames, klass