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=[...])

Development

uv sync --all-extras
uv run pytest

Metadata

Release files for sltcodec 1.0.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.0.0
File Size Uploaded
sltcodec-1.0.0.tar.gz 21.1 kB Details

Built distribution (wheel)

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

Total release size: 33.5 kB

Release files / sltcodec-1.0.0.tar.gz

Download URL sltcodec-1.0.0.tar.gz
Size 21.1 kB
Tags Source
SHA-256 checksum
How to use checksums
c797f6d6f85ecc40d32477d00cad21c4c446e6552927b1b1e16e8a9d492930f6
BLAKE2b-256 checksum
How to use checksums
8ee0a4feb8949122a898479f87ee616bfd79199f5db9ce8ee615ca5b31608208
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.0.0-py3-none-any.whl

Download URL sltcodec-1.0.0-py3-none-any.whl
Size 12.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e8443846c33b0a59a13b702c32aaf557e00b790ffd03d17ab3bbfc328683439a
BLAKE2b-256 checksum
How to use checksums
519a534b71cd52cf9b38265f3317ce70e6a56774a100dc37e43b09d6f1f7ce25
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

1.2.0

2 release files

1.1.0

2 release files

This release

1.0.0 This release

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