qubit_codec/lib.rs
1// =============================================================================
2// Copyright (c) 2026 Haixing Hu.
3//
4// SPDX-License-Identifier: Apache-2.0
5//
6// Licensed under the Apache License, Version 2.0.
7// =============================================================================
8//! # qubit-codec
9//!
10//! Domain-neutral codec traits and buffer conversion primitives.
11//!
12//! `qubit-codec` is the foundation shared by the Qubit binary, text, misc, and
13//! I/O codec crates. It defines the small contracts that concrete format crates
14//! build on, without shipping concrete binary or text formats itself.
15//!
16//! # Overview
17//!
18//! The crate provides:
19//!
20//! - [`Codec`] for low-level single-value codecs over caller-managed buffers.
21//! - [`CodecValueEncoder`] and [`CodecValueDecoder`] for owned one-value
22//! convenience APIs.
23//! - [`CodecTranscodeEncoder`], [`CodecTranscodeDecoder`], and
24//! [`CodecTranscodeConverter`] for strict streaming adapters around a
25//! [`Codec`].
26//! - [`engine::TranscodeEncodeEngine`], [`engine::TranscodeDecodeEngine`], and
27//! [`engine::TranscodeConvertEngine`] for policy-aware buffered loops.
28//! - [`engine::TranscodeEncodeHooks`] and [`engine::TranscodeDecodeHooks`] for
29//! replacement, skip, report, finish, and reset policy decisions.
30//! - [`Transcoder`], [`TranscodeProgress`], and [`TranscodeStatus`] for
31//! caller-managed streaming conversion.
32//! - [`ValueEncoder`] and [`ValueDecoder`] for whole-value convenience APIs.
33//! - [`ByteOrder`], [`ByteOrderSpec`], [`BigEndian`], [`LittleEndian`], and
34//! [`NativeEndian`] for shared byte-order metadata.
35//! - `qubit_utils::nonzero()` for checked `NonZeroUsize` construction shared by
36//! codec implementations.
37//!
38//! Concrete codecs live in sibling crates such as `qubit-codec-binary`,
39//! `qubit-codec-text`, and `qubit-codec-misc`.
40//!
41//! # Features
42//!
43//! The default feature set is empty. Features are independent.
44//!
45//! | Feature | Capability |
46//! | --- | --- |
47//! | `io` | Synchronous and asynchronous buffered bridges for `qubit-io`. |
48//! | `json` | Whole-value Serde JSON codecs for strings and bytes. Encoding requires `Serialize`; decoding requires `DeserializeOwned`. |
49//! | `registry` | Static string-wire and bytes-wire codec registration, macros, and runtime lookup. Registrations cannot be added at runtime. |
50//! | `json` + `registry` | Built-in registrations for `serde_json::Value` only. Custom DTOs require their own descriptor and unique registry ID. |
51//!
52//! See the [English user guide](https://github.com/qubit-ltd/rs-codec/blob/main/doc/user_guide.md)
53//! or the [Chinese user guide](https://github.com/qubit-ltd/rs-codec/blob/main/doc/user_guide.zh_CN.md)
54//! for setup, lifecycle handling, and registry examples.
55//!
56//! # Choosing an Abstraction
57//!
58//! Pick the smallest layer that matches the shape of the problem:
59//!
60//! ```text
61//! What are you writing?
62//!
63//! +-- A codec for one logical value
64//! | (UTF-8 char, LEB128 integer, fixed-width scalar, ...)
65//! | -> implement Codec
66//! |
67//! +-- A whole-value codec where a single-value quantum is not useful
68//! | (Base64 text, percent encoding, escaped strings, ...)
69//! | -> implement ValueEncoder<Input> / ValueDecoder<Input>
70//! |
71//! +-- A strict streaming wrapper around an existing Codec
72//! | -> use CodecTranscodeDecoder<C> / CodecTranscodeEncoder<C>
73//! | / CodecTranscodeConverter<D, E>
74//! |
75//! +-- An owned-output wrapper around an existing Codec
76//! | -> use CodecValueEncoder<C> / CodecValueDecoder<C>
77//! |
78//! +-- A streaming codec with policy decisions
79//! (skip, replace, count, report, finish output, ...)
80//! -> implement engine::TranscodeDecodeHooks<C>
81//! / engine::TranscodeEncodeHooks<C>
82//! and use engine::TranscodeDecodeEngine<C, H>
83//! / engine::TranscodeEncodeEngine<C, H>
84//! ```
85//!
86//! Unit-to-unit conversions, such as UTF-8 bytes to UTF-16 units, compose a
87//! decode side and an encode side. Use [`CodecTranscodeConverter`] for a strict
88//! pipeline and [`engine::TranscodeConvertEngine`] when either side needs
89//! policy hooks.
90//!
91//! # Layer Overview
92//!
93//! ```text
94//! concrete I/O crates
95//! |
96//! TranscodeDecodeInput / TranscodeEncodeOutput [feature = "io"]
97//! |
98//! Transcode*Engine + Transcode*Hooks
99//! CodecTranscodeDecoder / Encoder / Converter
100//! |
101//! Transcoder + TranscodeProgress + TranscodeStatus
102//! ValueEncoder / ValueDecoder
103//! |
104//! Codec
105//! ```
106//!
107//! Implementing further up the stack does not require rewriting the lower
108//! layers. The adapter types turn any suitable [`Codec`] into owned-value or
109//! streaming APIs. Drop down to the engine and hook layer when the codec needs
110//! continuous-stream semantics or policy decisions.
111
112#![deny(missing_docs)]
113#![deny(unsafe_op_in_unsafe_fn)]
114
115mod byte_order;
116mod codec;
117mod transcode;
118mod value;
119
120/// Policy-aware transcode engines, hooks, contexts, and policy actions.
121pub mod engine {
122 pub use crate::transcode::DecodeContext;
123 pub use crate::transcode::DecodeIncompleteAction;
124 pub use crate::transcode::DecodeIncompleteActionOf;
125 pub use crate::transcode::DecodeInvalidAction;
126 pub use crate::transcode::DecodeInvalidActionOf;
127 pub use crate::transcode::EncodeContext;
128 pub use crate::transcode::EncodeUnencodableAction;
129 pub use crate::transcode::EncodeUnencodableActionOf;
130 pub use crate::transcode::TranscodeConvertEngine;
131 pub use crate::transcode::TranscodeDecodeEngine;
132 pub use crate::transcode::TranscodeDecodeHooks;
133 pub use crate::transcode::TranscodeEncodeEngine;
134 pub use crate::transcode::TranscodeEncodeHooks;
135}
136
137pub use byte_order::BigEndian;
138pub use byte_order::ByteOrder;
139pub use byte_order::ByteOrderSpec;
140pub use byte_order::LittleEndian;
141pub use byte_order::NativeEndian;
142pub use codec::Codec;
143pub use codec::DecodeFailure;
144#[cfg(feature = "io")]
145pub use transcode::AsyncTranscodeDecodeInput;
146#[cfg(feature = "io")]
147pub use transcode::AsyncTranscodeDecodeStep;
148#[cfg(feature = "io")]
149pub use transcode::AsyncTranscodeEncodeOutput;
150pub use transcode::CapacityError;
151pub use transcode::CodecTranscodeConverter;
152pub use transcode::CodecTranscodeDecoder;
153pub use transcode::CodecTranscodeEncoder;
154pub use transcode::TranscodeContractError;
155pub use transcode::TranscodeConvertError;
156pub use transcode::TranscodeConvertErrorOf;
157pub use transcode::TranscodeConverter;
158pub use transcode::TranscodeDecodeError;
159pub use transcode::TranscodeDecodeErrorOf;
160#[cfg(feature = "io")]
161pub use transcode::TranscodeDecodeInput;
162pub use transcode::TranscodeDecoder;
163pub use transcode::TranscodeDomainError;
164pub use transcode::TranscodeEncodeError;
165pub use transcode::TranscodeEncodeErrorOf;
166#[cfg(feature = "io")]
167pub use transcode::TranscodeEncodeOutput;
168pub use transcode::TranscodeEncoder;
169pub use transcode::TranscodeFailure;
170pub use transcode::TranscodeProgress;
171pub use transcode::TranscodeStatus;
172pub use transcode::Transcoder;
173pub use value::CodecValueDecoder;
174pub use value::CodecValueEncoder;
175pub use value::DecodeLifecycleOutput;
176pub use value::DecodeLifecycleProgress;
177#[cfg(all(feature = "json", feature = "registry"))]
178pub use value::JSON_BYTES_VALUE_CODEC_ID;
179#[cfg(all(feature = "json", feature = "registry"))]
180pub use value::JSON_STRING_VALUE_CODEC_ID;
181#[cfg(feature = "json")]
182pub use value::JsonBytesValueCodec;
183#[cfg(feature = "json")]
184pub use value::JsonBytesValueDecoder;
185#[cfg(feature = "json")]
186pub use value::JsonBytesValueEncoder;
187#[cfg(feature = "json")]
188pub use value::JsonStringValueCodec;
189#[cfg(feature = "json")]
190pub use value::JsonStringValueDecoder;
191#[cfg(feature = "json")]
192pub use value::JsonStringValueEncoder;
193#[cfg(feature = "registry")]
194pub use value::ValueBytesCodecDescriptor;
195#[cfg(feature = "registry")]
196pub use value::ValueBytesCodecRegistration;
197#[cfg(feature = "registry")]
198#[doc(hidden)]
199pub use value::ValueBytesCodecRegistrationFactory;
200#[cfg(feature = "registry")]
201pub use value::ValueBytesCodecRegistry;
202#[cfg(feature = "registry")]
203pub use value::ValueCodecExecutionError;
204#[cfg(feature = "registry")]
205pub use value::ValueCodecId;
206#[cfg(feature = "registry")]
207pub use value::ValueCodecIdError;
208#[cfg(feature = "registry")]
209pub use value::ValueCodecRegistration;
210#[cfg(feature = "registry")]
211pub use value::ValueCodecRegistrationSource;
212#[cfg(feature = "registry")]
213pub use value::ValueCodecRegistry;
214#[cfg(feature = "registry")]
215pub use value::ValueCodecRegistryError;
216pub use value::ValueDecoder;
217pub use value::ValueEncoder;
218#[cfg(feature = "registry")]
219pub use value::ValueStringCodecDescriptor;
220#[cfg(feature = "registry")]
221pub use value::ValueStringCodecRegistration;
222#[cfg(feature = "registry")]
223#[doc(hidden)]
224pub use value::ValueStringCodecRegistrationFactory;
225#[cfg(feature = "registry")]
226pub use value::ValueStringCodecRegistry;
227
228#[cfg(feature = "registry")]
229#[doc(hidden)]
230pub mod __private {
231 pub use inventory;
232}