Исходный код bytespec.codecs.str
# Copyright (c) 2026 ink-developer
import codecs
from typing_extensions import override
from bytespec.codecs import ICodec
from bytespec.enums import ByteOrder
from bytespec.errors import DecodeError, EncodeError, SchemaError
from bytespec.models import PrefixLength
from ._utils import check_available
from .map import UINT_CODEC_MAPPING
[документация]
class StrCodec(ICodec[str]):
"""Text prefixed with the length in encoded bytes, not characters.
Args:
prefix_length: Prefix size: 1, 2, 4, or 8 bytes, or ``VarUInt``. Defaults to 4 bytes.
encoding: Python encoding, UTF-8 by default.
Raises:
SchemaError: Unsupported prefix or unknown encoding.
"""
def __init__(self, prefix_length: PrefixLength = 4, encoding: str = "utf-8") -> None:
self.prefix_length = prefix_length
self.encoding = encoding
try:
codecs.lookup(encoding)
except LookupError as exc:
raise SchemaError(f"StrCodec: invalid encoding {encoding!r}") from exc
codec = UINT_CODEC_MAPPING.get(prefix_length)
if codec is None:
raise SchemaError(f"StrCodec: invalid length prefix {prefix_length!r}")
self.codec = codec
super().__init__()
@override
def encode(self, value: str, byte_order: ByteOrder) -> bytes:
"""Encode text and prefix it with its byte length.
Raises:
EncodeError: The text cannot be represented in the encoding, or its length does not fit
in the prefix.
SchemaError: The selected Python codec is not a text encoding.
"""
try:
encoded = value.encode(self.encoding)
except UnicodeError as exc:
raise EncodeError(f"StrCodec ({self.encoding}): cannot encode {value!r}") from exc
except LookupError as exc:
raise SchemaError(f"StrCodec: invalid text encoding {self.encoding!r}") from exc
return self.codec.encode(len(encoded), byte_order) + encoded
@override
def decode(
self,
buffer: bytes,
byte_order: ByteOrder,
offset: int,
) -> tuple[str, int]:
"""Read a string and return it with its absolute end offset.
Raises:
DecodeError: There are not enough bytes, or the prefix or text is invalid.
SchemaError: The selected Python codec is not a text encoding.
ValueError: Negative offset.
"""
length, start = self.codec.decode(buffer, byte_order, offset)
end = start + length
check_available(buffer, start, length, codec=type(self).__name__)
try:
value = buffer[start:end].decode(self.encoding)
except UnicodeError as exc:
raise DecodeError(
f"StrCodec ({self.encoding}) at offset {start}: invalid string bytes"
) from exc
except LookupError as exc:
raise SchemaError(f"StrCodec: invalid text encoding {self.encoding!r}") from exc
return value, end