@@ -8,13 +8,21 @@ use serde_json::Value;
88
99use crate :: { Change , ChangeKind , Error , JsonSchemaType , Range } ;
1010
11- pub struct DiffWalker {
12- pub changes : Vec < Change > ,
11+ pub struct DiffWalker < F : FnMut ( Change ) > {
12+ pub cb : F ,
1313 pub lhs_root : RootSchema ,
1414 pub rhs_root : RootSchema ,
1515}
1616
17- impl DiffWalker {
17+ impl < F : FnMut ( Change ) > DiffWalker < F > {
18+ pub fn new ( cb : F , lhs_root : RootSchema , rhs_root : RootSchema ) -> Self {
19+ Self {
20+ cb,
21+ lhs_root,
22+ rhs_root,
23+ }
24+ }
25+
1826 fn diff_any_of (
1927 & mut self ,
2028 json_path : & str ,
@@ -27,21 +35,47 @@ impl DiffWalker {
2735 if let ( Some ( lhs_any_of) , Some ( rhs_any_of) ) =
2836 ( & mut lhs. subschemas ( ) . any_of , & mut rhs. subschemas ( ) . any_of )
2937 {
30- lhs_any_of. sort_by_cached_key ( |x| format ! ( "{x:?}" ) ) ;
31- rhs_any_of. sort_by_cached_key ( |x| format ! ( "{x:?}" ) ) ;
32-
33- for ( i, ( lhs_inner, rhs_inner) ) in
34- lhs_any_of. iter_mut ( ) . zip ( rhs_any_of. iter_mut ( ) ) . enumerate ( )
35- {
38+ match ( lhs_any_of. len ( ) , rhs_any_of. len ( ) ) {
39+ ( l, r) if l <= r => {
40+ lhs_any_of. append ( & mut vec ! [ Schema :: Bool ( false ) ; r - l] ) ;
41+ }
42+ ( l, r) => {
43+ rhs_any_of. append ( & mut vec ! [ Schema :: Bool ( false ) ; l - r] ) ;
44+ }
45+ }
46+ let max_len = lhs_any_of. len ( ) . max ( rhs_any_of. len ( ) ) ;
47+ lhs_any_of. resize ( max_len, Schema :: Bool ( false ) ) ;
48+ rhs_any_of. resize ( max_len, Schema :: Bool ( false ) ) ;
49+
50+ let mut mat = pathfinding:: matrix:: Matrix :: new ( max_len, max_len, 0i32 ) ;
51+ for ( i, l) in lhs_any_of. iter_mut ( ) . enumerate ( ) {
52+ for ( j, r) in rhs_any_of. iter_mut ( ) . enumerate ( ) {
53+ let mut count = 0 ;
54+ let counter = |_change : Change | count += 1 ;
55+ DiffWalker :: new (
56+ Box :: new ( counter) as Box < dyn FnMut ( Change ) > ,
57+ self . lhs_root . clone ( ) ,
58+ self . rhs_root . clone ( ) ,
59+ )
60+ . diff (
61+ "" ,
62+ & mut l. clone ( ) . into_object ( ) ,
63+ & mut r. clone ( ) . into_object ( ) ,
64+ ) ?;
65+ mat[ ( i, j) ] = count;
66+ }
67+ }
68+ let pairs = pathfinding:: kuhn_munkres:: kuhn_munkres_min ( & mat) . 1 ;
69+ for i in 0 ..max_len {
3670 let new_path = match is_rhs_split {
3771 true => json_path. to_owned ( ) ,
38- false => format ! ( "{json_path}.<anyOf:{i }>" ) ,
72+ false => format ! ( "{json_path}.<anyOf:{}>" , pairs [ i ] ) ,
3973 } ;
4074 self . do_diff (
4175 & new_path,
4276 true ,
43- & mut lhs_inner . clone ( ) . into_object ( ) ,
44- & mut rhs_inner . clone ( ) . into_object ( ) ,
77+ & mut lhs_any_of [ i ] . clone ( ) . into_object ( ) ,
78+ & mut rhs_any_of [ pairs [ i ] ] . clone ( ) . into_object ( ) ,
4579 ) ?;
4680 }
4781 }
@@ -59,7 +93,7 @@ impl DiffWalker {
5993 let rhs_ty = rhs. effective_type ( ) . into_set ( ) ;
6094
6195 for removed in lhs_ty. difference ( & rhs_ty) {
62- self . changes . push ( Change {
96+ ( self . cb ) ( Change {
6397 path : json_path. to_owned ( ) ,
6498 change : ChangeKind :: TypeRemove {
6599 removed : removed. clone ( ) ,
@@ -68,7 +102,7 @@ impl DiffWalker {
68102 }
69103
70104 for added in rhs_ty. difference ( & lhs_ty) {
71- self . changes . push ( Change {
105+ ( self . cb ) ( Change {
72106 path : json_path. to_owned ( ) ,
73107 change : ChangeKind :: TypeAdd {
74108 added : added. clone ( ) ,
@@ -81,25 +115,25 @@ impl DiffWalker {
81115 Self :: normalize_const ( lhs) ;
82116 Self :: normalize_const ( rhs) ;
83117 match ( & lhs. const_value , & rhs. const_value ) {
84- ( Some ( value) , None ) => self . changes . push ( Change {
118+ ( Some ( value) , None ) => ( self . cb ) ( Change {
85119 path : json_path. to_owned ( ) ,
86120 change : ChangeKind :: ConstRemove {
87121 removed : value. clone ( ) ,
88122 } ,
89123 } ) ,
90- ( None , Some ( value) ) => self . changes . push ( Change {
124+ ( None , Some ( value) ) => ( self . cb ) ( Change {
91125 path : json_path. to_owned ( ) ,
92126 change : ChangeKind :: ConstAdd {
93127 added : value. clone ( ) ,
94128 } ,
95129 } ) ,
96130 ( Some ( l) , Some ( r) ) if l != r => {
97131 if l. is_object ( ) && r. is_object ( ) { }
98- self . changes . push ( Change {
132+ ( self . cb ) ( Change {
99133 path : json_path. to_owned ( ) ,
100134 change : ChangeKind :: ConstRemove { removed : l. clone ( ) } ,
101135 } ) ;
102- self . changes . push ( Change {
136+ ( self . cb ) ( Change {
103137 path : json_path. to_owned ( ) ,
104138 change : ChangeKind :: ConstAdd { added : r. clone ( ) } ,
105139 } ) ;
@@ -124,7 +158,7 @@ impl DiffWalker {
124158 . map_or ( true , |x| x. clone ( ) . into_object ( ) . is_true ( ) ) ;
125159
126160 for removed in lhs_props. difference ( & rhs_props) {
127- self . changes . push ( Change {
161+ ( self . cb ) ( Change {
128162 path : json_path. to_owned ( ) ,
129163 change : ChangeKind :: PropertyRemove {
130164 lhs_additional_properties,
@@ -134,7 +168,7 @@ impl DiffWalker {
134168 }
135169
136170 for added in rhs_props. difference ( & lhs_props) {
137- self . changes . push ( Change {
171+ ( self . cb ) ( Change {
138172 path : json_path. to_owned ( ) ,
139173 change : ChangeKind :: PropertyAdd {
140174 lhs_additional_properties,
@@ -218,14 +252,14 @@ impl DiffWalker {
218252 rhs. number_validation ( ) . minimum ,
219253 Range :: Minimum ,
220254 ) {
221- self . changes . push ( diff)
255+ ( self . cb ) ( diff)
222256 }
223257 if let Some ( diff) = diff (
224258 lhs. number_validation ( ) . maximum ,
225259 rhs. number_validation ( ) . maximum ,
226260 Range :: Maximum ,
227261 ) {
228- self . changes . push ( diff)
262+ ( self . cb ) ( diff)
229263 }
230264 Ok ( ( ) )
231265 }
@@ -239,7 +273,7 @@ impl DiffWalker {
239273 match ( & lhs. array ( ) . items , & rhs. array ( ) . items ) {
240274 ( Some ( SingleOrVec :: Vec ( lhs_items) ) , Some ( SingleOrVec :: Vec ( rhs_items) ) ) => {
241275 if lhs_items. len ( ) != rhs_items. len ( ) {
242- self . changes . push ( Change {
276+ ( self . cb ) ( Change {
243277 path : json_path. to_owned ( ) ,
244278 change : ChangeKind :: TupleChange {
245279 new_length : rhs_items. len ( ) ,
@@ -267,7 +301,7 @@ impl DiffWalker {
267301 ) ?;
268302 }
269303 ( Some ( SingleOrVec :: Single ( lhs_inner) ) , Some ( SingleOrVec :: Vec ( rhs_items) ) ) => {
270- self . changes . push ( Change {
304+ ( self . cb ) ( Change {
271305 path : json_path. to_owned ( ) ,
272306 change : ChangeKind :: ArrayToTuple {
273307 new_length : rhs_items. len ( ) ,
@@ -284,7 +318,7 @@ impl DiffWalker {
284318 }
285319 }
286320 ( Some ( SingleOrVec :: Vec ( lhs_items) ) , Some ( SingleOrVec :: Single ( rhs_inner) ) ) => {
287- self . changes . push ( Change {
321+ ( self . cb ) ( Change {
288322 path : json_path. to_owned ( ) ,
289323 change : ChangeKind :: TupleToArray {
290324 old_length : lhs_items. len ( ) ,
@@ -321,7 +355,7 @@ impl DiffWalker {
321355 let rhs_required = & rhs. object ( ) . required ;
322356
323357 for removed in lhs_required. difference ( rhs_required) {
324- self . changes . push ( Change {
358+ ( self . cb ) ( Change {
325359 path : json_path. to_owned ( ) ,
326360 change : ChangeKind :: RequiredRemove {
327361 property : removed. clone ( ) ,
@@ -330,7 +364,7 @@ impl DiffWalker {
330364 }
331365
332366 for added in rhs_required. difference ( lhs_required) {
333- self . changes . push ( Change {
367+ ( self . cb ) ( Change {
334368 path : json_path. to_owned ( ) ,
335369 change : ChangeKind :: RequiredAdd {
336370 property : added. clone ( ) ,
@@ -532,6 +566,7 @@ impl JsonSchemaExt for SchemaObject {
532566 self . subschemas ( )
533567 . any_of
534568 . as_ref ( )
569+ . filter ( |schemas| schemas. len ( ) == 1 )
535570 . and_then ( |a| a. get ( 0 ) )
536571 . map ( |subschema| subschema. clone ( ) . into_object ( ) . number ( ) . clone ( ) )
537572 . unwrap_or_default ( )
0 commit comments