musli/
options.rs

1//! Serialization options.
2
3/// [`Options`] builder.
4pub struct Builder(Options);
5
6const DEFAULT: Options = (ByteOrder::NATIVE as Options) << BYTEORDER_BIT;
7
8/// Start building new options.
9///
10/// Call [`Builder::build`] to construct them.
11pub const fn new() -> Builder {
12    Builder(DEFAULT)
13}
14
15/// Type encapsulating a static options for an encoding.
16///
17/// Note: despite being made up of a primitive type, this cannot be serialized
18/// and correctly re-used. This is simply the case because of restrictions in
19/// constant evaluation.
20///
21/// Making assumptions about its layout might lead to unspecified behavior
22/// during encoding. Only use this type through the provided [`options`] APIs.
23///
24/// [`options`]: crate::options
25pub type Options = u128;
26
27const BYTEORDER_BIT: Options = 0;
28const INTEGER_BIT: Options = 1;
29const LENGTH_BIT: Options = 2;
30const MAP_KEYS_AS_NUMBERS_BIT: Options = 3;
31const FLOAT_BIT: Options = 8;
32const LENGTH_WIDTH_BIT: Options = 16;
33
34impl Builder {
35    /// Indicates if an integer serialization should be variable.
36    #[inline(always)]
37    pub const fn with_integer(self, integer: Integer) -> Self {
38        const MASK: Options = 0b11 << INTEGER_BIT;
39        Self((self.0 & !MASK) | ((integer as Options) << INTEGER_BIT))
40    }
41
42    /// Indicates the configuration of float serialization.
43    #[inline(always)]
44    pub const fn with_float(self, float: Float) -> Self {
45        const MASK: Options = 0b11 << FLOAT_BIT;
46        Self((self.0 & !MASK) | ((float as Options) << FLOAT_BIT))
47    }
48
49    /// Specify which byte order to use, if that's relevant.
50    #[inline(always)]
51    pub const fn with_byte_order(self, byte_order: ByteOrder) -> Self {
52        const MASK: Options = 0b1 << BYTEORDER_BIT;
53        Self((self.0 & !MASK) | ((byte_order as Options) << BYTEORDER_BIT))
54    }
55
56    /// Specify how lengths should be serialized.
57    #[inline(always)]
58    pub const fn with_length(self, length: Integer) -> Self {
59        const MASK: Options = 0b1 << LENGTH_BIT;
60        Self((self.0 & !MASK) | ((length as Options) << LENGTH_BIT))
61    }
62
63    /// Allows for treating string keys as numbers.
64    #[inline(always)]
65    pub const fn with_map_keys_as_numbers(self, value: bool) -> Self {
66        const MASK: Options = 0b1 << MAP_KEYS_AS_NUMBERS_BIT;
67        let value = if value { 1 } else { 0 };
68        Self((self.0 & !MASK) | (value << MAP_KEYS_AS_NUMBERS_BIT))
69    }
70
71    /// If length is set to [`Integer::Fixed`], specify the width of the length.
72    #[inline(always)]
73    pub const fn with_length_width(self, width: Width) -> Self {
74        const MASK: Options = 0b11 << LENGTH_WIDTH_BIT;
75        let this = self.with_length(Integer::Fixed);
76        Self((this.0 & !MASK) | ((width as Options) << LENGTH_WIDTH_BIT))
77    }
78
79    /// Build a flavor.
80    #[inline(always)]
81    pub const fn build(self) -> Options {
82        self.0
83    }
84}
85
86#[cfg(any(
87    feature = "storage",
88    feature = "wire",
89    feature = "descriptive",
90    feature = "json",
91    feature = "value"
92))]
93#[inline(always)]
94pub(crate) const fn integer<const OPT: Options>() -> Integer {
95    match (OPT >> INTEGER_BIT) & 0b1 {
96        0 => Integer::Variable,
97        _ => Integer::Fixed,
98    }
99}
100
101#[cfg(test)]
102#[inline(always)]
103pub(crate) const fn float<const OPT: Options>() -> Float {
104    match (OPT >> FLOAT_BIT) & 0b11 {
105        0 => Float::Integer,
106        1 => Float::Variable,
107        _ => Float::Fixed,
108    }
109}
110
111#[cfg(any(
112    feature = "storage",
113    feature = "wire",
114    feature = "descriptive",
115    feature = "json",
116    feature = "value"
117))]
118#[inline(always)]
119pub(crate) const fn length<const OPT: Options>() -> Integer {
120    match (OPT >> LENGTH_BIT) & 0b1 {
121        0 => Integer::Variable,
122        _ => Integer::Fixed,
123    }
124}
125
126#[cfg(any(
127    feature = "storage",
128    feature = "wire",
129    feature = "descriptive",
130    feature = "json",
131    feature = "value"
132))]
133#[inline(always)]
134pub(crate) const fn length_width<const OPT: Options>() -> Width {
135    match (OPT >> LENGTH_WIDTH_BIT) & 0b11 {
136        0 => Width::U8,
137        1 => Width::U16,
138        2 => Width::U32,
139        _ => Width::U64,
140    }
141}
142
143#[cfg(any(
144    feature = "storage",
145    feature = "wire",
146    feature = "descriptive",
147    feature = "json",
148    feature = "value"
149))]
150#[inline(always)]
151pub(crate) const fn byteorder<const OPT: Options>() -> ByteOrder {
152    match (OPT >> BYTEORDER_BIT) & 0b1 {
153        0 => ByteOrder::Little,
154        _ => ByteOrder::Big,
155    }
156}
157
158#[cfg(all(feature = "alloc", feature = "value"))]
159#[inline(always)]
160pub(crate) const fn is_map_keys_as_numbers<const OPT: Options>() -> bool {
161    ((OPT >> MAP_KEYS_AS_NUMBERS_BIT) & 0b1) == 1
162}
163
164/// Integer serialization mode.
165#[cfg_attr(test, derive(Debug, PartialEq))]
166#[repr(u8)]
167#[non_exhaustive]
168pub enum Integer {
169    /// Variable number encoding.
170    Variable = 0,
171    /// Fixed number encoding.
172    Fixed = 1,
173}
174
175/// Float serialization mode.
176#[cfg_attr(test, derive(Debug, PartialEq))]
177#[repr(u8)]
178#[non_exhaustive]
179pub enum Float {
180    /// Use the same serialization as integers, after coercing the bits of a
181    /// float into an unsigned integer.
182    Integer = 0,
183    /// Use variable float encoding.
184    Variable = 1,
185    /// Use fixed float encoding.
186    Fixed = 2,
187}
188
189/// Byte order to use when encoding numbers.
190///
191/// By default, this is the [`ByteOrder::NATIVE`] byte order of the target
192/// platform.
193#[derive(PartialEq, Eq)]
194#[cfg_attr(test, derive(Debug))]
195#[repr(u8)]
196#[non_exhaustive]
197pub enum ByteOrder {
198    /// Little endian byte order.
199    Little = 0,
200    /// Big endian byte order.
201    Big = 1,
202}
203
204impl ByteOrder {
205    /// The native byte order.
206    ///
207    /// [`Little`] for little and [`Big`] for big endian platforms.
208    ///
209    /// [`Little`]: ByteOrder::Little
210    /// [`Big`]: ByteOrder::Big
211    pub const NATIVE: Self = if cfg!(target_endian = "little") {
212        Self::Little
213    } else {
214        Self::Big
215    };
216
217    /// The network byte order.
218    ///
219    /// This is the same as [`Big`].
220    ///
221    /// [`Big`]: ByteOrder::Big
222    pub const NETWORK: Self = Self::Big;
223}
224
225#[doc(hidden)]
226#[cfg(any(
227    feature = "storage",
228    feature = "wire",
229    feature = "descriptive",
230    feature = "value"
231))]
232macro_rules! width_arm {
233    ($width:expr, $macro:path) => {
234        match $width {
235            $crate::options::Width::U8 => {
236                $macro!(u8)
237            }
238            $crate::options::Width::U16 => {
239                $macro!(u16)
240            }
241            $crate::options::Width::U32 => {
242                $macro!(u32)
243            }
244            $crate::options::Width::U64 => {
245                $macro!(u64)
246            }
247        }
248    };
249}
250
251#[cfg(any(
252    feature = "storage",
253    feature = "wire",
254    feature = "descriptive",
255    feature = "value"
256))]
257pub(crate) use width_arm;
258
259/// The width of a numerical type.
260#[derive(Clone, Copy)]
261#[cfg_attr(test, derive(Debug, PartialEq))]
262#[repr(u8)]
263#[non_exhaustive]
264pub enum Width {
265    /// 8 bit width.
266    U8 = 0,
267    /// 16 bit width.
268    U16 = 1,
269    /// 32 bit width.
270    U32 = 2,
271    /// 64 bit width.
272    U64 = 3,
273}
274
275#[test]
276fn test_builds() {
277    macro_rules! assert_or_default {
278        ($expr:expr, $test:expr, $default:expr, ()) => {
279            assert_eq!(
280                $test,
281                $default,
282                "{}: Expected default value for {}",
283                stringify!($expr),
284                stringify!($test)
285            );
286        };
287
288        ($expr:expr, $test:expr, $_default:expr, ($expected:expr)) => {
289            assert_eq!(
290                $test,
291                $expected,
292                "{}: Expected custom value for {}",
293                stringify!($expr),
294                stringify!($test)
295            );
296        };
297    }
298
299    macro_rules! test_case {
300        ($expr:expr => {
301            $(byteorder = $byteorder:expr,)?
302            $(integer = $integer:expr,)?
303            $(float = $float:expr,)?
304            $(length = $length:expr,)?
305            $(length_width = $length_width:expr,)?
306            $(is_map_keys_as_numbers = $is_map_keys_as_numbers:expr,)?
307        }) => {{
308            const O: Options = $expr.build();
309            assert_or_default!($expr, byteorder::<O>(), ByteOrder::NATIVE, ($($byteorder)?));
310            assert_or_default!($expr, integer::<O>(), Integer::Variable, ($($integer)?));
311            assert_or_default!($expr, float::<O>(), Float::Integer, ($($float)?));
312            assert_or_default!($expr, length::<O>(), Integer::Variable, ($($length)?));
313            assert_or_default!($expr, is_map_keys_as_numbers::<O>(), false, ($($is_map_keys_as_numbers)?));
314        }}
315    }
316
317    test_case! {
318        self::new() => {}
319    }
320
321    test_case! {
322        self::new().with_map_keys_as_numbers(true) => {
323            is_map_keys_as_numbers = true,
324        }
325    }
326
327    test_case! {
328        self::new().with_integer(Integer::Fixed) => {
329            integer = Integer::Fixed,
330        }
331    }
332
333    test_case! {
334        self::new().with_float(Float::Fixed) => {
335            float = Float::Fixed,
336        }
337    }
338
339    test_case! {
340        self::new().with_float(Float::Variable) => {
341            float = Float::Variable,
342        }
343    }
344
345    test_case! {
346        self::new().with_float(Float::Variable) => {
347            float = Float::Variable,
348        }
349    }
350
351    test_case! {
352        self::new().with_byte_order(ByteOrder::Big) => {
353            byteorder = ByteOrder::Big,
354        }
355    }
356
357    test_case! {
358        self::new().with_byte_order(ByteOrder::Little) => {
359            byteorder = ByteOrder::Little,
360        }
361    }
362
363    test_case! {
364        self::new().with_length_width(Width::U16) => {
365            length = Integer::Fixed,
366            length_width = Width::U16,
367        }
368    }
369
370    test_case! {
371        self::new().with_length_width(Width::U32) => {
372            length = Integer::Fixed,
373            length_width = Width::U32,
374        }
375    }
376
377    test_case! {
378        self::new().with_length_width(Width::U64) => {
379            length = Integer::Fixed,
380            length_width = Width::U64,
381        }
382    }
383}