@@ -11,7 +11,7 @@ use jiter::{JsonObject, JsonValue};
1111use  crate :: build_tools:: py_schema_err; 
1212use  crate :: errors:: { py_err_string,  ErrorType ,  LocItem ,  Location ,  ToErrorValue ,  ValError ,  ValLineError ,  ValResult } ; 
1313use  crate :: input:: StringMapping ; 
14- use  crate :: tools:: { extract_i64,  py_err} ; 
14+ use  crate :: tools:: { extract_i64,  mapping_get ,   py_err} ; 
1515
1616/// Used for getting items from python dicts, python objects, or JSON objects, in different ways 
1717#[ derive( Debug ) ]  
@@ -89,44 +89,12 @@ impl LookupKey {
8989    pub  fn  py_get_dict_item < ' py ,  ' s > ( 
9090        & ' s  self , 
9191        dict :  & Bound < ' py ,  PyDict > , 
92-     )  -> ValResult < Option < ( & ' s  LookupPath ,  Bound < ' py ,  PyAny > ) > >  { 
93-         match  self  { 
94-             Self :: Simple ( path)  => match  dict. get_item ( & path. first_item . py_key ) ? { 
95-                 Some ( value)  => { 
96-                     debug_assert ! ( path. rest. is_empty( ) ) ; 
97-                     Ok ( Some ( ( path,  value) ) ) 
98-                 } 
99-                 None  => Ok ( None ) , 
100-             } , 
101-             Self :: Choice  {  path1,  path2,  .. }  => match  dict. get_item ( & path1. first_item . py_key ) ? { 
102-                 Some ( value)  => { 
103-                     debug_assert ! ( path1. rest. is_empty( ) ) ; 
104-                     Ok ( Some ( ( path1,  value) ) ) 
105-                 } 
106-                 None  => match  dict. get_item ( & path2. first_item . py_key ) ? { 
107-                     Some ( value)  => { 
108-                         debug_assert ! ( path2. rest. is_empty( ) ) ; 
109-                         Ok ( Some ( ( path2,  value) ) ) 
110-                     } 
111-                     None  => Ok ( None ) , 
112-                 } , 
113-             } , 
114-             Self :: PathChoices ( path_choices)  => { 
115-                 for  path in  path_choices { 
116-                     let  Some ( first_value)  = dict. get_item ( & path. first_item . py_key ) ? else  { 
117-                         continue ; 
118-                     } ; 
119-                     // iterate over the path and plug each value into the py_any from the last step, 
120-                     // this could just be a loop but should be somewhat faster with a functional design 
121-                     if  let  Some ( v)  = path. rest . iter ( ) . try_fold ( first_value,  |d,  loc| loc. py_get_item ( & d) )  { 
122-                         // Successfully found an item, return it 
123-                         return  Ok ( Some ( ( path,  v) ) ) ; 
124-                     } 
125-                 } 
126-                 // got to the end of path_choices, without a match, return None 
127-                 Ok ( None ) 
128-             } 
129-         } 
92+     )  -> PyResult < Option < ( & ' s  LookupPath ,  Bound < ' py ,  PyAny > ) > >  { 
93+         self . get_impl ( 
94+             dict, 
95+             |dict,  path| dict. get_item ( & path. py_key ) , 
96+             |d,  loc| Ok ( loc. py_get_item ( & d) ) , 
97+         ) 
13098    } 
13199
132100    pub  fn  py_get_string_mapping_item < ' py ,  ' s > ( 
@@ -144,94 +112,23 @@ impl LookupKey {
144112    pub  fn  py_get_mapping_item < ' py ,  ' s > ( 
145113        & ' s  self , 
146114        dict :  & Bound < ' py ,  PyMapping > , 
147-     )  -> ValResult < Option < ( & ' s  LookupPath ,  Bound < ' py ,  PyAny > ) > >  { 
148-         match  self  { 
149-             Self :: Simple ( path)  => match  dict. get_item ( & path. first_item . py_key )  { 
150-                 Ok ( value)  => { 
151-                     debug_assert ! ( path. rest. is_empty( ) ) ; 
152-                     Ok ( Some ( ( path,  value) ) ) 
153-                 } 
154-                 _ => Ok ( None ) , 
155-             } , 
156-             Self :: Choice  {  path1,  path2,  .. }  => match  dict. get_item ( & path1. first_item . py_key )  { 
157-                 Ok ( value)  => { 
158-                     debug_assert ! ( path1. rest. is_empty( ) ) ; 
159-                     Ok ( Some ( ( path1,  value) ) ) 
160-                 } 
161-                 _ => match  dict. get_item ( & path2. first_item . py_key )  { 
162-                     Ok ( value)  => { 
163-                         debug_assert ! ( path2. rest. is_empty( ) ) ; 
164-                         Ok ( Some ( ( path2,  value) ) ) 
165-                     } 
166-                     _ => Ok ( None ) , 
167-                 } , 
168-             } , 
169-             Self :: PathChoices ( path_choices)  => { 
170-                 for  path in  path_choices { 
171-                     let  Some ( first_value)  = dict. get_item ( & path. first_item . py_key ) . ok ( )  else  { 
172-                         continue ; 
173-                     } ; 
174-                     // iterate over the path and plug each value into the py_any from the last step, 
175-                     // this could just be a loop but should be somewhat faster with a functional design 
176-                     if  let  Some ( v)  = path. rest . iter ( ) . try_fold ( first_value,  |d,  loc| loc. py_get_item ( & d) )  { 
177-                         // Successfully found an item, return it 
178-                         return  Ok ( Some ( ( path,  v) ) ) ; 
179-                     } 
180-                 } 
181-                 // got to the end of path_choices, without a match, return None 
182-                 Ok ( None ) 
183-             } 
184-         } 
115+     )  -> PyResult < Option < ( & ' s  LookupPath ,  Bound < ' py ,  PyAny > ) > >  { 
116+         self . get_impl ( 
117+             dict, 
118+             |dict,  path| mapping_get ( dict,  & path. py_key ) , 
119+             |d,  loc| Ok ( loc. py_get_item ( & d) ) , 
120+         ) 
185121    } 
186122
187123    pub  fn  simple_py_get_attr < ' py ,  ' s > ( 
188124        & ' s  self , 
189125        obj :  & Bound < ' py ,  PyAny > , 
190126    )  -> PyResult < Option < ( & ' s  LookupPath ,  Bound < ' py ,  PyAny > ) > >  { 
191-         match  self  { 
192-             Self :: Simple ( path)  => match  py_get_attrs ( obj,  & path. first_item . py_key ) ? { 
193-                 Some ( value)  => { 
194-                     debug_assert ! ( path. rest. is_empty( ) ) ; 
195-                     Ok ( Some ( ( path,  value) ) ) 
196-                 } 
197-                 None  => Ok ( None ) , 
198-             } , 
199-             Self :: Choice  {  path1,  path2,  .. }  => match  py_get_attrs ( obj,  & path1. first_item . py_key ) ? { 
200-                 Some ( value)  => { 
201-                     debug_assert ! ( path1. rest. is_empty( ) ) ; 
202-                     Ok ( Some ( ( path1,  value) ) ) 
203-                 } 
204-                 None  => match  py_get_attrs ( obj,  & path2. first_item . py_key ) ? { 
205-                     Some ( value)  => { 
206-                         debug_assert ! ( path2. rest. is_empty( ) ) ; 
207-                         Ok ( Some ( ( path2,  value) ) ) 
208-                     } 
209-                     None  => Ok ( None ) , 
210-                 } , 
211-             } , 
212-             Self :: PathChoices ( path_choices)  => { 
213-                 ' outer:  for  path in  path_choices { 
214-                     // similar to above, but using `py_get_attrs`, we can't use try_fold because of the extra Err 
215-                     // so we have to loop manually 
216-                     let  Some ( mut  v)  = path. first_item . py_get_attrs ( obj) ? else  { 
217-                         continue ; 
218-                     } ; 
219-                     for  loc in  & path. rest  { 
220-                         v = match  loc. py_get_attrs ( & v)  { 
221-                             Ok ( Some ( v) )  => v, 
222-                             Ok ( None )  => { 
223-                                 continue  ' outer; 
224-                             } 
225-                             Err ( e)  => return  Err ( e) , 
226-                         } 
227-                     } 
228-                     // Successfully found an item, return it 
229-                     return  Ok ( Some ( ( path,  v) ) ) ; 
230-                 } 
231-                 // got to the end of path_choices, without a match, return None 
232-                 Ok ( None ) 
233-             } 
234-         } 
127+         self . get_impl ( 
128+             obj, 
129+             |obj,  path| py_get_attrs ( obj,  & path. py_key ) , 
130+             |d,  loc| loc. py_get_attrs ( & d) , 
131+         ) 
235132    } 
236133
237134    pub  fn  py_get_attr < ' py ,  ' s > ( 
@@ -324,6 +221,57 @@ impl LookupKey {
324221        } 
325222    } 
326223
224+     fn  get_impl < ' s ,  ' a ,  SourceT ,  OutputT :  ' a > ( 
225+         & ' s  self , 
226+         source :  & ' a  SourceT , 
227+         lookup :  impl  Fn ( & ' a  SourceT ,  & ' s  PathItemString )  -> PyResult < Option < OutputT > > , 
228+         nested_lookup :  impl  Fn ( OutputT ,  & ' s  PathItem )  -> PyResult < Option < OutputT > > , 
229+     )  -> PyResult < Option < ( & ' s  LookupPath ,  OutputT ) > >  { 
230+         match  self  { 
231+             Self :: Simple ( path)  => match  lookup ( source,  & path. first_item ) ? { 
232+                 Some ( value)  => { 
233+                     debug_assert ! ( path. rest. is_empty( ) ) ; 
234+                     Ok ( Some ( ( path,  value) ) ) 
235+                 } 
236+                 None  => Ok ( None ) , 
237+             } , 
238+             Self :: Choice  {  path1,  path2,  .. }  => match  lookup ( source,  & path1. first_item ) ? { 
239+                 Some ( value)  => { 
240+                     debug_assert ! ( path1. rest. is_empty( ) ) ; 
241+                     Ok ( Some ( ( path1,  value) ) ) 
242+                 } 
243+                 None  => match  lookup ( source,  & path2. first_item ) ? { 
244+                     Some ( value)  => { 
245+                         debug_assert ! ( path2. rest. is_empty( ) ) ; 
246+                         Ok ( Some ( ( path2,  value) ) ) 
247+                     } 
248+                     None  => Ok ( None ) , 
249+                 } , 
250+             } , 
251+             Self :: PathChoices ( path_choices)  => { 
252+                 ' choices:  for  path in  path_choices { 
253+                     let  Some ( mut  value)  = lookup ( source,  & path. first_item ) ? else  { 
254+                         continue ; 
255+                     } ; 
256+ 
257+                     // iterate over the path and plug each value into the value from the last step 
258+                     for  loc in  & path. rest  { 
259+                         value = match  nested_lookup ( value,  loc)  { 
260+                             Ok ( Some ( v) )  => v, 
261+                             // this choice did not match, try the next one 
262+                             Ok ( None )  => continue  ' choices, 
263+                             Err ( e)  => return  Err ( e) , 
264+                         } 
265+                     } 
266+                     // Successfully found an item, return it 
267+                     return  Ok ( Some ( ( path,  value) ) ) ; 
268+                 } 
269+                 // got to the end of path_choices, without a match, return None 
270+                 Ok ( None ) 
271+             } 
272+         } 
273+     } 
274+ 
327275    pub  fn  error ( 
328276        & self , 
329277        error_type :  ErrorType , 
0 commit comments