Skip to main content

openapi_nexus/spec/oas32/spec/
callback.rs

1use std::{collections::BTreeMap, error::Error as StdError};
2
3use serde::{Deserialize, Serialize};
4
5use super::PathItem;
6
7/// Map of possible out-of band callbacks related to the parent operation.
8#[derive(Debug, Clone, Default, PartialEq, Deserialize, Serialize)]
9#[serde(try_from = "CallbackSerde", into = "CallbackSerde")]
10pub struct Callback {
11    /// Map of Path Item Objects for the callback.
12    pub paths: BTreeMap<String, PathItem>,
13
14    /// Specification extensions (keys with "x-" prefix as in the document).
15    pub extensions: BTreeMap<String, serde_json::Value>,
16}
17
18#[derive(Debug, Deserialize, Serialize)]
19#[serde(transparent)]
20struct CallbackSerde(serde_json::Map<String, serde_json::Value>);
21
22impl TryFrom<CallbackSerde> for Callback {
23    type Error = Box<dyn StdError>;
24
25    fn try_from(CallbackSerde(map): CallbackSerde) -> Result<Self, Self::Error> {
26        let (extensions, paths) = bisect_map(map, |key| key.starts_with("x-"));
27
28        let paths = paths
29            .into_iter()
30            .map(|(key, value)| serde_json::from_value(value).map(|v| (key, v)))
31            .collect::<Result<_, _>>()?;
32
33        Ok(Self {
34            paths,
35            extensions: extensions.into_iter().collect(),
36        })
37    }
38}
39
40fn bisect_map(
41    map: serde_json::Map<String, serde_json::Value>,
42    predicate: fn(&String) -> bool,
43) -> (
44    serde_json::Map<String, serde_json::Value>,
45    serde_json::Map<String, serde_json::Value>,
46) {
47    let mut first = map;
48    let mut second = first.clone();
49
50    first.retain(|key, _| predicate(key));
51    second.retain(|key, _| !predicate(key));
52
53    (first, second)
54}
55
56impl From<Callback> for CallbackSerde {
57    fn from(val: Callback) -> Self {
58        let Callback { paths, extensions } = val;
59
60        CallbackSerde(
61            paths
62                .into_iter()
63                .map(|(key, val)| {
64                    (
65                        key,
66                        serde_json::to_value(val).expect("path item serialization should not fail"),
67                    )
68                })
69                .chain(extensions)
70                .collect(),
71        )
72    }
73}