1use std::{fmt, mem::swap, ops::Deref, slice};
2
3use serde::{Deserialize, Deserializer, Serialize, de::Visitor};
4use serde_json::{Number as JsonNumber, Value};
5use serde_value::ValueDeserializer;
6use serde_with::skip_serializing_none;
7
8use crate::openapi::{Map, MaybeRef, macros};
9
10macros::define_openapi_spec_object! {
11 [override_with]:
12 #[derive(Default)]
13 pub struct Schema {
14 #[serde(rename = "type")]
16 pub schema_type: Option<SchemaType>,
17 #[serde(rename = "enum")]
18 #[serde(skip_serializing_if = "Vec::is_empty")]
19 pub enum_values: Vec<Value>,
20 #[serde(rename = "const")]
21 pub const_value: Option<Value>,
22 pub format: Option<Format>,
23
24 #[serde(skip_serializing_if = "Map::is_empty")]
26 pub properties: Map<String, MaybeRef<Schema>>,
27 pub property_names: Option<Box<MaybeRef<Schema>>>,
28 pub additional_properties: Option<Box<MaybeRef<Schema>>>,
29 pub max_properties: Option<u64>,
30 pub min_properties: Option<u64>,
31 #[serde(skip_serializing_if = "Vec::is_empty")]
32 pub required: Vec<String>,
33 #[serde(skip_serializing_if = "Map::is_empty")]
34 pub dependent_required: Map<String, Vec<String>>,
35
36 pub multiple_of: Option<JsonNumber>,
38 pub maximum: Option<JsonNumber>,
39 pub exclusive_maximum: Option<JsonNumber>,
40 pub minimum: Option<JsonNumber>,
41 pub exclusive_minimum: Option<JsonNumber>,
42
43 pub max_length: Option<u64>,
45 pub min_length: Option<u64>,
46 pub pattern: Option<String>,
47 pub content_encoding: Option<String>,
48 pub content_media_type: Option<String>,
49 pub content_schema: Option<Box<MaybeRef<Schema>>>,
50
51 pub items: Option<ArrayItems>,
53 #[serde(skip_serializing_if = "Vec::is_empty")]
54 pub prefix_items: Vec<MaybeRef<Schema>>,
55
56 pub max_items: Option<u64>,
57 pub min_items: Option<u64>,
58 pub unique_items: Option<bool>,
59 pub max_contains: Option<u64>,
60 pub min_contains: Option<u64>,
61
62 pub title: Option<String>,
64 pub description: Option<String>,
65 pub default: Option<Value>,
66 pub deprecated: Option<bool>,
67 pub read_only: Option<bool>,
68 pub write_only: Option<bool>,
69 pub example: Option<Value>,
70 #[serde(skip_serializing_if = "Vec::is_empty")]
71 pub examples: Vec<Value>,
72
73 #[serde(skip_serializing_if = "Vec::is_empty")]
75 pub all_of: Vec<MaybeRef<Schema>>,
76 #[serde(skip_serializing_if = "Vec::is_empty")]
77 pub one_of: Vec<MaybeRef<Schema>>,
78 #[serde(skip_serializing_if = "Vec::is_empty")]
79 pub any_of: Vec<MaybeRef<Schema>>,
80 pub discriminator: Option<Discriminator>,
81 }
82}
83
84impl Schema {
85 pub fn new_string_constant(string: impl Into<String>) -> Self {
86 Schema::default()
87 .with_schema_type(Type::String)
88 .with_enum_values(vec![Value::String(string.into())])
89 }
90 pub fn null() -> Self {
91 Schema::default().with_schema_type(Type::Null)
92 }
93}
94
95#[derive(PartialEq, Eq, Clone)]
96pub enum ArrayItems {
97 False,
98 Schema(Box<MaybeRef<Schema>>),
99}
100
101impl<I: Into<MaybeRef<Schema>>> From<I> for ArrayItems {
102 fn from(value: I) -> Self {
103 Self::Schema(Box::new(value.into()))
104 }
105}
106
107impl Serialize for ArrayItems {
108 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
109 where
110 S: serde::Serializer,
111 {
112 match self {
113 Self::False => serializer.serialize_bool(false),
114 Self::Schema(schema) => schema.serialize(serializer),
115 }
116 }
117}
118
119impl<'de> Deserialize<'de> for ArrayItems {
120 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
121 where
122 D: serde::Deserializer<'de>,
123 {
124 struct Vis;
125 impl<'de> Visitor<'de> for Vis {
126 type Value = ArrayItems;
127
128 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
129 formatter.write_str("false")
130 }
131
132 fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
133 where
134 E: serde::de::Error,
135 {
136 if !v {
137 Ok(ArrayItems::False)
138 } else {
139 Err(E::custom("array items must be false or a schema object"))
140 }
141 }
142 }
143 let value = deserializer.deserialize_any(serde_value::ValueVisitor)?;
144 if let Ok(schema) = Box::deserialize(ValueDeserializer::<D::Error>::new(value.clone())) {
145 return Ok(Self::Schema(schema));
146 }
147 ValueDeserializer::<D::Error>::new(value).deserialize_bool(Vis)
148 }
149}
150
151#[derive(PartialEq, Eq, Clone, Serialize, Deserialize)]
152#[serde(untagged)]
153pub enum SchemaType {
154 Single(Type),
155 Multiple(Vec<Type>),
156}
157
158impl SchemaType {
159 pub fn push(&mut self, ty: Type) {
160 match self {
161 Self::Single(prev_ty) => {
162 let mut swap_target = Type::Null;
163 swap(prev_ty, &mut swap_target);
164 *self = Self::Multiple(vec![swap_target, ty])
165 }
166 Self::Multiple(prev_types) => prev_types.push(ty),
167 }
168 }
169}
170
171impl Deref for SchemaType {
172 type Target = [Type];
173
174 fn deref(&self) -> &Self::Target {
175 match self {
176 Self::Single(single) => slice::from_ref(single),
177 Self::Multiple(multiple) => multiple,
178 }
179 }
180}
181
182impl From<Type> for SchemaType {
183 fn from(value: Type) -> Self {
184 Self::Single(value)
185 }
186}
187
188#[derive(PartialEq, Eq, Clone, Serialize, Deserialize)]
189#[serde(rename_all = "camelCase")]
190#[non_exhaustive]
191pub enum Type {
192 Null,
193 Boolean,
194 Object,
195 Array,
196 Number,
197 String,
198 Integer,
199}
200
201#[derive(PartialEq, Eq, Clone, Serialize, Deserialize)]
203#[serde(rename_all = "kebab-case")]
204#[non_exhaustive]
205pub enum Format {
206 Int8,
208 Int16,
209 Int32,
210 Int64,
211 Uint8,
212 Uint16,
213 Uint32,
214 Uint64,
215 Float,
216 Double,
217 Char,
219 Binary,
221
222 DateTimeLocal,
225 DateTime,
227 Date,
229 Time,
231 Duration,
233 Byte,
235 Base64Url,
237 Commonmark,
239 Decimal,
241
242 Email,
243 IdnEmail,
244
245 Hostname,
246 IdnHostname,
247
248 IPv4,
249 IPv6,
250
251 Uri,
252 UriReference,
253 Iri,
254 IriReference,
255 Uuid,
256
257 UriTemplate,
258
259 JsonPointer,
260 RelativeJsonPointer,
261
262 Regex,
263
264 #[serde(untagged)]
265 Other(String),
266}
267
268#[skip_serializing_none]
269#[derive(PartialEq, Eq, Clone, Serialize, Deserialize)]
270#[serde(rename_all = "camelCase")]
271#[non_exhaustive]
272pub struct Discriminator {
273 pub property_name: String,
274 #[serde(skip_serializing_if = "Map::is_empty")]
275 pub mapping: Map<String, String>,
276 pub default_mapping: Option<String>,
277}
278
279impl Discriminator {
280 pub fn new(property_name: String) -> Self {
281 Self {
282 property_name,
283 mapping: Default::default(),
284 default_mapping: Default::default(),
285 }
286 }
287}