serde_reflection/
trace.rs

1// Copyright (c) Facebook, Inc. and its affiliates
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4use crate::{
5    de::Deserializer,
6    error::{Error, Result},
7    format::*,
8    ser::Serializer,
9    value::Value,
10};
11use erased_discriminant::Discriminant;
12use once_cell::sync::Lazy;
13use serde::{de::DeserializeSeed, Deserialize, Serialize};
14use std::any::TypeId;
15use std::collections::BTreeMap;
16
17/// A map of container formats.
18pub type Registry = BTreeMap<String, ContainerFormat>;
19
20/// Structure to drive the tracing of Serde serialization and deserialization.
21/// This typically aims at computing a `Registry`.
22#[derive(Debug)]
23pub struct Tracer {
24    /// Hold configuration options.
25    pub(crate) config: TracerConfig,
26
27    /// Formats of the named containers discovered so far, while tracing
28    /// serialization and/or deserialization.
29    pub(crate) registry: Registry,
30
31    /// Enums that have detected to be yet incomplete (i.e. missing variants)
32    /// while tracing deserialization.
33    pub(crate) incomplete_enums: BTreeMap<String, EnumProgress>,
34
35    /// Discriminant associated with each variant of each enum.
36    pub(crate) discriminants: BTreeMap<(TypeId, VariantId<'static>), Discriminant>,
37}
38
39#[derive(Copy, Clone, Debug)]
40pub(crate) enum EnumProgress {
41    /// There are variant names that have not yet been traced.
42    NamedVariantsRemaining,
43    /// There are variant numbers that have not yet been traced.
44    IndexedVariantsRemaining,
45}
46
47#[derive(Eq, PartialEq, Ord, PartialOrd, Debug)]
48pub(crate) enum VariantId<'a> {
49    Index(u32),
50    Name(&'a str),
51}
52
53/// User inputs, aka "samples", recorded during serialization.
54/// This will help passing user-defined checks during deserialization.
55#[derive(Debug, Default)]
56pub struct Samples {
57    pub(crate) values: BTreeMap<&'static str, Value>,
58}
59
60impl Samples {
61    /// Create a new structure to hold value samples.
62    pub fn new() -> Self {
63        Self::default()
64    }
65
66    /// Obtain a (serialized) sample.
67    pub fn value(&self, name: &'static str) -> Option<&Value> {
68        self.values.get(name)
69    }
70}
71
72/// Configuration object to create a tracer.
73#[derive(Debug)]
74pub struct TracerConfig {
75    pub(crate) is_human_readable: bool,
76    pub(crate) record_samples_for_newtype_structs: bool,
77    pub(crate) record_samples_for_tuple_structs: bool,
78    pub(crate) record_samples_for_structs: bool,
79    pub(crate) default_bool_value: bool,
80    pub(crate) default_u8_value: u8,
81    pub(crate) default_u16_value: u16,
82    pub(crate) default_u32_value: u32,
83    pub(crate) default_u64_value: u64,
84    pub(crate) default_u128_value: u128,
85    pub(crate) default_i8_value: i8,
86    pub(crate) default_i16_value: i16,
87    pub(crate) default_i32_value: i32,
88    pub(crate) default_i64_value: i64,
89    pub(crate) default_i128_value: i128,
90    pub(crate) default_f32_value: f32,
91    pub(crate) default_f64_value: f64,
92    pub(crate) default_char_value: char,
93    pub(crate) default_borrowed_str_value: &'static str,
94    pub(crate) default_string_value: String,
95    pub(crate) default_borrowed_bytes_value: &'static [u8],
96    pub(crate) default_byte_buf_value: Vec<u8>,
97}
98
99impl Default for TracerConfig {
100    /// Create a new structure to hold value samples.
101    fn default() -> Self {
102        Self {
103            is_human_readable: false,
104            record_samples_for_newtype_structs: true,
105            record_samples_for_tuple_structs: false,
106            record_samples_for_structs: false,
107            default_bool_value: false,
108            default_u8_value: 0,
109            default_u16_value: 0,
110            default_u32_value: 0,
111            default_u64_value: 0,
112            default_u128_value: 0,
113            default_i8_value: 0,
114            default_i16_value: 0,
115            default_i32_value: 0,
116            default_i64_value: 0,
117            default_i128_value: 0,
118            default_f32_value: 0.0,
119            default_f64_value: 0.0,
120            default_char_value: 'A',
121            default_borrowed_str_value: "",
122            default_string_value: String::new(),
123            default_borrowed_bytes_value: b"",
124            default_byte_buf_value: Vec::new(),
125        }
126    }
127}
128
129macro_rules! define_default_value_setter {
130    ($method:ident, $ty:ty) => {
131        /// The default serialized value for this primitive type.
132        pub fn $method(mut self, value: $ty) -> Self {
133            self.$method = value;
134            self
135        }
136    };
137}
138
139impl TracerConfig {
140    /// Whether to trace the human readable encoding of (de)serialization.
141    #[allow(clippy::wrong_self_convention)]
142    pub fn is_human_readable(mut self, value: bool) -> Self {
143        self.is_human_readable = value;
144        self
145    }
146
147    /// Record samples of newtype structs during serialization and inject them during deserialization.
148    pub fn record_samples_for_newtype_structs(mut self, value: bool) -> Self {
149        self.record_samples_for_newtype_structs = value;
150        self
151    }
152
153    /// Record samples of tuple structs during serialization and inject them during deserialization.
154    pub fn record_samples_for_tuple_structs(mut self, value: bool) -> Self {
155        self.record_samples_for_tuple_structs = value;
156        self
157    }
158
159    /// Record samples of (regular) structs during serialization and inject them during deserialization.
160    pub fn record_samples_for_structs(mut self, value: bool) -> Self {
161        self.record_samples_for_structs = value;
162        self
163    }
164
165    define_default_value_setter!(default_bool_value, bool);
166    define_default_value_setter!(default_u8_value, u8);
167    define_default_value_setter!(default_u16_value, u16);
168    define_default_value_setter!(default_u32_value, u32);
169    define_default_value_setter!(default_u64_value, u64);
170    define_default_value_setter!(default_u128_value, u128);
171    define_default_value_setter!(default_i8_value, i8);
172    define_default_value_setter!(default_i16_value, i16);
173    define_default_value_setter!(default_i32_value, i32);
174    define_default_value_setter!(default_i64_value, i64);
175    define_default_value_setter!(default_i128_value, i128);
176    define_default_value_setter!(default_f32_value, f32);
177    define_default_value_setter!(default_f64_value, f64);
178    define_default_value_setter!(default_char_value, char);
179    define_default_value_setter!(default_borrowed_str_value, &'static str);
180    define_default_value_setter!(default_string_value, String);
181    define_default_value_setter!(default_borrowed_bytes_value, &'static [u8]);
182    define_default_value_setter!(default_byte_buf_value, Vec<u8>);
183}
184
185impl Tracer {
186    /// Start tracing deserialization.
187    pub fn new(config: TracerConfig) -> Self {
188        Self {
189            config,
190            registry: BTreeMap::new(),
191            incomplete_enums: BTreeMap::new(),
192            discriminants: BTreeMap::new(),
193        }
194    }
195
196    /// Trace the serialization of a particular value.
197    /// * Nested containers will be added to the tracing registry, indexed by
198    /// their (non-qualified) name.
199    /// * Sampled Rust values will be inserted into `samples` to benefit future calls
200    /// to the `trace_type_*` methods.
201    pub fn trace_value<T>(&mut self, samples: &mut Samples, value: &T) -> Result<(Format, Value)>
202    where
203        T: ?Sized + Serialize,
204    {
205        let serializer = Serializer::new(self, samples);
206        let (mut format, sample) = value.serialize(serializer)?;
207        format.reduce();
208        Ok((format, sample))
209    }
210
211    /// Trace a single deserialization of a particular type.
212    /// * Nested containers will be added to the tracing registry, indexed by
213    /// their (non-qualified) name.
214    /// * As a byproduct of deserialization, we also return a value of type `T`.
215    /// * Tracing deserialization of a type may fail if this type or some dependencies
216    /// have implemented a custom deserializer that validates data. The solution is
217    /// to make sure that `samples` holds enough sampled Rust values to cover all the
218    /// custom types.
219    pub fn trace_type_once<'de, T>(&mut self, samples: &'de Samples) -> Result<(Format, T)>
220    where
221        T: Deserialize<'de>,
222    {
223        let mut format = Format::unknown();
224        let deserializer = Deserializer::new(self, samples, &mut format);
225        let value = T::deserialize(deserializer)?;
226        format.reduce();
227        Ok((format, value))
228    }
229
230    /// Same as `trace_type_once` for seeded deserialization.
231    pub fn trace_type_once_with_seed<'de, S>(
232        &mut self,
233        samples: &'de Samples,
234        seed: S,
235    ) -> Result<(Format, S::Value)>
236    where
237        S: DeserializeSeed<'de>,
238    {
239        let mut format = Format::unknown();
240        let deserializer = Deserializer::new(self, samples, &mut format);
241        let value = seed.deserialize(deserializer)?;
242        format.reduce();
243        Ok((format, value))
244    }
245
246    /// Same as `trace_type_once` but if `T` is an enum, we repeat the process
247    /// until all variants of `T` are covered.
248    /// We accumulate and return all the sampled values at the end.
249    pub fn trace_type<'de, T>(&mut self, samples: &'de Samples) -> Result<(Format, Vec<T>)>
250    where
251        T: Deserialize<'de>,
252    {
253        let mut values = Vec::new();
254        loop {
255            let (format, value) = self.trace_type_once::<T>(samples)?;
256            values.push(value);
257            if let Format::TypeName(name) = &format {
258                if let Some(&progress) = self.incomplete_enums.get(name) {
259                    // Restart the analysis to find more variants of T.
260                    self.incomplete_enums.remove(name);
261                    if let EnumProgress::NamedVariantsRemaining = progress {
262                        values.pop().unwrap();
263                    }
264                    continue;
265                }
266            }
267            return Ok((format, values));
268        }
269    }
270
271    /// Trace a type `T` that is simple enough that no samples of values are needed.
272    /// * If `T` is an enum, the tracing iterates until all variants of `T` are covered.
273    /// * Accumulate and return all the sampled values at the end.
274    /// This is merely a shortcut for `self.trace_type` with a fixed empty set of samples.
275    pub fn trace_simple_type<'de, T>(&mut self) -> Result<(Format, Vec<T>)>
276    where
277        T: Deserialize<'de>,
278    {
279        static SAMPLES: Lazy<Samples> = Lazy::new(Samples::new);
280        self.trace_type(&SAMPLES)
281    }
282
283    /// Same as `trace_type` for seeded deserialization.
284    pub fn trace_type_with_seed<'de, S>(
285        &mut self,
286        samples: &'de Samples,
287        seed: S,
288    ) -> Result<(Format, Vec<S::Value>)>
289    where
290        S: DeserializeSeed<'de> + Clone,
291    {
292        let mut values = Vec::new();
293        loop {
294            let (format, value) = self.trace_type_once_with_seed(samples, seed.clone())?;
295            values.push(value);
296            if let Format::TypeName(name) = &format {
297                if let Some(&progress) = self.incomplete_enums.get(name) {
298                    // Restart the analysis to find more variants of T.
299                    self.incomplete_enums.remove(name);
300                    if let EnumProgress::NamedVariantsRemaining = progress {
301                        values.pop().unwrap();
302                    }
303                    continue;
304                }
305            }
306            return Ok((format, values));
307        }
308    }
309
310    /// Finish tracing and recover a map of normalized formats.
311    /// Returns an error if we detect incompletely traced types.
312    /// This may happen in a few of cases:
313    /// * We traced serialization of user-provided values but we are still missing the content
314    ///   of an option type, the content of a sequence type, the key or the value of a dictionary type.
315    /// * We traced deserialization of an enum type but we detect that some enum variants are still missing.
316    pub fn registry(self) -> Result<Registry> {
317        let mut registry = self.registry;
318        for (name, format) in registry.iter_mut() {
319            format
320                .normalize()
321                .map_err(|_| Error::UnknownFormatInContainer(name.clone()))?;
322        }
323        if self.incomplete_enums.is_empty() {
324            Ok(registry)
325        } else {
326            Err(Error::MissingVariants(
327                self.incomplete_enums.into_keys().collect(),
328            ))
329        }
330    }
331
332    /// Same as registry but always return a value, even if we detected issues.
333    /// This should only be use for debugging.
334    pub fn registry_unchecked(self) -> Registry {
335        let mut registry = self.registry;
336        for format in registry.values_mut() {
337            format.normalize().unwrap_or(());
338        }
339        registry
340    }
341
342    pub(crate) fn record_container(
343        &mut self,
344        samples: &mut Samples,
345        name: &'static str,
346        format: ContainerFormat,
347        value: Value,
348        record_value: bool,
349    ) -> Result<(Format, Value)> {
350        self.registry.entry(name.to_string()).unify(format)?;
351        if record_value {
352            samples.values.insert(name, value.clone());
353        }
354        Ok((Format::TypeName(name.into()), value))
355    }
356
357    pub(crate) fn record_variant(
358        &mut self,
359        samples: &mut Samples,
360        name: &'static str,
361        variant_index: u32,
362        variant_name: &'static str,
363        variant: VariantFormat,
364        variant_value: Value,
365    ) -> Result<(Format, Value)> {
366        let mut variants = BTreeMap::new();
367        variants.insert(
368            variant_index,
369            Named {
370                name: variant_name.into(),
371                value: variant,
372            },
373        );
374        let format = ContainerFormat::Enum(variants);
375        let value = Value::Variant(variant_index, Box::new(variant_value));
376        self.record_container(samples, name, format, value, false)
377    }
378
379    pub(crate) fn get_sample<'de, 'a>(
380        &'a self,
381        samples: &'de Samples,
382        name: &'static str,
383    ) -> Option<(&'a ContainerFormat, &'de Value)> {
384        match samples.value(name) {
385            Some(value) => {
386                let format = self
387                    .registry
388                    .get(name)
389                    .expect("recorded containers should have a format already");
390                Some((format, value))
391            }
392            None => None,
393        }
394    }
395}