Skip to content

Commit fece147

Browse files
authored
fix(unpack): allow dynamic offsets
Merge pull request #57 from tsheinen/fix-dynamic-offset-unpack
2 parents 508c998 + e46b327 commit fece147

2 files changed

Lines changed: 45 additions & 2 deletions

File tree

src/caterpillar/fields/_base.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -214,9 +214,13 @@ def offset(self) -> _ContextLambda[int] | int:
214214
@offset.setter
215215
def offset(self, value: _ContextLambda[int] | int):
216216
self.__offset = value
217-
self._has_offset = value not in (-1, None)
217+
# _ContextLambda is ExprMixin so `__eq__` is overridden
218+
# and `Tuple.__contains__` isn't correct. If value is an
219+
# instance of _ContextLambda we may assume it is not
220+
# -1 or None
221+
self._has_offset = value not in (-1, None) or isinstance(value, _ContextLambda)
218222
self._offset_is_lambda = callable(value)
219-
self._keep_pos = value in (-1, None)
223+
self._keep_pos = value in (-1, None) and not isinstance(value, _ContextLambda)
220224

221225
@property
222226
def amount(self) -> _LengthT | None:

test/_Py/fields/test_py_offset.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import pytest
2+
3+
from caterpillar.py import (
4+
struct,
5+
pack,
6+
unpack,
7+
uint8,
8+
this,
9+
)
10+
11+
def test_fixed_offset_unpack():
12+
atom = uint8 @ 4
13+
data = b"\x00\x00\x00\x00\x42"
14+
assert unpack(atom, data, as_field=True) == 0x42
15+
16+
def test_dynamic_offset_unpack():
17+
@struct
18+
class Format:
19+
offset: uint8
20+
data: uint8 @ this.offset
21+
22+
binary = b"\x04\x00\x00\x00\xAB"
23+
assert unpack(Format, binary) == Format(offset=4, data=0xAB)
24+
25+
# offset packs do not seem to be working correctly
26+
# These tests show the current behavior
27+
28+
def test_fixed_offset_pack():
29+
atom = uint8 @ 4
30+
assert pack(0x42, atom, as_field=True) == b"\x42"
31+
32+
def test_dynamic_offset_pack():
33+
@struct
34+
class Format:
35+
offset: uint8
36+
data: uint8 @ this.offset
37+
38+
obj = Format(offset=4, data=0xAB)
39+
assert pack(obj) == b"\x04\xab"

0 commit comments

Comments
 (0)