1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
use serde::{Deserialize, Serialize};
use crate::{OpenAPI, Schema};
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
#[serde(untagged)]
pub enum ReferenceOr<T> {
Reference {
#[serde(rename = "$ref")]
reference: String,
},
Item(T),
}
impl<T> ReferenceOr<T> {
pub fn ref_(r: &str) -> Self {
ReferenceOr::Reference {
reference: r.to_owned(),
}
}
pub fn boxed_item(item: T) -> ReferenceOr<Box<T>> {
ReferenceOr::Item(Box::new(item))
}
/// Converts this [ReferenceOr] to the item inside, if it exists.
///
/// The return value will be [Option::Some] if this was a [ReferenceOr::Item] or [Option::None] if this was a [ReferenceOr::Reference].
///
/// # Examples
///
/// ```
/// # use openapiv3::ReferenceOr;
///
/// let i = ReferenceOr::Item(1);
/// assert_eq!(i.into_item(), Some(1));
///
/// let j: ReferenceOr<u8> = ReferenceOr::Reference { reference: String::new() };
/// assert_eq!(j.into_item(), None);
/// ```
pub fn into_item(self) -> Option<T> {
match self {
ReferenceOr::Reference { .. } => None,
ReferenceOr::Item(i) => Some(i),
}
}
/// Returns a reference to to the item inside this [ReferenceOr], if it exists.
///
/// The return value will be [Option::Some] if this was a [ReferenceOr::Item] or [Option::None] if this was a [ReferenceOr::Reference].
///
/// # Examples
///
/// ```
/// # use openapiv3::ReferenceOr;
///
/// let i = ReferenceOr::Item(1);
/// assert_eq!(i.as_item(), Some(&1));
///
/// let j: ReferenceOr<u8> = ReferenceOr::Reference { reference: String::new() };
/// assert_eq!(j.as_item(), None);
/// ```
// TODO i believe this should be called as_ref() ?
pub fn as_item(&self) -> Option<&T> {
match self {
ReferenceOr::Reference { .. } => None,
ReferenceOr::Item(i) => Some(i),
}
}
pub fn as_mut(&mut self) -> Option<&mut T> {
match self {
ReferenceOr::Reference { .. } => None,
ReferenceOr::Item(i) => Some(i),
}
}
}
impl<T: 'static> ReferenceOr<T> {
pub fn as_ref(&self) -> ReferenceOr<&T> {
match self {
ReferenceOr::Reference { reference } => ReferenceOr::Reference { reference: reference.clone() },
ReferenceOr::Item(i) => ReferenceOr::Item(i),
}
}
}
pub fn get_component_name(reference: &str) -> Option<&str> {
let mut parts = reference.split('/');
if parts.next() != Some("#") {
return None;
}
if parts.next() != Some("components") {
return None;
}
if parts.next() != Some("schemas") {
return None;
}
parts.next()
}
impl ReferenceOr<Schema> {
pub fn resolve<'a>(&'a self, spec: &'a OpenAPI) -> &'a Schema {
match self {
ReferenceOr::Reference { reference } => {
let name = get_component_name(&reference).unwrap();
let components = spec.components.as_ref().unwrap();
let ref_or_schema = components.schemas.get(name).unwrap();
match ref_or_schema {
ReferenceOr::Item(schema) => schema,
ReferenceOr::Reference { .. } => ref_or_schema.resolve(spec),
}
},
ReferenceOr::Item(schema) => schema,
}
}
}
impl ReferenceOr<Box<Schema>> {
pub fn unbox(&self) -> ReferenceOr<Schema> {
match self {
ReferenceOr::Reference { reference } => ReferenceOr::Reference { reference: reference.clone() },
ReferenceOr::Item(boxed) => ReferenceOr::Item(*boxed.clone()),
}
}
}