serde_path/
error.rs

1use std::fmt;
2
3// this wrapper type is used as the deserializer error to hide the `serde::de::Error` impl which
4// would otherwise be public if we used `ErrorKind` as the error directly
5#[derive(Debug)]
6pub struct PathDeserializationError {
7    pub(crate) kind: ErrorKind,
8}
9
10impl PathDeserializationError {
11    pub(crate) fn new(kind: ErrorKind) -> Self {
12        Self { kind }
13    }
14
15    pub(crate) fn wrong_number_of_parameters() -> WrongNumberOfParameters<()> {
16        WrongNumberOfParameters { got: () }
17    }
18
19    #[track_caller]
20    pub(crate) fn unsupported_type(name: &'static str) -> Self {
21        Self::new(ErrorKind::UnsupportedType { name })
22    }
23}
24
25pub(crate) struct WrongNumberOfParameters<G> {
26    got: G,
27}
28
29impl<G> WrongNumberOfParameters<G> {
30    #[allow(clippy::unused_self)]
31    pub(crate) fn got<G2>(self, got: G2) -> WrongNumberOfParameters<G2> {
32        WrongNumberOfParameters { got }
33    }
34}
35
36impl WrongNumberOfParameters<usize> {
37    pub(crate) fn expected(self, expected: usize) -> PathDeserializationError {
38        PathDeserializationError::new(ErrorKind::WrongNumberOfParameters {
39            got: self.got,
40            expected,
41        })
42    }
43}
44
45impl serde::de::Error for PathDeserializationError {
46    #[inline]
47    fn custom<T>(msg: T) -> Self
48    where
49        T: fmt::Display,
50    {
51        Self {
52            kind: ErrorKind::Message(msg.to_string()),
53        }
54    }
55}
56
57impl fmt::Display for PathDeserializationError {
58    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59        self.kind.fmt(f)
60    }
61}
62
63impl std::error::Error for PathDeserializationError {}
64
65/// The kinds of errors that can happen we deserializing into a [`Path`].
66///
67/// This type is obtained through [`FailedToDeserializePathParams::kind`] or
68/// [`FailedToDeserializePathParams::into_kind`] and is useful for building
69/// more precise error messages.
70#[derive(Debug, PartialEq, Eq)]
71#[non_exhaustive]
72pub enum ErrorKind {
73    /// The URI contained the wrong number of parameters.
74    WrongNumberOfParameters {
75        /// The number of actual parameters in the URI.
76        got: usize,
77        /// The number of expected parameters.
78        expected: usize,
79    },
80
81    /// Failed to parse the value at a specific key into the expected type.
82    ///
83    /// This variant is used when deserializing into types that have named fields, such as structs.
84    ParseErrorAtKey {
85        /// The key at which the value was located.
86        key: String,
87        /// The value from the URI.
88        value: String,
89        /// The expected type of the value.
90        expected_type: &'static str,
91    },
92
93    /// Failed to parse the value at a specific index into the expected type.
94    ///
95    /// This variant is used when deserializing into sequence types, such as tuples.
96    ParseErrorAtIndex {
97        /// The index at which the value was located.
98        index: usize,
99        /// The value from the URI.
100        value: String,
101        /// The expected type of the value.
102        expected_type: &'static str,
103    },
104
105    /// Failed to parse a value into the expected type.
106    ///
107    /// This variant is used when deserializing into a primitive type (such as `String` and `u32`).
108    ParseError {
109        /// The value from the URI.
110        value: String,
111        /// The expected type of the value.
112        expected_type: &'static str,
113    },
114
115    /// A parameter contained text that, once percent decoded, wasn't valid UTF-8.
116    InvalidUtf8InPathParam {
117        /// The key at which the invalid value was located.
118        key: String,
119    },
120
121    /// Tried to serialize into an unsupported type such as nested maps.
122    ///
123    /// This error kind is caused by programmer errors and thus gets converted into a `500 Internal
124    /// Server Error` response.
125    UnsupportedType {
126        /// The name of the unsupported type.
127        name: &'static str,
128    },
129
130    /// Catch-all variant for errors that don't fit any other variant.
131    Message(String),
132}
133
134impl fmt::Display for ErrorKind {
135    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
136        match self {
137            ErrorKind::Message(error) => error.fmt(f),
138            ErrorKind::InvalidUtf8InPathParam { key } => write!(f, "Invalid UTF-8 in `{key}`"),
139            ErrorKind::WrongNumberOfParameters { got, expected } => {
140                write!(
141                    f,
142                    "Wrong number of path arguments for `Path`. Expected {expected} but got {got}"
143                )?;
144
145                if *expected == 1 {
146                    write!(f, ". Note that multiple parameters must be extracted with a tuple `Path<(_, _)>` or a struct `Path<YourParams>`")?;
147                }
148
149                Ok(())
150            }
151            ErrorKind::UnsupportedType { name } => write!(f, "Unsupported type `{name}`"),
152            ErrorKind::ParseErrorAtKey {
153                key,
154                value,
155                expected_type,
156            } => write!(
157                f,
158                "Cannot parse `{key}` with value `{value:?}` to a `{expected_type}`"
159            ),
160            ErrorKind::ParseError {
161                value,
162                expected_type,
163            } => write!(f, "Cannot parse `{value:?}` to a `{expected_type}`"),
164            ErrorKind::ParseErrorAtIndex {
165                index,
166                value,
167                expected_type,
168            } => write!(
169                f,
170                "Cannot parse value at index {index} with value `{value:?}` to a `{expected_type}`"
171            ),
172        }
173    }
174}