Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions packtype/types/assembly.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def _pt_lookup(self, field: type[Base] | Base) -> str:

@property
@functools.lru_cache # noqa: B019
def _pt_fields(self) -> dict:
def _pt_fields(self) -> dict[Base, str]:
return {getattr(self, x): x for x in self._PT_DEF.keys()}


Expand Down Expand Up @@ -136,8 +136,10 @@ def __str__(self) -> str:
for fname in self._PT_DEF.keys():
finst = getattr(self, fname)
lsb, msb = self._PT_RANGES[fname]
width = msb - lsb + 1
lines.append(
f" - [{msb:{max_bits}}:{lsb:{max_bits}}] {fname:{max_name}} = 0x{int(finst):X}"
f" |- [{msb:{max_bits}}:{lsb:{max_bits}}] {fname:{max_name}} "
f"= 0x{int(finst):0{(width + 3) // 4}X}"
)
return "\n".join(lines)

Expand Down
8 changes: 7 additions & 1 deletion packtype/types/scalar.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,13 @@ def _pt_name(cls) -> str:
if cls._PT_ATTACHED_TO is not None:
return cls._PT_ATTACHED_TO._pt_lookup(cls)
else:
return NumericPrimitive._pt_name(cls)
return f"{['Unsigned', 'Signed'][cls._PT_SIGNED]} Scalar[{cls._PT_WIDTH}]"

def __str__(self) -> str:
return f"{type(self)._pt_name()}: 0x{int(self):0{(self._PT_WIDTH + 3) // 4}X}"

def __repr__(self):
return str(self)


class Scalar(NumericPrimitive):
Expand Down
14 changes: 14 additions & 0 deletions packtype/types/union.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#

import functools
import textwrap

from .array import ArraySpec
from .assembly import Assembly
Expand Down Expand Up @@ -30,6 +31,19 @@ def __init__(
# NOTE: Fields are not constructed at this point, instead they are filled
# in lazily as they are requested by the consumer

def __str__(self) -> str:
parts = {}
for finst, fname in self._pt_fields.items():
parts[fname] = str(finst)
max_prefix = max(map(len, parts.keys()))
return f"{type(self).__name__}: 0x{int(self):X} (union):\n" + "\n".join(
(f" |- {p:{max_prefix}s} -> " + textwrap.indent(v, " " * (max_prefix + 8)).lstrip())
for p, v in parts.items()
)

def __repr__(self) -> str:
return self.__str__()

def __getattribute__(self, fname: str):
# Attempt to resolve the attribute from existing properties
try:
Expand Down
16 changes: 12 additions & 4 deletions tests/pysyntax/test_struct.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,18 @@ class TestStruct:
cd: Scalar[3]
ef: Scalar[9]

inst = TestStruct._pt_unpack((39 << 15) | (5 << 12) | 123)
assert inst.ab.value == 123
assert inst.cd.value == 5
assert inst.ef.value == 39
value = (39 << 15) | (5 << 12) | 123
inst = TestStruct._pt_unpack(value)
assert inst.ab.value == (ab_value := 123)
assert inst.cd.value == (cd_value := 5)
assert inst.ef.value == (ef_value := 39)

assert str(inst) == (
f"TestStruct: 0x{value:06X}\n"
f" |- [11: 0] ab = 0x{ab_value:03X}\n"
f" |- [14:12] cd = 0x{cd_value:01X}\n"
f" |- [23:15] ef = 0x{ef_value:03X}"
)


def test_struct_unpacking_from_msb():
Expand Down
27 changes: 21 additions & 6 deletions tests/pysyntax/test_union.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,12 +140,27 @@ class Packet:
raw: Scalar[32]
header: Header

inst = Packet._pt_unpack((0x7 << 28) | (0x5 << 24) | (0x75 << 16) | 0x1234)
assert int(inst.raw) == (0x7 << 28) | (0x5 << 24) | (0x75 << 16) | 0x1234
assert int(inst.header.address) == 0x1234
assert int(inst.header.length) == 0x75
assert int(inst.header.mode) == 0x5
assert int(inst.header.flags) == 0x7
hdr_addr_val = 0x1234
hdr_len_val = 0x75
hdr_mode_val = 0x5
hdr_flags_val = 0x7
value = (hdr_flags_val << 28) | (hdr_mode_val << 24) | (hdr_len_val << 16) | hdr_addr_val
inst = Packet._pt_unpack(value)
assert int(inst.raw) == value
assert int(inst.header.address) == hdr_addr_val
assert int(inst.header.length) == hdr_len_val
assert int(inst.header.mode) == hdr_mode_val
assert int(inst.header.flags) == hdr_flags_val

assert str(inst) == (
f"Packet: 0x{value:08X} (union):\n"
f" |- raw -> Unsigned Scalar[32]: 0x{value:08X}\n"
f" |- header -> Header: 0x{value:08X}\n"
f" |- [15: 0] address = 0x{hdr_addr_val:04X}\n"
f" |- [23:16] length = 0x{hdr_len_val:02X}\n"
f" |- [27:24] mode = 0x{hdr_mode_val:01X}\n"
f" |- [31:28] flags = 0x{hdr_flags_val:01X}"
)


def test_union_bad_widths():
Expand Down