Skip to main content

StructLayoutToolkitCodec

sltcodec is a small package for decoding and encoding bytearrays according to structured layout definitions. It uses sltcore for bit-level access and provides a simple API for turning a layout definition into binary data and back again.

Installation

pip install sltcodec

Primitive Type Set

PRIMITIVE_TYPES is the public set of built-in field types understood by the codec.

from sltcodec import PRIMITIVE_TYPES

print(PRIMITIVE_TYPES)
# {'bool', 'signed int', 'int', 'unsigned int', 'float', 'bytearray', 'bytes'}

Quick Example

FieldDef.description is an optional human-readable note that can be attached to each field definition.

decode returns a StructInstance. encode accepts a StructInstance and a destination bytearray.

from sltcore import InfoSize
from sltcodec import (FieldDef, FieldInstance, StructDef, StructInstance,
                      decode, encode)

struct_def = [
    FieldDef(name="flag",
             offset=InfoSize(0, 0),
             size=InfoSize(0, 1),
             type="bool",
             scale=1.0,
             description="Whether the feature is enabled"),
    FieldDef(name="value",
             offset=InfoSize(0, 1),
             size=InfoSize(1, 0),
             type="unsigned int",
             scale=1.0,
             description="The encoded numeric payload"),
]

encoded = encode(
    StructInstance(
        struct_def=StructDef(fields=struct_def),
        field_instances=[
            FieldInstance(struct_def[0], True),
            FieldInstance(struct_def[1], 0xA5),
        ],
    ),
    bytearray(),
)
decoded = decode(struct_def, encoded)

print(encoded)
print(decoded)
print(decoded.field_instances)

Output:

bytearray(b"\xd2\x80")
StructInstance(struct_def=StructDef(...), field_instances=[...])
[FieldInstance(field_def=FieldDef(name='flag', offset=InfoSize(byte=0, bit=0), size=InfoSize(byte=0, bit=1), type='bool', scale=1.0, repeat=None), value=True),
 FieldInstance(field_def=FieldDef(name='value', offset=InfoSize(byte=0, bit=1), size=InfoSize(byte=1, bit=0), type='unsigned int', scale=1.0, repeat=None), value=165)]

Nested Field Types

FieldDef.type can be a StructDef, not only a primitive type name. This allows you to define an inline nested structure and keep encode_field / decode_field behavior symmetrical.

from sltcore import InfoSize
from sltcodec import FieldDef, FieldInstance, StructDef, StructInstance, decode, encode

child_struct_def = [
    FieldDef(name="left", offset=InfoSize(0, 0), size=InfoSize(1, 0), type="unsigned int"),
    FieldDef(name="right", offset=InfoSize(1, 0), size=InfoSize(1, 0), type="unsigned int"),
]

parent_field_def = FieldDef(
    name="pair",
    offset=InfoSize(0, 0),
    size=InfoSize(2, 0),
    type=StructDef(
        name="Pair",
        description="Two adjacent unsigned ints",
        fields=child_struct_def,
    ),
)

encoded = encode(
    StructInstance(
        struct_def=StructDef(fields=[parent_field_def]),
        field_instances=[
            FieldInstance(
                parent_field_def,
                StructInstance(
                    struct_def=StructDef(fields=child_struct_def),
                    field_instances=[
                        FieldInstance(child_struct_def[0], 3),
                        FieldInstance(child_struct_def[1], 4),
                    ],
                ),
            )
        ],
    ),
    bytearray(),
)

decoded = decode([parent_field_def], encoded)
print(encoded)
print(decoded)
print(decoded.field_instances)

Output:

bytearray(b"\x03\x04")
StructInstance(struct_def=StructDef(...), field_instances=[...])
[FieldInstance(field_def=FieldDef(name='pair', offset=InfoSize(byte=0, bit=0), size=InfoSize(byte=2, bit=0), type=[...], scale=1.0, repeat=None),
               value=StructInstance(struct_def=StructDef(...), field_instances=[...]))]

Expression-Based Type Selection

FieldDef.type can also be an expression string. The expression is evaluated with previously processed field values in scope, so you can switch decoding/encoding type dynamically.

from sltcore import InfoSize
from sltcodec import (FieldDef, FieldInstance, StructDef, StructInstance,
                      decode, encode)

struct_def = [
    FieldDef(name="kind", offset=InfoSize(0, 0), size=InfoSize(1, 0), type="unsigned int"),
    FieldDef(
        name="payload",
        offset=InfoSize(1, 0),
        size="{1: 1, 2: 4}[kind]",
        type="{1: 'int', 2: 'float'}[kind]",
    ),
]

# kind=1 -> payload is int (1 byte)
encoded_int = encode(
    StructInstance(
        struct_def=StructDef(fields=struct_def),
        field_instances=[
            FieldInstance(struct_def[0], 1),
            FieldInstance(struct_def[1], 7),
        ],
    ),
    bytearray(),
)
decoded_int = decode(struct_def, encoded_int)

# kind=2 -> payload is float (4 bytes)
encoded_float = encode(
    StructInstance(
        struct_def=StructDef(fields=struct_def),
        field_instances=[
            FieldInstance(struct_def[0], 2),
            FieldInstance(struct_def[1], 1.5),
        ],
    ),
    bytearray(),
)
decoded_float = decode(struct_def, encoded_float)

print(encoded_int, decoded_int)
print(encoded_float, decoded_float)

Saving And Loading StructDef Dictionaries

You can persist reusable structure definitions by name with save_struct_def_dict / load_struct_def_dict.

from pathlib import Path

from sltcore import InfoSize
from sltcodec import FieldDef, StructDef, load_struct_def_dict, save_struct_def_dict

struct_defs = {
    "Header": StructDef(
        name="Header",
        description="Simple header",
        fields=[
            FieldDef(name="kind", offset=InfoSize(0, 0), size=InfoSize(1, 0), type="unsigned int"),
            FieldDef(name="flags", offset=InfoSize(1, 0), size=InfoSize(1, 0), type="unsigned int"),
        ],
    )
}

path = Path("struct_defs.json")
save_struct_def_dict(path, struct_defs)
loaded = load_struct_def_dict(path)

print(loaded["Header"].name)
print(loaded["Header"].description)

Example output:

bytearray(b"\x01\x07") StructInstance(struct_def=StructDef(...), field_instances=[...])
bytearray(b"\x02?\xc0\x00\x00") StructInstance(struct_def=StructDef(...), field_instances=[...])

Enum Definitions

FieldDef.enum_def_name holds only the name of an EnumDef, not the definition itself. Pass the actual definitions via an enum_def_dict (mapping name to EnumDef) to decode / encode so the matching EnumDef can be resolved and attached as FieldInstance.enum_item.

from sltcore import InfoSize
from sltcodec import EnumDef, FieldDef, decode

status_enum = EnumDef(name="Status", values={"OK": 0, "NG": 1})

struct_def = [
    FieldDef(name="status",
             offset=InfoSize(0, 0),
             size=InfoSize(1, 0),
             type="unsigned int",
             enum_def_name="Status"),
]

decoded = decode(struct_def, bytearray(b"\x01"),
                 enum_def_dict={"Status": status_enum})

print(decoded.field_instances[0].value)
print(decoded.field_instances[0].enum_item)

Output:

1
('NG', 1)

You can also persist enum definitions by name with save_enum_def_dict / load_enum_def_dict, mirroring StructDef dictionaries.

Development

uv sync --all-extras
uv run pytest

Metadata

Release files for sltcodec 1.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for sltcodec 1.2.0
File Size Uploaded
sltcodec-1.2.0.tar.gz 21.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for sltcodec 1.2.0
File Interpreter ABI Platform
sltcodec-1.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 34.7 kB

Release files / sltcodec-1.2.0.tar.gz

Download URL sltcodec-1.2.0.tar.gz
Size 21.8 kB
Tags Source
SHA-256 checksum
How to use checksums
0aacc41d9e6fc1177278d4035aadb0b83c8b0a784ab076812987d3bd4c52ed7a
BLAKE2b-256 checksum
How to use checksums
91f33147c8eb58a1da0f992e4aa204bc242de03b7caa7ef22a3f9122f3dc8e8e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / sltcodec-1.2.0-py3-none-any.whl

Download URL sltcodec-1.2.0-py3-none-any.whl
Size 12.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
400126b47a0d699519d9b3d7a31b11ff9e6e98eddf0e750fa1569d52a50083a7
BLAKE2b-256 checksum
How to use checksums
6a5e889a9de5b011ecc14aadc05cb97bfd99e93d57323268f0c5cf675075ed6d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release history Release notifications | RSS feed

2.7.4

2 release files

2.7.3

2 release files

2.7.2

2 release files

2.7.1

2 release files

2.7.0

2 release files

2.6.1

2 release files

2.6.0

2 release files

2.5.2

2 release files

2.5.1

2 release files

2.5.0

2 release files

2.4.1

2 release files

2.4.0

2 release files

2.3.0

2 release files

2.2.0

2 release files

2.1.1

2 release files

2.1.0

2 release files

2.0.0

2 release files

1.3.0

2 release files

1.2.1

2 release files

This release

1.2.0 This release

2 release files

1.1.0

2 release files

1.0.0

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page