class Deserializer:
    __codec_cache: CodecCache
    __reader: ByteIo

    def __init__(self, codec_cache: CodecCache, reader: BinaryIO):
        super().__init__()

        self.__codec_cache = codec_cache
        self.__reader = ByteIo(reader)

    def read(self, codec: None or Codec[T] = None) -> T:
        if codec is not None:
            return codec.read(self.__reader)

        found: Codec = self.__codec_cache.get(self.__reader.peek())
        return found.read(self.__reader)

    def close(self) -> None:
        self.__reader.close()
class Serializer:
    __codec_cache: CodecCache
    __writer: ByteIo

    def __init__(self, codec_cache: CodecCache, writer: BinaryIO):
        super().__init__()

        self.__codec_cache = codec_cache
        self.__writer = ByteIo(writer)

    def append(self, value: T, codec: None or Codec[T]) -> None:
        if codec is not None:
            codec.write(self.__writer, value)
            return

        codec: Codec[T] = self.__codec_cache.codec_for(value)

        if codec is None:
            raise ValueError(f"Missing codec for {type(value)}")

        codec.write(self.__writer, value)

    def close(self) -> None:
        self.__writer.close()