wincode/config/mod.rs
1//! Global configuration for wincode.
2//!
3//! This module provides configuration types and structs for configuring wincode's behavior.
4//! See [`Configuration`] for more details on how to configure wincode.
5//!
6//! Additionally, this module provides traits and functions that mirror the serialization,
7//! deserialization, and zero-copy traits and functions from the crate root, but with an
8//! additional configuration parameter.
9use {
10 crate::{
11 int_encoding::{BigEndian, ByteOrder, FixInt, IntEncoding, LittleEndian, VarInt},
12 len::{BincodeLen, SeqLen},
13 tag_encoding::TagEncoding,
14 },
15 core::marker::PhantomData,
16};
17
18pub const DEFAULT_PREALLOCATION_SIZE_LIMIT: usize = 4 << 20; // 4 MiB
19pub const PREALLOCATION_SIZE_LIMIT_DISABLED: usize = usize::MAX;
20
21/// Compile-time configuration for runtime behavior.
22///
23/// Defaults:
24/// - Zero-copy alignment check is enabled.
25/// - Preallocation size limit is 4 MiB.
26/// - Length encoding is [`BincodeLen`].
27/// - Byte order is [`LittleEndian`].
28/// - Integer encoding is [`FixInt`].
29/// - Tag encoding is [`u32`].
30pub struct Configuration<
31 const ZERO_COPY_ALIGN_CHECK: bool = true,
32 const PREALLOCATION_SIZE_LIMIT: usize = DEFAULT_PREALLOCATION_SIZE_LIMIT,
33 LengthEncoding = BincodeLen,
34 ByteOrder = LittleEndian,
35 IntEncoding = FixInt,
36 TagEncoding = u32,
37> {
38 _l: PhantomData<LengthEncoding>,
39 _b: PhantomData<ByteOrder>,
40 _i: PhantomData<IntEncoding>,
41 _t: PhantomData<TagEncoding>,
42}
43
44impl<
45 const ZERO_COPY_ALIGN_CHECK: bool,
46 const PREALLOCATION_SIZE_LIMIT: usize,
47 LengthEncoding,
48 ByteOrder,
49 IntEncoding,
50 TagEncoding,
51> Clone
52 for Configuration<
53 ZERO_COPY_ALIGN_CHECK,
54 PREALLOCATION_SIZE_LIMIT,
55 LengthEncoding,
56 ByteOrder,
57 IntEncoding,
58 TagEncoding,
59 >
60{
61 fn clone(&self) -> Self {
62 *self
63 }
64}
65
66impl<
67 const ZERO_COPY_ALIGN_CHECK: bool,
68 const PREALLOCATION_SIZE_LIMIT: usize,
69 LengthEncoding,
70 ByteOrder,
71 IntEncoding,
72 TagEncoding,
73> Copy
74 for Configuration<
75 ZERO_COPY_ALIGN_CHECK,
76 PREALLOCATION_SIZE_LIMIT,
77 LengthEncoding,
78 ByteOrder,
79 IntEncoding,
80 TagEncoding,
81 >
82{
83}
84
85const fn generate<
86 const ZERO_COPY_ALIGN_CHECK: bool,
87 const PREALLOCATION_SIZE_LIMIT: usize,
88 LengthEncoding,
89 ByteOrder,
90 IntEncoding,
91 TagEncoding,
92>() -> Configuration<
93 ZERO_COPY_ALIGN_CHECK,
94 PREALLOCATION_SIZE_LIMIT,
95 LengthEncoding,
96 ByteOrder,
97 IntEncoding,
98 TagEncoding,
99> {
100 Configuration {
101 _l: PhantomData,
102 _b: PhantomData,
103 _i: PhantomData,
104 _t: PhantomData,
105 }
106}
107
108impl Configuration {
109 /// Create a new configuration with the default settings.
110 ///
111 /// Defaults:
112 /// - Zero-copy alignment check is enabled.
113 /// - Preallocation size limit is 4 MiB.
114 /// - Length encoding is [`BincodeLen`].
115 /// - Byte order is [`LittleEndian`].
116 /// - Integer encoding is [`FixInt`].
117 pub const fn default() -> DefaultConfig {
118 generate()
119 }
120}
121
122pub type DefaultConfig = Configuration;
123
124impl<
125 const ZERO_COPY_ALIGN_CHECK: bool,
126 const PREALLOCATION_SIZE_LIMIT: usize,
127 LengthEncoding,
128 ByteOrder,
129 IntEncoding,
130 TagEncoding,
131>
132 Configuration<
133 ZERO_COPY_ALIGN_CHECK,
134 PREALLOCATION_SIZE_LIMIT,
135 LengthEncoding,
136 ByteOrder,
137 IntEncoding,
138 TagEncoding,
139 >
140{
141 #[expect(clippy::new_without_default)]
142 pub const fn new() -> Self {
143 generate()
144 }
145
146 /// Use the given [`SeqLen`] implementation for sequence length encoding.
147 ///
148 /// Default is [`BincodeLen`].
149 ///
150 /// Note that this default can be overridden for individual cases by using
151 /// [`containers`](crate::containers).
152 pub const fn with_length_encoding<L>(
153 self,
154 ) -> Configuration<ZERO_COPY_ALIGN_CHECK, PREALLOCATION_SIZE_LIMIT, L, ByteOrder, IntEncoding>
155 where
156 Configuration<ZERO_COPY_ALIGN_CHECK, PREALLOCATION_SIZE_LIMIT, L>: Config,
157 {
158 generate()
159 }
160
161 /// Use big-endian byte order.
162 ///
163 /// Note that changing the byte order will have a direct impact on zero-copy eligibility.
164 /// Integers are only eligible for zero-copy when configured byte order matches the native byte order.
165 ///
166 /// Default is [`LittleEndian`].
167 pub const fn with_big_endian(
168 self,
169 ) -> Configuration<
170 ZERO_COPY_ALIGN_CHECK,
171 PREALLOCATION_SIZE_LIMIT,
172 LengthEncoding,
173 BigEndian,
174 IntEncoding,
175 > {
176 generate()
177 }
178
179 /// Use little-endian byte order.
180 ///
181 /// Default is [`LittleEndian`].
182 pub const fn with_little_endian(
183 self,
184 ) -> Configuration<
185 ZERO_COPY_ALIGN_CHECK,
186 PREALLOCATION_SIZE_LIMIT,
187 LengthEncoding,
188 LittleEndian,
189 IntEncoding,
190 > {
191 generate()
192 }
193
194 /// Use target platform byte order.
195 ///
196 /// Will use the native byte order of the target platform.
197 #[cfg(target_endian = "little")]
198 pub const fn with_platform_endian(
199 self,
200 ) -> Configuration<
201 ZERO_COPY_ALIGN_CHECK,
202 PREALLOCATION_SIZE_LIMIT,
203 LengthEncoding,
204 LittleEndian,
205 IntEncoding,
206 > {
207 generate()
208 }
209
210 /// Use target platform byte order.
211 ///
212 /// Will use the native byte order of the target platform.
213 #[cfg(target_endian = "big")]
214 pub const fn with_platform_endian(
215 self,
216 ) -> Configuration<
217 ZERO_COPY_ALIGN_CHECK,
218 PREALLOCATION_SIZE_LIMIT,
219 LengthEncoding,
220 BigEndian,
221 IntEncoding,
222 > {
223 generate()
224 }
225
226 /// Use [`FixInt`] for integer encoding.
227 ///
228 /// Default is [`FixInt`].
229 pub const fn with_fixint_encoding(
230 self,
231 ) -> Configuration<
232 ZERO_COPY_ALIGN_CHECK,
233 PREALLOCATION_SIZE_LIMIT,
234 LengthEncoding,
235 ByteOrder,
236 FixInt,
237 > {
238 generate()
239 }
240
241 /// Use [`VarInt`] for integer encoding.
242 ///
243 /// Default is [`FixInt`].
244 ///
245 /// Performance note: variable length integer encoding will hurt serialization and deserialization
246 /// performance significantly relative to fixed width integer encoding. Additionally, all zero-copy
247 /// capabilities on integers will be lost. Variable length integer encoding may be beneficial if
248 /// reducing the resulting size of serialized data is important, but if serialization / deserialization
249 /// performance is important, fixed width integer encoding is highly recommended.
250 pub const fn with_varint_encoding(
251 self,
252 ) -> Configuration<
253 ZERO_COPY_ALIGN_CHECK,
254 PREALLOCATION_SIZE_LIMIT,
255 LengthEncoding,
256 ByteOrder,
257 VarInt,
258 > {
259 generate()
260 }
261
262 /// Use the given [`IntEncoding`] implementation for integer encoding.
263 ///
264 /// Can be used for custom, unofficial integer encodings.
265 ///
266 /// Default is [`FixInt`].
267 pub const fn with_int_encoding<I>(
268 self,
269 ) -> Configuration<ZERO_COPY_ALIGN_CHECK, PREALLOCATION_SIZE_LIMIT, LengthEncoding, ByteOrder, I>
270 where
271 Configuration<
272 ZERO_COPY_ALIGN_CHECK,
273 PREALLOCATION_SIZE_LIMIT,
274 LengthEncoding,
275 ByteOrder,
276 I,
277 >: Config,
278 {
279 generate()
280 }
281
282 /// Enable the zero-copy alignment check.
283 ///
284 /// If enabled, zero-copy deserialization will ensure that pointers are correctly aligned for the target type
285 /// before creating references.
286 /// You should keep this enabled unless you have a very specific use case for disabling it.
287 ///
288 /// This is enabled by default.
289 pub const fn enable_zero_copy_align_check(
290 self,
291 ) -> Configuration<true, PREALLOCATION_SIZE_LIMIT, LengthEncoding, ByteOrder, IntEncoding> {
292 generate()
293 }
294
295 /// Disable the zero-copy alignment check.
296 ///
297 /// When disabled, zero-copy deserialization (`&'de T` and `&'de [T]` for `T: ZeroCopy`)
298 /// will not verify that pointers into the buffer are correctly aligned before forming
299 /// references. Creating a misaligned reference is **undefined behavior**.
300 ///
301 /// # Safety
302 ///
303 /// You must guarantee every zero-copy reference is correctly aligned for its type.
304 ///
305 /// This holds when:
306 /// - The buffer is aligned to at least `align_of::<T>()` for each zero-copy type `T`,
307 /// and each zero-copy read occurs at an offset that preserves that alignment.
308 /// - Or you only deserialize types with alignment 1 (e.g., `&[u8]`, `&[u8; N]`, `&str`, etc).
309 ///
310 /// Only disable this when you control the serialized layout and can enforce
311 /// alignment; owned deserialization paths are unaffected.
312 pub const unsafe fn disable_zero_copy_align_check(
313 self,
314 ) -> Configuration<false, PREALLOCATION_SIZE_LIMIT, LengthEncoding, ByteOrder, IntEncoding>
315 {
316 generate()
317 }
318
319 /// Set the preallocation size limit in bytes.
320 ///
321 /// wincode will preallocate all sequences up to this limit, or error
322 /// if the size of the allocation would exceed this limit.
323 /// This is used to prevent malicious data from causing
324 /// excessive memory usage or OOM.
325 ///
326 /// The default limit is 4 MiB.
327 pub const fn with_preallocation_size_limit<const LIMIT: usize>(
328 self,
329 ) -> Configuration<ZERO_COPY_ALIGN_CHECK, LIMIT, LengthEncoding, ByteOrder, IntEncoding> {
330 generate()
331 }
332
333 /// Disable the preallocation size limit.
334 ///
335 /// <div class="warning">Warning: only do this if you absolutely trust your input.</div>
336 pub const fn disable_preallocation_size_limit(
337 self,
338 ) -> Configuration<
339 ZERO_COPY_ALIGN_CHECK,
340 PREALLOCATION_SIZE_LIMIT_DISABLED,
341 LengthEncoding,
342 ByteOrder,
343 IntEncoding,
344 > {
345 generate()
346 }
347
348 /// Use the given [`TagEncoding`] implementation for enum discriminant encoding.
349 ///
350 /// Default is [`u32`].
351 ///
352 /// This can be overriden for individual cases with the `#[wincode(tag_encoding = ...)]`
353 /// attribute.
354 pub const fn with_tag_encoding<T>(
355 self,
356 ) -> Configuration<
357 ZERO_COPY_ALIGN_CHECK,
358 PREALLOCATION_SIZE_LIMIT,
359 LengthEncoding,
360 ByteOrder,
361 IntEncoding,
362 T,
363 >
364 where
365 Configuration<
366 ZERO_COPY_ALIGN_CHECK,
367 PREALLOCATION_SIZE_LIMIT,
368 LengthEncoding,
369 ByteOrder,
370 IntEncoding,
371 T,
372 >: Config,
373 {
374 generate()
375 }
376}
377
378/// Trait for accessing configuration values when only the constant knobs are needed
379/// (e.g., `PREALLOCATION_SIZE_LIMIT`, `ZERO_COPY_ALIGN_CHECK`).
380///
381/// Split from [`Config`] to avoid dependency cycles that can overflow the compiler stack,
382/// such as [`SeqLen`] -> [`Config`] -> [`SeqLen`].
383///
384/// Prefer this trait over [`Config`] when you don't need configuration type parameters
385/// that themselves depend on [`Config`] (e.g., [`SeqLen`], which depends on [`ConfigCore`]).
386pub trait ConfigCore: 'static + Sized {
387 const PREALLOCATION_SIZE_LIMIT: Option<usize>;
388 const ZERO_COPY_ALIGN_CHECK: bool;
389 type ByteOrder: ByteOrder;
390 type IntEncoding: IntEncoding<Self::ByteOrder>;
391}
392
393impl<
394 const ZERO_COPY_ALIGN_CHECK: bool,
395 const PREALLOCATION_SIZE_LIMIT: usize,
396 LengthEncoding: 'static,
397 B,
398 I,
399 TagEncoding: 'static,
400> ConfigCore
401 for Configuration<
402 ZERO_COPY_ALIGN_CHECK,
403 PREALLOCATION_SIZE_LIMIT,
404 LengthEncoding,
405 B,
406 I,
407 TagEncoding,
408 >
409where
410 B: ByteOrder,
411 I: IntEncoding<B>,
412{
413 const PREALLOCATION_SIZE_LIMIT: Option<usize> =
414 if PREALLOCATION_SIZE_LIMIT == PREALLOCATION_SIZE_LIMIT_DISABLED {
415 None
416 } else {
417 Some(PREALLOCATION_SIZE_LIMIT)
418 };
419 const ZERO_COPY_ALIGN_CHECK: bool = ZERO_COPY_ALIGN_CHECK;
420 type ByteOrder = B;
421 type IntEncoding = I;
422}
423
424/// Trait for configuration access when you need access to type parameters that depend on [`Config`]
425/// (e.g., [`Config::LengthEncoding`]).
426///
427/// Prefer [`ConfigCore`] when you don't need those configuration type parameters that depend
428/// on [`Config`] (e.g., primitive types).
429pub trait Config: ConfigCore {
430 type LengthEncoding: SeqLen<Self> + 'static;
431 type TagEncoding: TagEncoding<Self> + 'static;
432}
433
434impl<
435 const ZERO_COPY_ALIGN_CHECK: bool,
436 const PREALLOCATION_SIZE_LIMIT: usize,
437 LengthEncoding: 'static,
438 B,
439 I,
440 T,
441> Config for Configuration<ZERO_COPY_ALIGN_CHECK, PREALLOCATION_SIZE_LIMIT, LengthEncoding, B, I, T>
442where
443 LengthEncoding: SeqLen<Self>,
444 T: TagEncoding<Self>,
445 B: ByteOrder,
446 I: IntEncoding<B>,
447{
448 type LengthEncoding = LengthEncoding;
449 type TagEncoding = T;
450}
451
452mod serde;
453pub use serde::*;