bincode_next/
lib.rs

1#![no_std]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3
4//! Bincode-next is a crate for encoding and decoding using a tiny binary
5//! serialization strategy.  Using it, you can easily go from having
6//! an object in memory, quickly serialize it to bytes, and then
7//! deserialize it back just as fast!
8//!
9//! If you're coming from bincode 1, check out our [migration guide](migration_guide/index.html)
10//!
11//! # Serde
12//!
13//! Starting from bincode 2, serde is now an optional dependency. If you want to use serde, please enable the `serde` feature. See [Features](#features) for more information.
14//!
15//! # Features
16//!
17//! |Name  |Default?|Affects MSRV?|Supported types for Encode/Decode|Enabled methods                                                  |Other|
18//! |------|--------|-------------|-----------------------------------------|-----------------------------------------------------------------|-----|
19//! |std   | Yes    | No          |`HashMap` and `HashSet`|`decode_from_std_read` and `encode_into_std_write`|
20//! |alloc | Yes    | No          |All common containers in alloc, like `Vec`, `String`, `Box`|`encode_to_vec`|
21//! |atomic| Yes    | No          |All `Atomic*` integer types, e.g. `AtomicUsize`, and `AtomicBool`||
22//! |derive| Yes    | No          |||Enables the `BorrowDecode`, `Decode` and `Encode` derive macros|
23//! |serde | No     | Yes (MSRV reliant on serde)|`Compat` and `BorrowCompat`, which will work for all types that implement serde's traits|serde-specific encode/decode functions in the [`serde`\] module|Note: There are several [known issues](serde/index.html#known-issues) when using serde and bincode|
24//!
25//! # Which functions to use
26//!
27//! Bincode has a couple of pairs of functions that are used in different situations.
28//!
29//! |Situation|Encode|Decode|
30//! |---|---|---
31//! |You're working with [`fs::File`\] or [`net::TcpStream`\]|[`encode_into_std_write`\]|[`decode_from_std_read`\]|
32//! |you're working with in-memory buffers|[`encode_to_vec`\]|[`decode_from_slice`\]|
33//! |You want to use a custom [Reader] and [Writer]|[`encode_into_writer`\]|[`decode_from_reader`\]|
34//! |You're working with pre-allocated buffers or on embedded targets|[`encode_into_slice`\]|[`decode_from_slice`\]|
35//!
36//! **Note:** If you're using `serde`, use `bincode_next::serde::...` instead of `bincode_next::...`
37//!
38//! # Example
39//!
40//! ```rust
41//! let mut slice = [0u8; 100];
42//!
43//! // You can encode any type that implements `Encode`.
44//! // You can automatically implement this trait on custom types with the `derive` feature.
45//! let input = (
46//!     0u8,
47//!     10u32,
48//!     10000i128,
49//!     'a',
50//!     [0u8, 1u8, 2u8, 3u8]
51//! );
52//!
53//! let length = bincode_next::encode_into_slice(
54//!     input,
55//!     &mut slice,
56//!     bincode_next::config::standard()
57//! ).unwrap();
58//!
59//! let slice = &slice[..length];
60//! println!("Bytes written: {:?}", slice);
61//!
62//! // Decoding works the same as encoding.
63//! // The trait used is `Decode`, and can also be automatically implemented with the `derive` feature.
64//! let decoded: (u8, u32, i128, char, [u8; 4]) = bincode_next::decode_from_slice(slice, bincode_next::config::standard()).unwrap().0;
65//!
66//! assert_eq!(decoded, input);
67//! ```
68//!
69//! [`fs::File`\]: `std::fs::File`
70//! [`net::TcpStream`\]: `std::net::TcpStream`
71//!
72
73// =========================================================================
74// RUST LINT CONFIGURATION: bincode-next
75// =========================================================================
76
77// -------------------------------------------------------------------------
78// LEVEL 1: CRITICAL ERRORS (Deny)
79// -------------------------------------------------------------------------
80#![deny(
81    // Rust Compiler Errors
82    dead_code,
83    unreachable_code,
84    improper_ctypes_definitions,
85    future_incompatible,
86    nonstandard_style,
87    rust_2018_idioms,
88    clippy::perf,
89    clippy::correctness,
90    clippy::suspicious,
91    clippy::unwrap_used,
92    clippy::expect_used,
93    clippy::indexing_slicing,
94    clippy::arithmetic_side_effects,
95    clippy::missing_safety_doc,
96    clippy::same_item_push,
97    clippy::implicit_clone,
98    clippy::all,
99    clippy::pedantic,
100    warnings,
101    missing_docs,
102    clippy::nursery,
103    clippy::single_call_fn,
104)]
105// -------------------------------------------------------------------------
106// LEVEL 2: STYLE WARNINGS (Warn)
107// -------------------------------------------------------------------------
108#![warn(
109    unsafe_code,
110    clippy::dbg_macro,
111    clippy::todo,
112    clippy::unnecessary_safety_comment
113)]
114// -------------------------------------------------------------------------
115// LEVEL 3: ALLOW/IGNORABLE (Allow)
116// -------------------------------------------------------------------------
117#![allow(
118    clippy::restriction,
119    clippy::inline_always,
120    unused_doc_comments,
121    clippy::empty_line_after_doc_comments
122)]
123#![crate_name = "bincode_next"]
124#![crate_type = "rlib"]
125
126#[cfg(feature = "alloc")]
127extern crate alloc;
128#[cfg(any(feature = "std", test))]
129extern crate std;
130
131mod atomic;
132mod features;
133pub(crate) mod utils;
134pub(crate) mod varint;
135
136use de::{read::Reader, Decoder};
137use enc::write::Writer;
138
139#[cfg(any(
140    feature = "alloc",
141    feature = "std",
142    feature = "derive",
143    feature = "serde"
144))]
145pub use features::*;
146
147pub mod config;
148#[macro_use]
149pub mod de;
150pub mod enc;
151pub mod error;
152
153pub use de::{BorrowDecode, Decode};
154pub use enc::Encode;
155
156use config::Config;
157
158/// Encode the given value into the given slice. Returns the amount of bytes that have been written.
159///
160/// See the [config] module for more information on configurations.
161///
162/// # Errors
163///
164/// Returns an `EncodeError` if the slice is too small or the value cannot be encoded.
165///
166/// [config]: config/index.html
167pub fn encode_into_slice<E: enc::Encode, C: Config>(
168    val: E,
169    dst: &mut [u8],
170    config: C,
171) -> Result<usize, error::EncodeError> {
172    let writer = enc::write::SliceWriter::new(dst);
173    let mut encoder = enc::EncoderImpl::<_, C>::new(writer, config);
174    val.encode(&mut encoder)?;
175    Ok(encoder.into_writer().bytes_written())
176}
177
178/// Encode the given value into a custom [`Writer`\].
179///
180/// See the [config] module for more information on configurations.
181///
182/// # Errors
183///
184/// Returns an `EncodeError` if the writer fails or the value cannot be encoded.
185///
186/// [config]: config/index.html
187pub fn encode_into_writer<E: enc::Encode, W: Writer, C: Config>(
188    val: E,
189    writer: W,
190    config: C,
191) -> Result<(), error::EncodeError> {
192    let mut encoder = enc::EncoderImpl::<_, C>::new(writer, config);
193    val.encode(&mut encoder)?;
194    Ok(())
195}
196
197/// Attempt to decode a given type `D` from the given slice. Returns the decoded output and the amount of bytes read.
198///
199/// Note that this does not work with borrowed types like `&str` or `&[u8]`. For that use [`borrow_decode_from_slice`\].
200///
201/// See the [config] module for more information on configurations.
202///
203/// # Errors
204///
205/// Returns a `DecodeError` if the slice is too small or the data is invalid.
206///
207/// [config]: config/index.html
208pub fn decode_from_slice<D: de::Decode<()>, C: Config>(
209    src: &[u8],
210    config: C,
211) -> Result<(D, usize), error::DecodeError> {
212    decode_from_slice_with_context(src, config, ())
213}
214
215/// Attempt to decode a given type `D` from the given slice with `Context`. Returns the decoded output and the amount of bytes read.
216///
217/// Note that this does not work with borrowed types like `&str` or `&[u8]`. For that use [`borrow_decode_from_slice`\].
218///
219/// See the [config] module for more information on configurations.
220///
221/// # Errors
222///
223/// Returns a `DecodeError` if the slice is too small or the data is invalid.
224///
225/// [config]: config/index.html
226pub fn decode_from_slice_with_context<Context, D: de::Decode<Context>, C: Config>(
227    src: &[u8],
228    config: C,
229    context: Context,
230) -> Result<(D, usize), error::DecodeError> {
231    let reader = de::read::SliceReader::new(src);
232    let mut decoder = de::DecoderImpl::<_, C, Context>::new(reader, config, context);
233    let result = D::decode(&mut decoder)?;
234    let bytes_read = src.len() - decoder.reader().slice.len();
235    Ok((result, bytes_read))
236}
237
238/// Attempt to decode a given type `D` from the given slice. Returns the decoded output and the amount of bytes read.
239///
240/// See the [config] module for more information on configurations.
241///
242/// # Errors
243///
244/// Returns a `DecodeError` if the slice is too small or the data is invalid.
245///
246/// [config]: config/index.html
247pub fn borrow_decode_from_slice<'a, D: de::BorrowDecode<'a, ()>, C: Config>(
248    src: &'a [u8],
249    config: C,
250) -> Result<(D, usize), error::DecodeError> {
251    borrow_decode_from_slice_with_context(src, config, ())
252}
253
254/// Attempt to decode a given type `D` from the given slice with `Context`. Returns the decoded output and the amount of bytes read.
255///
256/// See the [config] module for more information on configurations.
257///
258/// # Errors
259///
260/// Returns a `DecodeError` if the slice is too small or the data is invalid.
261///
262/// [config]: config/index.html
263pub fn borrow_decode_from_slice_with_context<
264    'a,
265    Context,
266    D: de::BorrowDecode<'a, Context>,
267    C: Config,
268>(
269    src: &'a [u8],
270    config: C,
271    context: Context,
272) -> Result<(D, usize), error::DecodeError> {
273    let reader = de::read::SliceReader::new(src);
274    let mut decoder = de::DecoderImpl::<_, C, Context>::new(reader, config, context);
275    let result = D::borrow_decode(&mut decoder)?;
276    let bytes_read = src.len() - decoder.reader().slice.len();
277    Ok((result, bytes_read))
278}
279
280/// Attempt to decode a given type `D` from the given [`Reader`\].
281///
282/// See the [config] module for more information on configurations.
283///
284/// # Errors
285///
286/// Returns a `DecodeError` if the reader fails or the data is invalid.
287///
288/// [config]: config/index.html
289pub fn decode_from_reader<D: de::Decode<()>, R: Reader, C: Config>(
290    reader: R,
291    config: C,
292) -> Result<D, error::DecodeError> {
293    let mut decoder = de::DecoderImpl::<_, C, ()>::new(reader, config, ());
294    D::decode(&mut decoder)
295}
296
297// TODO: Currently our doctests fail when trying to include the specs because the specs depend on `derive` and `alloc`.
298// But we want to have the specs in the docs always
299#[cfg(all(feature = "alloc", feature = "derive", doc))]
300pub mod spec {
301    #![doc = include_str!("../docs/spec.md")]
302}
303
304#[cfg(doc)]
305pub mod migration_guide {
306    #![doc = include_str!("../docs/migration_guide.md")]
307}
308
309// Test the examples in readme.md
310#[cfg(all(feature = "alloc", feature = "derive", doctest))]
311mod readme {
312    #![doc = include_str!("../README.md")]
313}