deser_incomplete/
error.rs

1use std::fmt::Display;
2
3use serde::de::{Expected, Unexpected};
4
5#[cfg(doc)]
6use serde::de::{DeserializeSeed, Deserializer};
7
8/// Either `DeserializerErr` or [`InternalError`] or [`InconsistentDeserializerError`].
9///
10/// Additional variants may be added in the future.
11#[derive(Debug, thiserror::Error)]
12#[error(transparent)]
13pub struct Error<DeserializerErr> {
14    // We always wrap in Box, mimicing serde_json. This is supposed to
15    // make the return types of lots of intermediate functions smaller
16    // and therefore faster. I don't know if this also matters for
17    // deser-incomplete.
18    err: Box<ErrorImpl<DeserializerErr>>,
19}
20
21#[derive(Debug, thiserror::Error)]
22pub(crate) enum ErrorImpl<DeserializerErr> {
23    /// The wrapped deserializer returned an error.
24    #[error(transparent)]
25    Deserializer(DeserializerErr),
26    #[error(transparent)]
27    Internal(InternalError),
28    /// The deserializer behaved in an inconsistent / nondeterministic way.
29    #[error(transparent)]
30    InconsistentDeserializer(InconsistentDeserializerError),
31}
32
33#[derive(Debug, thiserror::Error)]
34#[non_exhaustive]
35pub enum InternalError {
36    #[error(
37        "the maximum number of backtracks has been exceeded (see tracing logs for pointers to avoid a high number of backtracks)"
38    )]
39    TooManyBacktracks,
40    #[error(
41        "could not find a potential backtrack point (do you have #[serde(default)] on your top-level type? are your settings too strict?) (after {after_backtracks} backtracks)"
42    )]
43    NoPotentialBacktrackPoint { after_backtracks: usize },
44    #[error("bug in {pkg} (please report): {0}", pkg = std::env!("CARGO_PKG_NAME"))]
45    Bug(BugError),
46}
47
48#[derive(Debug, thiserror::Error)]
49#[error(transparent)]
50pub struct BugError(BugEnum);
51
52#[derive(Debug, thiserror::Error)]
53pub(crate) enum BugEnum {
54    #[error("our visitor should store the obtained value on the stack, but it's missing")]
55    OkButValueMissingFromStack,
56}
57
58#[derive(Debug, thiserror::Error)]
59#[non_exhaustive]
60pub enum InconsistentDeserializerError {}
61
62#[derive(Debug, thiserror::Error)]
63pub enum FallbackError {
64    #[error("The fallback took the visitor to compute a value, but didn't return a Result.")]
65    FallbackDidntCompute,
66    #[error("While constructing a fallback value: {0}")]
67    FallbackVisitor(serde::de::value::Error),
68}
69
70impl<DeserializerErr> Error<DeserializerErr> {
71    pub(crate) fn from_de(err: DeserializerErr) -> Self {
72        Self {
73            err: Box::new(ErrorImpl::Deserializer(err)),
74        }
75    }
76
77    /// Was it an error from the wrapped deserializer?
78    pub fn as_deserializer_error(&self) -> Option<&DeserializerErr> {
79        match &*self.err {
80            ErrorImpl::Deserializer(err) => Some(err),
81            _ => None,
82        }
83    }
84
85    pub fn into_deserializer_error(self) -> Option<DeserializerErr> {
86        match *self.err {
87            ErrorImpl::Deserializer(err) => Some(err),
88            _ => None,
89        }
90    }
91
92    pub fn as_internal_error(&self) -> Option<&InternalError> {
93        match &*self.err {
94            ErrorImpl::Internal(err) => Some(err),
95            _ => None,
96        }
97    }
98
99    pub fn into_internal_error(self) -> Option<InternalError> {
100        match *self.err {
101            ErrorImpl::Internal(err) => Some(err),
102            _ => None,
103        }
104    }
105
106    /// Was the deserializer being inconsistent?
107    pub fn as_inconsistent_deserializer_error(&self) -> Option<&InconsistentDeserializerError> {
108        match &*self.err {
109            ErrorImpl::InconsistentDeserializer(err) => Some(err),
110            _ => None,
111        }
112    }
113
114    pub fn into_inconsistent_deserializer_error(self) -> Option<InconsistentDeserializerError> {
115        match *self.err {
116            ErrorImpl::InconsistentDeserializer(err) => Some(err),
117            _ => None,
118        }
119    }
120}
121
122impl<DeserializerErr> Error<DeserializerErr>
123where
124    DeserializerErr: serde::de::Error,
125{
126    /// In some situations, we need to carry an error across the external
127    /// [`Deserializer`]'s error type. So, in case this error was not originally
128    /// a deserializer error, then make this a custom error.
129    ///
130    /// This is necessary for wrapping [`DeserializeSeed`].
131    pub fn unpack_or_make_custom(self) -> DeserializerErr {
132        match *self.err {
133            ErrorImpl::Deserializer(err) => err,
134            _ => DeserializerErr::custom(format!("{}: {self}", std::env!("CARGO_PKG_NAME"))),
135        }
136    }
137}
138
139impl<DeserializerErr> From<InternalError> for Error<DeserializerErr> {
140    fn from(err: InternalError) -> Self {
141        Self {
142            err: Box::new(ErrorImpl::Internal(err)),
143        }
144    }
145}
146
147impl From<BugEnum> for InternalError {
148    fn from(err: BugEnum) -> Self {
149        InternalError::Bug(BugError(err))
150    }
151}
152
153impl<DeserializerErr> From<BugEnum> for Error<DeserializerErr> {
154    fn from(err: BugEnum) -> Self {
155        Self {
156            err: Box::new(ErrorImpl::Internal(err.into())),
157        }
158    }
159}
160
161impl<DeserializerErr> From<InconsistentDeserializerError> for Error<DeserializerErr> {
162    fn from(err: InconsistentDeserializerError) -> Self {
163        Self {
164            err: Box::new(ErrorImpl::InconsistentDeserializer(err)),
165        }
166    }
167}
168
169impl<DeserializerErr> serde::de::Error for Error<DeserializerErr>
170where
171    DeserializerErr: serde::de::Error,
172{
173    fn custom<T>(msg: T) -> Self
174    where
175        T: Display,
176    {
177        Self::from_de(DeserializerErr::custom(msg))
178    }
179
180    #[cold]
181    fn invalid_type(unexp: Unexpected, exp: &dyn Expected) -> Self {
182        Self::from_de(DeserializerErr::invalid_type(unexp, exp))
183    }
184
185    #[cold]
186    fn invalid_value(unexp: Unexpected, exp: &dyn Expected) -> Self {
187        Self::from_de(DeserializerErr::invalid_value(unexp, exp))
188    }
189
190    #[cold]
191    fn invalid_length(len: usize, exp: &dyn Expected) -> Self {
192        Self::from_de(DeserializerErr::invalid_length(len, exp))
193    }
194
195    #[cold]
196    fn unknown_variant(variant: &str, expected: &'static [&'static str]) -> Self {
197        Self::from_de(DeserializerErr::unknown_variant(variant, expected))
198    }
199
200    #[cold]
201    fn unknown_field(field: &str, expected: &'static [&'static str]) -> Self {
202        Self::from_de(DeserializerErr::unknown_field(field, expected))
203    }
204
205    #[cold]
206    fn missing_field(field: &'static str) -> Self {
207        Self::from_de(DeserializerErr::missing_field(field))
208    }
209
210    #[cold]
211    fn duplicate_field(field: &'static str) -> Self {
212        Self::from_de(DeserializerErr::duplicate_field(field))
213    }
214}
215
216impl<DeserializerErr> Error<DeserializerErr>
217where
218    DeserializerErr: std::error::Error + Send + Sync + 'static,
219{
220    pub fn erase(self) -> Error<Box<dyn std::error::Error + Send + Sync>> {
221        let inner = *self.err;
222
223        let err = Box::new(match inner {
224            ErrorImpl::Deserializer(err) => {
225                ErrorImpl::Deserializer(Box::new(err) as Box<dyn std::error::Error + Send + Sync>)
226            }
227            ErrorImpl::Internal(err) => ErrorImpl::Internal(err),
228            ErrorImpl::InconsistentDeserializer(err) => ErrorImpl::InconsistentDeserializer(err),
229        });
230
231        Error { err }
232    }
233}