Parse a JSON object starting after the opening '{'. Returns (parsed_object, end_char_index, end_byte_index).
(
&self,
pystr: PyUtf8StrRef,
start_char_idx: usize,
start_byte_idx: usize,
scan_once: &PyObjectRef,
memo: &mut HashMap<String,
| 227 | /// Parse a JSON object starting after the opening '{'. |
| 228 | /// Returns (parsed_object, end_char_index, end_byte_index). |
| 229 | fn parse_object( |
| 230 | &self, |
| 231 | pystr: PyUtf8StrRef, |
| 232 | start_char_idx: usize, |
| 233 | start_byte_idx: usize, |
| 234 | scan_once: &PyObjectRef, |
| 235 | memo: &mut HashMap<String, PyStrRef>, |
| 236 | vm: &VirtualMachine, |
| 237 | ) -> PyResult<(PyObjectRef, usize, usize)> { |
| 238 | flame_guard!("JsonScanner::parse_object"); |
| 239 | |
| 240 | let bytes = pystr.as_bytes(); |
| 241 | let wtf8 = pystr.as_wtf8(); |
| 242 | let mut char_idx = start_char_idx; |
| 243 | let mut byte_idx = start_byte_idx; |
| 244 | |
| 245 | // Skip initial whitespace |
| 246 | let ws = skip_whitespace(&bytes[byte_idx..]); |
| 247 | char_idx += ws; |
| 248 | byte_idx += ws; |
| 249 | |
| 250 | // Check for empty object |
| 251 | match bytes.get(byte_idx) { |
| 252 | Some(b'}') => { |
| 253 | return self.finalize_object(vec![], char_idx + 1, byte_idx + 1, vm); |
| 254 | } |
| 255 | Some(b'"') => { |
| 256 | // Continue to parse first key |
| 257 | } |
| 258 | _ => { |
| 259 | return Err(self.make_decode_error( |
| 260 | "Expecting property name enclosed in double quotes", |
| 261 | pystr, |
| 262 | char_idx, |
| 263 | vm, |
| 264 | )); |
| 265 | } |
| 266 | } |
| 267 | |
| 268 | let mut pairs: Vec<(PyObjectRef, PyObjectRef)> = Vec::new(); |
| 269 | |
| 270 | loop { |
| 271 | // We're now at '"', skip it |
| 272 | char_idx += 1; |
| 273 | byte_idx += 1; |
| 274 | |
| 275 | // Parse key string using scanstring with byte slice |
| 276 | let (key_wtf8, chars_consumed, bytes_consumed) = |
| 277 | machinery::scanstring(&wtf8[byte_idx..], char_idx, self.strict) |
| 278 | .map_err(|e| py_decode_error(e, pystr.clone().into_wtf8(), vm))?; |
| 279 | |
| 280 | char_idx += chars_consumed; |
| 281 | byte_idx += bytes_consumed; |
| 282 | |
| 283 | // Key memoization - reuse existing key strings |
| 284 | let key_str = key_wtf8.to_string(); |
| 285 | let key: PyObjectRef = match memo.get(&key_str) { |
| 286 | Some(cached) => cached.clone().into(), |
no test coverage detected