Skip to content

v0.3.0

Choose a tag to compare

@devrandom-release-plz devrandom-release-plz released this 03 Jul 21:53
bc9a75a

Added

  • (#68) [breaking] self-addressing builder prefixes (write/read parity) (#71)
  • (#31) prelude + flattened re-exports (#66)

Other

  • (#32) runnable examples for the primitive→event walk-through (#70)
  • (#64) reproducible concurrent-parse allocation-payoff harness (#65)
  • (#30) zero-copy stream parsing + test/coverage/mutation safeguards (#63)
  • (#57) kill the utils dumping grounds + cohesive b64 (naming + error de-collision) (#62)
  • (#29) add isolated base64-crate baseline; no faster codec found (#61)
  • (#57) include stream in the no_std flake build
  • (#57) [breaking] split b64 module into int/binary/charset
  • (#57) [breaking] rename utils module -> b64, kill utils::utils inception
  • (#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_intb64::decode_int (input bound widened to AsRef<[u8]>).
  • core::indexer::error::{ParseError, ValidationError}
    {IndexerParseError, IndexerValidationError}.
  • stream::util module removed; stream::binary module renamed stream::qb2
    (re-exported functions keep their stream:: paths).