You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
(#56) [breaking] make encode_int infallible, fold stream::int_to_b64 into it
(#56) consolidate base64 alphabet to one canonical table
Added
api (#68):SerializedEvent::identifier() -> Option<Identifier<'static>>
bridge for chaining KEL events — hands an inception's self-addressing prefix to
the next builder without re-parsing JSON.
(#68)
api (#68):Clone for Matter (all primitive aliases) and Identifier.
(#68)
docs (#68): examples kel_chain (a real icp -> ixn -> rot self-addressing
chain) and delegated_inception (a self-addressing delegator), closing #32
examples #5/#6.
(#68)
devx (#31): ergonomic public surface — flagship types are now reachable at
the crate root (cesr::Matter, cesr::Verfer, cesr::CesrGroup, …) and at
their module root (cesr::core::Matter), and a new cesr::prelude re-exports
the common traits (CesrEncode, KeriSerialize/KeriDeserialize, Algorithm, ConfigTrait) plus headliner types for use cesr::prelude::*;. Purely
additive — existing module paths are unchanged. The one name collision, CesrVersion, is disambiguated at the root as cesr::CesrVersion (core) and cesr::StreamCesrVersion (stream). Free functions remain module-qualified
(cesr::b64::encode_int).
bench (#29):benches/base64.rs — isolated base64-crate URL_SAFE_NO_PAD
microbenchmarks at 32/64/1024 B, the reference baseline for the Base64 inner
loop. Investigation outcome: a specialized scalar codec and stack-buffer
allocation removal were both implemented and measured end-to-end, and both regressed (decode +8–16 %, encode +6 %). At CESR sizes the encode/decode
seams are already overhead-bound on the fast base64 engine plus thread-cached
small allocations — no faster codec is available, so no production change ships.
See #29 for the full measurement table.
test/ci (#30): zero-copy safeguards — tests/allocation.rs (thread-local
counting allocator) asserting group-iteration allocations stay invariant to
group count, so a regression to per-group copying fails the suite; per-shape
aliasing tests proving parsers slice rather than copy; full GroupsV2 iterator
coverage; a stream_parse_scaling benchmark (N = 1..256 groups); cargo-mutants
in the dev shell for on-demand mutation testing (core stream logic: 100% of
non-equivalent mutants killed); and on-demand llvm-cov coverage via nix build .#coverage plus a post-merge workflow (mirrors the bombay repo).
None of these are gating checks. QuadletGroup::to_bytes() — O(1) shared-buffer
accessor.
bench (#64):examples/concurrent_parse.rs — a reproducible concurrent-parse
allocation-payoff harness (run: cargo run --release --example concurrent_parse --features stream) answering the #30 follow-up "does the allocation reduction
actually pay off?". It pits two real, public production arms parsing the same
16-group stream: copy-once groups() (2 allocs/stream) vs a parse_group()
loop that faithfully reproduces the pre-#30 per-group copy (32 allocs/stream,
plus O(N²) remainder re-copying — exactly origin/main's behavior). A
single-threaded armed counting allocator self-checks the 1-vs-N invariant before
any timing; the timed passes run disarmed across 1/2/4/8 threads so instrumentation
never perturbs wall-clock. Verdict: VINDICATED. On a 14-core Apple M-series
(release): copy-once/per-group throughput ratio 2.52× / 1.88× / 3.25× / 3.88× at
1/2/4/8 threads — copy-once wins at every thread count and the gap widens under
contention (per-group scales only ~4.2× across an 8× thread increase — the
allocator-contention signature). This does not contradict #30's single-thread
regression note below: that used a 2-group fixture where O(N²)≈O(N) so the copy
savings vanish; the win here needs both a larger group count and the faithful
O(N²) origin/main baseline. Numbers are wall-clock and machine-dependent — the
harness is a run-and-read measurement, not a CI gate.
Changed
api (#68)!:RotationBuilder::prefix, InteractionBuilder::prefix, DelegatedInceptionBuilder::delegator, and DelegatedRotationBuilder::prefix
now take impl Into<Identifier<'static>> instead of Prefixer<'static>.
Existing Prefixer call sites keep compiling; self-addressing (transferable)
prefixes and delegators are now expressible, closing the write-path/read-path
parity gap for both the direct (icp -> ixn -> rot) and delegated
(dip -> drt) KEL chains.
(#68)
perf (#30): stream group parsing now slices a shared bytes::Bytes instead
of Bytes::copy_from_slice, trading a small amount of per-parse CPU (Arc
refcounting + a level of indirection) for fewer heap allocations — the
intended benefit for allocator-pressure / fragmentation / no_std. Allocation
count per multi-group message drops from ~N to 1 (0 on the async codec's
non-quadlet decode path, which is now zero-copy on success). unwrap_generic_group
and Groups/GroupsV2 slice a once-copied region instead of re-copying. Public parse_group / parse_group_v2 / parse_message / groups / groups_v2
signatures are unchanged — non-breaking. This is not a throughput win.
Measured cost (accepted, since fewer allocations is the goal): parsing is ~22–28 % slower on small streams — CodSpeed on this PR: controller_idx_sigs_1sig −27.7 %, multi_group_controller_witness −21.7 %; the
fixed overhead amortizes toward parity as stream size grows (per-group cost is
~equal to main at N≥16 groups). Borrowed Matter<'a> and a parser-combinator
crate were evaluated and deliberately not adopted (see the issue).
(#30)
Changed
refactor (#57)!: Killed the remaining "utils" dumping grounds. stream::util
is removed (its int_to_b64/b64_to_int now route through b64::encode_int / b64::decode_int); core::utils's code-size lookups moved to core::matter::code::hard; stream::binary is renamed stream::qb2 (public stream::qb64_to_qb2/qb2_to_qb64 paths unchanged). The single Base64 byte
lookup is b64::alphabet::b64_byte_to_index.
Breaking
RotationBuilder::prefix / InteractionBuilder::prefix / DelegatedInceptionBuilder::delegator / DelegatedRotationBuilder::prefix now
take impl Into<Identifier<'static>> instead of Prefixer<'static> (#68).
b64::decode_to_int → b64::decode_int (input bound widened to AsRef<[u8]>).