Source code for scfile.core.io.base

"""
Extends IOBase to support struct-based I/O.
"""

import io
import struct
from typing import Any, Optional

import numpy as np

from scfile.enums import ByteOrder, F, UnicodeErrors


[docs] class StructIO(io.IOBase): """Low-level binary I/O with structured packing/unpacking operations.""" order: ByteOrder = ByteOrder.LITTLE unicode_errors: str = UnicodeErrors.REPLACE def _pack(self, fmt: str, *values: Any) -> bytes: return struct.pack(str(fmt), *values) def _unpack(self, fmt: str) -> tuple[Any, ...]: size = struct.calcsize(str(fmt)) data = self.read(size) return struct.unpack(fmt, data) def _readarray(self, dtype: str, count: int, order: Optional[ByteOrder] = None): order = order or self.order datatype = np.dtype(f"{order}{dtype}") datasize = count * datatype.itemsize return np.frombuffer(self.read(datasize), dtype=datatype, count=count) def _readb(self, fmt: str, order: Optional[ByteOrder] = None) -> Any: order = order or self.order return self._unpack(f"{order}{fmt}")[0] def _reads(self, prefix: str = F.U16, order: Optional[ByteOrder] = None) -> bytes: order = order or self.order size = self._readb(prefix, order) return self._unpack(f"{size}s")[0] def _readutf8(self) -> str: return self._reads().decode("utf-8", errors=self.unicode_errors) def _writeb(self, fmt: str, *values: Any, order: Optional[ByteOrder] = None) -> None: order = order or self.order data = self._pack(f"{order}{fmt}", *values) self.write(data) def _writenull(self, size: int = 4) -> None: self.write(bytes(size)) def _writeutf8(self, string: str) -> None: self.write(string.encode("utf-8", errors=self.unicode_errors))