Metadata-Version: 2.4
Name: structwire
Version: 0.1.0
Summary: A small schema-driven binary payload codec for Python.
Author: Nidhal Abidi
License-Expression: MIT
Project-URL: Homepage, https://github.com/nidops/structwire
Project-URL: Documentation, https://github.com/nidops/structwire/blob/master/docs/SCHEMA.md
Project-URL: Source, https://github.com/nidops/structwire
Project-URL: Issues, https://github.com/nidops/structwire/issues
Keywords: binary,codec,schema,embedded,payload,bitfield,yaml
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: PyYAML>=6.0
Provides-Extra: test
Requires-Dist: pytest>=8; extra == "test"
Requires-Dist: hypothesis>=6; extra == "test"
Requires-Dist: readme-renderer[md]>=44; extra == "test"
Provides-Extra: dev
Requires-Dist: build>=1.2; extra == "dev"
Requires-Dist: coverage>=7; extra == "dev"
Requires-Dist: mypy>=1.13; extra == "dev"
Requires-Dist: pytest>=8; extra == "dev"
Requires-Dist: hypothesis>=6; extra == "dev"
Requires-Dist: ruff>=0.8; extra == "dev"
Requires-Dist: twine>=6.2; extra == "dev"
Requires-Dist: packaging>=24.2; extra == "dev"
Requires-Dist: readme-renderer[md]>=44; extra == "dev"
Requires-Dist: types-PyYAML>=6.0.12; extra == "dev"
Dynamic: license-file

# StructWire

StructWire converts fixed-layout binary payloads to Python values and back.
Use it when a device message, file record or test fixture has a known byte layout.
Define fields in Python or YAML, then reuse a compiled codec to encode and decode.
Your application supplies the bytes and handles transport I/O and routing.

## Install

Python 3.11 or newer is required. Install from the source checkout:

```bash
git clone https://github.com/nidops/structwire.git
cd structwire
python -m pip install .
```

Version `0.1.0` is an alpha API. PyYAML is installed automatically for YAML loading.

## Quick start

```python
from structwire import Field, Layout

codec = Layout(
    Field("temperature_c", "i16le", scale=0.1),
    Field("state", "u8"),
).compile()

payload = codec.encode({"temperature_c": 23.5, "state": 1})
assert payload == bytes.fromhex("eb 00 01")
assert codec.decode(payload) == {"temperature_c": 23.5, "state": 1}
```

Compile a layout once and reuse its codec.

## YAML example

Save this as `codecs.yaml`:

```yaml
version: 1
codecs:
  node_status:
    size: 4
    fields:
      - name: mode
        type: enum
        values: {0: asleep, 1: awake, 2: fault}
      - name: supply_voltage
        type: uint16_le
        offset: 2
        scale: 0.001
        unit: V
```

```python
from structwire import catalog_from_yaml

catalog = catalog_from_yaml("codecs.yaml")
payload = bytes.fromhex("01 00 88 13")
values = catalog.decode("node_status", payload)
assert values == {"mode": "awake", "supply_voltage": 5.0}
assert catalog.encode("node_status", values) == payload
```

Offsets and sizes are in bytes. Here, byte 1 is unused and encodes as zero.
`unit` is display metadata; it does not change the conversion.

## Supported layouts

- Signed and unsigned 8/16/24/32/64-bit integers, with explicit byte order.
- IEEE-754 32/64-bit floats, BCD, fixed ASCII, bytes and MAC addresses.
- Enums, named flags, booleans and masked sub-fields.
- Numeric scaling and bias, explicit offsets and optional total payload size.
- Immutable layouts and reusable compiled codecs, with exact-length decoding by default.
- Named catalogs and single-layout loaders for YAML or Python mappings.

## Limitations

Unscaled integers preserve their full range, including 64-bit values. Scaling uses
Python floats, so some values cannot be represented exactly. Integer encoding
rejects values between raw counts, allowing small rounding errors; decoding raises
`DecodeError` if scaling loses the original count. For exact arithmetic, decode
unscaled integers and convert them in your application.

Encoding zeroes unused bytes and bits, encodes booleans as 0 or 1, and writes only
declared masks from flags mappings. Arbitrary payloads may therefore change after
decoding and re-encoding. See the
[compatibility contract](https://github.com/nidops/structwire/blob/master/docs/COMPATIBILITY.md)
for precise round-trip and floating-point guarantees.

Variable-length fields, nested/repeated layouts and checksums are not supported.

Schemas are trusted configuration. Safe YAML loading does not impose resource
limits; applications must bound untrusted schema and payload sizes. See
[schema resource limits](https://github.com/nidops/structwire/blob/master/docs/SCHEMA.md#trusted-schemas-and-resource-limits).

## Documentation and examples

- [Python API](https://github.com/nidops/structwire/blob/master/docs/API.md)
- [Schema reference](https://github.com/nidops/structwire/blob/master/docs/SCHEMA.md)
- [Examples](https://github.com/nidops/structwire/tree/master/examples)
- [Questions and bug reports](https://github.com/nidops/structwire/issues)

MIT. See [LICENSE](https://github.com/nidops/structwire/blob/master/LICENSE).
