Releases: sofa-buffers/generator
Release list
v0.23.0
What's Changed
- fix(dart): a string-free scope must skip a string, not validate it (§6.4) by @Andste82 in #269
- fix(all but c/c-cpp): the declared integer width is a validity bound (#266) by @Andste82 in #274
- fix(rust,zig,java,csharp,dart): a skip is scoped and inert (#268 #270 #271 #272 #273) by @Andste82 in #276
- fix(dart): the fp32 raw-bits companion must be consumer-visible (#275) by @Andste82 in #278
- fix(bench): repair the two recipes that made rust-no-std and dart unmeasurable by @Andste82 in #280
- fix(cpp): arm readArray's element-width bound (#279) by @Andste82 in #281
- fix(bench): warm up the go harness before the collected op by @Andste82 in #282
- feat(bench): measure allow_dynamic, and record which python engine ran by @Andste82 in #284
- feat(bench): measure corelib-py's accelerator as its own row by @Andste82 in #285
- fix(rust): stack only live scopes, so a deep skip can't lose the field after it (#283) by @Andste82 in #286
- fix(cpp): compile the harness JSON reader as C, so clang can build the project by @Andste82 in #287
- refactor(cpp): guard an empty default with empty(), not a comparison by @Andste82 in #288
- feat(cpp)!: allow_dynamic selects storage on corelib: cpp too by @Andste82 in #289
- fix(c): don't double the " * " prefix in generated doc comments by @Andste82 in #290
- feat!: align the generated encode/decode API — public feed(), one streaming-encode name by @Andste82 in #291
- feat(typescript)!: chunked decode via decoder()/feed() by @Andste82 in #292
- fix(zig): a reassembled payload gets its own storage, not the shared buffer (#293) by @Andste82 in #294
- fix(zig)!: the streaming decoder owns its payloads, it cannot borrow (#295) by @Andste82 in #296
- fix(typescript): malformed UTF-8 leaves feed() as SofabError, not a TypeError (#297) by @Andste82 in #298
- feat(rust): allow_dynamic selects storage on corelib: rs too by @Andste82 in #299
- fix(typescript): the streaming visitor must test an array's element kind before bounding it (#300) by @Andste82 in #301
- chore(bench): regenerate results.txt from a full run by @Andste82 in #302
- feat(all): state a field's schema bound in its own doc comment by @Andste82 in #309
- fix(java): a schema type is a public class in its own file by @Andste82 in #310
- docs(rust): no_std: false also changes the crate shape by @Andste82 in #311
- fix(typescript): take the fixlen maxlen verdict at the length word by @Andste82 in #303
- fix(typescript): latch an array element's declared width at that element (#267) by @Andste82 in #304
- fix(go,dart,python): latch a schema bound at the word that carries it (#267) by @Andste82 in #277
- docs: record where a schema bound is latched, per backend (#267) by @Andste82 in #313
- docs: two CORELIB_PLAN rules went normative; record them and pin the evidence by @Andste82 in #314
- test(dart): take trydecode's first line with sed, not head by @Andste82 in #315
- feat(go): decode straight out of an io.Reader via AcceptStream (#312) by @Andste82 in #316
- test(rust): give rs-static a streaming leg (#306) by @Andste82 in #317
- fix(typescript): keep an fp32 array element's wire bits on the visitor path (#300) by @Andste82 in #318
- fix(rust,java,csharp,zig): latch a fixlen bound at its length word (#267) by @Andste82 in #319
- fix(typescript): a wrapper element's maxlen goes into the reader (#300) by @Andste82 in #320
- fix(go,dart,python): latch an array element's declared width at that element (#267) by @Andste82 in #321
- fix(rust): install an OStream through the fallible constructor by @Andste82 in #328
- docs(architecture,zig): heap-free field storage is a stated backend axis (#323) by @Andste82 in #324
- feat(go,python,typescript,dart)!: the caller owns the encode buffer by @Andste82 in #329
- fix(go,dart): guard a nested array row's element width by @Andste82 in #331
- fix(cpp): encode() must not cap an unbounded message at the ceiling by @Andste82 in #332
- fix(python): declare a schema-bounded field so the receiver cap stops binding it by @Andste82 in #333
- perf(java)!: the array path — decode -25% on the array-heavy shape by @Andste82 in #334
- perf(typescript): close the protobufjs gap on decode; fix bigint fields holding numbers by @Andste82 in #335
- bench: make the int64 axis measurable, and guard against a row that cannot (#336) by @Andste82 in #337
- feat(kotlin): an eleventh target, against corelib-kotlin-mp by @Andste82 in #340
- chore(deps): update gradle/actions action to v6 by @renovate[bot] in #341
- devcontainer: a kotlinc for the review corpus by @Andste82 in #342
- feat(typescript)!: int64 long backs u64/i64 scalars with Long, and the push decoder takes corelib's Long channel by @Andste82 in #343
- docs(architecture): §8 says where a static helper lives, by its shape by @Andste82 in #346
- docs(architecture): §8 asks for no version floor; API_VERSION cannot express one by @Andste82 in #347
- perf(typescript): take corelib's Long channel on the push decoder where it pays by @Andste82 in #348
- generator: emit the helper blocks only where something calls them by @Andste82 in #349
- refactor(go)!: emit sofab.UTF8Valid, the corelib's initialism-correct name by @Andste82 in #350
- refactor(zig)!: emit sofab.utf8Valid, the corelib's camelCase spelling by @Andste82 in #351
- fix(typescript): a nested row's element carries its declared width on the push path too by @Andste82 in #353
- refactor(zig)!: take the corelib's arrays.at instead of emitting the cast by @Andste82 in #354
- refactor(go)!: take corelib-go's collectors instead of emitting them (#345) by @Andste82 in #356
- refactor(java)!: take corelib-java's support layer instead of emitting it by @Andste82 in #357
- refactor(typescript)!: call the corelib's generated-layer helpers, stop emitting copies by @Andste82 in #359
- refactor(csharp)!: take the corelib's decode-side support helpers by @Andste82 in #360
- refactor(rust)!: take the corelib's PayloadAcc instead of emitting the accumulator by @Andste82 in #361
- refactor(cpp)!: take the corelib's MessageSeq instead of emitting WrapperSeq by @Andste82 in #362
- refactor(zig)!: take the corelib's support types instead of emitting them by @Andste82 in #363
- refactor(dart)!: reject through MessageVisitor.invalidate(), not a flag of our own by @Andste82 in #355
- refactor(kotlin)!: take the corelib's support layer instead of emitting Sbuf.kt by @Andste82 in #358
- refactor(dart)!: take the corelib's visitor base, list compare and strict UTF-8 by @Andste82 in #364
- refactor(dart)!: take the corelib's element collectors by @Andste82 in #365
- refactor(go)!: decline an unknown subtree instead of no-op'ing through it by @Andste82 in #366
- refactor(typescript)!: decline an unknown subtree instead of routing it to _DEAD ...
v0.22.0
What's Changed
- fix(rust,java,csharp): resolve the string destination before validating UTF-8 (§6.4) by @Andste82 in #258
- test(cpp): the over-index reject fires from the fixlen word, not the element header by @Andste82 in #261
- fix(all push-API backends): key a fixlen array's decode arm by element subtype (§4.8) by @Andste82 in #260
- chore(ci): drop the corelib pins now that the F-0042 corelibs are on main by @Andste82 in #262
- fix(go,dart): validate a string at its destination, never on a skip (§6.4) by @Andste82 in #263
- chore(ci): drop the corelib pins now that the F-0038 corelibs are on main by @Andste82 in #264
Full Changelog: v0.21.1...v0.22.0
v0.21.1
Two decode defects found by Crucible against the
0.21.0 / corelib 0.9.0 family. Both are generated-code fixes; no corelib change is needed,
and 0.21.1 works with the same corelib 0.9.0.
#235 — TypeScript quieted an fp32 signaling NaN
Generated TypeScript round-tripped an fp32 through a JS number (a 64-bit double), which turns
0x7F800001 into 0x7FC00001 — a violation of MESSAGE_SPEC §4.6, which requires a bit-for-bit
float round-trip with no normalization. It was the last of the thirteen drivers still doing this.
Decode now reads the wire bytes through corelib-ts's raw channel and keeps them beside the
convenience number; encode re-emits them verbatim while a hand-set value always wins.
Generated-API note: each fp32 scalar and native fp32[] gains a companion
<name>Fp32Raw: Uint8Array | null, non-null only when the decoded value was a NaN. The value API
is unchanged, presence (§2) still reads the value alone, and the JSON harness is byte-identical —
a NaN renders as null there, which is exactly why JSON could not catch this.
Known limit: an fp32 row nested inside a wrapper array (array<array<fp32>>) still widens; a
row has no field of its own to carry the companion.
#254 — java and csharp sized a skipped array from its own header
A native array field whose header carries the wrong array wire type must be skipped under §7.3.
Both backends skipped the elements but still resized the declared field from the skipped header's
count, so the field ended up holding a one-element array the wire never carried — the length
leaked, not the element. Eleven of thirteen implementations were already correct.
Two causes, both fixed: the skip arm folded UNSIGNED and SIGNED into one case, so a mistyped
header disarmed the discard counter instead of arming it; and the allocation block ran regardless
of the wire kind. The kind check now also precedes the schema-count bound, so an over-count
mistyped array is no longer a false INVALID — §7.3 applies the bound only to a field that
survives it.
Verification
Both fixes reproduce the defect on the pristine 0.21.0 tree first, with real bytes through the
generated harnesses, and both add a conformance leg that was independently shown to fail before
the fix — neither defect had anything exercising it, which is why they survived.
What's Changed
- fix(typescript): fp32 signaling NaN survives a round-trip (#235) by @Andste82 in #255
- fix(java,csharp): a §7.3-mistyped array must not size the declared field (#254) by @Andste82 in #256
Full Changelog: v0.21.0...v0.21.1
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
v0.20.0
What's Changed
- docs(npm): make the package README user-facing; move publishing to PUBLISHING.md by @Andste82 in #210
- feat(dart): add Dart target backend against corelib-dart by @Andste82 in #211
- ci: publish all sofabgen binaries as an artifact on every push to main by @Andste82 in #212
- ci: upload main-branch binaries per-platform, matching the release workflow by @Andste82 in #213
- devcontainer: install the Dart SDK (+ unzip) and ripgrep by @Andste82 in #214
Full Changelog: v0.19.7...v0.20.0
v0.19.7
What's Changed
- docs(release): warn that release.yml's name is the npm OIDC identity by @Andste82 in #208
- dist(npm): give each platform package a README pointing to the main package by @Andste82 in #209
Full Changelog: v0.19.6...v0.19.7
v0.19.6
What's Changed
- chore(deps): update actions/checkout action to v7 by @renovate[bot] in #195
- chore(deps): update dependency node to v24 by @renovate[bot] in #198
- chore(deps): update actions/setup-node action to v7 by @renovate[bot] in #196
- dist(npm): trusted publishing (OIDC) instead of token by @Andste82 in #197
- release: make the git tag the single source of truth for the version by @Andste82 in #199
- fix(#193): skip an fp array delivered to a scalar-declared fp id (§7.3) by @Andste82 in #202
- chore(renovate): stop bumping the generator-- pins by @Andste82 in #207
Full Changelog: v0.19.5...v0.19.6
v0.19.5
What's Changed
Full Changelog: v0.19.4...v0.19.5
v0.19.4
What's Changed
- build(devcontainer): add .NET 10 SDK and ARM newlib for the bench toolchain by @Andste82 in #187
- fix(codegen): §7.3 wrapper-element skip (both directions) + §5.2 INVALID precedence (#188, #189, #190) by @Andste82 in #191
- release: v0.19.4 by @Andste82 in #192
Full Changelog: v0.19.3...v0.19.4
v0.19.3
What's Changed
- fix(bench): pin zig/csharp codegen ISA so the Bench workflow can measure them by @Andste82 in #182
- fix(decode): §7.3 — skip an integer array delivered to a scalar id (#183) by @Andste82 in #184
- chore(deps): update actions/setup-python action to v7 by @renovate[bot] in #185
- release: v0.19.3 by @Andste82 in #186
Full Changelog: v0.19.2...v0.19.3