v0.21.0
MESSAGE_SPEC §2/§3/§5.1, family-wide. This release lands the generator half of
sofa-buffers/documentation#29 together with corelib 0.9.0 in all eleven
corelibs — they must be used together.
The wire changes
An all-default sequence is omitted, not framed empty (§2). A struct/union/array
field whose value equals its declared default disappears from the wire; absence
reconstructs it. An all-default message is zero bytes.
count is a capacity, not a length (§3). A field declared count: N may carry
0 .. N elements; N never reaches the wire, and the wire count M is the
array's length. [1,2,3,0,0] and [1,2,3] are different values. The
trim-on-encode / fill-on-decode pair that generated code shipped until now is gone.
Wrapper-array elements are sparse in the interior, and the last one is always
written (§2/§5.1). The element id is the array index, so the decoded length is
highest present id + 1 — which makes the rule follow from a single fact: nothing
that carries the length may be elided, and everything else may be. An interior
element equal to its element default is omitted and leaves an id gap (a string/
blob is not written, a struct/union element is not framed either); the
element at the highest index is always written, a leaf as its value and a sequence
element as an empty frame.
Fixes
- #247 — wrapper elements were appended rather than placed at their id, so an
interior id gap shifted every later element and a reopened id became a second
element instead of merging (§7.4). Ten backends were affected. - #250 — the cpp backend emitted non-compiling code for
array<array<string|blob|struct>>
on both C++ legs; the row container went to a collector that only accepts leaf
elements. - #246 — the Python and TypeScript
FixlenSubtypeimport gates missed
wrapper-array elements, so generated code referenced a symbol it never imported. - #249 — a §7.3 mistyped child left a phantom default element in a C++ struct array.
- #248 — closed with a comment: the defect it reports is fixed, but by the
opposite mechanism to the one it requested, because the spec turned mid-flight.
Also fixed along the way, all found while verifying the above: a memory-corruption
bug in generated C++ (corelib: c-cpp with allow_dynamic: true reinterpreted a
std::vector's own pointers as an enum/boolean array's first elements, so wire bytes
overwrote the heap pointer that was later freed); an unbounded nested-row decode in
Rust; missing over-count enforcement on nested native rows in Python; and id-blind
row collectors that shifted every later row once interior gaps became reachable.
Storage
Targets whose count: N array lowered to a fixed-size type could not express a value
shorter than N. The C backend now carries an explicit length for every compact array
and every wrapper holder, and the C++ backend uses length-carrying containers on all
three profiles. Both C++ storage modes therefore agree on the wire again.
Verification
go test ./..., all ten conformance suites, and CI green against the merged
corelibs on main — not against the development branches. The shared vector set grew
to 81 and is byte-identical in all eleven corelib repos.
What's Changed
- fix(rust): provision full wire-type feature set for the no-std decoder (#215) by @Andste82 in #217
- chore(docs): remove the c-cpp embedded-footprint plan doc by @Andste82 in #218
- fix(rust): over-count arrays reject at the count header so INVALID dominates truncation (#216) by @Andste82 in #219
- fix(python): over-count arrays reject at the count header so INVALID dominates truncation (#216) by @Andste82 in #220
- fix(zig): over-count arrays reject at the count header so INVALID dominates truncation (#216) by @Andste82 in #221
- fix(go,dart,ts): reject over-bound arrays/strings at the header so INVALID dominates truncation (#216) by @Andste82 in #222
- fix(cpp): install a measure-phase schema so over-bound+truncated is INVALID (#216) by @Andste82 in #223
- fix(dart,go): gate the maxlen header guard on the declared fixlen subtype (#224) by @Andste82 in #225
- fix(dart): preserve fp32 signaling NaN bit-for-bit (#226) by @Andste82 in #227
- fix(cpp): gate the measure-phase maxlen bound on the declared fixlen subtype (#229) by @Andste82 in #231
- fix(cpp): derive the reassembly cap from byte spans, not element counts (#228) by @Andste82 in #234
- docs: cross-corelib decode reader-model reference by @Andste82 in #230
- feat(cpp): §7.3 moves into the corelib reads, and allow_dynamic becomes a storage choice by @Andste82 in #237
- docs(generator): the per-target pages describe per-target options only by @Andste82 in #240
- feat: allow_dynamic selects the container; one worst-case size walk for every backend by @Andste82 in #241
- feat(rust): generated code can reach the corelib's streaming, both directions by @Andste82 in #242
- feat(c): expose the corelib's streaming, and close the last test gaps by @Andste82 in #243
- docs(npm): give the npm README pages the project header and logo by @Andste82 in #245
- fix(all): wrapper-array element placement, refill to N, and trailing-run trim (#246–#250) by @Andste82 in #252
- feat!: MESSAGE_SPEC §2/§3/§5.1 — omit all-default sequences, and
countis a capacity by @Andste82 in #244
Full Changelog: v0.20.0...v0.21.0