74 lines
2.8 KiB
Python
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)
|