tamasfe_schemars/schema.rs
1/*!
2JSON Schema types.
3*/
4
5#[cfg(feature = "impl_json_schema")]
6use crate as schemars;
7#[cfg(feature = "impl_json_schema")]
8use crate::JsonSchema;
9use crate::{Map, Set};
10use serde::{Deserialize, Serialize};
11use serde_json::Value;
12
13/// A JSON Schema.
14#[allow(clippy::large_enum_variant)]
15#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
16#[cfg_attr(feature = "impl_json_schema", derive(JsonSchema))]
17#[serde(untagged)]
18pub enum Schema {
19 /// A trivial boolean JSON Schema.
20 ///
21 /// The schema `true` matches everything (always passes validation), whereas the schema `false`
22 /// matches nothing (always fails validation).
23 Bool(bool),
24 /// A JSON Schema object.
25 Object(SchemaObject),
26}
27
28impl Schema {
29 /// Creates a new `$ref` schema.
30 ///
31 /// The given reference string should be a URI reference. This will usually be a JSON Pointer
32 /// in [URI Fragment representation](https://tools.ietf.org/html/rfc6901#section-6).
33 pub fn new_ref(reference: String) -> Self {
34 SchemaObject::new_ref(reference).into()
35 }
36
37 /// Returns `true` if `self` is a `$ref` schema.
38 ///
39 /// If `self` is a [`SchemaObject`] with `Some` [`reference`](struct.SchemaObject.html#structfield.reference) set, this returns `true`.
40 /// Otherwise, returns `false`.
41 pub fn is_ref(&self) -> bool {
42 match self {
43 Schema::Object(o) => o.is_ref(),
44 _ => false,
45 }
46 }
47
48 /// Converts the given schema (if it is a boolean schema) into an equivalent schema object.
49 ///
50 /// If the given schema is already a schema object, this has no effect.
51 ///
52 /// # Example
53 /// ```
54 /// use schemars::schema::{Schema, SchemaObject};
55 ///
56 /// let bool_schema = Schema::Bool(true);
57 ///
58 /// assert_eq!(bool_schema.into_object(), SchemaObject::default());
59 /// ```
60 pub fn into_object(self) -> SchemaObject {
61 match self {
62 Schema::Object(o) => o,
63 Schema::Bool(true) => SchemaObject::default(),
64 Schema::Bool(false) => SchemaObject {
65 subschemas: Some(Box::new(SubschemaValidation {
66 not: Some(Schema::Object(Default::default()).into()),
67 ..Default::default()
68 })),
69 ..Default::default()
70 },
71 }
72 }
73}
74
75impl From<SchemaObject> for Schema {
76 fn from(o: SchemaObject) -> Self {
77 Schema::Object(o)
78 }
79}
80
81impl From<bool> for Schema {
82 fn from(b: bool) -> Self {
83 Schema::Bool(b)
84 }
85}
86
87/// The root object of a JSON Schema document.
88#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)]
89#[cfg_attr(feature = "impl_json_schema", derive(JsonSchema))]
90#[serde(rename_all = "camelCase", default)]
91pub struct RootSchema {
92 /// The `$schema` keyword.
93 ///
94 /// See [JSON Schema 8.1.1. The "$schema" Keyword](https://tools.ietf.org/html/draft-handrews-json-schema-02#section-8.1.1).
95 #[serde(rename = "$schema", skip_serializing_if = "Option::is_none")]
96 pub meta_schema: Option<String>,
97 /// The root schema itself.
98 #[serde(flatten)]
99 pub schema: SchemaObject,
100 /// The `definitions` keyword.
101 ///
102 /// In JSON Schema draft 2019-09 this was replaced by $defs, but in Schemars this is still
103 /// serialized as `definitions` for backward-compatibility.
104 ///
105 /// See [JSON Schema 8.2.5. Schema Re-Use With "$defs"](https://tools.ietf.org/html/draft-handrews-json-schema-02#section-8.2.5),
106 /// and [JSON Schema (draft 07) 9. Schema Re-Use With "definitions"](https://tools.ietf.org/html/draft-handrews-json-schema-validation-01#section-9).
107 #[serde(alias = "$defs", skip_serializing_if = "Map::is_empty")]
108 pub definitions: Map<String, Schema>,
109}
110
111/// A JSON Schema object.
112#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)]
113#[cfg_attr(feature = "impl_json_schema", derive(JsonSchema))]
114#[serde(rename_all = "camelCase", default)]
115pub struct SchemaObject {
116 /// Properties which annotate the [`SchemaObject`] which typically have no effect when an object is being validated against the schema.
117 #[serde(flatten, deserialize_with = "skip_if_default")]
118 pub metadata: Option<Box<Metadata>>,
119 /// The `type` keyword.
120 ///
121 /// See [JSON Schema Validation 6.1.1. "type"](https://tools.ietf.org/html/draft-handrews-json-schema-validation-02#section-6.1.1)
122 /// and [JSON Schema 4.2.1. Instance Data Model](https://tools.ietf.org/html/draft-handrews-json-schema-02#section-4.2.1).
123 #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
124 pub instance_type: Option<SingleOrVec<InstanceType>>,
125 /// The `format` keyword.
126 ///
127 /// See [JSON Schema Validation 7. A Vocabulary for Semantic Content With "format"](https://tools.ietf.org/html/draft-handrews-json-schema-validation-02#section-7).
128 #[serde(skip_serializing_if = "Option::is_none")]
129 pub format: Option<String>,
130 /// The `enum` keyword.
131 ///
132 /// See [JSON Schema Validation 6.1.2. "enum"](https://tools.ietf.org/html/draft-handrews-json-schema-validation-02#section-6.1.2)
133 #[serde(rename = "enum", skip_serializing_if = "Option::is_none")]
134 pub enum_values: Option<Vec<Value>>,
135 /// The `const` keyword.
136 ///
137 /// See [JSON Schema Validation 6.1.3. "const"](https://tools.ietf.org/html/draft-handrews-json-schema-validation-02#section-6.1.3)
138 #[serde(
139 rename = "const",
140 skip_serializing_if = "Option::is_none",
141 deserialize_with = "allow_null"
142 )]
143 pub const_value: Option<Value>,
144 /// Properties of the [`SchemaObject`] which define validation assertions in terms of other schemas.
145 #[serde(flatten, deserialize_with = "skip_if_default")]
146 pub subschemas: Option<Box<SubschemaValidation>>,
147 /// Properties of the [`SchemaObject`] which define validation assertions for numbers.
148 #[serde(flatten, deserialize_with = "skip_if_default")]
149 pub number: Option<Box<NumberValidation>>,
150 /// Properties of the [`SchemaObject`] which define validation assertions for strings.
151 #[serde(flatten, deserialize_with = "skip_if_default")]
152 pub string: Option<Box<StringValidation>>,
153 /// Properties of the [`SchemaObject`] which define validation assertions for arrays.
154 #[serde(flatten, deserialize_with = "skip_if_default")]
155 pub array: Option<Box<ArrayValidation>>,
156 /// Properties of the [`SchemaObject`] which define validation assertions for objects.
157 #[serde(flatten, deserialize_with = "skip_if_default")]
158 pub object: Option<Box<ObjectValidation>>,
159 /// The `$ref` keyword.
160 ///
161 /// See [JSON Schema 8.2.4.1. Direct References with "$ref"](https://tools.ietf.org/html/draft-handrews-json-schema-02#section-8.2.4.1).
162 #[serde(rename = "$ref", skip_serializing_if = "Option::is_none")]
163 pub reference: Option<String>,
164 /// Arbitrary extra properties which are not part of the JSON Schema specification, or which `schemars` does not support.
165 #[serde(flatten)]
166 pub extensions: Map<String, Value>,
167}
168
169// Deserializing "null" to `Option<Value>` directly results in `None`,
170// this function instead makes it deserialize to `Some(Value::Null)`.
171fn allow_null<'de, D>(de: D) -> Result<Option<Value>, D::Error>
172where
173 D: serde::Deserializer<'de>,
174{
175 Value::deserialize(de).map(Option::Some)
176}
177
178fn skip_if_default<'de, D, T>(deserializer: D) -> Result<Option<Box<T>>, D::Error>
179where
180 D: serde::Deserializer<'de>,
181 T: Deserialize<'de> + Default + PartialEq,
182{
183 let value = T::deserialize(deserializer)?;
184 if value == T::default() {
185 Ok(None)
186 } else {
187 Ok(Some(Box::new(value)))
188 }
189}
190
191macro_rules! get_or_insert_default_fn {
192 ($name:ident, $ret:ty) => {
193 get_or_insert_default_fn!(
194 concat!("Returns a mutable reference to this schema's [`", stringify!($ret), "`](#structfield.", stringify!($name), "), creating it if it was `None`."),
195 $name,
196 $ret
197 );
198 };
199 ($doc:expr, $name:ident, $ret:ty) => {
200 #[doc = $doc]
201 pub fn $name(&mut self) -> &mut $ret {
202 self.$name.get_or_insert_with(Default::default)
203 }
204 };
205}
206
207impl SchemaObject {
208 /// Creates a new `$ref` schema.
209 ///
210 /// The given reference string should be a URI reference. This will usually be a JSON Pointer
211 /// in [URI Fragment representation](https://tools.ietf.org/html/rfc6901#section-6).
212 pub fn new_ref(reference: String) -> Self {
213 SchemaObject {
214 reference: Some(reference),
215 ..Default::default()
216 }
217 }
218
219 /// Returns `true` if `self` is a `$ref` schema.
220 ///
221 /// If `self` has `Some` [`reference`](struct.SchemaObject.html#structfield.reference) set, this returns `true`.
222 /// Otherwise, returns `false`.
223 pub fn is_ref(&self) -> bool {
224 self.reference.is_some()
225 }
226
227 get_or_insert_default_fn!(metadata, Metadata);
228 get_or_insert_default_fn!(subschemas, SubschemaValidation);
229 get_or_insert_default_fn!(number, NumberValidation);
230 get_or_insert_default_fn!(string, StringValidation);
231 get_or_insert_default_fn!(array, ArrayValidation);
232 get_or_insert_default_fn!(object, ObjectValidation);
233}
234
235impl From<Schema> for SchemaObject {
236 fn from(schema: Schema) -> Self {
237 schema.into_object()
238 }
239}
240
241/// Properties which annotate a [`SchemaObject`] which typically have no effect when an object is being validated against the schema.
242#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)]
243#[cfg_attr(feature = "impl_json_schema", derive(JsonSchema))]
244#[serde(rename_all = "camelCase", default)]
245pub struct Metadata {
246 /// The `$id` keyword.
247 ///
248 /// See [JSON Schema 8.2.2. The "$id" Keyword](https://tools.ietf.org/html/draft-handrews-json-schema-02#section-8.2.2).
249 #[serde(rename = "$id", skip_serializing_if = "Option::is_none")]
250 pub id: Option<String>,
251 /// The `title` keyword.
252 ///
253 /// See [JSON Schema Validation 9.1. "title" and "description"](https://tools.ietf.org/html/draft-handrews-json-schema-validation-02#section-9.1).
254 #[serde(skip_serializing_if = "Option::is_none")]
255 pub title: Option<String>,
256 /// The `description` keyword.
257 ///
258 /// See [JSON Schema Validation 9.1. "title" and "description"](https://tools.ietf.org/html/draft-handrews-json-schema-validation-02#section-9.1).
259 #[serde(skip_serializing_if = "Option::is_none")]
260 pub description: Option<String>,
261 /// The `default` keyword.
262 ///
263 /// See [JSON Schema Validation 9.2. "default"](https://tools.ietf.org/html/draft-handrews-json-schema-validation-02#section-9.2).
264 #[serde(
265 skip_serializing_if = "Option::is_none",
266 deserialize_with = "allow_null"
267 )]
268 pub default: Option<Value>,
269 /// The `deprecated` keyword.
270 ///
271 /// See [JSON Schema Validation 9.3. "deprecated"](https://tools.ietf.org/html/draft-handrews-json-schema-validation-02#section-9.3).
272 #[serde(skip_serializing_if = "is_false")]
273 pub deprecated: bool,
274 /// The `readOnly` keyword.
275 ///
276 /// See [JSON Schema Validation 9.4. "readOnly" and "writeOnly"](https://tools.ietf.org/html/draft-handrews-json-schema-validation-02#section-9.4).
277 #[serde(skip_serializing_if = "is_false")]
278 pub read_only: bool,
279 /// The `writeOnly` keyword.
280 ///
281 /// See [JSON Schema Validation 9.4. "readOnly" and "writeOnly"](https://tools.ietf.org/html/draft-handrews-json-schema-validation-02#section-9.4).
282 #[serde(skip_serializing_if = "is_false")]
283 pub write_only: bool,
284 /// The `examples` keyword.
285 ///
286 /// See [JSON Schema Validation 9.5. "examples"](https://tools.ietf.org/html/draft-handrews-json-schema-validation-02#section-9.5).
287 #[serde(skip_serializing_if = "Vec::is_empty")]
288 pub examples: Vec<Value>,
289}
290
291#[allow(clippy::trivially_copy_pass_by_ref)]
292fn is_false(b: &bool) -> bool {
293 !b
294}
295
296/// Properties of a [`SchemaObject`] which define validation assertions in terms of other schemas.
297#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)]
298#[cfg_attr(feature = "impl_json_schema", derive(JsonSchema))]
299#[serde(rename_all = "camelCase", default)]
300pub struct SubschemaValidation {
301 /// The `allOf` keyword.
302 ///
303 /// See [JSON Schema 9.2.1.1. "allOf"](https://tools.ietf.org/html/draft-handrews-json-schema-02#section-9.2.1.1).
304 #[serde(skip_serializing_if = "Option::is_none")]
305 pub all_of: Option<Vec<Schema>>,
306 /// The `anyOf` keyword.
307 ///
308 /// See [JSON Schema 9.2.1.2. "anyOf"](https://tools.ietf.org/html/draft-handrews-json-schema-02#section-9.2.1.2).
309 #[serde(skip_serializing_if = "Option::is_none")]
310 pub any_of: Option<Vec<Schema>>,
311 /// The `oneOf` keyword.
312 ///
313 /// See [JSON Schema 9.2.1.3. "oneOf"](https://tools.ietf.org/html/draft-handrews-json-schema-02#section-9.2.1.3).
314 #[serde(skip_serializing_if = "Option::is_none")]
315 pub one_of: Option<Vec<Schema>>,
316 /// The `not` keyword.
317 ///
318 /// See [JSON Schema 9.2.1.4. "not"](https://tools.ietf.org/html/draft-handrews-json-schema-02#section-9.2.1.4).
319 #[serde(skip_serializing_if = "Option::is_none")]
320 pub not: Option<Box<Schema>>,
321 /// The `if` keyword.
322 ///
323 /// See [JSON Schema 9.2.2.1. "if"](https://tools.ietf.org/html/draft-handrews-json-schema-02#section-9.2.2.1).
324 #[serde(rename = "if", skip_serializing_if = "Option::is_none")]
325 pub if_schema: Option<Box<Schema>>,
326 /// The `then` keyword.
327 ///
328 /// See [JSON Schema 9.2.2.2. "then"](https://tools.ietf.org/html/draft-handrews-json-schema-02#section-9.2.2.2).
329 #[serde(rename = "then", skip_serializing_if = "Option::is_none")]
330 pub then_schema: Option<Box<Schema>>,
331 /// The `else` keyword.
332 ///
333 /// See [JSON Schema 9.2.2.3. "else"](https://tools.ietf.org/html/draft-handrews-json-schema-02#section-9.2.2.3).
334 #[serde(rename = "else", skip_serializing_if = "Option::is_none")]
335 pub else_schema: Option<Box<Schema>>,
336}
337
338/// Properties of a [`SchemaObject`] which define validation assertions for numbers.
339#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)]
340#[cfg_attr(feature = "impl_json_schema", derive(JsonSchema))]
341#[serde(rename_all = "camelCase", default)]
342pub struct NumberValidation {
343 /// The `multipleOf` keyword.
344 ///
345 /// See [JSON Schema Validation 6.2.1. "multipleOf"](https://tools.ietf.org/html/draft-handrews-json-schema-validation-02#section-6.2.1).
346 #[serde(skip_serializing_if = "Option::is_none")]
347 pub multiple_of: Option<f64>,
348 /// The `maximum` keyword.
349 ///
350 /// See [JSON Schema Validation 6.2.2. "maximum"](https://tools.ietf.org/html/draft-handrews-json-schema-validation-02#section-6.2.2).
351 #[serde(skip_serializing_if = "Option::is_none")]
352 pub maximum: Option<f64>,
353 /// The `exclusiveMaximum` keyword.
354 ///
355 /// See [JSON Schema Validation 6.2.3. "exclusiveMaximum"](https://tools.ietf.org/html/draft-handrews-json-schema-validation-02#section-6.2.3).
356 #[serde(skip_serializing_if = "Option::is_none")]
357 pub exclusive_maximum: Option<f64>,
358 /// The `minimum` keyword.
359 ///
360 /// See [JSON Schema Validation 6.2.4. "minimum"](https://tools.ietf.org/html/draft-handrews-json-schema-validation-02#section-6.2.4).
361 #[serde(skip_serializing_if = "Option::is_none")]
362 pub minimum: Option<f64>,
363 /// The `exclusiveMinimum` keyword.
364 ///
365 /// See [JSON Schema Validation 6.2.5. "exclusiveMinimum"](https://tools.ietf.org/html/draft-handrews-json-schema-validation-02#section-6.2.5).
366 #[serde(skip_serializing_if = "Option::is_none")]
367 pub exclusive_minimum: Option<f64>,
368}
369
370/// Properties of a [`SchemaObject`] which define validation assertions for strings.
371#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)]
372#[cfg_attr(feature = "impl_json_schema", derive(JsonSchema))]
373#[serde(rename_all = "camelCase", default)]
374pub struct StringValidation {
375 /// The `maxLength` keyword.
376 ///
377 /// See [JSON Schema Validation 6.3.1. "maxLength"](https://tools.ietf.org/html/draft-handrews-json-schema-validation-02#section-6.3.1).
378 #[serde(skip_serializing_if = "Option::is_none")]
379 pub max_length: Option<u32>,
380 /// The `minLength` keyword.
381 ///
382 /// See [JSON Schema Validation 6.3.2. "minLength"](https://tools.ietf.org/html/draft-handrews-json-schema-validation-02#section-6.3.2).
383 #[serde(skip_serializing_if = "Option::is_none")]
384 pub min_length: Option<u32>,
385 /// The `pattern` keyword.
386 ///
387 /// See [JSON Schema Validation 6.3.3. "pattern"](https://tools.ietf.org/html/draft-handrews-json-schema-validation-02#section-6.3.3).
388 #[serde(skip_serializing_if = "Option::is_none")]
389 pub pattern: Option<String>,
390}
391
392/// Properties of a [`SchemaObject`] which define validation assertions for arrays.
393#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)]
394#[cfg_attr(feature = "impl_json_schema", derive(JsonSchema))]
395#[serde(rename_all = "camelCase", default)]
396pub struct ArrayValidation {
397 /// The `items` keyword.
398 ///
399 /// See [JSON Schema 9.3.1.1. "items"](https://tools.ietf.org/html/draft-handrews-json-schema-02#section-9.3.1.1).
400 #[serde(skip_serializing_if = "Option::is_none")]
401 pub items: Option<SingleOrVec<Schema>>,
402 /// The `additionalItems` keyword.
403 ///
404 /// See [JSON Schema 9.3.1.2. "additionalItems"](https://tools.ietf.org/html/draft-handrews-json-schema-02#section-9.3.1.2).
405 #[serde(skip_serializing_if = "Option::is_none")]
406 pub additional_items: Option<Box<Schema>>,
407 /// The `maxItems` keyword.
408 ///
409 /// See [JSON Schema Validation 6.4.1. "maxItems"](https://tools.ietf.org/html/draft-handrews-json-schema-validation-02#section-6.4.1).
410 #[serde(skip_serializing_if = "Option::is_none")]
411 pub max_items: Option<u32>,
412 /// The `minItems` keyword.
413 ///
414 /// See [JSON Schema Validation 6.4.2. "minItems"](https://tools.ietf.org/html/draft-handrews-json-schema-validation-02#section-6.4.2).
415 #[serde(skip_serializing_if = "Option::is_none")]
416 pub min_items: Option<u32>,
417 /// The `uniqueItems` keyword.
418 ///
419 /// See [JSON Schema Validation 6.4.3. "uniqueItems"](https://tools.ietf.org/html/draft-handrews-json-schema-validation-02#section-6.4.3).
420 #[serde(skip_serializing_if = "Option::is_none")]
421 pub unique_items: Option<bool>,
422 /// The `contains` keyword.
423 ///
424 /// See [JSON Schema 9.3.1.4. "contains"](https://tools.ietf.org/html/draft-handrews-json-schema-02#section-9.3.1.4).
425 #[serde(skip_serializing_if = "Option::is_none")]
426 pub contains: Option<Box<Schema>>,
427}
428
429/// Properties of a [`SchemaObject`] which define validation assertions for objects.
430#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)]
431#[cfg_attr(feature = "impl_json_schema", derive(JsonSchema))]
432#[serde(rename_all = "camelCase", default)]
433pub struct ObjectValidation {
434 /// The `maxProperties` keyword.
435 ///
436 /// See [JSON Schema Validation 6.5.1. "maxProperties"](https://tools.ietf.org/html/draft-handrews-json-schema-validation-02#section-6.5.1).
437 #[serde(skip_serializing_if = "Option::is_none")]
438 pub max_properties: Option<u32>,
439 /// The `minProperties` keyword.
440 ///
441 /// See [JSON Schema Validation 6.5.2. "minProperties"](https://tools.ietf.org/html/draft-handrews-json-schema-validation-02#section-6.5.2).
442 #[serde(skip_serializing_if = "Option::is_none")]
443 pub min_properties: Option<u32>,
444 /// The `required` keyword.
445 ///
446 /// See [JSON Schema Validation 6.5.3. "required"](https://tools.ietf.org/html/draft-handrews-json-schema-validation-02#section-6.5.3).
447 #[serde(skip_serializing_if = "Set::is_empty")]
448 pub required: Set<String>,
449 /// The `properties` keyword.
450 ///
451 /// See [JSON Schema 9.3.2.1. "properties"](https://tools.ietf.org/html/draft-handrews-json-schema-02#section-9.3.2.1).
452 #[serde(skip_serializing_if = "Map::is_empty")]
453 pub properties: Map<String, Schema>,
454 /// The `patternProperties` keyword.
455 ///
456 /// See [JSON Schema 9.3.2.2. "patternProperties"](https://tools.ietf.org/html/draft-handrews-json-schema-02#section-9.3.2.2).
457 #[serde(skip_serializing_if = "Map::is_empty")]
458 pub pattern_properties: Map<String, Schema>,
459 /// The `additionalProperties` keyword.
460 ///
461 /// See [JSON Schema 9.3.2.3. "additionalProperties"](https://tools.ietf.org/html/draft-handrews-json-schema-02#section-9.3.2.3).
462 #[serde(skip_serializing_if = "Option::is_none")]
463 pub additional_properties: Option<Box<Schema>>,
464 /// The `propertyNames` keyword.
465 ///
466 /// See [JSON Schema 9.3.2.5. "propertyNames"](https://tools.ietf.org/html/draft-handrews-json-schema-02#section-9.3.2.5).
467 #[serde(skip_serializing_if = "Option::is_none")]
468 pub property_names: Option<Box<Schema>>,
469}
470
471/// The possible types of values in JSON Schema documents.
472///
473/// See [JSON Schema 4.2.1. Instance Data Model](https://tools.ietf.org/html/draft-handrews-json-schema-02#section-4.2.1).
474#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
475#[cfg_attr(feature = "impl_json_schema", derive(JsonSchema))]
476#[serde(rename_all = "camelCase")]
477pub enum InstanceType {
478 Null,
479 Boolean,
480 Object,
481 Array,
482 Number,
483 String,
484 Integer,
485}
486
487/// A type which can be serialized as a single item, or multiple items.
488///
489/// In some contexts, a `Single` may be semantically distinct from a `Vec` containing only item.
490#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
491#[cfg_attr(feature = "impl_json_schema", derive(JsonSchema))]
492#[serde(untagged)]
493pub enum SingleOrVec<T> {
494 Single(Box<T>),
495 Vec(Vec<T>),
496}
497
498impl<T> From<T> for SingleOrVec<T> {
499 fn from(single: T) -> Self {
500 SingleOrVec::Single(Box::new(single))
501 }
502}
503
504impl<T> From<Vec<T>> for SingleOrVec<T> {
505 fn from(vec: Vec<T>) -> Self {
506 SingleOrVec::Vec(vec)
507 }
508}