serde_reflection/
error.rs

1// Copyright (c) Facebook, Inc. and its affiliates
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4use serde::{de, ser};
5use std::fmt;
6use thiserror::Error;
7
8/// Result type used in this crate.
9pub type Result<T, E = Error> = std::result::Result<T, E>;
10
11/// Error type used in this crate.
12#[derive(Clone, Debug, Error, PartialEq)]
13pub enum Error {
14    #[error("{0}")]
15    Custom(String),
16    #[error("Not supported: {0}")]
17    NotSupported(&'static str),
18    #[error("Failed to deserialize {0}")]
19    DeserializationError(&'static str),
20    #[error("In container {0}, recorded value for serialization format {1:?} failed to deserialize into {2}")]
21    UnexpectedDeserializationFormat(&'static str, crate::ContainerFormat, &'static str),
22    #[error("Incompatible formats detected: {0} {1}")]
23    Incompatible(String, String),
24    #[error("Incomplete tracing detected")]
25    UnknownFormat,
26    #[error("Incomplete tracing detected inside container: {0}")]
27    UnknownFormatInContainer(String),
28    #[error("Missing variants detected for specific enums: {0:?}")]
29    MissingVariants(Vec<String>),
30}
31
32impl ser::Error for Error {
33    fn custom<T: fmt::Display>(msg: T) -> Self {
34        Error::Custom(format!("Failed to serialize value: \"{}\"", msg))
35    }
36}
37
38impl de::Error for Error {
39    fn custom<T: fmt::Display>(msg: T) -> Self {
40        Error::Custom(format!("Failed to deserialize value: \"{}\"", msg))
41    }
42}
43
44impl Error {
45    /// Provides a longer description of the possible cause of an error during tracing.
46    pub fn explanation(&self) -> String {
47        use Error::*;
48
49        match self {
50            Custom(_) => {
51                r#"
52An error was returned by a Serde trait during (de)serialization tracing. In practice, this happens when
53user-provided code 'impl<'de> Deserialize<'de> for Foo { .. }' rejects a candidate value of type `Foo`
54provided by serde-reflection.
55
56To fix this, add a call `tracer.trace_value(foo, &mut samples)` so that a correct value `foo` is
57recorded *before* `tracer.trace_type` is called.
58"#.to_string()
59            }
60            NotSupported(_) => {
61                r#"
62An unsupported callback was called during (de)serialization tracing. In practice, this happens when an
63unsupported Serde attribute is used. Attributes specific to self-describing formats (JSON, YAML, TOML)
64are generally not supported. This includes: `#[serde(flatten)]`, `#[serde(tag = "type")]`,
65`#[serde(tag = "t", content = "c")]`, and `#[serde(untagged)]`.
66
67To fix this, avoid unsupported Serde attributes or use custom (de)serialize implementations with different
68behaviors depending on the Serde callback `(De)Serializer::is_human_readable()`.
69"#.to_string()
70            }
71            DeserializationError(_) => {
72                r#"
73This internal error should not be surfaced during tracing.
74"#.to_string()
75            }
76            UnexpectedDeserializationFormat(_, _, _) => {
77                r#"
78A value recorded by `trace_value` fails to deserialize as expected during a `trace_type` call. This can
79happen if custom implementations of the Serialize and Deserialize traits do not agree.
80
81Verify the implementations of Serialize and Deserialize for the given format.
82"#.to_string()
83            }
84
85            Incompatible(_, _) => {
86                r#"
87Two formats computed for the same entity do not match. This can happen if custom implementations of
88the Serialize and Deserialize traits do not agree, e.g. if one uses `Vec<u8>` and the other one uses `&[u8]`
89(implying bytes) --- see the crate `serde_bytes` for more context in this particular example.
90
91Verify the implementations of Serialize and Deserialize for the given format.
92"#.to_string()
93            }
94            UnknownFormat => {
95                r#"
96This internal error is returned should not be surfaced during tracing.
97"#.to_string()
98            }
99            UnknownFormatInContainer(name) => {
100                format!(r#"
101A final registry was requested but some formats are still unknown within the container {}. This can
102happen if `tracer.trace_value` was called on a value `foo` which does not reveal some of the underlying
103formats. E.g. if a field `x` of struct `Foo` has type `Option<String>` and `foo` is value of type
104`Foo` such that `foo.x == None`, then tracing the value `foo` may result in a format `Option<Unknown>`
105for the field `x`. The same applies to empty vectors and empty maps.
106
107To fix this, avoid `trace_value` and prefer `trace_type` when possible, or make sure to trace at
108least one value `foo` such that `foo.x` is not empty.
109"#,
110                name)
111            }
112            MissingVariants(names) => {
113                format!(r#"
114A registry was requested with `tracer.registry()` but some variants have not been analyzed yet
115inside the given enums {:?}.
116
117To fix this, make sure to call `tracer.trace_type<T>(..)` at least once for each enum type `T` in the
118corpus of definitions. You may also use `tracer.registry_unchecked()` for debugging.
119"#,
120                names)
121            }
122        }
123    }
124}