salvo_oapi/openapi/schema/
array.rs1use serde::de::Visitor;
2use serde::{Deserialize, Serialize};
3use serde_json::Value;
4
5use crate::schema::{AllOf, AnyOf, BasicType, Object, OneOf, Ref};
6use crate::{Deprecated, PropMap, RefOr, Schema, SchemaType, Xml};
7
8#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
12#[serde(untagged)]
13pub enum ArrayItems {
14 RefOrSchema(Box<RefOr<Schema>>),
16 #[serde(with = "array_items_false")]
22 False,
23}
24
25impl Default for ArrayItems {
26 fn default() -> Self {
27 Self::RefOrSchema(Box::new(Object::with_type(BasicType::Object).into()))
28 }
29}
30
31impl From<RefOr<Schema>> for ArrayItems {
32 fn from(value: RefOr<Schema>) -> Self {
33 Self::RefOrSchema(Box::new(value))
34 }
35}
36
37impl From<Schema> for ArrayItems {
38 fn from(value: Schema) -> Self {
39 Self::RefOrSchema(Box::new(RefOr::Type(value)))
40 }
41}
42
43impl From<Object> for ArrayItems {
44 fn from(value: Object) -> Self {
45 Self::RefOrSchema(Box::new(value.into()))
46 }
47}
48
49impl From<Ref> for ArrayItems {
50 fn from(value: Ref) -> Self {
51 Self::RefOrSchema(Box::new(value.into()))
52 }
53}
54
55impl From<AllOf> for ArrayItems {
56 fn from(value: AllOf) -> Self {
57 Self::RefOrSchema(Box::new(value.into()))
58 }
59}
60
61impl From<AnyOf> for ArrayItems {
62 fn from(value: AnyOf) -> Self {
63 Self::RefOrSchema(Box::new(value.into()))
64 }
65}
66
67impl From<OneOf> for ArrayItems {
68 fn from(value: OneOf) -> Self {
69 Self::RefOrSchema(Box::new(value.into()))
70 }
71}
72
73impl From<Array> for ArrayItems {
74 fn from(value: Array) -> Self {
75 Self::RefOrSchema(Box::new(value.into()))
76 }
77}
78
79mod array_items_false {
80 use super::*;
81
82 pub(super) fn serialize<S: serde::Serializer>(serializer: S) -> Result<S::Ok, S::Error> {
83 serializer.serialize_bool(false)
84 }
85
86 pub(super) fn deserialize<'de, D: serde::Deserializer<'de>>(
87 deserializer: D,
88 ) -> Result<(), D::Error> {
89 struct ItemsFalseVisitor;
90
91 impl<'de> Visitor<'de> for ItemsFalseVisitor {
92 type Value = ();
93 fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
94 where
95 E: serde::de::Error,
96 {
97 if !v {
98 Ok(())
99 } else {
100 Err(serde::de::Error::custom(format!(
101 "invalid boolean value: {v}, expected false"
102 )))
103 }
104 }
105
106 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
107 formatter.write_str("expected boolean false")
108 }
109 }
110
111 deserializer.deserialize_bool(ItemsFalseVisitor)
112 }
113}
114
115#[non_exhaustive]
119#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
120#[serde(rename_all = "camelCase")]
121pub struct Array {
122 #[serde(rename = "type")]
124 pub schema_type: SchemaType,
125
126 #[serde(skip_serializing_if = "Option::is_none")]
128 pub title: Option<String>,
129
130 pub items: ArrayItems,
132
133 #[serde(skip_serializing_if = "Vec::is_empty", default)]
138 pub prefix_items: Vec<RefOr<Schema>>,
139
140 #[serde(skip_serializing_if = "Option::is_none")]
142 pub description: Option<String>,
143
144 #[serde(skip_serializing_if = "Option::is_none")]
146 pub deprecated: Option<Deprecated>,
147
148 #[serde(skip_serializing_if = "Vec::is_empty", default)]
150 pub examples: Vec<Value>,
151
152 #[serde(rename = "default", skip_serializing_if = "Option::is_none")]
154 pub default_value: Option<Value>,
155
156 #[serde(skip_serializing_if = "Option::is_none")]
158 pub max_items: Option<usize>,
159
160 #[serde(skip_serializing_if = "Option::is_none")]
162 pub min_items: Option<usize>,
163
164 #[serde(default, skip_serializing_if = "super::is_false")]
167 pub unique_items: bool,
168
169 #[serde(skip_serializing_if = "Option::is_none")]
171 pub xml: Option<Xml>,
172
173 #[serde(skip_serializing_if = "Option::is_none")]
178 pub content_encoding: Option<String>,
179
180 #[serde(skip_serializing_if = "Option::is_none")]
185 pub content_media_type: Option<String>,
186
187 #[serde(skip_serializing_if = "PropMap::is_empty", flatten)]
189 pub extensions: PropMap<String, serde_json::Value>,
190}
191
192impl Default for Array {
193 fn default() -> Self {
194 Self {
195 title: Default::default(),
196 schema_type: BasicType::Array.into(),
197 unique_items: bool::default(),
198 items: Default::default(),
199 prefix_items: Vec::default(),
200 description: Default::default(),
201 deprecated: Default::default(),
202 examples: Default::default(),
203 default_value: Default::default(),
204 max_items: Default::default(),
205 min_items: Default::default(),
206 xml: Default::default(),
207 content_encoding: Default::default(),
208 content_media_type: Default::default(),
209 extensions: Default::default(),
210 }
211 }
212}
213
214impl Array {
215 #[must_use]
225 pub fn new() -> Self {
226 Self::default()
227 }
228 #[must_use]
230 pub fn items<I: Into<ArrayItems>>(mut self, items: I) -> Self {
231 self.items = items.into();
232 self
233 }
234
235 #[must_use]
240 pub fn prefix_items<I: IntoIterator<Item = S>, S: Into<RefOr<Schema>>>(
241 mut self,
242 items: I,
243 ) -> Self {
244 self.prefix_items = items
245 .into_iter()
246 .map(|item| item.into())
247 .collect::<Vec<_>>();
248 self
249 }
250
251 #[must_use]
264 pub fn schema_type<T: Into<SchemaType>>(mut self, schema_type: T) -> Self {
265 self.schema_type = schema_type.into();
266 self
267 }
268
269 #[must_use]
271 pub fn title(mut self, title: impl Into<String>) -> Self {
272 self.title = Some(title.into());
273 self
274 }
275
276 #[must_use]
278 pub fn description(mut self, description: impl Into<String>) -> Self {
279 self.description = Some(description.into());
280 self
281 }
282
283 #[must_use]
285 pub fn deprecated(mut self, deprecated: Deprecated) -> Self {
286 self.deprecated = Some(deprecated);
287 self
288 }
289
290 #[must_use]
292 pub fn example<V: Into<Value>>(mut self, example: V) -> Self {
293 self.examples.push(example.into());
294 self
295 }
296
297 #[must_use]
299 pub fn examples<I: IntoIterator<Item = V>, V: Into<Value>>(mut self, examples: I) -> Self {
300 self.examples = examples.into_iter().map(Into::into).collect();
301 self
302 }
303
304 #[must_use]
307 pub fn default_value(mut self, default: Value) -> Self {
308 self.default_value = Some(default);
309 self
310 }
311
312 #[must_use]
314 pub fn max_items(mut self, max_items: usize) -> Self {
315 self.max_items = Some(max_items);
316 self
317 }
318
319 #[must_use]
321 pub fn min_items(mut self, min_items: usize) -> Self {
322 self.min_items = Some(min_items);
323 self
324 }
325
326 #[must_use]
328 pub fn unique_items(mut self, unique_items: bool) -> Self {
329 self.unique_items = unique_items;
330 self
331 }
332
333 #[must_use]
335 pub fn xml(mut self, xml: Xml) -> Self {
336 self.xml = Some(xml);
337 self
338 }
339
340 #[must_use]
343 pub fn content_encoding<S: Into<String>>(mut self, content_encoding: S) -> Self {
344 self.content_encoding = Some(content_encoding.into());
345 self
346 }
347
348 #[must_use]
351 pub fn content_media_type<S: Into<String>>(mut self, content_media_type: S) -> Self {
352 self.content_media_type = Some(content_media_type.into());
353 self
354 }
355
356 #[must_use]
358 pub fn add_extension<K: Into<String>>(mut self, key: K, value: serde_json::Value) -> Self {
359 self.extensions.insert(key.into(), value);
360 self
361 }
362}
363
364impl From<Array> for Schema {
365 fn from(array: Array) -> Self {
366 Self::Array(array)
367 }
368}
369
370impl From<Array> for RefOr<Schema> {
371 fn from(array: Array) -> Self {
372 Self::Type(Schema::Array(array))
373 }
374}
375
376#[cfg(test)]
391mod tests {
392 use assert_json_diff::assert_json_eq;
393 use serde_json::json;
394
395 use super::*;
396 use crate::Object;
397
398 #[test]
399 fn test_build_array() {
400 let array = Array::new()
401 .items(Object::with_type(BasicType::String))
402 .title("title")
403 .description("description")
404 .deprecated(Deprecated::False)
405 .examples([
406 Value::String("example1".to_owned()),
407 Value::String("example2".to_owned()),
408 ])
409 .default_value(Value::String("default".to_owned()))
410 .max_items(10)
411 .min_items(1)
412 .unique_items(true)
413 .xml(Xml::new());
414
415 assert_json_eq!(
416 array,
417 json!({
418 "type": "array",
419 "items": {
420 "type": "string"
421 },
422 "title": "title",
423 "description": "description",
424 "deprecated": false,
425 "examples": ["example1", "example2"],
426 "default": "default",
427 "maxItems": 10,
428 "minItems": 1,
429 "uniqueItems": true,
430 "xml": {},
431 })
432 )
433 }
434
435 #[test]
436 fn test_schema_from_array() {
437 let array = Array::default();
438 let schema = Schema::from(array);
439 assert_json_eq!(
440 schema,
441 json!({
442 "type": "array",
443 "items": {
444 "type": "object"
445 }
446 })
447 )
448 }
449
450 #[test]
451 fn test_array_with_extensions() {
452 let expected = json!("value");
453 let json_value = Array::default().add_extension("x-some-extension", expected.clone());
454
455 let value = serde_json::to_value(&json_value).unwrap();
456 assert_eq!(value.get("x-some-extension"), Some(&expected));
457 }
458
459 #[test]
460 fn test_array_with_prefix_items() {
461 let array = Array::new().items(ArrayItems::False).prefix_items([
462 Object::with_type(BasicType::String),
463 Object::with_type(BasicType::Number),
464 ]);
465
466 assert_json_eq!(
467 array,
468 json!({
469 "type": "array",
470 "items": false,
471 "prefixItems": [
472 { "type": "string" },
473 { "type": "number" }
474 ]
475 })
476 )
477 }
478
479 #[test]
480 fn test_array_items_false_deserialize() {
481 let json = json!({
482 "type": "array",
483 "items": false,
484 "prefixItems": [
485 { "type": "string" }
486 ]
487 });
488 let array: Array = serde_json::from_value(json).unwrap();
489 assert_eq!(array.items, ArrayItems::False);
490 assert_eq!(array.prefix_items.len(), 1);
491 }
492}