Skip to content

Commit c3f6b6b

Browse files
committed
separate _parse_array and _parse_object
1 parent c8a669e commit c3f6b6b

File tree

1 file changed

+69
-41
lines changed

1 file changed

+69
-41
lines changed

src/python.rs

Lines changed: 69 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)