import struct
from abc import ABC, abstractmethod
from typing import Any, TypeVar
T = TypeVar("T")
class StrictType(ABC):
"""
Abstract class for StrictType. Defines standard ``__pack__`` and ``__unpack__`` functions.
:cvar FORMAT: Format specifier used when packing obj
:cvar STANDARD_SIZE: Standard size of obj in bytes
"""
@property
@abstractmethod
def FORMAT(self):
pass
@property
@abstractmethod
def STANDARD_SIZE(self):
pass
def __pack__(self) -> bytes:
return struct.pack(self.FORMAT, self)
def __unpack__(self, data: bytes) -> (T, bytes):
return (
struct.unpack(self.FORMAT, data[: self.STANDARD_SIZE])[0],
data[self.STANDARD_SIZE :],
)
[docs]class Char(str, StrictType):
"""
Represents the strict type for a char.
"""
FORMAT: str = "=c"
STANDARD_SIZE: int = 1
def __init__(self, c: str = "\0"):
"""
Initializes
:param c:
"""
if len(c) != 1:
raise Exception("Char may only take arguments of length 1")
super(str, Char).__init__(c)
def __pack__(self) -> bytes:
return struct.pack(self.FORMAT, self.encode("ascii"))
def __unpack__(self, data: bytes) -> (float, bytes):
return (
struct.unpack(self.FORMAT, data[: self.STANDARD_SIZE])[0].decode("ascii"),
data[self.STANDARD_SIZE :],
)
[docs]class UnsignedChar(int, StrictType):
"""
Represents the strict type for an unsigned char.
"""
FORMAT: str = "=B"
STANDARD_SIZE: int = 1
def __init__(self, c: int = 0):
if not 0 <= c <= 255:
raise Exception("UnsignedChar must be between 0 and 255")
super(int, UnsignedChar).__init__(c)
[docs]class SignedChar(int, StrictType):
"""
Represents the strict type for a signed char.
"""
FORMAT: str = "=b"
STANDARD_SIZE: int = 1
def __init__(self, c: int = 0):
if not -128 <= c <= 127:
raise Exception("SignedChar must be between -128 and 127")
super(int, SignedChar).__init__(c)
[docs]class Short(int, StrictType):
"""
Represents the strict type for a short.
"""
FORMAT: str = "=h"
STANDARD_SIZE: int = 2
def __init__(self, n: int = 0):
if not -32768 <= n <= 32767:
raise Exception("Short must be between -32768 and 32767")
super(int, Short).__init__(n)
[docs]class UnsignedShort(int, StrictType):
"""
Represents the strict type for an unsigned short.
"""
FORMAT: str = "=H"
STANDARD_SIZE: int = 2
def __init__(self, n: int = 0):
if not 0 <= n <= 65535:
raise Exception("Short must be between 0 and 65535")
super(int, UnsignedShort).__init__(n)
[docs]class Int(int, StrictType):
"""
Represents the strict type for an integer.
"""
FORMAT: str = "=i"
STANDARD_SIZE: int = 4
def __init__(self, n: int = 0):
if not -2147483648 <= n <= 2147483647:
raise Exception("Short must be between -2147483648 and 2147483647")
super(int, Int).__init__(n)
[docs]class UnsignedInt(int, StrictType):
"""
Represents the strict type for an unsigned integer.
"""
FORMAT: str = "=I"
STANDARD_SIZE: int = 4
def __init__(self, n: int = 0):
if not 0 <= n <= 4294967295:
raise Exception("Unsigned Integer must be between 0 and 4294967295")
super(int, UnsignedInt).__init__(n)
[docs]class Long(int, StrictType):
"""
Represents the strict type for an long.
"""
FORMAT: str = "=l"
STANDARD_SIZE: int = 4
def __init__(self, n: int = 0):
if not -2147483648 <= n <= 2147483647:
raise Exception("Long must be between -2147483648 and 2147483647")
super(int, Long).__init__(n)
[docs]class UnsignedLong(int, StrictType):
"""
Represents the strict type for an unsigned long.
"""
FORMAT: str = "=L"
STANDARD_SIZE: int = 4
def __init__(self, n: int = 0):
if not 0 <= n <= 4294967295:
raise Exception("UnsignedLong must be between 0 and 4294967295")
super(int, UnsignedLong).__init__(n)
[docs]class LongLong(int, StrictType):
"""
Represents the strict type for a long long.
"""
FORMAT: str = "=q"
STANDARD_SIZE: int = 8
def __init__(self, n: int = 0):
if not -9223372036854775808 <= n <= 9223372036854775807:
raise Exception("LongLong must be between 0 and 9223372036854775807")
super(int, LongLong).__init__(n)
[docs]class UnsignedLongLong(int, StrictType):
"""
Represents the strict type for an unsigned long long.
"""
FORMAT: str = "=Q"
STANDARD_SIZE: int = 8
def __init__(self, n: int = 0):
if not 0 <= n <= 18446744073709551615:
raise Exception(
"UnsignedLongLong must be between 0 and 18446744073709551615"
)
super(int, UnsignedLongLong).__init__(n)
[docs]class Float(float, StrictType):
"""
Represents the strict type for a float.
"""
FORMAT: str = "=f"
STANDARD_SIZE: int = 4
def __init__(self, n: int = 0):
super(float, Float).__init__(n)
[docs]class Double(float, StrictType):
"""
Represents the strict type for a double.
"""
FORMAT: str = "=d"
STANDARD_SIZE: int = 8
def __init__(self, n: int = 0):
super(float, Double).__init__(n)