@@ -78,16 +78,8 @@ impl<'j> PythonParser<'j> {
7878 match $result {
7979 Ok ( k) => k,
8080 Err ( e) => {
81- return if self . allow_partial {
82- match e. error_type {
83- JsonErrorType :: EofWhileParsingList
84- | JsonErrorType :: EofWhileParsingObject
85- | JsonErrorType :: EofWhileParsingString
86- | JsonErrorType :: EofWhileParsingValue
87- | JsonErrorType :: ExpectedListCommaOrEnd
88- | JsonErrorType :: ExpectedObjectCommaOrEnd => Ok ( $partial_value. into_any( ) ) ,
89- _ => Err ( e) ,
90- }
81+ return if self . _allow_partial_err( & e) {
82+ Ok ( $partial_value. into_any( ) )
9183 } else {
9284 Err ( e)
9385 }
@@ -116,17 +108,10 @@ impl<'j> PythonParser<'j> {
116108 Peek :: Array => {
117109 let list = if let Some ( peek_first) = tri ! ( self . parser. array_first( ) , PyList :: empty_bound( py) ) {
118110 let mut vec: SmallVec < [ Bound < ' _ , PyAny > ; 8 ] > = SmallVec :: with_capacity ( 8 ) ;
119- let v = tri ! (
120- self . _check_take_value:: <StringCache >( py, peek_first) ,
121- PyList :: empty_bound( py)
122- ) ;
123- vec. push ( v) ;
124- while let Some ( peek) = tri ! ( self . parser. array_step( ) , PyList :: new_bound( py, vec) ) {
125- let v = tri ! (
126- self . _check_take_value:: <StringCache >( py, peek) ,
127- PyList :: new_bound( py, vec)
128- ) ;
129- vec. push ( v) ;
111+ if let Err ( e) = self . _parse_array :: < StringCache > ( py, peek_first, & mut vec) {
112+ if !self . _allow_partial_err ( & e) {
113+ return Err ( e) ;
114+ }
130115 }
131116 PyList :: new_bound ( py, vec)
132117 } else {
@@ -136,26 +121,9 @@ impl<'j> PythonParser<'j> {
136121 }
137122 Peek :: Object => {
138123 let dict = PyDict :: new_bound ( py) ;
139-
140- let set_item = |key : Bound < ' py , PyAny > , value : Bound < ' py , PyAny > | {
141- let r = unsafe { ffi:: PyDict_SetItem ( dict. as_ptr ( ) , key. as_ptr ( ) , value. as_ptr ( ) ) } ;
142- // AFAIK this shouldn't happen since the key will always be a string which is hashable
143- // we panic here rather than returning a result and using `?` below as it's up to 14% faster
144- // presumably because there are fewer branches
145- if r == -1 {
146- panic ! ( "PyDict_SetItem failed" )
147- }
148- } ;
149- if let Some ( first_key) = tri ! ( self . parser. object_first:: <StringDecoder >( & mut self . tape) , dict) {
150- let first_key = StringCache :: get ( py, first_key. as_str ( ) ) ;
151- let peek = tri ! ( self . parser. peek( ) , dict) ;
152- let first_value = tri ! ( self . _check_take_value:: <StringCache >( py, peek) , dict) ;
153- set_item ( first_key, first_value) ;
154- while let Some ( key) = tri ! ( self . parser. object_step:: <StringDecoder >( & mut self . tape) , dict) {
155- let key = StringCache :: get ( py, key. as_str ( ) ) ;
156- let peek = tri ! ( self . parser. peek( ) , dict) ;
157- let value = tri ! ( self . _check_take_value:: <StringCache >( py, peek) , dict) ;
158- set_item ( key, value) ;
124+ if let Err ( e) = self . _parse_object :: < StringCache > ( py, & dict) {
125+ if !self . _allow_partial_err ( & e) {
126+ return Err ( e) ;
159127 }
160128 }
161129 Ok ( dict. into_any ( ) )
@@ -180,6 +148,66 @@ impl<'j> PythonParser<'j> {
180148 }
181149 }
182150
151+ fn _parse_array < ' py , StringCache : StringMaybeCache > (
152+ & mut self ,
153+ py : Python < ' py > ,
154+ peek_first : Peek ,
155+ vec : & mut SmallVec < [ Bound < ' py , PyAny > ; 8 ] > ,
156+ ) -> JsonResult < ( ) > {
157+ let v = self . _check_take_value :: < StringCache > ( py, peek_first) ?;
158+ vec. push ( v) ;
159+ while let Some ( peek) = self . parser . array_step ( ) ? {
160+ let v = self . _check_take_value :: < StringCache > ( py, peek) ?;
161+ vec. push ( v) ;
162+ }
163+ Ok ( ( ) )
164+ }
165+
166+ fn _parse_object < ' py , StringCache : StringMaybeCache > (
167+ & mut self ,
168+ py : Python < ' py > ,
169+ dict : & Bound < ' py , PyDict > ,
170+ ) -> JsonResult < ( ) > {
171+ let set_item = |key : Bound < ' py , PyAny > , value : Bound < ' py , PyAny > | {
172+ let r = unsafe { ffi:: PyDict_SetItem ( dict. as_ptr ( ) , key. as_ptr ( ) , value. as_ptr ( ) ) } ;
173+ // AFAIK this shouldn't happen since the key will always be a string which is hashable
174+ // we panic here rather than returning a result and using `?` below as it's up to 14% faster
175+ // presumably because there are fewer branches
176+ if r == -1 {
177+ panic ! ( "PyDict_SetItem failed" )
178+ }
179+ } ;
180+ if let Some ( first_key) = self . parser . object_first :: < StringDecoder > ( & mut self . tape ) ? {
181+ let first_key = StringCache :: get ( py, first_key. as_str ( ) ) ;
182+ let peek = self . parser . peek ( ) ?;
183+ let first_value = self . _check_take_value :: < StringCache > ( py, peek) ?;
184+ set_item ( first_key, first_value) ;
185+ while let Some ( key) = self . parser . object_step :: < StringDecoder > ( & mut self . tape ) ? {
186+ let key = StringCache :: get ( py, key. as_str ( ) ) ;
187+ let peek = self . parser . peek ( ) ?;
188+ let value = self . _check_take_value :: < StringCache > ( py, peek) ?;
189+ set_item ( key, value) ;
190+ }
191+ }
192+ Ok ( ( ) )
193+ }
194+
195+ fn _allow_partial_err ( & self , e : & JsonError ) -> bool {
196+ if self . allow_partial {
197+ matches ! (
198+ e. error_type,
199+ JsonErrorType :: EofWhileParsingList
200+ | JsonErrorType :: EofWhileParsingObject
201+ | JsonErrorType :: EofWhileParsingString
202+ | JsonErrorType :: EofWhileParsingValue
203+ | JsonErrorType :: ExpectedListCommaOrEnd
204+ | JsonErrorType :: ExpectedObjectCommaOrEnd
205+ )
206+ } else {
207+ false
208+ }
209+ }
210+
183211 fn _check_take_value < ' py , StringCache : StringMaybeCache > (
184212 & mut self ,
185213 py : Python < ' py > ,
0 commit comments