@@ -8,13 +8,21 @@ use serde_json::Value;
8
8
9
9
use crate :: { Change , ChangeKind , Error , JsonSchemaType , Range } ;
10
10
11
- pub struct DiffWalker {
12
- pub changes : Vec < Change > ,
11
+ pub struct DiffWalker < F : FnMut ( Change ) > {
12
+ pub cb : F ,
13
13
pub lhs_root : RootSchema ,
14
14
pub rhs_root : RootSchema ,
15
15
}
16
16
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
+
18
26
fn diff_any_of (
19
27
& mut self ,
20
28
json_path : & str ,
@@ -27,21 +35,47 @@ impl DiffWalker {
27
35
if let ( Some ( lhs_any_of) , Some ( rhs_any_of) ) =
28
36
( & mut lhs. subschemas ( ) . any_of , & mut rhs. subschemas ( ) . any_of )
29
37
{
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 {
36
70
let new_path = match is_rhs_split {
37
71
true => json_path. to_owned ( ) ,
38
- false => format ! ( "{json_path}.<anyOf:{i }>" ) ,
72
+ false => format ! ( "{json_path}.<anyOf:{}>" , pairs [ i ] ) ,
39
73
} ;
40
74
self . do_diff (
41
75
& new_path,
42
76
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 ( ) ,
45
79
) ?;
46
80
}
47
81
}
@@ -59,7 +93,7 @@ impl DiffWalker {
59
93
let rhs_ty = rhs. effective_type ( ) . into_set ( ) ;
60
94
61
95
for removed in lhs_ty. difference ( & rhs_ty) {
62
- self . changes . push ( Change {
96
+ ( self . cb ) ( Change {
63
97
path : json_path. to_owned ( ) ,
64
98
change : ChangeKind :: TypeRemove {
65
99
removed : removed. clone ( ) ,
@@ -68,7 +102,7 @@ impl DiffWalker {
68
102
}
69
103
70
104
for added in rhs_ty. difference ( & lhs_ty) {
71
- self . changes . push ( Change {
105
+ ( self . cb ) ( Change {
72
106
path : json_path. to_owned ( ) ,
73
107
change : ChangeKind :: TypeAdd {
74
108
added : added. clone ( ) ,
@@ -81,25 +115,25 @@ impl DiffWalker {
81
115
Self :: normalize_const ( lhs) ;
82
116
Self :: normalize_const ( rhs) ;
83
117
match ( & lhs. const_value , & rhs. const_value ) {
84
- ( Some ( value) , None ) => self . changes . push ( Change {
118
+ ( Some ( value) , None ) => ( self . cb ) ( Change {
85
119
path : json_path. to_owned ( ) ,
86
120
change : ChangeKind :: ConstRemove {
87
121
removed : value. clone ( ) ,
88
122
} ,
89
123
} ) ,
90
- ( None , Some ( value) ) => self . changes . push ( Change {
124
+ ( None , Some ( value) ) => ( self . cb ) ( Change {
91
125
path : json_path. to_owned ( ) ,
92
126
change : ChangeKind :: ConstAdd {
93
127
added : value. clone ( ) ,
94
128
} ,
95
129
} ) ,
96
130
( Some ( l) , Some ( r) ) if l != r => {
97
131
if l. is_object ( ) && r. is_object ( ) { }
98
- self . changes . push ( Change {
132
+ ( self . cb ) ( Change {
99
133
path : json_path. to_owned ( ) ,
100
134
change : ChangeKind :: ConstRemove { removed : l. clone ( ) } ,
101
135
} ) ;
102
- self . changes . push ( Change {
136
+ ( self . cb ) ( Change {
103
137
path : json_path. to_owned ( ) ,
104
138
change : ChangeKind :: ConstAdd { added : r. clone ( ) } ,
105
139
} ) ;
@@ -124,7 +158,7 @@ impl DiffWalker {
124
158
. map_or ( true , |x| x. clone ( ) . into_object ( ) . is_true ( ) ) ;
125
159
126
160
for removed in lhs_props. difference ( & rhs_props) {
127
- self . changes . push ( Change {
161
+ ( self . cb ) ( Change {
128
162
path : json_path. to_owned ( ) ,
129
163
change : ChangeKind :: PropertyRemove {
130
164
lhs_additional_properties,
@@ -134,7 +168,7 @@ impl DiffWalker {
134
168
}
135
169
136
170
for added in rhs_props. difference ( & lhs_props) {
137
- self . changes . push ( Change {
171
+ ( self . cb ) ( Change {
138
172
path : json_path. to_owned ( ) ,
139
173
change : ChangeKind :: PropertyAdd {
140
174
lhs_additional_properties,
@@ -218,14 +252,14 @@ impl DiffWalker {
218
252
rhs. number_validation ( ) . minimum ,
219
253
Range :: Minimum ,
220
254
) {
221
- self . changes . push ( diff)
255
+ ( self . cb ) ( diff)
222
256
}
223
257
if let Some ( diff) = diff (
224
258
lhs. number_validation ( ) . maximum ,
225
259
rhs. number_validation ( ) . maximum ,
226
260
Range :: Maximum ,
227
261
) {
228
- self . changes . push ( diff)
262
+ ( self . cb ) ( diff)
229
263
}
230
264
Ok ( ( ) )
231
265
}
@@ -239,7 +273,7 @@ impl DiffWalker {
239
273
match ( & lhs. array ( ) . items , & rhs. array ( ) . items ) {
240
274
( Some ( SingleOrVec :: Vec ( lhs_items) ) , Some ( SingleOrVec :: Vec ( rhs_items) ) ) => {
241
275
if lhs_items. len ( ) != rhs_items. len ( ) {
242
- self . changes . push ( Change {
276
+ ( self . cb ) ( Change {
243
277
path : json_path. to_owned ( ) ,
244
278
change : ChangeKind :: TupleChange {
245
279
new_length : rhs_items. len ( ) ,
@@ -267,7 +301,7 @@ impl DiffWalker {
267
301
) ?;
268
302
}
269
303
( Some ( SingleOrVec :: Single ( lhs_inner) ) , Some ( SingleOrVec :: Vec ( rhs_items) ) ) => {
270
- self . changes . push ( Change {
304
+ ( self . cb ) ( Change {
271
305
path : json_path. to_owned ( ) ,
272
306
change : ChangeKind :: ArrayToTuple {
273
307
new_length : rhs_items. len ( ) ,
@@ -284,7 +318,7 @@ impl DiffWalker {
284
318
}
285
319
}
286
320
( Some ( SingleOrVec :: Vec ( lhs_items) ) , Some ( SingleOrVec :: Single ( rhs_inner) ) ) => {
287
- self . changes . push ( Change {
321
+ ( self . cb ) ( Change {
288
322
path : json_path. to_owned ( ) ,
289
323
change : ChangeKind :: TupleToArray {
290
324
old_length : lhs_items. len ( ) ,
@@ -321,7 +355,7 @@ impl DiffWalker {
321
355
let rhs_required = & rhs. object ( ) . required ;
322
356
323
357
for removed in lhs_required. difference ( rhs_required) {
324
- self . changes . push ( Change {
358
+ ( self . cb ) ( Change {
325
359
path : json_path. to_owned ( ) ,
326
360
change : ChangeKind :: RequiredRemove {
327
361
property : removed. clone ( ) ,
@@ -330,7 +364,7 @@ impl DiffWalker {
330
364
}
331
365
332
366
for added in rhs_required. difference ( lhs_required) {
333
- self . changes . push ( Change {
367
+ ( self . cb ) ( Change {
334
368
path : json_path. to_owned ( ) ,
335
369
change : ChangeKind :: RequiredAdd {
336
370
property : added. clone ( ) ,
@@ -532,6 +566,7 @@ impl JsonSchemaExt for SchemaObject {
532
566
self . subschemas ( )
533
567
. any_of
534
568
. as_ref ( )
569
+ . filter ( |schemas| schemas. len ( ) == 1 )
535
570
. and_then ( |a| a. get ( 0 ) )
536
571
. map ( |subschema| subschema. clone ( ) . into_object ( ) . number ( ) . clone ( ) )
537
572
. unwrap_or_default ( )
0 commit comments