Serdde is format-neutral typed serialization for Dudu. Derive macros generate ordinary Dudu methods that write directly to, and read directly from, a wire protocol. Typed JSON, CBOR, and DSON operations do not construct an intermediate dynamic tree.
from serdde.json import dumps
from serdde.json import loads
from serdde.macros import Serde
@derive(Serde)
class Player:
id: u64
name: str
scores: list[i32]
player = Player(id=7, name="Ada", scores=[2, 3, 5])
encoded = dumps(player)
decoded = loads[Player](encoded.value)@derive(Serde) uses Dudu's public macro AST. The Dudu compiler contains no
Serdde registry, format logic, package-name check, or native-library special
case. Generated methods are normal checked Dudu code and can be inspected with
duc expand.
From Git:
[deps]
serdde = { git = "https://github.com/dudu-language/serdde.git", branch = "master" }For local development:
[deps]
serdde = { path = "../serdde" }dudu build, dudu run, and dudu test fetch missing Git dependencies. The
resolved commit is recorded in dudu.lock.
| Format | Typed modules | Dynamic module | Intended use |
|---|---|---|---|
| JSON | serdde.json |
serdde.json_value |
Text interchange and APIs |
| CBOR | serdde.cbor |
serdde.cbor_value |
Compact deterministic binary interchange |
| DSON | serdde.dson |
serdde.dson_value |
Exact typed text for debugging and tests |
Each typed format provides dumps, loads[T], dumps_into, dumps_with,
loads_with, and dumps_into_with. The _with forms apply an explicit adapter
to a standalone value. Field adapters use @Serde(adapter="AdapterName").
Dynamic data is an explicit choice. Import Value from serdde.value, convert
typed values with serdde.convert, or parse/write a tree through a format's
*_value module. Dynamic operations use the same serializer/deserializer
protocol as an ordinary backend; they are not underneath typed wire calls.
| Area | Behavior |
|---|---|
| Derives | Serialize, Deserialize, and Serde for classes, generic classes, enums, and recursive models |
| Scalars | bool, char, signed and unsigned integers, usize, f32, f64, and str |
| Containers | list, set, string-keyed dict, arbitrary-rank fixed arrays, Option, Result, and variant |
| Enums | unit and named-payload variants; external, internal, adjacent, and untagged representations |
| Configuration | rename rules, aliases, defaults, directional skips, predicates, flattening, and unknown-field policy |
| External types | direct field and top-level adapters, including imported C++ templates |
| Errors | stable kinds, field/index paths, format names, and source positions |
| CBOR schemas | deterministic name-keyed maps and explicit stable compact integer field IDs |
Raw pointers and references are not serialized implicitly. Their ownership and identity require a handwritten codec or adapter.
JSON typed reads use yyjson behind a private reader boundary. Object entries are indexed once and decoded directly into destination fields. JSON writes use a small direct writer with checked UTF-8, escaping, integer conversion, and finite-float policy. simdjson On-Demand, RapidJSON SAX, yyjson, Glaze, and nlohmann/json are retained in the reproducible candidate matrix. The production reader/writer choice is based on complete Serdde typed operations, not parser-only or writer-only microbenchmarks.
CBOR follows RFC 8949. Typed classes use deterministic maps whose default keys
are serialized field names. @Serde(compact=True) uses explicit field IDs;
IDs are never derived from declaration order, hashes, native offsets, or ABI
layout. Golden bytes and Rust ciborium interoperability are tested.
DSON distinguishes signed integers, unsigned integers, and floats in text. It implements the same direct protocols and is useful when exact categories need to be visible.
Run the normal local validation suite:
./scripts/test_all.shValidate only the standalone CMake entry point:
./scripts/test_cmake.shValidate clean path consumption, or an exact published Git revision:
./scripts/test_package_consumers.sh
./scripts/test_package_consumers.sh --git-ref REVInspect generated code:
duc expand examples/basic.dd --show-originsRun all equivalent benchmark smoke cases:
./scripts/bench_wire.sh --smokeRun and publish the complete benchmark matrix separately:
./scripts/bench_wire.sh --all --publishThe matrix covers Serdde direct, Serdde Value, Rust Serde, yyjson, simdjson
On-Demand, RapidJSON SAX, nlohmann/json, and Glaze across JSON and CBOR where
supported. It records latency, throughput, allocations, allocated bytes, peak
RSS, wire size, binary size, generated C++ size, and cold/warm compilation
cost.
- API
- Architecture
- Configuration
- Wire formats
- Schema evolution
- Generated code
- Editor behavior
- Benchmarks
- Direct-wire design and delivery record
Apache-2.0 OR MIT.