rmp_serde/
config.rs

1//! Change MessagePack behavior with configuration wrappers.
2
3/// Represents configuration that dicatates what the serializer does.
4///
5/// Implemented as an empty trait depending on a hidden trait in order to allow changing the
6/// methods of this trait without breaking backwards compatibility.
7pub trait SerializerConfig: sealed::SerializerConfig {}
8
9impl<T: sealed::SerializerConfig> SerializerConfig for T {}
10
11pub(crate) mod sealed {
12    use crate::config::BytesMode;
13
14    /// This is the inner trait - the real `SerializerConfig`.
15    ///
16    /// This hack disallows external implementations and usage of `SerializerConfig` and thus
17    /// allows us to change `SerializerConfig` methods freely without breaking backwards compatibility.
18    pub trait SerializerConfig: Copy {
19        /// Determines the value of `Serializer::is_human_readable` and
20        /// `Deserializer::is_human_readable`.
21        fn is_human_readable(&self) -> bool;
22
23        /// String struct fields
24        fn is_named(&self) -> bool;
25        fn bytes(&self) -> BytesMode;
26    }
27}
28
29#[derive(Copy, Clone, Debug)]
30pub(crate) struct RuntimeConfig {
31    pub(crate) is_human_readable: bool,
32    pub(crate) is_named: bool,
33    pub(crate) bytes: BytesMode,
34}
35
36/// When to encode `[u8]` as `bytes` rather than a sequence
37/// of integers. Serde without `serde_bytes` has trouble
38/// using `bytes`, and this is hack to force it. It may
39/// break some data types.
40#[non_exhaustive]
41#[derive(Debug, Copy, Clone, Default, PartialEq, Eq)]
42pub enum BytesMode {
43    /// Use bytes only when Serde requires it
44    /// (typically only when `serde_bytes` is used)
45    #[default]
46    Normal,
47    /// Use bytes for slices, `Vec`, and a few other types that
48    /// use `Iterator` in Serde.
49    ///
50    /// This may break some implementations of `Deserialize`.
51    ///
52    /// This does not include fixed-length arrays.
53    ForceIterables,
54    /// Use bytes for everything that looks like a container of `u8`.
55    /// This breaks some implementations of `Deserialize`.
56    ForceAll,
57}
58
59impl RuntimeConfig {
60    pub(crate) fn new(other: impl sealed::SerializerConfig) -> Self {
61        Self {
62            is_human_readable: other.is_human_readable(),
63            is_named: other.is_named(),
64            bytes: other.bytes(),
65        }
66    }
67}
68
69impl sealed::SerializerConfig for RuntimeConfig {
70    #[inline]
71    fn is_human_readable(&self) -> bool {
72        self.is_human_readable
73    }
74
75    #[inline]
76    fn is_named(&self) -> bool {
77        self.is_named
78    }
79
80    #[inline]
81    fn bytes(&self) -> BytesMode {
82        self.bytes
83    }
84}
85
86/// The default serializer/deserializer configuration.
87///
88/// This configuration:
89/// - Writes structs as a tuple, without field names
90/// - Writes enum variants as integers
91/// - Writes and reads types as binary, not human-readable
92//
93/// This is the most compact representation.
94#[derive(Copy, Clone, Debug)]
95pub struct DefaultConfig;
96
97impl sealed::SerializerConfig for DefaultConfig {
98    #[inline(always)]
99    fn is_named(&self) -> bool {
100        false
101    }
102
103    #[inline(always)]
104    fn is_human_readable(&self) -> bool {
105        false
106    }
107
108    #[inline(always)]
109    fn bytes(&self) -> BytesMode {
110        BytesMode::default()
111    }
112}
113
114/// Config wrapper, that overrides struct serialization by packing as a map with field names.
115///
116/// MessagePack specification does not tell how to serialize structs. This trait allows you to
117/// extend serialization to match your app's requirements.
118///
119/// Default `Serializer` implementation writes structs as a tuple, i.e. only its length is encoded,
120/// because it is the most compact representation.
121#[derive(Copy, Clone, Debug)]
122pub struct StructMapConfig<C>(C);
123
124impl<C> StructMapConfig<C> {
125    /// Creates a `StructMapConfig` inheriting unchanged configuration options from the given configuration.
126    #[inline]
127    pub fn new(inner: C) -> Self {
128        StructMapConfig(inner)
129    }
130}
131
132impl<C> sealed::SerializerConfig for StructMapConfig<C>
133where
134    C: sealed::SerializerConfig,
135{
136    #[inline(always)]
137    fn is_named(&self) -> bool {
138        true
139    }
140
141    #[inline(always)]
142    fn is_human_readable(&self) -> bool {
143        self.0.is_human_readable()
144    }
145
146    fn bytes(&self) -> BytesMode {
147        self.0.bytes()
148    }
149}
150
151/// Config wrapper that overrides struct serlization by packing as a tuple without field
152/// names.
153#[derive(Copy, Clone, Debug)]
154pub struct StructTupleConfig<C>(C);
155
156impl<C> StructTupleConfig<C> {
157    /// Creates a `StructTupleConfig` inheriting unchanged configuration options from the given configuration.
158    #[inline]
159    pub fn new(inner: C) -> Self {
160        StructTupleConfig(inner)
161    }
162}
163
164impl<C> sealed::SerializerConfig for StructTupleConfig<C>
165where
166    C: sealed::SerializerConfig,
167{
168    #[inline(always)]
169    fn is_named(&self) -> bool {
170        false
171    }
172
173    #[inline(always)]
174    fn is_human_readable(&self) -> bool {
175        self.0.is_human_readable()
176    }
177
178    fn bytes(&self) -> BytesMode {
179        self.0.bytes()
180    }
181}
182
183/// Config wrapper that overrides `Serializer::is_human_readable` and
184/// `Deserializer::is_human_readable` to return `true`.
185#[derive(Copy, Clone, Debug)]
186pub struct HumanReadableConfig<C>(C);
187
188impl<C> HumanReadableConfig<C> {
189    /// Creates a `HumanReadableConfig` inheriting unchanged configuration options from the given configuration.
190    #[inline]
191    pub fn new(inner: C) -> Self {
192        Self(inner)
193    }
194}
195
196impl<C> sealed::SerializerConfig for HumanReadableConfig<C>
197where
198    C: sealed::SerializerConfig,
199{
200    #[inline(always)]
201    fn is_named(&self) -> bool {
202        self.0.is_named()
203    }
204
205    #[inline(always)]
206    fn is_human_readable(&self) -> bool {
207        true
208    }
209
210    fn bytes(&self) -> BytesMode {
211        self.0.bytes()
212    }
213}
214
215/// Config wrapper that overrides `Serializer::is_human_readable` and
216/// `Deserializer::is_human_readable` to return `false`.
217#[derive(Copy, Clone, Debug)]
218pub struct BinaryConfig<C>(C);
219
220impl<C> BinaryConfig<C> {
221    /// Creates a `BinaryConfig` inheriting unchanged configuration options from the given configuration.
222    #[inline(always)]
223    pub fn new(inner: C) -> Self {
224        Self(inner)
225    }
226}
227
228impl<C> sealed::SerializerConfig for BinaryConfig<C>
229where
230    C: sealed::SerializerConfig,
231{
232    #[inline(always)]
233    fn is_named(&self) -> bool {
234        self.0.is_named()
235    }
236
237    #[inline(always)]
238    fn is_human_readable(&self) -> bool {
239        false
240    }
241
242    fn bytes(&self) -> BytesMode {
243        self.0.bytes()
244    }
245}