Coverage Report

Created: 2025-11-28 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/bincode-2.0.1/src/config.rs
Line
Count
Source
1
//! The config module is used to change the behavior of bincode's encoding and decoding logic.
2
//!
3
//! *Important* make sure you use the same config for encoding and decoding, or else bincode will not work properly.
4
//!
5
//! To use a config, first create a type of [Configuration]. This type will implement trait [Config] for use with bincode.
6
//!
7
//! ```
8
//! let config = bincode::config::standard()
9
//!     // pick one of:
10
//!     .with_big_endian()
11
//!     .with_little_endian()
12
//!     // pick one of:
13
//!     .with_variable_int_encoding()
14
//!     .with_fixed_int_encoding();
15
//! ```
16
//!
17
//! See [Configuration] for more information on the configuration options.
18
19
pub(crate) use self::internal::*;
20
use core::marker::PhantomData;
21
22
/// The Configuration struct is used to build bincode configurations. The [Config] trait is implemented
23
/// by this struct when a valid configuration has been constructed.
24
///
25
/// The following methods are mutually exclusive and will overwrite each other. The last call to one of these methods determines the behavior of the configuration:
26
///
27
/// - [with_little_endian] and [with_big_endian]
28
/// - [with_fixed_int_encoding] and [with_variable_int_encoding]
29
///
30
///
31
/// [with_little_endian]: #method.with_little_endian
32
/// [with_big_endian]: #method.with_big_endian
33
/// [with_fixed_int_encoding]: #method.with_fixed_int_encoding
34
/// [with_variable_int_encoding]: #method.with_variable_int_encoding
35
#[derive(Copy, Clone, Debug)]
36
pub struct Configuration<E = LittleEndian, I = Varint, L = NoLimit> {
37
    _e: PhantomData<E>,
38
    _i: PhantomData<I>,
39
    _l: PhantomData<L>,
40
}
41
42
// When adding more features to configuration, follow these steps:
43
// - Create 2 or more structs that can be used as a type (e.g. Limit and NoLimit)
44
// - Add an `Internal...Config` to the `internal` module
45
// - Make sure `Config` and `impl<T> Config for T` extend from this new trait
46
// - Add a generic to `Configuration`
47
// - Add this generic to `impl<...> Default for Configuration<...>`
48
// - Add this generic to `const fn generate<...>()`
49
// - Add this generic to _every_ function in `Configuration`
50
// - Add your new methods
51
52
/// The default config for bincode 2.0. By default this will be:
53
/// - Little endian
54
/// - Variable int encoding
55
0
pub const fn standard() -> Configuration {
56
0
    generate()
57
0
}
58
59
/// Creates the "legacy" default config. This is the default config that was present in bincode 1.0
60
/// - Little endian
61
/// - Fixed int length encoding
62
0
pub const fn legacy() -> Configuration<LittleEndian, Fixint, NoLimit> {
63
0
    generate()
64
0
}
65
66
impl<E, I, L> Default for Configuration<E, I, L> {
67
0
    fn default() -> Self {
68
0
        generate()
69
0
    }
70
}
71
72
0
const fn generate<E, I, L>() -> Configuration<E, I, L> {
73
0
    Configuration {
74
0
        _e: PhantomData,
75
0
        _i: PhantomData,
76
0
        _l: PhantomData,
77
0
    }
78
0
}
Unexecuted instantiation: bincode::config::generate::<bincode::config::LittleEndian, bincode::config::Fixint, bincode::config::NoLimit>
Unexecuted instantiation: bincode::config::generate::<bincode::config::LittleEndian, bincode::config::Varint, bincode::config::NoLimit>
79
80
impl<E, I, L> Configuration<E, I, L> {
81
    /// Makes bincode encode all integer types in big endian.
82
0
    pub const fn with_big_endian(self) -> Configuration<BigEndian, I, L> {
83
0
        generate()
84
0
    }
85
86
    /// Makes bincode encode all integer types in little endian.
87
0
    pub const fn with_little_endian(self) -> Configuration<LittleEndian, I, L> {
88
0
        generate()
89
0
    }
90
91
    /// Makes bincode encode all integer types with a variable integer encoding.
92
    ///
93
    /// Encoding an unsigned integer v (of any type excepting u8) works as follows:
94
    ///
95
    /// 1. If `u < 251`, encode it as a single byte with that value.
96
    /// 2. If `251 <= u < 2**16`, encode it as a literal byte 251, followed by a u16 with value `u`.
97
    /// 3. If `2**16 <= u < 2**32`, encode it as a literal byte 252, followed by a u32 with value `u`.
98
    /// 4. If `2**32 <= u < 2**64`, encode it as a literal byte 253, followed by a u64 with value `u`.
99
    /// 5. If `2**64 <= u < 2**128`, encode it as a literal byte 254, followed by a u128 with value `u`.
100
    ///
101
    /// Then, for signed integers, we first convert to unsigned using the zigzag algorithm,
102
    /// and then encode them as we do for unsigned integers generally. The reason we use this
103
    /// algorithm is that it encodes those values which are close to zero in less bytes; the
104
    /// obvious algorithm, where we encode the cast values, gives a very large encoding for all
105
    /// negative values.
106
    ///
107
    /// The zigzag algorithm is defined as follows:
108
    ///
109
    /// ```rust
110
    /// # type Signed = i32;
111
    /// # type Unsigned = u32;
112
    /// fn zigzag(v: Signed) -> Unsigned {
113
    ///     match v {
114
    ///         0 => 0,
115
    ///         // To avoid the edge case of Signed::min_value()
116
    ///         // !n is equal to `-n - 1`, so this is:
117
    ///         // !n * 2 + 1 = 2(-n - 1) + 1 = -2n - 2 + 1 = -2n - 1
118
    ///         v if v < 0 => !(v as Unsigned) * 2 - 1,
119
    ///         v if v > 0 => (v as Unsigned) * 2,
120
    /// #       _ => unreachable!()
121
    ///     }
122
    /// }
123
    /// ```
124
    ///
125
    /// And works such that:
126
    ///
127
    /// ```rust
128
    /// # let zigzag = |n: i64| -> u64 {
129
    /// #     match n {
130
    /// #         0 => 0,
131
    /// #         v if v < 0 => !(v as u64) * 2 + 1,
132
    /// #         v if v > 0 => (v as u64) * 2,
133
    /// #         _ => unreachable!(),
134
    /// #     }
135
    /// # };
136
    /// assert_eq!(zigzag(0), 0);
137
    /// assert_eq!(zigzag(-1), 1);
138
    /// assert_eq!(zigzag(1), 2);
139
    /// assert_eq!(zigzag(-2), 3);
140
    /// assert_eq!(zigzag(2), 4);
141
    /// // etc
142
    /// assert_eq!(zigzag(i64::min_value()), u64::max_value());
143
    /// ```
144
    ///
145
    /// Note that u256 and the like are unsupported by this format; if and when they are added to the
146
    /// language, they may be supported via the extension point given by the 255 byte.
147
0
    pub const fn with_variable_int_encoding(self) -> Configuration<E, Varint, L> {
148
0
        generate()
149
0
    }
150
151
    /// Fixed-size integer encoding.
152
    ///
153
    /// * Fixed size integers are encoded directly
154
    /// * Enum discriminants are encoded as u32
155
    /// * Lengths and usize are encoded as u64
156
0
    pub const fn with_fixed_int_encoding(self) -> Configuration<E, Fixint, L> {
157
0
        generate()
158
0
    }
159
160
    /// Sets the byte limit to `limit`.
161
0
    pub const fn with_limit<const N: usize>(self) -> Configuration<E, I, Limit<N>> {
162
0
        generate()
163
0
    }
164
165
    /// Clear the byte limit.
166
0
    pub const fn with_no_limit(self) -> Configuration<E, I, NoLimit> {
167
0
        generate()
168
0
    }
169
}
170
171
/// Indicates a type is valid for controlling the bincode configuration
172
pub trait Config:
173
    InternalEndianConfig + InternalIntEncodingConfig + InternalLimitConfig + Copy + Clone
174
{
175
    /// This configuration's Endianness
176
    fn endianness(&self) -> Endianness;
177
178
    /// This configuration's Integer Encoding
179
    fn int_encoding(&self) -> IntEncoding;
180
181
    /// This configuration's byte limit, or `None` if no limit is configured
182
    fn limit(&self) -> Option<usize>;
183
}
184
185
impl<T> Config for T
186
where
187
    T: InternalEndianConfig + InternalIntEncodingConfig + InternalLimitConfig + Copy + Clone,
188
{
189
0
    fn endianness(&self) -> Endianness {
190
0
        <T as InternalEndianConfig>::ENDIAN
191
0
    }
192
193
0
    fn int_encoding(&self) -> IntEncoding {
194
0
        <T as InternalIntEncodingConfig>::INT_ENCODING
195
0
    }
196
197
0
    fn limit(&self) -> Option<usize> {
198
0
        <T as InternalLimitConfig>::LIMIT
199
0
    }
200
}
201
202
/// Encodes all integer types in big endian.
203
#[derive(Copy, Clone)]
204
pub struct BigEndian {}
205
206
impl InternalEndianConfig for BigEndian {
207
    const ENDIAN: Endianness = Endianness::Big;
208
}
209
210
/// Encodes all integer types in little endian.
211
#[derive(Copy, Clone)]
212
pub struct LittleEndian {}
213
214
impl InternalEndianConfig for LittleEndian {
215
    const ENDIAN: Endianness = Endianness::Little;
216
}
217
218
/// Use fixed-size integer encoding.
219
#[derive(Copy, Clone)]
220
pub struct Fixint {}
221
222
impl InternalIntEncodingConfig for Fixint {
223
    const INT_ENCODING: IntEncoding = IntEncoding::Fixed;
224
}
225
226
/// Use variable integer encoding.
227
#[derive(Copy, Clone)]
228
pub struct Varint {}
229
230
impl InternalIntEncodingConfig for Varint {
231
    const INT_ENCODING: IntEncoding = IntEncoding::Variable;
232
}
233
234
/// Sets an unlimited byte limit.
235
#[derive(Copy, Clone)]
236
pub struct NoLimit {}
237
impl InternalLimitConfig for NoLimit {
238
    const LIMIT: Option<usize> = None;
239
}
240
241
/// Sets the byte limit to N.
242
#[derive(Copy, Clone)]
243
pub struct Limit<const N: usize> {}
244
impl<const N: usize> InternalLimitConfig for Limit<N> {
245
    const LIMIT: Option<usize> = Some(N);
246
}
247
248
/// Endianness of a `Configuration`.
249
#[derive(PartialEq, Eq)]
250
#[non_exhaustive]
251
pub enum Endianness {
252
    /// Little Endian encoding, see `LittleEndian`.
253
    Little,
254
    /// Big Endian encoding, see `BigEndian`.
255
    Big,
256
}
257
258
/// Integer Encoding of a `Configuration`.
259
#[derive(PartialEq, Eq)]
260
#[non_exhaustive]
261
pub enum IntEncoding {
262
    /// Fixed Integer Encoding, see `Fixint`.
263
    Fixed,
264
    /// Variable Integer Encoding, see `Varint`.
265
    Variable,
266
}
267
268
mod internal {
269
    use super::{Configuration, Endianness, IntEncoding};
270
271
    pub trait InternalEndianConfig {
272
        const ENDIAN: Endianness;
273
    }
274
275
    impl<E: InternalEndianConfig, I, L> InternalEndianConfig for Configuration<E, I, L> {
276
        const ENDIAN: Endianness = E::ENDIAN;
277
    }
278
279
    pub trait InternalIntEncodingConfig {
280
        const INT_ENCODING: IntEncoding;
281
    }
282
283
    impl<E, I: InternalIntEncodingConfig, L> InternalIntEncodingConfig for Configuration<E, I, L> {
284
        const INT_ENCODING: IntEncoding = I::INT_ENCODING;
285
    }
286
287
    pub trait InternalLimitConfig {
288
        const LIMIT: Option<usize>;
289
    }
290
291
    impl<E, I, L: InternalLimitConfig> InternalLimitConfig for Configuration<E, I, L> {
292
        const LIMIT: Option<usize> = L::LIMIT;
293
    }
294
}