/rust/registry/src/index.crates.io-1949cf8c6b5b557f/schemars-1.2.1/src/schema.rs
Line | Count | Source |
1 | | /*! |
2 | | JSON Schema types. |
3 | | */ |
4 | | |
5 | | use crate::_alloc_prelude::*; |
6 | | use ref_cast::{ref_cast_custom, RefCastCustom}; |
7 | | use serde::{Deserialize, Serialize}; |
8 | | use serde_json::{Map, Value}; |
9 | | |
10 | | /// A JSON Schema. |
11 | | /// |
12 | | /// This wraps a JSON [`Value`] that must be either an [object](Value::Object) or a |
13 | | /// [bool](Value::Bool). |
14 | | /// |
15 | | /// A custom JSON schema can be created using the [`json_schema!`](crate::json_schema) macro: |
16 | | /// ``` |
17 | | /// use schemars::{Schema, json_schema}; |
18 | | /// |
19 | | /// let my_schema: Schema = json_schema!({ |
20 | | /// "type": ["object", "null"] |
21 | | /// }); |
22 | | /// ``` |
23 | | /// |
24 | | /// Because a `Schema` is a thin wrapper around a `Value`, you can also use |
25 | | /// [`TryFrom::try_from`]/[`TryInto::try_into`] to create a `Schema` from an existing `Value`. |
26 | | /// This operation is fallible, because only [objects](Value::Object) and [bools](Value::Bool) can |
27 | | /// be converted in this way. |
28 | | /// |
29 | | /// ``` |
30 | | /// use schemars::{Schema, json_schema}; |
31 | | /// use serde_json::json; |
32 | | /// |
33 | | /// let json_object = json!({"type": ["object", "null"]}); |
34 | | /// let object_schema: Schema = json_object.try_into().unwrap(); |
35 | | /// |
36 | | /// let json_bool = json!(true); |
37 | | /// let bool_schema: Schema = json_bool.try_into().unwrap(); |
38 | | /// |
39 | | /// let json_string = json!("This is neither an object nor a bool!"); |
40 | | /// assert!(Schema::try_from(json_string).is_err()); |
41 | | /// |
42 | | /// // You can also convert a `&Value`/`&mut Value` to a `&Schema`/`&mut Schema` the same way: |
43 | | /// |
44 | | /// let json_object = json!({"type": ["object", "null"]}); |
45 | | /// let object_schema_ref: &Schema = (&json_object).try_into().unwrap(); |
46 | | /// |
47 | | /// let mut json_object = json!({"type": ["object", "null"]}); |
48 | | /// let object_schema_mut: &mut Schema = (&mut json_object).try_into().unwrap(); |
49 | | /// ``` |
50 | | /// |
51 | | /// Similarly, you can use [`From`]/[`Into`] to (infallibly) create a `Schema` from an existing |
52 | | /// [`Map<String, Value>`] or [`bool`]. |
53 | | /// |
54 | | /// ``` |
55 | | /// use schemars::{Schema, json_schema}; |
56 | | /// use serde_json::{Map, json}; |
57 | | /// |
58 | | /// let mut map = Map::new(); |
59 | | /// map.insert("type".to_owned(), json!(["object", "null"])); |
60 | | /// let object_schema: Schema = map.into(); |
61 | | /// |
62 | | /// let bool_schema: Schema = true.into(); |
63 | | /// ``` |
64 | | #[derive(Debug, Clone, PartialEq, RefCastCustom)] |
65 | | #[repr(transparent)] |
66 | | pub struct Schema(Value); |
67 | | |
68 | | impl<'de> Deserialize<'de> for Schema { |
69 | 0 | fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> |
70 | 0 | where |
71 | 0 | D: serde::Deserializer<'de>, |
72 | | { |
73 | 0 | let value = Value::deserialize(deserializer)?; |
74 | 0 | Schema::validate(&value)?; |
75 | 0 | Ok(Schema(value)) |
76 | 0 | } |
77 | | } |
78 | | |
79 | | impl Serialize for Schema { |
80 | 0 | fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> |
81 | 0 | where |
82 | 0 | S: serde::Serializer, |
83 | | { |
84 | 0 | ser::OrderedKeywordWrapper::from(&self.0).serialize(serializer) |
85 | 0 | } |
86 | | } |
87 | | |
88 | | impl PartialEq<bool> for Schema { |
89 | 0 | fn eq(&self, other: &bool) -> bool { |
90 | 0 | self.as_bool() == Some(*other) |
91 | 0 | } |
92 | | } |
93 | | |
94 | | impl PartialEq<Map<String, Value>> for Schema { |
95 | 0 | fn eq(&self, other: &Map<String, Value>) -> bool { |
96 | 0 | self.as_object() == Some(other) |
97 | 0 | } |
98 | | } |
99 | | |
100 | | impl PartialEq<Value> for Schema { |
101 | 0 | fn eq(&self, other: &Value) -> bool { |
102 | 0 | self.as_value() == other |
103 | 0 | } |
104 | | } |
105 | | |
106 | | impl PartialEq<Schema> for bool { |
107 | 0 | fn eq(&self, other: &Schema) -> bool { |
108 | 0 | other == self |
109 | 0 | } |
110 | | } |
111 | | |
112 | | impl PartialEq<Schema> for Map<String, Value> { |
113 | 0 | fn eq(&self, other: &Schema) -> bool { |
114 | 0 | other == self |
115 | 0 | } |
116 | | } |
117 | | |
118 | | impl PartialEq<Schema> for Value { |
119 | 0 | fn eq(&self, other: &Schema) -> bool { |
120 | 0 | other == self |
121 | 0 | } |
122 | | } |
123 | | |
124 | | impl Schema { |
125 | | /// Creates a new schema object with a single string property `"$ref"`. |
126 | | /// |
127 | | /// The given reference string should be a URI reference. This will usually be a JSON Pointer |
128 | | /// in [URI Fragment representation](https://tools.ietf.org/html/rfc6901#section-6). |
129 | | #[must_use] |
130 | 0 | pub fn new_ref(reference: String) -> Self { |
131 | 0 | let mut map = Map::new(); |
132 | 0 | map.insert("$ref".to_owned(), Value::String(reference)); |
133 | 0 | Self(Value::Object(map)) |
134 | 0 | } |
135 | | |
136 | | /// Borrows the `Schema`'s underlying JSON value. |
137 | | #[must_use] |
138 | 0 | pub fn as_value(&self) -> &Value { |
139 | 0 | &self.0 |
140 | 0 | } |
141 | | |
142 | | /// If the `Schema`'s underlying JSON value is a bool, returns the bool value. |
143 | | #[must_use] |
144 | 0 | pub fn as_bool(&self) -> Option<bool> { |
145 | 0 | self.0.as_bool() |
146 | 0 | } |
147 | | |
148 | | /// If the `Schema`'s underlying JSON value is an object, borrows the object as a `Map` of |
149 | | /// properties. |
150 | | #[must_use] |
151 | 0 | pub fn as_object(&self) -> Option<&Map<String, Value>> { |
152 | 0 | self.0.as_object() |
153 | 0 | } |
154 | | |
155 | | /// If the `Schema`'s underlying JSON value is an object, mutably borrows the object as a `Map` |
156 | | /// of properties. |
157 | | #[must_use] |
158 | 0 | pub fn as_object_mut(&mut self) -> Option<&mut Map<String, Value>> { |
159 | 0 | self.0.as_object_mut() |
160 | 0 | } |
161 | | |
162 | 0 | pub(crate) fn try_to_object(self) -> Result<Map<String, Value>, bool> { |
163 | 0 | match self.0 { |
164 | 0 | Value::Object(m) => Ok(m), |
165 | 0 | Value::Bool(b) => Err(b), |
166 | 0 | _ => unreachable!(), |
167 | | } |
168 | 0 | } |
169 | | |
170 | 0 | pub(crate) fn try_as_object_mut(&mut self) -> Result<&mut Map<String, Value>, bool> { |
171 | 0 | match &mut self.0 { |
172 | 0 | Value::Object(m) => Ok(m), |
173 | 0 | Value::Bool(b) => Err(*b), |
174 | 0 | _ => unreachable!(), |
175 | | } |
176 | 0 | } |
177 | | |
178 | | /// Returns the `Schema`'s underlying JSON value. |
179 | | #[must_use] |
180 | 0 | pub fn to_value(self) -> Value { |
181 | 0 | self.0 |
182 | 0 | } |
183 | | |
184 | | /// Converts the `Schema` (if it wraps a bool value) into an equivalent object schema. Then |
185 | | /// mutably borrows the object as a `Map` of properties. |
186 | | /// |
187 | | /// `true` is transformed into an empty schema `{}`, which successfully validates against all |
188 | | /// possible values. `false` is transformed into the schema `{"not": {}}`, which does not |
189 | | /// successfully validate against any value. |
190 | | #[allow(clippy::missing_panics_doc)] |
191 | 0 | pub fn ensure_object(&mut self) -> &mut Map<String, Value> { |
192 | 0 | if let Some(b) = self.as_bool() { |
193 | 0 | let mut map = Map::new(); |
194 | 0 | if !b { |
195 | 0 | map.insert("not".into(), Value::Object(Map::new())); |
196 | 0 | } |
197 | 0 | self.0 = Value::Object(map); |
198 | 0 | } |
199 | | |
200 | 0 | self.0 |
201 | 0 | .as_object_mut() |
202 | 0 | .expect("Schema value should be of type Object.") |
203 | 0 | } |
204 | | |
205 | | /// Inserts a property into the schema, replacing any previous value. |
206 | | /// |
207 | | /// If the schema wraps a bool value, it will first be converted into an equivalent object |
208 | | /// schema. |
209 | | /// |
210 | | /// If the schema did not have this key present, `None` is returned. |
211 | | /// |
212 | | /// If the schema did have this key present, the value is updated, and the old value is |
213 | | /// returned. |
214 | | /// |
215 | | /// # Example |
216 | | /// ``` |
217 | | /// use schemars::json_schema; |
218 | | /// use serde_json::json; |
219 | | /// |
220 | | /// let mut schema = json_schema!(true); |
221 | | /// assert_eq!(schema.insert("type".to_owned(), "array".into()), None); |
222 | | /// assert_eq!(schema.insert("type".to_owned(), "object".into()), Some(json!("array"))); |
223 | | /// |
224 | | /// assert_eq!(schema, json_schema!({"type": "object"})); |
225 | | /// ``` |
226 | 0 | pub fn insert(&mut self, k: String, v: Value) -> Option<Value> { |
227 | 0 | self.ensure_object().insert(k, v) |
228 | 0 | } |
229 | | |
230 | | /// If the `Schema`'s underlying JSON value is an object, gets a reference to that object's |
231 | | /// value for the given key if it exists. |
232 | | /// |
233 | | /// This always returns `None` for bool schemas. |
234 | | /// |
235 | | /// # Example |
236 | | /// ``` |
237 | | /// use schemars::json_schema; |
238 | | /// use serde_json::json; |
239 | | /// |
240 | | /// let obj_schema = json_schema!({"type": "array"}); |
241 | | /// assert_eq!(obj_schema.get("type"), Some(&json!("array"))); |
242 | | /// assert_eq!(obj_schema.get("format"), None); |
243 | | /// |
244 | | /// let bool_schema = json_schema!(true); |
245 | | /// assert_eq!(bool_schema.get("type"), None); |
246 | | /// ``` |
247 | | #[must_use] |
248 | 0 | pub fn get<Q>(&self, key: &Q) -> Option<&Value> |
249 | 0 | where |
250 | 0 | String: core::borrow::Borrow<Q>, |
251 | 0 | Q: ?Sized + Ord + Eq + core::hash::Hash, |
252 | | { |
253 | 0 | self.0.as_object().and_then(|o| o.get(key)) |
254 | 0 | } |
255 | | |
256 | | /// If the `Schema`'s underlying JSON value is an object, gets a mutable reference to that |
257 | | /// object's value for the given key if it exists. |
258 | | /// |
259 | | /// This always returns `None` for bool schemas. |
260 | | /// |
261 | | /// # Example |
262 | | /// ``` |
263 | | /// use schemars::json_schema; |
264 | | /// use serde_json::{json, Value}; |
265 | | /// |
266 | | /// let mut obj_schema = json_schema!({ "properties": {} }); |
267 | | /// if let Some(Value::Object(properties)) = obj_schema.get_mut("properties") { |
268 | | /// properties.insert("anything".to_owned(), true.into()); |
269 | | /// } |
270 | | /// assert_eq!(obj_schema, json_schema!({ "properties": { "anything": true } })); |
271 | | /// ``` |
272 | | #[must_use] |
273 | 0 | pub fn get_mut<Q>(&mut self, key: &Q) -> Option<&mut Value> |
274 | 0 | where |
275 | 0 | String: core::borrow::Borrow<Q>, |
276 | 0 | Q: ?Sized + Ord + Eq + core::hash::Hash, |
277 | | { |
278 | 0 | self.0.as_object_mut().and_then(|o| o.get_mut(key)) |
279 | 0 | } |
280 | | |
281 | | /// If the `Schema`'s underlying JSON value is an object, looks up a value within the schema |
282 | | /// by a JSON Pointer. |
283 | | /// |
284 | | /// If the given pointer begins with a `#`, then the rest of the value is assumed to be in |
285 | | /// "URI Fragment Identifier Representation", and will be percent-decoded accordingly. |
286 | | /// |
287 | | /// For more information on JSON Pointer, read [RFC6901](https://tools.ietf.org/html/rfc6901). |
288 | | /// |
289 | | /// This always returns `None` for bool schemas. |
290 | | /// |
291 | | /// # Example |
292 | | /// ``` |
293 | | /// use schemars::json_schema; |
294 | | /// use serde_json::json; |
295 | | /// |
296 | | /// let schema = json_schema!({ |
297 | | /// "properties": { |
298 | | /// "anything": true |
299 | | /// }, |
300 | | /// "$defs": { |
301 | | /// "🚀": true |
302 | | /// } |
303 | | /// }); |
304 | | /// |
305 | | /// assert_eq!(schema.pointer("/properties/anything").unwrap(), &json!(true)); |
306 | | /// assert_eq!(schema.pointer("#/$defs/%F0%9F%9A%80").unwrap(), &json!(true)); |
307 | | /// assert_eq!(schema.pointer("/does/not/exist"), None); |
308 | | /// ``` |
309 | | #[must_use] |
310 | 0 | pub fn pointer(&self, pointer: &str) -> Option<&Value> { |
311 | 0 | if let Some(percent_encoded) = pointer.strip_prefix('#') { |
312 | 0 | let decoded = crate::encoding::percent_decode(percent_encoded)?; |
313 | 0 | self.0.pointer(&decoded) |
314 | | } else { |
315 | 0 | self.0.pointer(pointer) |
316 | | } |
317 | 0 | } |
318 | | |
319 | | /// If the `Schema`'s underlying JSON value is an object, looks up a value by a JSON Pointer |
320 | | /// and returns a mutable reference to that value. |
321 | | /// |
322 | | /// If the given pointer begins with a `#`, then the rest of the value is assumed to be in |
323 | | /// "URI Fragment Identifier Representation", and will be percent-decoded accordingly. |
324 | | /// |
325 | | /// For more information on JSON Pointer, read [RFC6901](https://tools.ietf.org/html/rfc6901). |
326 | | /// |
327 | | /// This always returns `None` for bool schemas. |
328 | | /// |
329 | | /// # Example |
330 | | /// ``` |
331 | | /// use schemars::{json_schema, Schema}; |
332 | | /// use serde_json::json; |
333 | | /// |
334 | | /// let mut schema = json_schema!({ |
335 | | /// "properties": { |
336 | | /// "anything": true |
337 | | /// }, |
338 | | /// "$defs": { |
339 | | /// "🚀": true |
340 | | /// } |
341 | | /// }); |
342 | | /// |
343 | | /// assert_eq!(schema.pointer_mut("/properties/anything").unwrap(), &json!(true)); |
344 | | /// assert_eq!(schema.pointer_mut("#/$defs/%F0%9F%9A%80").unwrap(), &json!(true)); |
345 | | /// assert_eq!(schema.pointer_mut("/does/not/exist"), None); |
346 | | /// ``` |
347 | | #[must_use] |
348 | 0 | pub fn pointer_mut(&mut self, pointer: &str) -> Option<&mut Value> { |
349 | 0 | if let Some(percent_encoded) = pointer.strip_prefix('#') { |
350 | 0 | let decoded = crate::encoding::percent_decode(percent_encoded)?; |
351 | 0 | self.0.pointer_mut(&decoded) |
352 | | } else { |
353 | 0 | self.0.pointer_mut(pointer) |
354 | | } |
355 | 0 | } |
356 | | |
357 | | /// If the `Schema`'s underlying JSON value is an object, removes and returns its value for the |
358 | | /// given key. |
359 | | /// |
360 | | /// This always returns `None` for bool schemas, without modifying them. |
361 | | /// |
362 | | /// # Example |
363 | | /// ``` |
364 | | /// use schemars::json_schema; |
365 | | /// use serde_json::json; |
366 | | /// |
367 | | /// let mut schema = json_schema!({"type": "array"}); |
368 | | /// assert_eq!(schema.remove("type"), Some(json!("array"))); |
369 | | /// assert_eq!(schema, json_schema!({})); |
370 | | /// ``` |
371 | 0 | pub fn remove<Q>(&mut self, key: &Q) -> Option<Value> |
372 | 0 | where |
373 | 0 | String: core::borrow::Borrow<Q>, |
374 | 0 | Q: ?Sized + Ord + Eq + core::hash::Hash, |
375 | | { |
376 | 0 | self.0.as_object_mut().and_then(|o| o.remove(key)) |
377 | 0 | } |
378 | | |
379 | 0 | pub(crate) fn has_type(&self, ty: &str) -> bool { |
380 | 0 | match self.0.get("type") { |
381 | 0 | Some(Value::Array(values)) => values.iter().any(|v| v.as_str() == Some(ty)), |
382 | 0 | Some(Value::String(s)) => s == ty, |
383 | 0 | _ => false, |
384 | | } |
385 | 0 | } |
386 | | |
387 | 0 | fn validate<E: serde::de::Error>(value: &Value) -> Result<(), E> { |
388 | | use serde::de::Unexpected; |
389 | 0 | let unexpected = match value { |
390 | 0 | Value::Bool(_) | Value::Object(_) => return Ok(()), |
391 | 0 | Value::Null => Unexpected::Unit, |
392 | 0 | Value::Number(n) => { |
393 | 0 | if let Some(u) = n.as_u64() { |
394 | 0 | Unexpected::Unsigned(u) |
395 | 0 | } else if let Some(i) = n.as_i64() { |
396 | 0 | Unexpected::Signed(i) |
397 | 0 | } else if let Some(f) = n.as_f64() { |
398 | 0 | Unexpected::Float(f) |
399 | | } else { |
400 | 0 | unreachable!() |
401 | | } |
402 | | } |
403 | 0 | Value::String(s) => Unexpected::Str(s), |
404 | 0 | Value::Array(_) => Unexpected::Seq, |
405 | | }; |
406 | | |
407 | 0 | Err(E::invalid_type(unexpected, &"object or boolean")) |
408 | 0 | } |
409 | | |
410 | | #[ref_cast_custom] |
411 | 0 | fn ref_cast(value: &Value) -> &Self; |
412 | | |
413 | | #[ref_cast_custom] |
414 | 0 | fn ref_cast_mut(value: &mut Value) -> &mut Self; |
415 | | } |
416 | | |
417 | | impl From<Schema> for Value { |
418 | 0 | fn from(v: Schema) -> Value { |
419 | 0 | v.0 |
420 | 0 | } |
421 | | } |
422 | | |
423 | | impl core::convert::TryFrom<Value> for Schema { |
424 | | type Error = serde_json::Error; |
425 | | |
426 | 0 | fn try_from(value: Value) -> serde_json::Result<Schema> { |
427 | 0 | Schema::validate(&value)?; |
428 | 0 | Ok(Schema(value)) |
429 | 0 | } |
430 | | } |
431 | | |
432 | | impl<'a> core::convert::TryFrom<&'a Value> for &'a Schema { |
433 | | type Error = serde_json::Error; |
434 | | |
435 | 0 | fn try_from(value: &Value) -> serde_json::Result<&Schema> { |
436 | 0 | Schema::validate(value)?; |
437 | 0 | Ok(Schema::ref_cast(value)) |
438 | 0 | } |
439 | | } |
440 | | |
441 | | impl<'a> core::convert::TryFrom<&'a mut Value> for &'a mut Schema { |
442 | | type Error = serde_json::Error; |
443 | | |
444 | 0 | fn try_from(value: &mut Value) -> serde_json::Result<&mut Schema> { |
445 | 0 | Schema::validate(value)?; |
446 | 0 | Ok(Schema::ref_cast_mut(value)) |
447 | 0 | } |
448 | | } |
449 | | |
450 | | impl Default for Schema { |
451 | 0 | fn default() -> Self { |
452 | 0 | Self(Value::Object(Map::new())) |
453 | 0 | } |
454 | | } |
455 | | |
456 | | impl From<Map<String, Value>> for Schema { |
457 | 0 | fn from(o: Map<String, Value>) -> Self { |
458 | 0 | Schema(Value::Object(o)) |
459 | 0 | } |
460 | | } |
461 | | |
462 | | impl From<bool> for Schema { |
463 | 0 | fn from(b: bool) -> Self { |
464 | 0 | Schema(Value::Bool(b)) |
465 | 0 | } |
466 | | } |
467 | | |
468 | | impl crate::JsonSchema for Schema { |
469 | 0 | fn schema_name() -> alloc::borrow::Cow<'static, str> { |
470 | 0 | "Schema".into() |
471 | 0 | } |
472 | | |
473 | 0 | fn schema_id() -> alloc::borrow::Cow<'static, str> { |
474 | 0 | "schemars::Schema".into() |
475 | 0 | } |
476 | | |
477 | 0 | fn json_schema(_: &mut crate::SchemaGenerator) -> Schema { |
478 | 0 | crate::json_schema!({ |
479 | 0 | "type": ["object", "boolean"] |
480 | | }) |
481 | 0 | } |
482 | | } |
483 | | |
484 | | mod ser { |
485 | | use serde::ser::{Serialize, SerializeMap, SerializeSeq}; |
486 | | use serde_json::Value; |
487 | | |
488 | | // The order of properties in a JSON Schema object is insignificant, but we explicitly order |
489 | | // some of them here to make them easier for a human to read. All other properties are ordered |
490 | | // either lexicographically (by default) or by insertion order (if `preserve_order` is enabled) |
491 | | const ORDERED_KEYWORDS_START: [&str; 7] = [ |
492 | | "$id", |
493 | | "$schema", |
494 | | "title", |
495 | | "description", |
496 | | "type", |
497 | | "format", |
498 | | "properties", |
499 | | ]; |
500 | | const ORDERED_KEYWORDS_END: [&str; 2] = ["$defs", "definitions"]; |
501 | | |
502 | | // `no_reorder` is true when the value is expected to be an object that is NOT a schema, |
503 | | // but the object's property values are expected to be schemas. In this case, we do not |
504 | | // reorder the object's direct properties, but we do reorder nested (subschema) properties. |
505 | | // |
506 | | // When `no_reorder` is false, then the value is expected to be one of: |
507 | | // - a JSON schema object |
508 | | // - an array of JSON schemas |
509 | | // - a JSON primitive value (null/string/number/bool) |
510 | | // |
511 | | // If any of these expectations are not met, then the value should still be serialized in a |
512 | | // valid way, but the property ordering may be unclear. |
513 | | pub(super) struct OrderedKeywordWrapper<'a> { |
514 | | value: &'a Value, |
515 | | no_reorder: bool, |
516 | | } |
517 | | |
518 | | impl<'a> From<&'a Value> for OrderedKeywordWrapper<'a> { |
519 | 0 | fn from(value: &'a Value) -> Self { |
520 | 0 | Self { |
521 | 0 | value, |
522 | 0 | no_reorder: false, |
523 | 0 | } |
524 | 0 | } |
525 | | } |
526 | | |
527 | | impl Serialize for OrderedKeywordWrapper<'_> { |
528 | 0 | fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> |
529 | 0 | where |
530 | 0 | S: serde::Serializer, |
531 | | { |
532 | 0 | fn serialize_schema_property<S>( |
533 | 0 | map: &mut S::SerializeMap, |
534 | 0 | key: &str, |
535 | 0 | value: &Value, |
536 | 0 | ) -> Result<(), S::Error> |
537 | 0 | where |
538 | 0 | S: serde::Serializer, |
539 | | { |
540 | 0 | if matches!(key, "examples" | "default") || key.starts_with("x-") { |
541 | | // Value(s) of `examples`/`default` are plain values, not schemas. |
542 | | // Also don't reorder values of custom properties. |
543 | 0 | map.serialize_entry(key, value) |
544 | | } else { |
545 | 0 | let no_reorder = matches!( |
546 | 0 | key, |
547 | 0 | "properties" |
548 | 0 | | "patternProperties" |
549 | 0 | | "dependentSchemas" |
550 | 0 | | "$defs" |
551 | 0 | | "definitions" |
552 | | ); |
553 | 0 | map.serialize_entry(key, &OrderedKeywordWrapper { value, no_reorder }) |
554 | | } |
555 | 0 | } |
556 | | |
557 | 0 | match self.value { |
558 | 0 | Value::Array(array) => { |
559 | 0 | let mut seq = serializer.serialize_seq(Some(array.len()))?; |
560 | 0 | for value in array { |
561 | 0 | seq.serialize_element(&OrderedKeywordWrapper::from(value))?; |
562 | | } |
563 | 0 | seq.end() |
564 | | } |
565 | 0 | Value::Object(object) if self.no_reorder => { |
566 | 0 | let mut map = serializer.serialize_map(Some(object.len()))?; |
567 | | |
568 | 0 | for (key, value) in object { |
569 | | // Don't use `serialize_schema_property` because `object` is NOT expected |
570 | | // to be a schema (but `value` is expected to be a schema) |
571 | 0 | map.serialize_entry(key, &OrderedKeywordWrapper::from(value))?; |
572 | | } |
573 | | |
574 | 0 | map.end() |
575 | | } |
576 | 0 | Value::Object(object) => { |
577 | 0 | let mut map = serializer.serialize_map(Some(object.len()))?; |
578 | | |
579 | 0 | for key in ORDERED_KEYWORDS_START { |
580 | 0 | if let Some(value) = object.get(key) { |
581 | 0 | serialize_schema_property::<S>(&mut map, key, value)?; |
582 | 0 | } |
583 | | } |
584 | | |
585 | 0 | for (key, value) in object { |
586 | 0 | if !ORDERED_KEYWORDS_START.contains(&key.as_str()) |
587 | 0 | && !ORDERED_KEYWORDS_END.contains(&key.as_str()) |
588 | | { |
589 | 0 | serialize_schema_property::<S>(&mut map, key, value)?; |
590 | 0 | } |
591 | | } |
592 | | |
593 | 0 | for key in ORDERED_KEYWORDS_END { |
594 | 0 | if let Some(value) = object.get(key) { |
595 | 0 | serialize_schema_property::<S>(&mut map, key, value)?; |
596 | 0 | } |
597 | | } |
598 | | |
599 | 0 | map.end() |
600 | | } |
601 | | Value::Null | Value::Bool(_) | Value::Number(_) | Value::String(_) => { |
602 | 0 | self.value.serialize(serializer) |
603 | | } |
604 | | } |
605 | 0 | } |
606 | | } |
607 | | } |