sx/sx/types/int.py

74 lines
2.8 KiB
Python

from typing import Optional as O, Union as U
from ..core.base import Type, Context, PossibleDynamic
from ..core.io import Stream, Endian
from .transforms import Mapped
class Int(Type[int]):
__slots__ = ('bits', 'endian', 'signed')
def __init__(self, bits: PossibleDynamic[int], endian: PossibleDynamic[Endian], signed: PossibleDynamic[bool]) -> None:
self.bits = bits
self.endian = endian
self.signed = signed
def parse(self, context: Context, stream: Stream) -> int:
n = context.get(self.bits)
bs = stream.read(n // 8)
return int.from_bytes(bs, byteorder=context.get(self.endian).to_python(), signed=context.get(self.signed))
def dump(self, context: Context, stream: Stream, value: U[int, float]) -> None:
if isinstance(value, float):
if value.is_integer():
value = int(value)
else:
raise ValueError(f'can not encode float {value!r} as integer')
n = context.get(self.bits)
bs = value.to_bytes(n // 8, byteorder=context.get(self.endian).to_python(), signed=context.get(self.signed))
return stream.write(bs)
def default(self, context: Context) -> int:
return 0
def sizeof(self, context: Context, value: O[int]) -> O[int]:
size = context.peek(self.bits)
if size is not None:
size //= 8
return size
def __str__(self) -> str:
endian = {Endian.Big: 'be', Endian.Little: 'le'}.get(self.endian, self.endian) if self.bits != 8 else ''
sign = {True: '', False: 'u'}.get(self.signed, self.signed)
return f'{sign}int{self.bits}{endian}'
def __repr__(self) -> str:
return f'<{__name__}.{self.__class__.__name__}({self.bits!r}, {self.endian!r}, signed: {self.signed!r})>'
int8 = Int(8, endian=Endian.Little, signed=True)
uint8 = Int(8, endian=Endian.Little, signed=False)
int16le = Int(16, endian=Endian.Little, signed=True)
int16be = Int(16, endian=Endian.Big, signed=True)
uint16le = Int(16, endian=Endian.Little, signed=False)
uint16be = Int(16, endian=Endian.Big, signed=False)
int32le = Int(32, endian=Endian.Little, signed=True)
int32be = Int(32, endian=Endian.Big, signed=True)
uint32le = Int(32, endian=Endian.Little, signed=False)
uint32be = Int(32, endian=Endian.Big, signed=False)
int64le = Int(64, endian=Endian.Little, signed=True)
int64be = Int(64, endian=Endian.Big, signed=True)
uint64le = Int(64, endian=Endian.Little, signed=False)
uint64be = Int(64, endian=Endian.Big, signed=False)
class Bool(Type[bool]):
def __new__(self, child: Type, true_value: int = 1, false_value: int = 0) -> Mapped:
return Mapped(child, {true_value: True, false_value: False},
str='bool',
repr=f'<{__name__}.Bool({child!r}, true: {true_value!r}, false: {false_value!r})>',
)
bool = Bool(uint8)