11use pyo3:: types:: { PyList , PyModule , PyTuple } ;
22use pyo3:: { intern, prelude:: * } ;
33
4+ fn getattr < ' py > (
5+ obj : & Bound < ' py , PyAny > ,
6+ attr_name : & Bound < ' py , PyAny > ,
7+ ) -> Option < Bound < ' py , PyAny > > {
8+ let py = obj. py ( ) ;
9+
10+ let mut resp_ptr: * mut pyo3:: ffi:: PyObject = std:: ptr:: null_mut ( ) ;
11+ let attr_ptr = unsafe {
12+ pyo3:: ffi:: PyObject_GetOptionalAttr ( obj. as_ptr ( ) , attr_name. as_ptr ( ) , & mut resp_ptr)
13+ } ;
14+
15+ if attr_ptr == 1 {
16+ Some ( unsafe { Bound :: from_owned_ptr ( py, resp_ptr) } )
17+ } else {
18+ None
19+ }
20+ }
21+
422fn walk_node < ' py > (
523 node : Bound < ' py , PyAny > ,
624 field_names : Bound < ' py , PyTuple > ,
@@ -10,18 +28,18 @@ fn walk_node<'py>(
1028
1129 // Recursively walk through child nodes
1230 for field in field_names {
13- if let Ok ( Some ( child) ) = node . getattr_opt ( unsafe { field. cast_unchecked ( ) } ) {
31+ if let Some ( child) = getattr ( & node , & field) {
1432 if child. is_exact_instance_of :: < PyList > ( ) {
1533 for item in unsafe { child. cast_unchecked :: < PyList > ( ) } {
16- if let Ok ( Some ( subfields) ) = item . getattr_opt ( intern ! ( item. py( ) , "_fields" ) ) {
34+ if let Some ( subfields) = getattr ( & item , intern ! ( item. py( ) , "_fields" ) ) {
1735 walk_node (
1836 item,
1937 unsafe { subfields. cast_into_unchecked :: < PyTuple > ( ) } ,
2038 result_list,
2139 ) ?;
2240 }
2341 }
24- } else if let Ok ( Some ( subfields) ) = child . getattr_opt ( intern ! ( child. py( ) , "_fields" ) ) {
42+ } else if let Some ( subfields) = getattr ( & child , intern ! ( child. py( ) , "_fields" ) ) {
2543 walk_node (
2644 child,
2745 unsafe { subfields. cast_into_unchecked :: < PyTuple > ( ) } ,
0 commit comments