serdapt/
try_from.rs

1// Copyright (c) 2024 Stephane Raux. Distributed under the 0BSD license.
2
3use crate::{DeserializeWith, Id};
4use core::{fmt::Display, marker::PhantomData};
5use serde::Deserializer;
6
7/// Adapter to deserialize using a [`TryFrom`](core::convert::TryFrom) conversion
8///
9/// This adapter works by deserializing a value of type `T` using adapter `F`, and then attempting
10/// a conversion from `T` to the target type.
11///
12/// # Example
13/// ```
14/// use serde::Deserialize;
15/// use serde_json::json;
16///
17/// #[derive(Deserialize)]
18/// struct Foo(#[serde(with = "serdapt::TryFrom::<u32>")] char);
19///
20/// let x = serde_json::from_value::<Foo>(json!(b'a')).unwrap();
21/// assert_eq!(x.0, 'a');
22/// ```
23pub struct TryFrom<T, F = Id> {
24    _convert: PhantomData<fn(T)>,
25    _f: PhantomData<F>,
26}
27
28impl<T, F> TryFrom<T, F> {
29    /// Deserializes value with adapter
30    pub fn deserialize<'de, U, D>(deserializer: D) -> Result<U, D::Error>
31    where
32        D: Deserializer<'de>,
33        Self: DeserializeWith<'de, U>,
34    {
35        Self::deserialize_with(deserializer)
36    }
37}
38
39impl<'de, T, U, F> DeserializeWith<'de, U> for TryFrom<T, F>
40where
41    U: core::convert::TryFrom<T>,
42    U::Error: Display,
43    F: DeserializeWith<'de, T>,
44{
45    fn deserialize_with<D>(deserializer: D) -> Result<U, D::Error>
46    where
47        D: serde::Deserializer<'de>,
48    {
49        F::deserialize_with(deserializer)?
50            .try_into()
51            .map_err(serde::de::Error::custom)
52    }
53}
54
55#[cfg(test)]
56mod tests {
57    use serde::Deserialize;
58    use serde_json::json;
59
60    #[derive(Debug, Deserialize)]
61    struct Foo(
62        #[allow(unused)]
63        #[serde(with = "crate::TryFrom::<u32>")]
64        char,
65    );
66
67    #[test]
68    fn try_from_adapter_fails_to_deserialize_if_conversion_fails() {
69        serde_json::from_value::<Foo>(json!(0xd800)).unwrap_err();
70    }
71}