Expand description
§tsoracle-codec
The one version-prefixed postcard codec shared across tsoracle — every persisted blob is framed as [version_byte | postcard(value)] so an on-disk layout change fails loudly instead of misdecoding.
§Why it exists
Both consensus toolkits (tsoracle-paxos-toolkit, tsoracle-openraft-toolkit) carried a near-identical encode/decode/CodecError copy of this framing. Every persisted struct — a Ballot, a HighWaterCommand log entry, a snapshot, a Raft log record — is stamped with a leading schema-version byte; a node upgraded mid-flight that reads prior-version bytes hits a structured version mismatch rather than silently parsing them against a new struct layout. This crate is the single home for that framing.
§What’s in the box
encode(version, value)— serializesvaluewithpostcardand prependsversion, yielding[version | postcard(value)].decode(expected_version, bytes)— checks the leading byte againstexpected_version(returningCodecError::Versionon mismatch) before deserializing the body, and rejects any bytes left unconsumed past a valid body withCodecError::TrailingBytesrather than silently discarding them.CodecError—Empty,Version { expected, actual },Encode(postcard::Error),Decode(postcard::Error),TrailingBytes { extra }. Encode and decode failures are kept distinct, and the underlyingpostcard::Erroris carried as the error source (noFromconversion) so a stray?never silently becomes aCodecError.TrailingBytesflags surplus bytes after an otherwise-valid body — for a format that exists to catch drift, garbage appended by a partial overwrite is a corruption signal, not noise to drop.codec_io_error(context, err)— maps aCodecErrortostd::io::Errorfor consumers whose trait surface speaksio::Error(the openraftRaftLogStorage/RaftStateMachineimpls). AVersionmismatch becomesErrorKind::InvalidDataso a foreign-schema record is distinguishable from a generic decode failure;contextis prefixed onto the message so the failing boundary is identifiable. Shared so the mismatch-to-InvalidDatacontract can’t drift between those impls.
The schema-version number is deliberately not owned here. version is a parameter, so each consumer keeps its own SCHEMA_VERSION constant and evolves its on-disk format independently of the others.
§Quick reference
# consumer Cargo.toml
[dependencies]
tsoracle-codec = { workspace = true }// Each consumer owns its own schema version.
pub const SCHEMA_VERSION: u8 = 1;
let framed = tsoracle_codec::encode(SCHEMA_VERSION, &value)?;
let value: MyType = tsoracle_codec::decode(SCHEMA_VERSION, &framed)?;Bump the consumer’s SCHEMA_VERSION when a persisted struct’s postcard layout changes in a backward-incompatible way (field reorder/insert/remove); a stale reader then fails with CodecError::Version instead of misdecoding.
§Related
postcard— the compactserdewire format this frames.tsoracle-failpoint,tsoracle-yieldpoint— the other shared micro-crates that exist so a single behavior is not duplicated across the workspace.
Enums§
- Codec
Error - Failure modes of the version-prefixed postcard codec.
Traits§
- Versioned
Codec - A type whose persisted and on-wire representation is versioned.
Functions§
- codec_
io_ error - Map a
CodecErrorto anio::Error, tagging the message withcontextso the failing boundary is identifiable. - decode
- Decode a payload produced by
encode, rejecting a version mismatch. - decode_
framed - Decode a
[version | body]payload, rejecting a version outside the reader’s supported range[min_version, max_version]withCodecError::VersionUnsupportedbefore any body parse. An in-range version is dispatched toVersionedCodec::decode_version, up-converting older layouts into the current type. - decode_
postcard_ exact - Deserialize a bare postcard body, rejecting surplus trailing bytes. A
versioned format that exists to catch drift treats trailing garbage as
corruption (e.g. a partial overwrite), not a clean record. Used by
VersionedCodec::decode_versionimplementations per version. - encode
- Encode
valueas[version | postcard(value)]. - encode_
framed - Encode
valueas[version | body], wherebodyisvalue’s layout atversion(seeVersionedCodec::encode_version). - encode_
postcard - Serialize
valueto a bare postcard body (no version prefix). Used byVersionedCodec::encode_versionimplementations per version.