openapiv3/
util.rs

1use std::hash::Hash;
2use std::marker::PhantomData;
3
4use indexmap::IndexMap;
5use serde::{
6    de::{IgnoredAny, Visitor},
7    Deserialize, Deserializer,
8};
9
10/// Use this as a serde skip_serializing_if attribute to skip serializing `false` values:
11/// struct Foo {
12///     #[serde(default, skip_serializing_if = "is_false")]
13///     pub my_optional_property: bool,
14/// }
15#[allow(clippy::trivially_copy_pass_by_ref)] // needs to match signature for use in serde attribute
16#[inline]
17pub const fn is_false(v: &bool) -> bool {
18    !(*v)
19}
20
21pub(crate) fn deserialize_extensions<'de, D>(
22    deserializer: D,
23) -> Result<IndexMap<String, serde_json::Value>, D::Error>
24where
25    D: Deserializer<'de>,
26{
27    deserializer.deserialize_map(PredicateVisitor(
28        |key: &String| key.starts_with("x-"),
29        PhantomData,
30    ))
31}
32
33/// Used to deserialize IndexMap<K, V> that are flattened within other structs.
34/// This only adds keys that satisfy the given predicate.
35pub(crate) struct PredicateVisitor<F, K, V>(pub F, pub PhantomData<(K, V)>);
36
37impl<'de, F, K, V> Visitor<'de> for PredicateVisitor<F, K, V>
38where
39    F: Fn(&K) -> bool,
40    K: Deserialize<'de> + Eq + Hash,
41    V: Deserialize<'de>,
42{
43    type Value = IndexMap<K, V>;
44
45    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
46        formatter.write_str("a map whose fields obey a predicate")
47    }
48
49    fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
50    where
51        A: serde::de::MapAccess<'de>,
52    {
53        let mut ret = Self::Value::default();
54
55        loop {
56            match map.next_key::<K>() {
57                Err(_) => (),
58                Ok(None) => break,
59                Ok(Some(key)) if self.0(&key) => {
60                    let _ = ret.insert(key, map.next_value()?);
61                }
62                Ok(Some(_)) => {
63                    let _ = map.next_value::<IgnoredAny>()?;
64                }
65            }
66        }
67
68        Ok(ret)
69    }
70}