@@ -65,10 +65,61 @@ impl UnionSerializer {
65
65
}
66
66
}
67
67
}
68
+
69
+ fn _to_python (
70
+ & self ,
71
+ value : & Bound < ' _ , PyAny > ,
72
+ include : Option < & Bound < ' _ , PyAny > > ,
73
+ exclude : Option < & Bound < ' _ , PyAny > > ,
74
+ extra : & Extra ,
75
+ ) -> ToPythonExtractorResult {
76
+ to_python_extractor ( value, include, exclude, extra, & self . choices )
77
+ }
68
78
}
69
79
70
80
impl_py_gc_traverse ! ( UnionSerializer { choices } ) ;
71
81
82
+ #[ derive( Debug ) ]
83
+ enum ToPythonExtractorResult {
84
+ Success ( PyObject ) ,
85
+ Errors ( SmallVec < [ PyErr ; SMALL_UNION_THRESHOLD ] > ) ,
86
+ }
87
+
88
+ fn to_python_extractor (
89
+ value : & Bound < ' _ , PyAny > ,
90
+ include : Option < & Bound < ' _ , PyAny > > ,
91
+ exclude : Option < & Bound < ' _ , PyAny > > ,
92
+ extra : & Extra ,
93
+ choices : & [ CombinedSerializer ] ,
94
+ ) -> ToPythonExtractorResult {
95
+ let mut errors: SmallVec < [ PyErr ; SMALL_UNION_THRESHOLD ] > = SmallVec :: new ( ) ;
96
+
97
+ for comb_serializer in choices {
98
+ match comb_serializer {
99
+ CombinedSerializer :: Union ( union_serializer) => {
100
+ match union_serializer. _to_python ( value, include, exclude, extra) {
101
+ ToPythonExtractorResult :: Errors ( errs) => errors. extend ( errs) ,
102
+ ToPythonExtractorResult :: Success ( success) => return ToPythonExtractorResult :: Success ( success) ,
103
+ }
104
+ }
105
+ CombinedSerializer :: TaggedUnion ( tagged_union_serializer) => {
106
+ match tagged_union_serializer. _to_python ( value, include, exclude, extra) {
107
+ ToPythonExtractorResult :: Errors ( errs) => errors. extend ( errs) ,
108
+ ToPythonExtractorResult :: Success ( success) => return ToPythonExtractorResult :: Success ( success) ,
109
+ }
110
+ }
111
+ _ => {
112
+ match comb_serializer. to_python ( value, include, exclude, extra) {
113
+ Ok ( v) => return ToPythonExtractorResult :: Success ( v) ,
114
+ Err ( err) => errors. push ( err) ,
115
+ } ;
116
+ }
117
+ }
118
+ }
119
+
120
+ ToPythonExtractorResult :: Errors ( errors)
121
+ }
122
+
72
123
fn to_python (
73
124
value : & Bound < ' _ , PyAny > ,
74
125
include : Option < & Bound < ' _ , PyAny > > ,
@@ -80,14 +131,13 @@ fn to_python(
80
131
// try the serializers in left to right order with error_on fallback=true
81
132
let mut new_extra = extra. clone ( ) ;
82
133
new_extra. check = SerCheck :: Strict ;
83
- let mut errors: SmallVec < [ PyErr ; SMALL_UNION_THRESHOLD ] > = SmallVec :: new ( ) ;
84
134
85
- for comb_serializer in choices {
86
- match comb_serializer . to_python ( value , include , exclude , & new_extra ) {
87
- Ok ( v ) => return Ok ( v ) ,
88
- Err ( err ) => errors . push ( err ) ,
89
- }
90
- }
135
+ let res = to_python_extractor ( value , include , exclude , & new_extra , choices ) ;
136
+
137
+ let errors = match res {
138
+ ToPythonExtractorResult :: Success ( obj ) => return Ok ( obj ) ,
139
+ ToPythonExtractorResult :: Errors ( errs ) => errs ,
140
+ } ;
91
141
92
142
if retry_with_lax_check {
93
143
new_extra. check = SerCheck :: Lax ;
@@ -392,6 +442,38 @@ impl TypeSerializer for TaggedUnionSerializer {
392
442
}
393
443
394
444
impl TaggedUnionSerializer {
445
+ fn _to_python (
446
+ & self ,
447
+ value : & Bound < ' _ , PyAny > ,
448
+ include : Option < & Bound < ' _ , PyAny > > ,
449
+ exclude : Option < & Bound < ' _ , PyAny > > ,
450
+ extra : & Extra ,
451
+ ) -> ToPythonExtractorResult {
452
+ let mut new_extra = extra. clone ( ) ;
453
+ new_extra. check = SerCheck :: Strict ;
454
+
455
+ if let Some ( tag) = self . get_discriminator_value ( value, extra) {
456
+ let tag_str = tag. to_string ( ) ;
457
+ if let Some ( & serializer_index) = self . lookup . get ( & tag_str) {
458
+ let serializer = & self . choices [ serializer_index] ;
459
+
460
+ match serializer. to_python ( value, include, exclude, & new_extra) {
461
+ Ok ( v) => return ToPythonExtractorResult :: Success ( v) ,
462
+ Err ( _) => {
463
+ if self . retry_with_lax_check ( ) {
464
+ new_extra. check = SerCheck :: Lax ;
465
+ if let Ok ( v) = serializer. to_python ( value, include, exclude, & new_extra) {
466
+ return ToPythonExtractorResult :: Success ( v) ;
467
+ }
468
+ }
469
+ }
470
+ }
471
+ }
472
+ }
473
+
474
+ to_python_extractor ( value, include, exclude, extra, & self . choices )
475
+ }
476
+
395
477
fn get_discriminator_value ( & self , value : & Bound < ' _ , PyAny > , extra : & Extra ) -> Option < Py < PyAny > > {
396
478
let py = value. py ( ) ;
397
479
let discriminator_value = match & self . discriminator {
0 commit comments