Skip to content

Commit

Permalink
sized packing
Browse files Browse the repository at this point in the history
  • Loading branch information
biggus-developerus committed Jul 20, 2024
1 parent 1576386 commit a987244
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 0 deletions.
1 change: 1 addition & 0 deletions packer/_types/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from .base import *
from .float_types import *
from .int_types import *
from .sized_packers import *
32 changes: 32 additions & 0 deletions packer/_types/sized_packers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
__all__ = ("SizedData",)

from typing import Type, Callable
from .base import TypeDescriptor

def _pack_sized_data_wrapper(size: int) -> Callable:
def inner_packer(val: bytes) -> bytes:
if (data_len:=len(val)) < size:
raise ValueError(f"Attempted to pack data of size {data_len}, expected data of size {size}.")
return val
return inner_packer

def _unpack_sized_data_wrapper(size: int) -> Callable:
def inner_unpack(data: bytearray) -> tuple[int, bytearray]:
return (size, data[:size])
return inner_unpack

class SizedDataMeta(type):
def __getitem__(cls, data_size: int) -> Type["SizedData"]:
return type(
f"{cls.__name__}({data_size})",
(TypeDescriptor,),
{
"__data_size__": data_size,
"pack": _pack_sized_data_wrapper(data_size),
"unpack": _unpack_sized_data_wrapper(data_size),
}
)

class SizedData(metaclass=SizedDataMeta):
def pack(val: bytes) -> bytes: ...
def unpack(data: bytearray) -> tuple[int, bytearray]: ...
31 changes: 31 additions & 0 deletions tests/test_sized_packing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import math
import struct
from dataclasses import (
dataclass,
)

from packer import (
SizedData,
Pack,
packable,
)


@packable
@dataclass
class SizedDataStruct:
sized_data: Pack[SizedData[10]] = None
sized_data2: Pack[SizedData[50]] = None

def test_sized_packing() -> bool:
t = SizedDataStruct()
t.sized_data = bytearray(b"h"*5 + b"i"*5)
t.sized_data2 = bytearray(50)

assert len(t.pack()) == 60 and t.pack() == bytearray(b"hhhhhiiiii\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")
assert t.unpack(bytearray(b"x"*5 + b"d"*5) + bytearray(50)) == 60
assert t.sized_data == bytearray(b"x"*5 + b"d"*5)
assert t.sized_data2 == bytearray(50)

if __name__ == "__main__":
test_sized_packing()

0 comments on commit a987244

Please sign in to comment.