deserr/
lib.rs

1#![doc = include_str!("../README.md")]
2#![doc(
3    html_favicon_url = "https://raw.githubusercontent.com/meilisearch/deserr/main/assets/deserr.ico?raw=true"
4)]
5#![doc(
6    html_logo_url = "https://raw.githubusercontent.com/meilisearch/deserr/main/assets/deserr_squared.png?raw=true"
7)]
8
9#[cfg(feature = "actix-web")]
10pub mod actix_web;
11#[cfg(feature = "axum")]
12pub mod axum;
13pub mod errors;
14mod impls;
15#[cfg(feature = "serde-cs")]
16pub mod serde_cs;
17#[cfg(feature = "serde-json")]
18pub mod serde_json;
19mod value;
20
21extern crate self as deserr;
22
23/**
24It is possible to derive the `Deserr` trait for structs and enums with named fields.
25The derive proc macro accept many arguments, explained below:
26
27The basic usage is as follows:
28```
29use deserr::Deserr;
30
31#[derive(Deserr)]
32struct MyStruct {
33    x: bool,
34    y: u8,
35}
36```
37This will implement `impl<E> Deserr<E> MyStruct` for all `E: DeserializeError`.
38
39To use it on enums, the attribute `tag` must be added:
40```
41use deserr::Deserr;
42
43#[derive(Deserr)]
44#[deserr(tag = "my_enum_tag")]
45enum MyEnum {
46    A,
47    B { x: bool, y: u8 }
48}
49```
50This will correctly deserialize the given enum for values of this shape:
51```json
52{
53    "my_enum_tag": "A"
54}
55// or
56{
57    "my_enum_tag": "B",
58    "x": true,
59    "y": 1
60}
61```
62
63It is possible to change the name of the keys corresponding to each field using the `rename` and `rename_all`
64attributes:
65
66```rust
67use deserr::Deserr;
68#[derive(Deserr)]
69#[deserr(rename_all = camelCase)]
70struct MyStruct {
71    my_field: bool,
72    #[deserr(rename = "goodbye_world")]
73    hello_world: u8,
74}
75```
76will parse the following:
77```json
78{
79    "myField": 1,
80    "goodbye_world": 2
81}
82```
83*/
84pub use deserr_internal::Deserr;
85pub use value::{IntoValue, Map, Sequence, Value, ValueKind, ValuePointer, ValuePointerRef};
86
87use std::ops::ControlFlow;
88
89/// A trait for types that can be deserialized from a [`Value`]. The generic type
90/// parameter `E` is the custom error that is returned when deserialization fails.
91pub trait Deserr<E: DeserializeError>: Sized {
92    /// Attempts to deserialize `Self` from the given value. Note that this method is an
93    /// implementation detail. You probably want to use the [`deserialize`] function directly instead.
94    fn deserialize_from_value<V: IntoValue>(
95        value: Value<V>,
96        location: ValuePointerRef,
97    ) -> Result<Self, E>;
98}
99
100/// Deserialize the given value.
101///
102/// This function has three generic arguments, two of which can often be inferred.
103/// 1. `Ret` is the type we want to deserialize to. For example: `MyStruct`
104/// 2. `Val` is the type of the value given as argument. For example: `serde_json::Value`
105/// 3. `E` is the error type we want to get when deserialization fails. For example: `MyError`
106pub fn deserialize<Ret, Val, E>(value: Val) -> Result<Ret, E>
107where
108    Ret: Deserr<E>,
109    Val: IntoValue,
110    E: DeserializeError,
111{
112    Ret::deserialize_from_value(value.into_value(), ValuePointerRef::Origin)
113}
114
115/// A trait which describes how to combine two errors together.
116pub trait MergeWithError<T>: Sized {
117    /// Merge two errors together.
118    ///
119    /// ## Arguments:
120    /// - `self_`: the existing error, if any
121    /// - `other`: the new error
122    /// - `merge_location`: the location where the merging happens.
123    ///
124    /// ## Return value
125    /// It should return the merged error inside a `Result`.
126    ///
127    /// The variant of the returned result should be `Ok(e)` to signal that the deserialization
128    /// should continue (to accumulate more errors), or `Err(e)` to stop the deserialization immediately.
129    ///
130    /// Note that in both cases, the deserialization should eventually fail.
131    ///
132    /// ## Example
133    /// Imagine you have the following json:
134    /// ```json
135    /// {
136    ///    "w": true,
137    ///    "x" : { "y": 1 }
138    /// }
139    /// ```
140    /// It may be that deserializing the first field, `w`, fails with error `suberror: E`. This is the
141    /// first deserialization error we encounter, so the current error value is `None`. The function `Self::merge`
142    /// is called as follows:
143    /// ```ignore
144    /// // let mut error = None;
145    /// // let mut location : ValuePointerRef::Origin;
146    /// error = Some(Self::merge(error, suberror, location.push_key("w"))?);
147    /// // if the returned value was Err(e), then we returned early from the deserialize method
148    /// // otherwise, `error` is now set
149    /// ```
150    /// Later on, we encounter a new suberror originating from `x.y`. The `merge` function is called again:
151    /// ```ignore
152    /// // let mut error = Some(..);
153    /// // let mut location : ValuePointerRef::Origin;
154    /// error = Some(Self::merge(error, suberror, location.push_key("x"))?);
155    /// // if the returned value was Err(e), then we returned early from the deserialize method
156    /// // otherwise, `error` is now the result of its merging with suberror.
157    /// ```
158    /// Note that even though the suberror originated at `x.y`, the `merge_location` argument was `x`
159    /// because that is where the merge happened.
160    fn merge(
161        self_: Option<Self>,
162        other: T,
163        merge_location: ValuePointerRef,
164    ) -> ControlFlow<Self, Self>;
165}
166
167pub enum ErrorKind<'a, V: IntoValue> {
168    IncorrectValueKind {
169        actual: Value<V>,
170        accepted: &'a [ValueKind],
171    },
172    MissingField {
173        field: &'a str,
174    },
175    UnknownKey {
176        key: &'a str,
177        accepted: &'a [&'a str],
178    },
179    UnknownValue {
180        value: &'a str,
181        accepted: &'a [&'a str],
182    },
183    BadSequenceLen {
184        actual: V::Sequence,
185        expected: usize,
186    },
187    Unexpected {
188        msg: String,
189    },
190}
191
192/// A trait for errors returned by [`deserialize_from_value`](Deserr::deserialize_from_value).
193pub trait DeserializeError: Sized + MergeWithError<Self> {
194    fn error<V: IntoValue>(
195        self_: Option<Self>,
196        error: ErrorKind<V>,
197        location: ValuePointerRef,
198    ) -> ControlFlow<Self, Self>;
199}
200
201/// Used by the derive proc macro. Do not use.
202#[doc(hidden)]
203pub enum FieldState<T> {
204    Missing,
205    Err,
206    Some(T),
207}
208
209impl<T> FieldState<T> {
210    pub fn is_missing(&self) -> bool {
211        matches!(self, FieldState::Missing)
212    }
213
214    #[track_caller]
215    pub fn unwrap(self) -> T {
216        match self {
217            FieldState::Some(x) => x,
218            _ => panic!("Unwrapping an empty field state"),
219        }
220    }
221
222    #[track_caller]
223    pub fn unwrap_or(self, value: T) -> T {
224        match self {
225            FieldState::Some(x) => x,
226            FieldState::Missing => value,
227            FieldState::Err => value,
228        }
229    }
230
231    #[track_caller]
232    pub fn ok_or<E>(self, err: E) -> Result<T, E> {
233        match self {
234            FieldState::Some(x) => Ok(x),
235            FieldState::Missing => Err(err),
236            FieldState::Err => Err(err),
237        }
238    }
239
240    pub fn map<U>(self, f: impl Fn(T) -> U) -> FieldState<U> {
241        match self {
242            FieldState::Some(x) => FieldState::Some(f(x)),
243            FieldState::Missing => FieldState::Missing,
244            FieldState::Err => FieldState::Err,
245        }
246    }
247}
248
249/// Extract the `ControlFlow` result if it's the same type.
250pub fn take_cf_content<T>(r: ControlFlow<T, T>) -> T {
251    match r {
252        ControlFlow::Continue(x) => x,
253        ControlFlow::Break(x) => x,
254    }
255}