sltcodec 1.3.0__tar.gz → 2.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sltcodec-2.1.0/PKG-INFO +315 -0
- sltcodec-2.1.0/README.md +98 -0
- sltcodec-2.1.0/README_pypi.md +298 -0
- {sltcodec-1.3.0 → sltcodec-2.1.0}/pyproject.toml +2 -2
- {sltcodec-1.3.0 → sltcodec-2.1.0}/src/sltcodec/__init__.py +6 -6
- {sltcodec-1.3.0 → sltcodec-2.1.0}/src/sltcodec/codec.py +100 -59
- {sltcodec-1.3.0 → sltcodec-2.1.0}/src/sltcodec/types.py +22 -0
- {sltcodec-1.3.0 → sltcodec-2.1.0}/tests/test_codec.py +124 -432
- sltcodec-2.1.0/tests/test_persistence.py +58 -0
- sltcodec-2.1.0/tests/test_types.py +439 -0
- {sltcodec-1.3.0 → sltcodec-2.1.0}/uv.lock +1 -1
- sltcodec-1.3.0/PKG-INFO +0 -303
- sltcodec-1.3.0/README.md +0 -286
- {sltcodec-1.3.0 → sltcodec-2.1.0}/.github/workflows/publish_to_pypi.yml +0 -0
- {sltcodec-1.3.0 → sltcodec-2.1.0}/.github/workflows/publish_to_testpypi.yml +0 -0
- {sltcodec-1.3.0 → sltcodec-2.1.0}/.gitignore +0 -0
- {sltcodec-1.3.0 → sltcodec-2.1.0}/.python-version +0 -0
- {sltcodec-1.3.0 → sltcodec-2.1.0}/.vscode/launch.json +0 -0
- {sltcodec-1.3.0 → sltcodec-2.1.0}/.vscode/settings.json +0 -0
- {sltcodec-1.3.0 → sltcodec-2.1.0}/LICENSE +0 -0
- {sltcodec-1.3.0 → sltcodec-2.1.0}/bump_major.ps1 +0 -0
- {sltcodec-1.3.0 → sltcodec-2.1.0}/bump_minor.ps1 +0 -0
- {sltcodec-1.3.0 → sltcodec-2.1.0}/bump_patch.ps1 +0 -0
sltcodec-2.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: sltcodec
|
|
3
|
+
Version: 2.1.0
|
|
4
|
+
Summary: Decode and encode bytearrays according to struct layout definitions using sltcore.
|
|
5
|
+
Project-URL: Homepage, https://github.com/fangface-hub/StructLayoutToolkitCodec
|
|
6
|
+
Project-URL: Documentation, https://readthedocs.org
|
|
7
|
+
Project-URL: Repository, https://github.com/fangface-hub/StructLayoutToolkitCodec
|
|
8
|
+
Project-URL: Issues, https://github.com/fangface-hub/StructLayoutToolkitCodec/issues
|
|
9
|
+
Author: fangface
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: byte,deserialization,layout,serialization,struct
|
|
13
|
+
Requires-Python: >=3.12
|
|
14
|
+
Requires-Dist: sltcalc>=0.1.0
|
|
15
|
+
Requires-Dist: sltcore>=1.5.0
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
|
|
18
|
+
# StructLayoutToolkitCodec
|
|
19
|
+
|
|
20
|
+
`sltcodec` encodes and decodes bytearrays according to structured layout definitions. It uses `sltcore` for bit-level access.
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pip install sltcodec
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Quick Example
|
|
29
|
+
|
|
30
|
+
`StructLayout` bundles the root structure name with its `TypeDict`. Pass the same layout to both `encode` and `decode`.
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
from sltcore import InfoSize
|
|
34
|
+
from sltcodec import (
|
|
35
|
+
FieldDef,
|
|
36
|
+
FieldInstance,
|
|
37
|
+
StructDef,
|
|
38
|
+
StructInstance,
|
|
39
|
+
StructLayout,
|
|
40
|
+
TypeDict,
|
|
41
|
+
decode,
|
|
42
|
+
encode,
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
fields = [
|
|
46
|
+
FieldDef(name="flag", offset=InfoSize(0, 0), size=InfoSize(0, 1), type="bool"),
|
|
47
|
+
FieldDef(name="value", offset=InfoSize(0, 1), size=InfoSize(1, 0), type="unsigned int"),
|
|
48
|
+
]
|
|
49
|
+
struct_def = StructDef(name="Packet", fields=fields)
|
|
50
|
+
layout = StructLayout(
|
|
51
|
+
struct_def_name="Packet",
|
|
52
|
+
type_dict=TypeDict(struct_dict={"Packet": struct_def}),
|
|
53
|
+
)
|
|
54
|
+
instance = StructInstance(
|
|
55
|
+
struct_def=struct_def,
|
|
56
|
+
field_instances=[
|
|
57
|
+
FieldInstance(fields[0], True),
|
|
58
|
+
FieldInstance(fields[1], 0xA5),
|
|
59
|
+
],
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
encoded = encode(layout, instance, bytearray())
|
|
63
|
+
decoded = decode(layout, encoded)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Field Types
|
|
67
|
+
|
|
68
|
+
The public `PRIMITIVE_TYPES` set contains:
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
{"bool", "signed int", "int", "unsigned int", "float", "bytearray", "bytes"}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
`FieldDef.type` may also be a nested `StructDef` or an expression string. Expressions can use values from previously processed fields, allowing dynamic types and sizes. Repeated fields, byte swapping, padding, ranges, and enum metadata are supported.
|
|
75
|
+
|
|
76
|
+
## Enums And Named Structures
|
|
77
|
+
|
|
78
|
+
Store named structures in `TypeDict.struct_dict` and enums in `TypeDict.enum_dict`. A field refers to an enum by its `enum_def_name`; the codec resolves it through `StructLayout.type_dict`.
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
| `__lt__(other)` | Compare enum definitions using their serialized ordering. |
|
|
82
|
+
from sltcore import InfoSize
|
|
83
|
+
from sltcodec import EnumDef, FieldDef, StructDef, StructLayout, TypeDict, decode
|
|
84
|
+
|
|
85
|
+
enum_def = EnumDef(name="Status", values={"OK": 0, "NG": 1})
|
|
86
|
+
packet = StructDef(
|
|
87
|
+
name="Packet",
|
|
88
|
+
fields=[FieldDef(
|
|
89
|
+
name="status",
|
|
90
|
+
offset=InfoSize(0, 0),
|
|
91
|
+
size=InfoSize(1, 0),
|
|
92
|
+
type="unsigned int",
|
|
93
|
+
enum_def_name="Status",
|
|
94
|
+
)],
|
|
95
|
+
)
|
|
96
|
+
layout = StructLayout(
|
|
97
|
+
struct_def_name="Packet",
|
|
98
|
+
type_dict=TypeDict(
|
|
99
|
+
struct_dict={"Packet": packet},
|
|
100
|
+
enum_dict={"Status": enum_def},
|
|
101
|
+
),
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
decoded = decode(layout, bytearray(b"\x01"))
|
|
105
|
+
| `__lt__(other)` | Compare field definitions using their serialized ordering. |
|
|
106
|
+
assert decoded.field_instances[0].enum_item == ("NG", 1)
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Saving And Loading
|
|
110
|
+
|
|
111
|
+
Persist a complete `StructLayout`, including its root structure name, structure definitions, and enum definitions, with `save_struct_layout` and `load_struct_layout`.
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
from pathlib import Path
|
|
115
|
+
from sltcodec import load_struct_layout, save_struct_layout
|
|
116
|
+
|
|
117
|
+
path = Path("struct_layout.json")
|
|
118
|
+
save_struct_layout(layout, path)
|
|
119
|
+
loaded = load_struct_layout(path)
|
|
120
|
+
| `__lt__(other)` | Compare field instances using field-definition order. |
|
|
121
|
+
assert loaded == layout
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
`InfoSize` values are stored as typed JSON dictionaries. Expression-based offsets and sizes remain strings and are evaluated when the layout is used.
|
|
125
|
+
|
|
126
|
+
## Public API Reference
|
|
127
|
+
|
|
128
|
+
The following symbols are exported by `sltcodec.__all__` in this order:
|
|
129
|
+
|
|
130
|
+
| Symbol | Description |
|
|
131
|
+
| --- | --- |
|
|
132
|
+
| `PRIMITIVE_TYPES` | Set of built-in field type names supported by the codec. |
|
|
133
|
+
| `EnumDef` | Immutable definition of an enumeration. |
|
|
134
|
+
| `EnumDict` | Dictionary-like container for `EnumDef` objects. |
|
|
135
|
+
| `FieldDef` | Immutable definition of one structured field. |
|
|
136
|
+
| `FieldInstance` | Immutable field definition and decoded/encodable value pair. |
|
|
137
|
+
| `StructDef` | Immutable definition that groups fields into a structure. |
|
|
138
|
+
| `StructDict` | Dictionary-like container for `StructDef` objects. |
|
|
139
|
+
| `StructInstance` | Decoded/encodable structure instance containing field instances. |
|
|
140
|
+
| `StructLayout` | Bundle of the root structure name and its `TypeDict`. |
|
|
141
|
+
| `TypeDict` | Bundle of named structure and enum dictionaries. |
|
|
142
|
+
| `decode` | Decode bytes according to a `StructLayout`. |
|
|
143
|
+
| `encode` | Encode a `StructInstance` according to a `StructLayout`. |
|
|
144
|
+
| `load_struct_layout` | Load a `StructLayout` from JSON. |
|
|
145
|
+
| `save_struct_layout` | Save a `StructLayout` as JSON. |
|
|
146
|
+
|
|
147
|
+
### Types (`types.py`)
|
|
148
|
+
|
|
149
|
+
Classes are listed in their definition order. The member tables show the
|
|
150
|
+
dataclass fields or constructor attributes. Methods beginning with `_` are
|
|
151
|
+
internal implementation details and are omitted from the public method tables.
|
|
152
|
+
|
|
153
|
+
#### `EnumDef`
|
|
154
|
+
|
|
155
|
+
| Member | Type | Description |
|
|
156
|
+
| --- | --- | --- |
|
|
157
|
+
| `name` | `str` | Enumeration name. |
|
|
158
|
+
| `description` | `str \| None` | Optional description. |
|
|
159
|
+
| `values` | `dict[str, int]` | Mapping from enumeration names to integer values. |
|
|
160
|
+
|
|
161
|
+
| Method | Description |
|
|
162
|
+
| --- | --- |
|
|
163
|
+
| `to_dict()` | Convert the definition to a JSON-compatible dictionary. |
|
|
164
|
+
| `to_json()` | Convert the definition to a JSON string. |
|
|
165
|
+
| `from_dict(data)` | Create an `EnumDef` from a dictionary. |
|
|
166
|
+
| `serialize()` | Convert the definition to a typed dictionary. |
|
|
167
|
+
| `deserialize(data)` | Create an `EnumDef` from a typed dictionary. |
|
|
168
|
+
| `from_json(data)` | Create an `EnumDef` from a JSON string. |
|
|
169
|
+
| `__lt__(other)` | Compare enum definitions using their serialized ordering. |
|
|
170
|
+
|
|
171
|
+
#### `FieldDef`
|
|
172
|
+
|
|
173
|
+
| Member | Type | Description |
|
|
174
|
+
| --- | --- | --- |
|
|
175
|
+
| `name` | `str` | Field name. |
|
|
176
|
+
| `offset` | `InfoSize \| str` | Static offset or expression. |
|
|
177
|
+
| `size` | `InfoSize \| str` | Static size or expression. |
|
|
178
|
+
| `type` | `str \| StructDef` | Primitive, named, or nested field type. |
|
|
179
|
+
| `scale` | `float` | Numeric scale applied to the field. |
|
|
180
|
+
| `repeat` | `int \| None` | Number of repeated field values. |
|
|
181
|
+
| `description` | `str \| None` | Optional field description. |
|
|
182
|
+
| `range_expression` | `str \| None` | Optional value-range expression. |
|
|
183
|
+
| `enum_def_name` | `str \| None` | Name of the associated enum definition. |
|
|
184
|
+
| `byte_swap` | `bool \| str` | Whether to reverse bytes, or an expression controlling it. |
|
|
185
|
+
|
|
186
|
+
| Method | Description |
|
|
187
|
+
| --- | --- |
|
|
188
|
+
| `split_repeat(index, offset=None, size=None)` | Create one field definition from a repeated field. |
|
|
189
|
+
| `to_dict()` | Convert the definition to a JSON-compatible dictionary. |
|
|
190
|
+
| `to_json()` | Convert the definition to a JSON string. |
|
|
191
|
+
| `from_dict(data)` | Create a `FieldDef` from a dictionary. |
|
|
192
|
+
| `from_json(data)` | Create a `FieldDef` from a JSON string. |
|
|
193
|
+
| `__lt__(other)` | Compare field definitions using their serialized ordering. |
|
|
194
|
+
|
|
195
|
+
#### `FieldInstance`
|
|
196
|
+
|
|
197
|
+
| Member | Type | Description |
|
|
198
|
+
| --- | --- | --- |
|
|
199
|
+
| `field_def` | `FieldDef` | Definition of the field. |
|
|
200
|
+
| `value` | `Any` | Decoded or encodable field value. |
|
|
201
|
+
| `enum_item` | `tuple[str, int] \| None` | Matching enum name and value, when available. |
|
|
202
|
+
| `is_padding` | `bool` | Whether this instance represents padding. |
|
|
203
|
+
|
|
204
|
+
| Method | Description |
|
|
205
|
+
| --- | --- |
|
|
206
|
+
| `range_check(env=None)` | Evaluate the field's range expression. |
|
|
207
|
+
| `from_value(field_def, value, type_dict=None, is_padding=False)` | Create an instance and resolve matching enum metadata. |
|
|
208
|
+
| `with_value(value, type_dict=None)` | Return a new instance with the given value; keeps `field_def` and `is_padding` and recomputes `enum_item`. |
|
|
209
|
+
| `__lt__(other)` | Compare field instances using field-definition order. |
|
|
210
|
+
|
|
211
|
+
#### `StructDef`
|
|
212
|
+
|
|
213
|
+
| Member | Type | Description |
|
|
214
|
+
| --- | --- | --- |
|
|
215
|
+
| `name` | `str` | Structure name. |
|
|
216
|
+
| `description` | `str` | Structure description. |
|
|
217
|
+
| `fields` | `list[FieldDef]` | Ordered field definitions. |
|
|
218
|
+
|
|
219
|
+
| Method | Description |
|
|
220
|
+
| --- | --- |
|
|
221
|
+
| `to_dict()` | Convert the definition to a JSON-compatible dictionary. |
|
|
222
|
+
| `to_json()` | Convert the definition to a JSON string. |
|
|
223
|
+
| `from_dict(data)` | Create a `StructDef` from a dictionary or legacy field list. |
|
|
224
|
+
| `from_json(data)` | Create a `StructDef` from a JSON string. |
|
|
225
|
+
| `__lt__(other)` | Compare structure definitions using their serialized ordering. |
|
|
226
|
+
|
|
227
|
+
#### `StructInstance`
|
|
228
|
+
|
|
229
|
+
| Member | Type | Description |
|
|
230
|
+
| --- | --- | --- |
|
|
231
|
+
| `struct_def` | `StructDef` | Structure definition for the instance. |
|
|
232
|
+
| `field_instances` | `list[FieldInstance]` | Stored field instances, kept in field order. |
|
|
233
|
+
| `size` | `InfoSize` | Total structure size. |
|
|
234
|
+
|
|
235
|
+
| Method | Description |
|
|
236
|
+
| --- | --- |
|
|
237
|
+
| `append_field_instance(field_instance)` | Append one field instance. |
|
|
238
|
+
| `extend_field_instances(field_instances)` | Append multiple field instances. |
|
|
239
|
+
| `__iter__()` | Iterate over field instances. |
|
|
240
|
+
| `__len__()` | Return the number of field instances. |
|
|
241
|
+
| `__getitem__(index)` | Get a field instance by index. |
|
|
242
|
+
| `__post_init__()` | Normalize field order, size, and generated padding after construction. |
|
|
243
|
+
| `__lt__(other)` | Compare structure instances using their serialized ordering. |
|
|
244
|
+
|
|
245
|
+
#### `EnumDict`
|
|
246
|
+
|
|
247
|
+
| Member | Type | Description |
|
|
248
|
+
| --- | --- | --- |
|
|
249
|
+
| `_items` | `dict[str, EnumDef]` | Stored enum definitions. Use mapping operations or `items_dict()`. |
|
|
250
|
+
|
|
251
|
+
| Method | Description |
|
|
252
|
+
| --- | --- |
|
|
253
|
+
| `__getitem__(key)` | Get an enum definition by name. |
|
|
254
|
+
| `__setitem__(key, value)` | Store an enum definition. |
|
|
255
|
+
| `__delitem__(key)` | Delete an enum definition. |
|
|
256
|
+
| `__iter__()` | Iterate over enum names. |
|
|
257
|
+
| `__len__()` | Return the number of enum definitions. |
|
|
258
|
+
| `items_dict()` | Return the underlying dictionary. |
|
|
259
|
+
|
|
260
|
+
#### `StructDict`
|
|
261
|
+
|
|
262
|
+
| Member | Type | Description |
|
|
263
|
+
| --- | --- | --- |
|
|
264
|
+
| `_items` | `dict[str, StructDef]` | Stored structure definitions. Use mapping operations or `items_dict()`. |
|
|
265
|
+
|
|
266
|
+
| Method | Description |
|
|
267
|
+
| --- | --- |
|
|
268
|
+
| `__getitem__(key)` | Get a structure definition by name. |
|
|
269
|
+
| `__setitem__(key, value)` | Store a structure definition. |
|
|
270
|
+
| `__delitem__(key)` | Delete a structure definition. |
|
|
271
|
+
| `__iter__()` | Iterate over structure names. |
|
|
272
|
+
| `__len__()` | Return the number of structure definitions. |
|
|
273
|
+
| `items_dict()` | Return the underlying dictionary. |
|
|
274
|
+
|
|
275
|
+
#### `TypeDict`
|
|
276
|
+
|
|
277
|
+
| Member | Type | Description |
|
|
278
|
+
| --- | --- | --- |
|
|
279
|
+
| `enum_dict` | `EnumDict` | Named enum definitions. |
|
|
280
|
+
| `struct_dict` | `StructDict` | Named structure definitions. |
|
|
281
|
+
|
|
282
|
+
`TypeDict(enum_dict=None, struct_dict=None)` constructs both containers from
|
|
283
|
+
optional dictionaries.
|
|
284
|
+
|
|
285
|
+
#### `StructLayout`
|
|
286
|
+
|
|
287
|
+
| Member | Type | Description |
|
|
288
|
+
| --- | --- | --- |
|
|
289
|
+
| `struct_def_name` | `str` | Key of the root structure in `type_dict.struct_dict`. |
|
|
290
|
+
| `type_dict` | `TypeDict` | Structure and enum definitions used for resolution. |
|
|
291
|
+
|
|
292
|
+
`StructLayout(struct_def_name, type_dict)` constructs a layout bundle.
|
|
293
|
+
|
|
294
|
+
### Codec (`codec.py`)
|
|
295
|
+
|
|
296
|
+
The following public definitions are listed in their definition order. Names
|
|
297
|
+
beginning with `_` are internal helpers and are not part of the public API.
|
|
298
|
+
|
|
299
|
+
| Definition | Signature | Description |
|
|
300
|
+
| --- | --- | --- |
|
|
301
|
+
| `PRIMITIVE_TYPES` | `set[str]` | Built-in field type names. |
|
|
302
|
+
| `save_struct_layout` | `(struct_layout, path) -> None` | Save a layout to a JSON file. |
|
|
303
|
+
| `load_struct_layout` | `(path) -> StructLayout` | Load a layout from a JSON file. |
|
|
304
|
+
| `save_struct_def_dict` | `(path, struct_def_dict) -> None` | Save a structure-definition dictionary through the layout format. |
|
|
305
|
+
| `load_struct_def_dict` | `(path) -> dict[str, StructDef]` | Load a structure-definition dictionary. |
|
|
306
|
+
| `save_enum_def_dict` | `(path, enum_def_dict) -> None` | Save an enum-definition dictionary through the layout format. |
|
|
307
|
+
| `load_enum_def_dict` | `(path) -> dict[str, EnumDef]` | Load an enum-definition dictionary. |
|
|
308
|
+
| `encode` | `(struct_layout, struct_instance, buf, padding_alignment_bits=32) -> bytearray` | Encode a complete structure. |
|
|
309
|
+
| `decode_field` | `(field_def, data, env=None, type_dict=None, padding_alignment_bits=32) -> FieldInstance \| None` | Decode one field. |
|
|
310
|
+
| `decode` | `(struct_layout, data, padding_alignment_bits=32) -> StructInstance` | Decode a complete structure. |
|
|
311
|
+
|
|
312
|
+
`save_struct_def_dict`, `load_struct_def_dict`, `save_enum_def_dict`, and
|
|
313
|
+
`load_enum_def_dict` are available from `sltcodec.codec` for dictionary-level
|
|
314
|
+
compatibility. The package root exports the complete `StructLayout` API:
|
|
315
|
+
`save_struct_layout` and `load_struct_layout`.
|
sltcodec-2.1.0/README.md
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# StructLayoutToolkitCodec Development
|
|
2
|
+
|
|
3
|
+
This repository contains `sltcodec`, a Python package for encoding and
|
|
4
|
+
decoding bytearrays according to structured layout definitions.
|
|
5
|
+
|
|
6
|
+
The package description and user-facing API examples used for PyPI are in
|
|
7
|
+
[README_pypi.md](README_pypi.md).
|
|
8
|
+
|
|
9
|
+
## Development Setup
|
|
10
|
+
|
|
11
|
+
This project requires Python 3.12 or newer and uses `uv` for dependency and
|
|
12
|
+
environment management.
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
uv sync --all-extras
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
The project also keeps a local virtual environment at `.venv` when using the
|
|
19
|
+
standard `uv` workflow.
|
|
20
|
+
|
|
21
|
+
## Run Tests
|
|
22
|
+
|
|
23
|
+
Run the complete test suite:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
uv run pytest
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Run a focused test module:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
uv run pytest tests/test_codec.py -q
|
|
33
|
+
uv run pytest tests/test_types.py -q
|
|
34
|
+
uv run pytest tests/test_persistence.py -q
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Tests are organized by responsibility:
|
|
38
|
+
|
|
39
|
+
- `tests/test_codec.py`: encoding, decoding, padding, repetition, and byte swapping
|
|
40
|
+
- `tests/test_types.py`: field, enum, structure, and instance behavior
|
|
41
|
+
- `tests/test_persistence.py`: `StructLayout` JSON persistence
|
|
42
|
+
|
|
43
|
+
## Source Layout
|
|
44
|
+
|
|
45
|
+
```text
|
|
46
|
+
src/sltcodec/
|
|
47
|
+
__init__.py Public package exports
|
|
48
|
+
codec.py Encoding, decoding, and layout persistence
|
|
49
|
+
types.py Field, enum, structure, and layout types
|
|
50
|
+
tests/ Pytest test modules
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Public API Changes
|
|
54
|
+
|
|
55
|
+
`encode` and `decode` receive one `StructLayout` object. The structure
|
|
56
|
+
definition is resolved by `struct_layout.struct_def_name` from
|
|
57
|
+
`struct_layout.type_dict.struct_dict`; enum definitions are resolved from the
|
|
58
|
+
same `TypeDict`.
|
|
59
|
+
|
|
60
|
+
Layout persistence uses the explicit names `save_struct_layout` and
|
|
61
|
+
`load_struct_layout`. The former `save_type_dict` and `load_type_dict` API is
|
|
62
|
+
not part of the current public interface.
|
|
63
|
+
|
|
64
|
+
`FieldInstance` stays frozen. To change a decoded value, use
|
|
65
|
+
`FieldInstance.with_value(value, type_dict=None)`, which returns a new
|
|
66
|
+
instance instead of mutating the original. It keeps `field_def` and
|
|
67
|
+
`is_padding`, and recomputes `enum_item` from the new value and `type_dict`
|
|
68
|
+
by delegating to `FieldInstance.from_value`.
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
updated_field = field_instance.with_value(
|
|
72
|
+
new_value,
|
|
73
|
+
struct_layout.type_dict,
|
|
74
|
+
)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Versioning And Release
|
|
78
|
+
|
|
79
|
+
Version bump scripts are provided for patch, minor, and major releases:
|
|
80
|
+
|
|
81
|
+
```powershell
|
|
82
|
+
.\bump_patch.ps1
|
|
83
|
+
.\bump_minor.ps1
|
|
84
|
+
.\bump_major.ps1
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Review the generated version change and run the full test suite before
|
|
88
|
+
building or publishing a package.
|
|
89
|
+
|
|
90
|
+
## Build
|
|
91
|
+
|
|
92
|
+
The package uses Hatchling as its build backend. The package metadata points
|
|
93
|
+
to `README_pypi.md` so the PyPI project page contains the consumer-facing
|
|
94
|
+
documentation rather than repository development notes.
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
uv build
|
|
98
|
+
```
|