dyn_encoding/lib.rs
1//! Wire-format codec abstraction for the Riak protocol layer.
2//!
3//! `dyn-encoding` defines a small, object-safe trait surface that lets
4//! a single connection negotiate between a number of structured
5//! encodings on a per-request basis. The crate ships baseline
6//! implementations for all seven encodings called out in the brief:
7//!
8//! * [`JsonCodec`] -- `application/json` (via `serde_json`)
9//! * [`CborCodec`] -- `application/cbor` (via `ciborium`)
10//! * [`ProtobufCodec`] -- `application/x-protobuf` (via `prost`)
11//! * [`FlatbuffersCodec`] -- `application/octet-stream;schema=flatbuffers`
12//! (via `flatbuffers`)
13//! * [`CapnpCodec`] -- `application/capnproto` (via `capnp`)
14//! * [`BebopCodec`] -- `application/x-bebop` (via `bebop`)
15//! * [`BsonCodec`] -- `application/bson` (via `bson`)
16//!
17//! Schema-first codecs (protobuf, FlatBuffers, Cap'n Proto, Bebop)
18//! reify bytes through per-type traits exported alongside each
19//! codec ([`FlatbuffersWire`], [`CapnpWire`], [`BebopWire`]; the
20//! protobuf codec uses `prost::Message` directly). Schema-less
21//! codecs (JSON, CBOR, BSON) reuse `serde::Serialize +
22//! DeserializeOwned`. The trait surface is shaped so adding an
23//! eighth codec is a mechanical exercise: a new module under
24//! `codec/`, a new `register` entry point bounded on the codec's
25//! native trait, and a single line in
26//! [`CodecRegistry::with_baseline`].
27//!
28//! # Two-layer design
29//!
30//! The codec abstraction is split into two cooperating traits:
31//!
32//! 1. [`WireValue`]: implemented by the structured types that travel
33//! on the wire. Provides a stable [`WireTypeId`] for content-type
34//! plus type negotiation.
35//! 2. [`ErasedWireValue`]: an object-safe view over `WireValue` so
36//! codec implementations can take `&dyn ErasedWireValue` without
37//! being generic. A blanket impl on every `T: WireValue` makes
38//! this transparent at call sites.
39//!
40//! Each codec is itself object-safe via the [`WireCodec`] trait,
41//! so [`CodecRegistry`] can store a heterogeneous bag of codecs
42//! and look one up by content-type.
43//!
44//! # Per-codec type registration
45//!
46//! Schema-first codecs (protobuf today, FlatBuffers / Cap'n Proto /
47//! Bebop tomorrow) require knowing the concrete message type to
48//! reify bytes. Schema-less codecs (JSON / CBOR / BSON) could in
49//! principle dispatch through `erased_serde`, but doing so would
50//! diverge from the schema-first path. To keep all codec impls
51//! shaped the same way, every codec carries an internal
52//! per-[`WireTypeId`] registration table populated through the
53//! codec's own `register::<T>()` entry point.
54//!
55//! # Example
56//!
57//! ```
58//! use dyn_encoding::{
59//! CodecRegistry, ErasedWireValue, JsonCodec, WireTypeId, WireValue,
60//! };
61//! use serde::{Deserialize, Serialize};
62//!
63//! #[derive(Debug, Default, Deserialize, PartialEq, Serialize)]
64//! struct GetReq {
65//! bucket: String,
66//! key: Vec<u8>,
67//! timeout_ms: u32,
68//! }
69//!
70//! impl WireValue for GetReq {
71//! fn wire_type_id() -> WireTypeId {
72//! WireTypeId::new("riak.GetReq")
73//! }
74//! }
75//!
76//! // Build a codec, register the message type, install into a
77//! // registry keyed by content-type.
78//! let mut json = JsonCodec::new();
79//! json.register::<GetReq>();
80//!
81//! let mut registry = CodecRegistry::new();
82//! registry.register(json);
83//!
84//! let codec = registry
85//! .for_content_type("application/json")
86//! .expect("json codec is registered");
87//!
88//! let req = GetReq {
89//! bucket: "bk".into(),
90//! key: b"k".to_vec(),
91//! timeout_ms: 5_000,
92//! };
93//! let bytes = codec.encode(&req).expect("encode");
94//! let back = codec.decode(GetReq::wire_type_id(), &bytes).expect("decode");
95//! assert_eq!(back.type_id(), GetReq::wire_type_id());
96//! ```
97
98#![forbid(unsafe_code)]
99#![warn(missing_docs)]
100
101mod codec;
102mod error;
103mod registry;
104mod value;
105
106pub use crate::codec::bebop::{BebopCodec, BebopWire};
107pub use crate::codec::bson::BsonCodec;
108pub use crate::codec::capnp::{CapnpCodec, CapnpWire};
109pub use crate::codec::cbor::CborCodec;
110pub use crate::codec::flatbuffers::{FlatbuffersCodec, FlatbuffersWire};
111pub use crate::codec::json::JsonCodec;
112pub use crate::codec::protobuf::ProtobufCodec;
113pub use crate::error::CodecError;
114pub use crate::registry::CodecRegistry;
115pub use crate::value::{ErasedWireValue, WireCodec, WireTypeId, WireValue};