shex_ast/ast/
serde_string_or_struct.rs

1//! Tools for working with fields that might contain a string, or might
2//! contain a struct.
3//! This code is based on: <https://github.com/emk/compose_yml/blob/7e8e0f47dcc41cf08e15fe082ef4c40b5f0475eb/src/v2/string_or_struct.rs>
4
5use serde::de::{self, Deserialize, DeserializeSeed, Deserializer, SeqAccess};
6use serde::ser::{Serialize, Serializer};
7use std::fmt::{self, Display};
8use std::marker::PhantomData;
9use std::str::FromStr;
10
11/// Handle a value which may either a struct that deserializes as type `T`,
12/// or a bare string that can be turned into a type `T` using
13/// `FromStr::from_str`.  We do this in a clever way that allows us to be
14/// generic over multiple such types, and which allows us to use the
15/// structure deserialization code automatically generated by serde.
16///
17/// An earlier and much uglier version of this parser was the inspiration
18/// for [this official `serde`
19/// example](https://serde.rs/string-or-struct.html), which in turn forms
20/// the basis of this code.
21pub fn deserialize_string_or_struct<'de, T, D>(d: D) -> Result<T, D::Error>
22where
23    T: Deserialize<'de> + FromStr,
24    <T as FromStr>::Err: Display,
25    D: Deserializer<'de>,
26{
27    /// Declare an internal visitor type to handle our input.
28    struct StringOrStruct<T>(PhantomData<T>);
29
30    impl<'de, T> de::Visitor<'de> for StringOrStruct<T>
31    where
32        T: Deserialize<'de> + FromStr,
33        <T as FromStr>::Err: Display,
34    {
35        type Value = T;
36
37        fn visit_str<E>(self, value: &str) -> Result<T, E>
38        where
39            E: de::Error,
40        {
41            FromStr::from_str(value).map_err(|err| {
42                // Just convert the underlying error type into a string and
43                // pass it to serde as a custom error.
44                de::Error::custom(format!("{}", err))
45            })
46        }
47
48        fn visit_map<M>(self, visitor: M) -> Result<T, M::Error>
49        where
50            M: de::MapAccess<'de>,
51        {
52            let mvd = de::value::MapAccessDeserializer::new(visitor);
53            Deserialize::deserialize(mvd)
54        }
55
56        fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
57            write!(formatter, "a string or a map")
58        }
59    }
60
61    d.deserialize_any(StringOrStruct(PhantomData))
62}
63
64/// Like `string_or_struct`, but it also handles the case where the
65/// value is optional.
66///
67/// We could probably make this more generic, supporting underlying
68/// functions other than `string_or_struct`, but that's a project for
69/// another day.
70pub fn deserialize_opt_string_or_struct<'de, T, D>(d: D) -> Result<Option<T>, D::Error>
71where
72    T: Deserialize<'de> + FromStr,
73    <T as FromStr>::Err: Display,
74    D: Deserializer<'de>,
75{
76    /// Declare an internal visitor type to handle our input.
77    struct OptStringOrStruct<T>(PhantomData<T>);
78
79    impl<'de, T> de::Visitor<'de> for OptStringOrStruct<T>
80    where
81        T: Deserialize<'de> + FromStr,
82        <T as FromStr>::Err: Display,
83    {
84        type Value = Option<T>;
85
86        fn visit_none<E>(self) -> Result<Self::Value, E>
87        where
88            E: de::Error,
89        {
90            Ok(None)
91        }
92
93        fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
94        where
95            D: Deserializer<'de>,
96        {
97            deserialize_string_or_struct(deserializer).map(Some)
98        }
99
100        fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
101            write!(formatter, "a null, a string or a map")
102        }
103    }
104
105    d.deserialize_option(OptStringOrStruct(PhantomData))
106}
107
108/// Some structs can be serialized as a string,
109/// but only under certain circumstances.
110pub trait SerializeStringOrStruct: Serialize {
111    /// Serialize either a string representation of this struct, or a full
112    /// struct if the object cannot be represented as a string.
113    fn serialize_string_or_struct<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
114    where
115        S: Serializer;
116}
117
118/// Serialize the specified value as a string if we can, and a struct
119/// otherwise.
120pub fn serialize_string_or_struct<T, S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
121where
122    T: SerializeStringOrStruct,
123    S: Serializer,
124{
125    value.serialize_string_or_struct(serializer)
126}
127
128/// Like `serialize_string_or_struct`, but can also handle missing values.
129pub fn serialize_opt_string_or_struct<T, S>(
130    value: &Option<T>,
131    serializer: S,
132) -> Result<S::Ok, S::Error>
133where
134    T: SerializeStringOrStruct,
135    S: Serializer,
136{
137    /// A fun little trick: We need to pass `value` to `serialize_some`,
138    /// but we don't want `serialize_some` to call the normal `serialize`
139    /// method on it.
140    /// So we define a local wrapper type that overrides the
141    /// serialization.  This is one of the more subtle tricks of generic
142    /// programming in Rust: using a "newtype" wrapper struct to override
143    /// how a trait is applied to a class.
144    struct Wrap<'a, T>(&'a T)
145    where
146        T: SerializeStringOrStruct;
147
148    impl<'a, T> Serialize for Wrap<'a, T>
149    where
150        T: 'a + SerializeStringOrStruct,
151    {
152        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
153        where
154            S: Serializer,
155        {
156            match *self {
157                Wrap(v) => serialize_string_or_struct(v, serializer),
158            }
159        }
160    }
161
162    match *value {
163        None => serializer.serialize_none(),
164        Some(ref v) => serializer.serialize_some(&Wrap(v)),
165    }
166}
167
168pub fn deserialize_opt_box_string_or_struct<'de, T, D>(d: D) -> Result<Option<Box<T>>, D::Error>
169where
170    T: Deserialize<'de> + FromStr,
171    <T as FromStr>::Err: Display,
172    D: Deserializer<'de>,
173{
174    /// Declare an internal visitor type to handle our input.
175    struct OptBoxStringOrStruct<T>(PhantomData<T>);
176
177    impl<'de, T> de::Visitor<'de> for OptBoxStringOrStruct<T>
178    where
179        T: Deserialize<'de> + FromStr,
180        <T as FromStr>::Err: Display,
181    {
182        type Value = Option<Box<T>>;
183
184        fn visit_none<E>(self) -> Result<Self::Value, E>
185        where
186            E: de::Error,
187        {
188            Ok(None)
189        }
190
191        fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
192        where
193            D: Deserializer<'de>,
194        {
195            deserialize_string_or_struct(deserializer).map(|e| Some(Box::new(e)))
196        }
197
198        fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
199            write!(formatter, "a null, a string or a map")
200        }
201    }
202
203    d.deserialize_option(OptBoxStringOrStruct(PhantomData))
204}
205
206/// Like `serialize_string_or_struct`, but can also handle missing values.
207pub fn serialize_opt_box_string_or_struct<T, S>(
208    value: &Option<Box<T>>,
209    serializer: S,
210) -> Result<S::Ok, S::Error>
211where
212    T: SerializeStringOrStruct,
213    S: Serializer,
214{
215    /// A fun little trick: We need to pass `value` to `serialize_some`,
216    /// but we don't want `serialize_some` to call the normal `serialize`
217    /// method on it.
218    /// So we define a local wrapper type that overrides the
219    /// serialization.  This is one of the more subtle tricks of generic
220    /// programming in Rust: using a "newtype" wrapper struct to override
221    /// how a trait is applied to a class.
222    struct Wrap<'a, T>(&'a T)
223    where
224        T: SerializeStringOrStruct;
225
226    impl<'a, T> Serialize for Wrap<'a, T>
227    where
228        T: 'a + SerializeStringOrStruct,
229    {
230        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
231        where
232            S: Serializer,
233        {
234            match *self {
235                Wrap(v) => serialize_string_or_struct(v, serializer),
236            }
237        }
238    }
239
240    match *value {
241        None => serializer.serialize_none(),
242        Some(ref v) => serializer.serialize_some(&Wrap(v.as_ref())),
243    }
244}
245
246#[derive(Debug, Clone)]
247pub struct SeqAccessError;
248
249// This is just an unfinished attempt...
250#[allow(dead_code)]
251pub fn deserialize_vec_box_string_or_struct<'de, T, D>(d: D) -> Result<Vec<Box<T>>, D::Error>
252where
253    T: Deserialize<'de> + FromStr,
254    <T as FromStr>::Err: Display,
255    D: Deserializer<'de>,
256{
257    /// Declare an internal visitor type to handle our input.
258    struct VecBoxStringOrStruct<T>(PhantomData<T>);
259    struct SeqAccessStringOrStruct<T>(PhantomData<T>);
260
261    impl<'de, T> de::SeqAccess<'de> for SeqAccessStringOrStruct<T>
262    where
263        T: Deserialize<'de> + FromStr,
264        <T as FromStr>::Err: Display,
265    {
266        type Error = serde_json::Error;
267
268        fn next_element_seed<A>(
269            &mut self,
270            _v: A,
271        ) -> Result<Option<<A as DeserializeSeed<'de>>::Value>, <Self as SeqAccess<'de>>::Error>
272        where
273            A: DeserializeSeed<'de>,
274        {
275            todo!()
276        }
277    }
278
279    impl<'de, T> de::Visitor<'de> for VecBoxStringOrStruct<T>
280    where
281        T: Deserialize<'de> + FromStr,
282        <T as FromStr>::Err: Display,
283    {
284        type Value = Vec<Box<T>>;
285
286        fn visit_seq<A>(self, mut visitor: A) -> Result<Self::Value, A::Error>
287        where
288            A: SeqAccess<'de>,
289        {
290            let mut values = Vec::new();
291            while let Some(value) = visitor.next_element()? {
292                values.push(value);
293            }
294            Ok(values)
295        }
296
297        fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
298            write!(formatter, "an array of values")
299        }
300    }
301
302    d.deserialize_seq(VecBoxStringOrStruct(PhantomData))
303}
304
305/// Like `serialize_string_or_struct`, but can also handle missing values.
306#[allow(dead_code)]
307pub fn serialize_vec_box_string_or_struct<T, S>(
308    _value: &[Box<T>],
309    serializer: S,
310) -> Result<S::Ok, S::Error>
311where
312    T: SerializeStringOrStruct,
313    S: Serializer,
314{
315    /// A fun little trick: We need to pass `value` to `serialize_some`,
316    /// but we don't want `serialize_some` to call the normal `serialize`
317    /// method on it.
318    /// So we define a local wrapper type that overrides the
319    /// serialization.  This is one of the more subtle tricks of generic
320    /// programming in Rust: using a "newtype" wrapper struct to override
321    /// how a trait is applied to a class.
322    struct Wrap<'a, T>(&'a T)
323    where
324        T: SerializeStringOrStruct;
325
326    impl<'a, T> Serialize for Wrap<'a, T>
327    where
328        T: 'a + SerializeStringOrStruct,
329    {
330        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
331        where
332            S: Serializer,
333        {
334            match *self {
335                Wrap(v) => serialize_string_or_struct(v, serializer),
336            }
337        }
338    }
339    /* match *value {
340        None => serializer.serialize_none(),
341        Some(ref v) => serializer.serialize_some(&Wrap(v.as_ref())),
342    }*/
343    serializer.serialize_none()
344}