Skip to main content

defuse_serde_utils/
cow.rs

1use std::{borrow::Cow, marker::PhantomData};
2
3use serde::{Deserializer, Serializer};
4use serde_with::{DeserializeAs, SerializeAs, ser::SerializeAsWrap};
5
6/// A `serde_with` "as" marker for `Cow<'a, [T]>`.
7/// `serde_with` has a blanket `SerializeAs`/`DeserializeAs` for `[T]`/`Vec<T>`,
8/// but neither for `Cow<'a, [T]>` with a generic `T`
9pub struct AsCowSlice<As: ?Sized>(PhantomData<As>);
10
11impl<T, As> SerializeAs<Cow<'_, [T]>> for AsCowSlice<As>
12where
13    T: Clone,
14    As: SerializeAs<T>,
15{
16    fn serialize_as<S>(source: &Cow<'_, [T]>, serializer: S) -> Result<S::Ok, S::Error>
17    where
18        S: Serializer,
19    {
20        serializer.collect_seq(source.iter().map(SerializeAsWrap::<T, As>::new))
21    }
22}
23
24impl<'de, 'a, T, As> DeserializeAs<'de, Cow<'a, [T]>> for AsCowSlice<As>
25where
26    T: Clone,
27    As: DeserializeAs<'de, T>,
28{
29    fn deserialize_as<D>(deserializer: D) -> Result<Cow<'a, [T]>, D::Error>
30    where
31        D: Deserializer<'de>,
32    {
33        <Vec<As> as DeserializeAs<'de, Vec<T>>>::deserialize_as(deserializer).map(Cow::Owned)
34    }
35}
36
37#[cfg(feature = "schemars-v0_8")]
38const _: () = {
39    use schemars::{SchemaGenerator, schema::Schema};
40    use serde_with::schemars_0_8::JsonSchemaAs;
41
42    impl<T, As> JsonSchemaAs<Cow<'_, [T]>> for AsCowSlice<As>
43    where
44        T: Clone,
45        As: JsonSchemaAs<T>,
46    {
47        fn schema_name() -> String {
48            <Vec<As> as JsonSchemaAs<Vec<T>>>::schema_name()
49        }
50
51        fn json_schema(generator: &mut SchemaGenerator) -> Schema {
52            <Vec<As> as JsonSchemaAs<Vec<T>>>::json_schema(generator)
53        }
54
55        fn is_referenceable() -> bool {
56            <Vec<As> as JsonSchemaAs<Vec<T>>>::is_referenceable()
57        }
58    }
59};
60
61#[cfg(test)]
62mod tests {
63    use super::*;
64    use serde::{Deserialize, Serialize};
65    use serde_with::{DisplayFromStr, serde_as};
66
67    #[serde_as]
68    #[derive(Debug, Serialize, Deserialize)]
69    struct S<'a> {
70        #[serde_as(as = "AsCowSlice<DisplayFromStr>")]
71        amounts: Cow<'a, [u128]>,
72    }
73
74    #[test]
75    fn serializes_as_strings() {
76        let s = S {
77            amounts: Cow::Owned(vec![1, u128::MAX]),
78        };
79        let json = serde_json::to_string(&s).unwrap();
80        assert_eq!(json, format!(r#"{{"amounts":["1","{}"]}}"#, u128::MAX));
81    }
82
83    #[test]
84    fn roundtrip() {
85        let s = S {
86            amounts: Cow::Owned(vec![0, 42, u128::MAX]),
87        };
88        let json = serde_json::to_string(&s).unwrap();
89        let back: S = serde_json::from_str(&json).unwrap();
90        assert_eq!(back.amounts.into_owned(), vec![0, 42, u128::MAX]);
91    }
92}