Исходный код bytespec.codecs.bytes

# Copyright (c) 2026 ink-developer

from typing_extensions import override

from bytespec.codecs import ICodec
from bytespec.enums import ByteOrder
from bytespec.errors import EncodeError, SchemaError
from bytespec.models import PrefixLength

from ._utils import check_available
from .map import UINT_CODEC_MAPPING


[документация] class BytesCodec(ICodec[bytes]): """Bytes prefixed with their length. Args: prefix_length: Prefix size: 1, 2, 4, or 8 bytes, or ``VarUInt``. Defaults to 4 bytes. The prefix itself is not included in the stored length. Raises: SchemaError: Unsupported prefix, including ``VarInt``. """ def __init__(self, prefix_length: PrefixLength = 4) -> None: self.prefix_length = prefix_length codec = UINT_CODEC_MAPPING.get(prefix_length) if codec is None: raise SchemaError(f"BytesCodec: invalid length prefix {prefix_length!r}") self.codec = codec super().__init__() @override def encode(self, value: bytes, byte_order: ByteOrder) -> bytes: """Write the length of value followed by the bytes themselves. Raises: EncodeError: The length does not fit in the selected prefix. """ return self.codec.encode(len(value), byte_order) + value @override def decode(self, buffer: bytes, byte_order: ByteOrder, offset: int) -> tuple[bytes, int]: """Read the prefix and return the bytes with their absolute end offset. Raises: DecodeError: The prefix or declared data is incomplete or invalid. ValueError: Negative offset. """ length, start = self.codec.decode(buffer, byte_order, offset) end = start + length check_available(buffer, start, length, codec=type(self).__name__) return buffer[start:end], end
[документация] class FixedBytesCodec(BytesCodec): """Exactly length bytes without a length prefix. Args: length: The nonnegative fixed size of the value. Raises: SchemaError: Negative length. """ def __init__(self, length: int) -> None: if length < 0: raise SchemaError(f"FixedBytesCodec: length must be non-negative, got {length}") self.length = length @override def encode(self, value: bytes, byte_order: ByteOrder) -> bytes: """Return value after checking its length; byte order has no effect. Raises: EncodeError: The size of value is not equal to length. """ if len(value) != self.length: raise EncodeError(f"FixedBytesCodec: expected {self.length} bytes, got {len(value)}") return value @override def decode( self, buffer: bytes, byte_order: ByteOrder, offset: int, ) -> tuple[bytes, int]: """Read length bytes and return them with their absolute end offset. Raises: DecodeError: There are not enough bytes. ValueError: Negative offset. """ end = offset + self.length check_available(buffer, offset, self.length, codec=type(self).__name__) return buffer[offset:end], end