@@ -16,6 +16,7 @@ use core::convert::TryInto;
1616use std:: borrow:: Cow ;
1717use std:: cmp:: Ordering ;
1818use std:: collections:: VecDeque ;
19+ use std:: str:: from_utf8;
1920
2021use crate :: constants:: * ;
2122use crate :: error:: * ;
@@ -232,22 +233,13 @@ pub fn get_by_index(value: &[u8], index: usize) -> Option<Vec<u8>> {
232233 let header = read_u32 ( value, 0 ) . unwrap ( ) ;
233234 match header & CONTAINER_HEADER_TYPE_MASK {
234235 ARRAY_CONTAINER_TAG => {
235- let length = ( header & CONTAINER_HEADER_LEN_MASK ) as usize ;
236- if index >= length {
237- return None ;
238- }
239- let mut jentry_offset = 4 ;
240- let mut val_offset = 4 * length + 4 ;
241- for i in 0 ..length {
236+ let offsets = get_offsets_by_index ( value, 0 , header, index) ;
237+
238+ offsets. map ( |( jentry_offset, val_offset) | {
242239 let encoded = read_u32 ( value, jentry_offset) . unwrap ( ) ;
243240 let jentry = JEntry :: decode_jentry ( encoded) ;
244241 let val_length = jentry. length as usize ;
245- if i < index {
246- jentry_offset += 4 ;
247- val_offset += val_length;
248- continue ;
249- }
250- let val = match jentry. type_code {
242+ match jentry. type_code {
251243 CONTAINER_TAG => value[ val_offset..val_offset + val_length] . to_vec ( ) ,
252244 _ => {
253245 let mut buf = Vec :: with_capacity ( 8 + val_length) ;
@@ -258,10 +250,8 @@ pub fn get_by_index(value: &[u8], index: usize) -> Option<Vec<u8>> {
258250 }
259251 buf
260252 }
261- } ;
262- return Some ( val) ;
263- }
264- None
253+ }
254+ } )
265255 }
266256 _ => None ,
267257 }
@@ -289,40 +279,8 @@ pub fn get_by_name(value: &[u8], name: &str, ignore_case: bool) -> Option<Vec<u8
289279 let header = read_u32 ( value, 0 ) . unwrap ( ) ;
290280 match header & CONTAINER_HEADER_TYPE_MASK {
291281 OBJECT_CONTAINER_TAG => {
292- let length = ( header & CONTAINER_HEADER_LEN_MASK ) as usize ;
293- let mut jentry_offset = 4 ;
294- let mut val_offset = 8 * length + 4 ;
295-
296- let mut key_jentries: VecDeque < JEntry > = VecDeque :: with_capacity ( length) ;
297- for _ in 0 ..length {
298- let encoded = read_u32 ( value, jentry_offset) . unwrap ( ) ;
299- let key_jentry = JEntry :: decode_jentry ( encoded) ;
300-
301- jentry_offset += 4 ;
302- val_offset += key_jentry. length as usize ;
303- key_jentries. push_back ( key_jentry) ;
304- }
282+ let offsets = get_offsets_by_name ( value, 0 , header, name, ignore_case) ;
305283
306- let mut offsets = None ;
307- let mut key_offset = 8 * length + 4 ;
308- while let Some ( key_jentry) = key_jentries. pop_front ( ) {
309- let prev_key_offset = key_offset;
310- key_offset += key_jentry. length as usize ;
311- let key =
312- unsafe { std:: str:: from_utf8_unchecked ( & value[ prev_key_offset..key_offset] ) } ;
313- // first match the value with the same name, if not found,
314- // then match the value with the ignoring case name.
315- if name. eq ( key) {
316- offsets = Some ( ( jentry_offset, val_offset) ) ;
317- break ;
318- } else if ignore_case && name. eq_ignore_ascii_case ( key) && offsets. is_none ( ) {
319- offsets = Some ( ( jentry_offset, val_offset) ) ;
320- }
321- let val_encoded = read_u32 ( value, jentry_offset) . unwrap ( ) ;
322- let val_jentry = JEntry :: decode_jentry ( val_encoded) ;
323- jentry_offset += 4 ;
324- val_offset += val_jentry. length as usize ;
325- }
326284 if let Some ( ( jentry_offset, val_offset) ) = offsets {
327285 let encoded = read_u32 ( value, jentry_offset) . unwrap ( ) ;
328286 let jentry = JEntry :: decode_jentry ( encoded) ;
@@ -348,6 +306,172 @@ pub fn get_by_name(value: &[u8], name: &str, ignore_case: bool) -> Option<Vec<u8
348306 }
349307}
350308
309+ /// Extracts JSON sub-object at the specified path,
310+ /// where path elements can be either field keys or array indexes encoded in utf-8 string.
311+ pub fn get_by_keypath < ' a , I : Iterator < Item = & ' a [ u8 ] > > (
312+ value : & [ u8 ] ,
313+ keypath : I ,
314+ ) -> Option < Vec < u8 > > {
315+ if !is_jsonb ( value) {
316+ return match parse_value ( value) {
317+ Ok ( val) => {
318+ let mut current_val = & val;
319+ for key in keypath {
320+ match from_utf8 ( key) {
321+ Ok ( k) => {
322+ let res = match current_val {
323+ Value :: Array ( arr) => match k. parse :: < usize > ( ) {
324+ Ok ( idx) => arr. get ( idx) ,
325+ Err ( _) => None ,
326+ } ,
327+ Value :: Object ( obj) => obj. get ( k) ,
328+ _ => None ,
329+ } ;
330+ match res {
331+ Some ( v) => current_val = v,
332+ None => return None ,
333+ } ;
334+ }
335+ Err ( _) => return None ,
336+ }
337+ }
338+ Some ( current_val. to_vec ( ) )
339+ }
340+ Err ( _) => None ,
341+ } ;
342+ }
343+
344+ let mut curr_val_offset = 0 ;
345+ let mut curr_jentry_encoded = 0 ;
346+ let mut curr_jentry: Option < JEntry > = None ;
347+
348+ for key in keypath {
349+ match from_utf8 ( key) {
350+ Ok ( k) => {
351+ if let Some ( ref jentry) = curr_jentry {
352+ if jentry. type_code != CONTAINER_TAG {
353+ return None ;
354+ }
355+ } ;
356+ let header = read_u32 ( value, curr_val_offset) . unwrap ( ) ;
357+ match header & CONTAINER_HEADER_TYPE_MASK {
358+ OBJECT_CONTAINER_TAG => {
359+ match get_offsets_by_name ( value, curr_val_offset, header, k, false ) {
360+ Some ( ( jentry_offset, value_offset) ) => {
361+ curr_jentry_encoded = read_u32 ( value, jentry_offset) . unwrap ( ) ;
362+ curr_jentry = Some ( JEntry :: decode_jentry ( curr_jentry_encoded) ) ;
363+ curr_val_offset = value_offset;
364+ }
365+ None => return None ,
366+ } ;
367+ }
368+ ARRAY_CONTAINER_TAG => match k. parse :: < usize > ( ) {
369+ Ok ( idx) => {
370+ match get_offsets_by_index ( value, curr_val_offset, header, idx) {
371+ Some ( ( jentry_offset, value_offset) ) => {
372+ curr_jentry_encoded = read_u32 ( value, jentry_offset) . unwrap ( ) ;
373+ curr_jentry = Some ( JEntry :: decode_jentry ( curr_jentry_encoded) ) ;
374+ curr_val_offset = value_offset;
375+ }
376+ None => return None ,
377+ }
378+ }
379+ Err ( _) => return None ,
380+ } ,
381+ _ => return None ,
382+ }
383+ }
384+ Err ( _) => return None ,
385+ }
386+ }
387+ curr_jentry. map ( |jentry| {
388+ let val_length = jentry. length as usize ;
389+ match jentry. type_code {
390+ CONTAINER_TAG => value[ curr_val_offset..curr_val_offset + val_length] . to_vec ( ) ,
391+ _ => {
392+ let mut buf: Vec < u8 > = Vec :: with_capacity ( val_length + 8 ) ;
393+ let scalar_header = SCALAR_CONTAINER_TAG ;
394+ buf. extend_from_slice ( & scalar_header. to_be_bytes ( ) ) ;
395+ buf. extend_from_slice ( & curr_jentry_encoded. to_be_bytes ( ) ) ;
396+ if val_length > 0 {
397+ buf. extend_from_slice ( & value[ curr_val_offset..curr_val_offset + val_length] ) ;
398+ }
399+ buf
400+ }
401+ }
402+ } )
403+ }
404+
405+ fn get_offsets_by_name (
406+ value : & [ u8 ] ,
407+ offset : usize ,
408+ header : u32 ,
409+ name : & str ,
410+ ignore_case : bool ,
411+ ) -> Option < ( usize , usize ) > {
412+ let length = ( header & CONTAINER_HEADER_LEN_MASK ) as usize ;
413+ let mut jentry_offset = offset + 4 ;
414+ let mut val_offset = offset + 8 * length + 4 ;
415+
416+ let mut key_jentries: VecDeque < JEntry > = VecDeque :: with_capacity ( length) ;
417+ for _ in 0 ..length {
418+ let encoded = read_u32 ( value, jentry_offset) . unwrap ( ) ;
419+ let key_jentry = JEntry :: decode_jentry ( encoded) ;
420+
421+ jentry_offset += 4 ;
422+ val_offset += key_jentry. length as usize ;
423+ key_jentries. push_back ( key_jentry) ;
424+ }
425+
426+ let mut offsets = None ;
427+ let mut key_offset = offset + 8 * length + 4 ;
428+ while let Some ( key_jentry) = key_jentries. pop_front ( ) {
429+ let prev_key_offset = key_offset;
430+ key_offset += key_jentry. length as usize ;
431+ let key = unsafe { std:: str:: from_utf8_unchecked ( & value[ prev_key_offset..key_offset] ) } ;
432+ // first match the value with the same name, if not found,
433+ // then match the value with the ignoring case name.
434+ if name. eq ( key) {
435+ offsets = Some ( ( jentry_offset, val_offset) ) ;
436+ break ;
437+ } else if ignore_case && name. eq_ignore_ascii_case ( key) && offsets. is_none ( ) {
438+ offsets = Some ( ( jentry_offset, val_offset) ) ;
439+ }
440+ let val_encoded = read_u32 ( value, jentry_offset) . unwrap ( ) ;
441+ let val_jentry = JEntry :: decode_jentry ( val_encoded) ;
442+ jentry_offset += 4 ;
443+ val_offset += val_jentry. length as usize ;
444+ }
445+ offsets
446+ }
447+
448+ fn get_offsets_by_index (
449+ value : & [ u8 ] ,
450+ offset : usize ,
451+ header : u32 ,
452+ index : usize ,
453+ ) -> Option < ( usize , usize ) > {
454+ let length = ( header & CONTAINER_HEADER_LEN_MASK ) as usize ;
455+ if index >= length {
456+ return None ;
457+ }
458+ let mut jentry_offset = offset + 4 ;
459+ let mut val_offset = offset + 4 * length + 4 ;
460+
461+ for i in 0 ..length {
462+ let encoded = read_u32 ( value, jentry_offset) . unwrap ( ) ;
463+ let jentry = JEntry :: decode_jentry ( encoded) ;
464+ let val_length = jentry. length as usize ;
465+ if i < index {
466+ jentry_offset += 4 ;
467+ val_offset += val_length;
468+ continue ;
469+ }
470+ return Some ( ( jentry_offset, val_offset) ) ;
471+ }
472+ None
473+ }
474+
351475/// Get the keys of a `JSONB` object.
352476pub fn object_keys ( value : & [ u8 ] ) -> Option < Vec < u8 > > {
353477 if !is_jsonb ( value) {
0 commit comments