11//! Schema-related structure definitions
22
3- use serde:: { Deserialize , Serialize , ser:: SerializeStruct } ;
3+ use serde:: {
4+ Deserialize , Serialize ,
5+ de:: MapAccess ,
6+ ser:: { SerializeSeq , SerializeStruct } ,
7+ } ;
48use std:: collections:: BTreeMap ;
59
610/// Schema reference or inline schema.
@@ -29,24 +33,51 @@ impl<'de> Deserialize<'de> for SchemaRef {
2933 fn deserialize < D > ( deserializer : D ) -> Result < Self , D :: Error >
3034 where
3135 D : serde:: Deserializer < ' de > ,
36+ {
37+ deserializer. deserialize_map ( SchemaRefVisitor )
38+ }
39+ }
40+
41+ struct SchemaRefVisitor ;
42+
43+ impl < ' de > serde:: de:: Visitor < ' de > for SchemaRefVisitor {
44+ type Value = SchemaRef ;
45+
46+ fn expecting ( & self , formatter : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
47+ formatter. write_str ( "an OpenAPI schema reference or inline schema object" )
48+ }
49+
50+ fn visit_map < M > ( self , mut access : M ) -> Result < Self :: Value , M :: Error >
51+ where
52+ M : MapAccess < ' de > ,
3253 {
3354 use serde:: de:: Error as _;
34- // OpenAPI is always JSON; buffer the node so a *pure* reference
35- // can be distinguished from a `$ref` carrying sibling keywords.
36- let value = serde_json:: Value :: deserialize ( deserializer) ?;
37- // Pure reference: an object whose ONLY key is `$ref` with a string
38- // value. A `$ref` with any sibling (`nullable`, `description`, …)
39- // is an inline schema, so the siblings are preserved instead of
40- // being dropped by the prior untagged `Ref`-first match.
41- if let serde_json:: Value :: Object ( map) = & value
42- && map. len ( ) == 1
43- && let Some ( serde_json:: Value :: String ( ref_path) ) = map. get ( "$ref" )
44- {
45- return Ok ( Self :: Ref ( Reference :: new ( ref_path. clone ( ) ) ) ) ;
55+
56+ let mut ref_path = None ;
57+ let mut inline = serde_json:: Map :: new ( ) ;
58+ while let Some ( key) = access. next_key :: < String > ( ) ? {
59+ let value = access. next_value :: < serde_json:: Value > ( ) ?;
60+ if key == "$ref"
61+ && ref_path. is_none ( )
62+ && inline. is_empty ( )
63+ && let serde_json:: Value :: String ( path) = value
64+ {
65+ ref_path = Some ( path) ;
66+ } else {
67+ if let Some ( path) = ref_path. take ( ) {
68+ inline. insert ( "$ref" . to_owned ( ) , serde_json:: Value :: String ( path) ) ;
69+ }
70+ inline. insert ( key, value) ;
71+ }
72+ }
73+
74+ if let Some ( path) = ref_path {
75+ return Ok ( SchemaRef :: Ref ( Reference :: new ( path) ) ) ;
4676 }
47- serde_json:: from_value :: < Schema > ( value)
48- . map ( |schema| Self :: Inline ( Box :: new ( schema) ) )
49- . map_err ( D :: Error :: custom)
77+
78+ serde_json:: from_value :: < Schema > ( serde_json:: Value :: Object ( inline) )
79+ . map ( |schema| SchemaRef :: Inline ( Box :: new ( schema) ) )
80+ . map_err ( M :: Error :: custom)
5081 }
5182}
5283
@@ -286,6 +317,74 @@ impl Serialize for NumberConstraint {
286317 }
287318}
288319
320+ struct NullableRefSchema < ' a > {
321+ ref_path : & ' a str ,
322+ }
323+
324+ impl Serialize for NullableRefSchema < ' _ > {
325+ fn serialize < S > ( & self , serializer : S ) -> Result < S :: Ok , S :: Error >
326+ where
327+ S : serde:: Serializer ,
328+ {
329+ let mut out = serializer. serialize_struct ( "Schema" , 1 ) ?;
330+ out. serialize_field ( "$ref" , self . ref_path ) ?;
331+ out. end ( )
332+ }
333+ }
334+
335+ struct NullSchema ;
336+
337+ impl Serialize for NullSchema {
338+ fn serialize < S > ( & self , serializer : S ) -> Result < S :: Ok , S :: Error >
339+ where
340+ S : serde:: Serializer ,
341+ {
342+ let mut out = serializer. serialize_struct ( "Schema" , 1 ) ?;
343+ out. serialize_field ( "type" , & SchemaType :: Null ) ?;
344+ out. end ( )
345+ }
346+ }
347+
348+ struct NullableRefAnyOf < ' a > {
349+ ref_path : & ' a str ,
350+ }
351+
352+ impl Serialize for NullableRefAnyOf < ' _ > {
353+ fn serialize < S > ( & self , serializer : S ) -> Result < S :: Ok , S :: Error >
354+ where
355+ S : serde:: Serializer ,
356+ {
357+ let mut seq = serializer. serialize_seq ( Some ( 2 ) ) ?;
358+ seq. serialize_element ( & NullableRefSchema {
359+ ref_path : self . ref_path ,
360+ } ) ?;
361+ seq. serialize_element ( & NullSchema ) ?;
362+ seq. end ( )
363+ }
364+ }
365+
366+ struct ExamplesWithLegacy < ' a > {
367+ example : Option < & ' a serde_json:: Value > ,
368+ examples : & ' a [ serde_json:: Value ] ,
369+ }
370+
371+ impl Serialize for ExamplesWithLegacy < ' _ > {
372+ fn serialize < S > ( & self , serializer : S ) -> Result < S :: Ok , S :: Error >
373+ where
374+ S : serde:: Serializer ,
375+ {
376+ let len = self . examples . len ( ) + usize:: from ( self . example . is_some ( ) ) ;
377+ let mut seq = serializer. serialize_seq ( Some ( len) ) ?;
378+ if let Some ( example) = self . example {
379+ seq. serialize_element ( example) ?;
380+ }
381+ for example in self . examples {
382+ seq. serialize_element ( example) ?;
383+ }
384+ seq. end ( )
385+ }
386+ }
387+
289388#[ derive( Deserialize , Serialize ) ]
290389#[ serde( untagged) ]
291390enum SchemaTypeWire {
@@ -430,13 +529,7 @@ impl Serialize for Schema {
430529 let mut out = serializer. serialize_struct ( "Schema" , 42 ) ?;
431530 if let Some ( ref_path) = & self . ref_path {
432531 if nullable_ref {
433- out. serialize_field (
434- "anyOf" ,
435- & [
436- SchemaRef :: Ref ( Reference :: new ( ref_path. clone ( ) ) ) ,
437- SchemaRef :: Inline ( Box :: new ( Self :: new ( SchemaType :: Null ) ) ) ,
438- ] ,
439- ) ?;
532+ out. serialize_field ( "anyOf" , & NullableRefAnyOf { ref_path } ) ?;
440533 } else {
441534 out. serialize_field ( "$ref" , ref_path) ?;
442535 }
@@ -463,13 +556,22 @@ impl Serialize for Schema {
463556 }
464557 match ( & self . example , & self . examples ) {
465558 ( Some ( example) , Some ( examples) ) => {
466- let mut combined_examples = Vec :: with_capacity ( examples. len ( ) + 1 ) ;
467- combined_examples. push ( example) ;
468- combined_examples. extend ( examples) ;
469- out. serialize_field ( "examples" , & combined_examples) ?;
559+ out. serialize_field (
560+ "examples" ,
561+ & ExamplesWithLegacy {
562+ example : Some ( example) ,
563+ examples,
564+ } ,
565+ ) ?;
470566 }
471567 ( Some ( example) , None ) => {
472- out. serialize_field ( "examples" , & [ example] ) ?;
568+ out. serialize_field (
569+ "examples" ,
570+ & ExamplesWithLegacy {
571+ example : Some ( example) ,
572+ examples : & [ ] ,
573+ } ,
574+ ) ?;
473575 }
474576 ( None , Some ( examples) ) => {
475577 out. serialize_field ( "examples" , examples) ?;
0 commit comments