@@ -95,13 +95,9 @@ fn postgres_array_to_py<'py, T: IntoPyObject<'py> + Clone>(
9595 array : Option < Array < T > > ,
9696) -> Option < Py < PyList > > {
9797 array. map ( |array| {
98- inner_postgres_array_to_py (
99- py,
100- array. dimensions ( ) ,
101- array. iter ( ) . cloned ( ) . collect :: < Vec < T > > ( ) ,
102- 0 ,
103- 0 ,
104- )
98+ // Collect data once instead of creating copies in recursion
99+ let data: Vec < T > = array. iter ( ) . cloned ( ) . collect ( ) ;
100+ inner_postgres_array_to_py ( py, array. dimensions ( ) , & data, 0 , 0 )
105101 } )
106102}
107103
@@ -110,44 +106,60 @@ fn postgres_array_to_py<'py, T: IntoPyObject<'py> + Clone>(
110106fn inner_postgres_array_to_py < ' py , T > (
111107 py : Python < ' py > ,
112108 dimensions : & [ Dimension ] ,
113- data : Vec < T > ,
109+ data : & [ T ] ,
114110 dimension_index : usize ,
115- mut lower_bound : usize ,
111+ data_offset : usize ,
116112) -> Py < PyList >
117113where
118114 T : IntoPyObject < ' py > + Clone ,
119115{
120- let current_dimension = dimensions. get ( dimension_index) ;
121-
122- if let Some ( current_dimension) = current_dimension {
123- let possible_next_dimension = dimensions. get ( dimension_index + 1 ) ;
124- match possible_next_dimension {
125- Some ( next_dimension) => {
126- let final_list = PyList :: empty ( py) ;
127-
128- for _ in 0 ..current_dimension. len as usize {
129- if dimensions. get ( dimension_index + 1 ) . is_some ( ) {
130- let inner_pylist = inner_postgres_array_to_py (
131- py,
132- dimensions,
133- data[ lower_bound..next_dimension. len as usize + lower_bound] . to_vec ( ) ,
134- dimension_index + 1 ,
135- 0 ,
136- ) ;
137- final_list. append ( inner_pylist) . unwrap ( ) ;
138- lower_bound += next_dimension. len as usize ;
139- }
140- }
141-
142- return final_list. unbind ( ) ;
143- }
144- None => {
145- return PyList :: new ( py, data) . unwrap ( ) . unbind ( ) ; // TODO unwrap is unsafe
146- }
116+ // Check bounds early
117+ if dimension_index >= dimensions. len ( ) || data_offset >= data. len ( ) {
118+ return PyList :: empty ( py) . unbind ( ) ;
119+ }
120+
121+ let current_dimension = & dimensions[ dimension_index] ;
122+ let current_len = current_dimension. len as usize ;
123+
124+ // If this is the last dimension, create a list with the actual data
125+ if dimension_index + 1 >= dimensions. len ( ) {
126+ let end_offset = ( data_offset + current_len) . min ( data. len ( ) ) ;
127+ let slice = & data[ data_offset..end_offset] ;
128+
129+ // Create Python list more efficiently
130+ return match PyList :: new ( py, slice. iter ( ) . cloned ( ) ) {
131+ Ok ( list) => list. unbind ( ) ,
132+ Err ( _) => PyList :: empty ( py) . unbind ( ) ,
133+ } ;
134+ }
135+
136+ // For multi-dimensional arrays, recursively create nested lists
137+ let final_list = PyList :: empty ( py) ;
138+
139+ // Calculate the size of each sub-array
140+ let sub_array_size = dimensions[ dimension_index + 1 ..]
141+ . iter ( )
142+ . map ( |d| d. len as usize )
143+ . product :: < usize > ( ) ;
144+
145+ let mut current_offset = data_offset;
146+
147+ for _ in 0 ..current_len {
148+ if current_offset >= data. len ( ) {
149+ break ;
147150 }
151+
152+ let inner_list =
153+ inner_postgres_array_to_py ( py, dimensions, data, dimension_index + 1 , current_offset) ;
154+
155+ if final_list. append ( inner_list) . is_err ( ) {
156+ break ;
157+ }
158+
159+ current_offset += sub_array_size;
148160 }
149161
150- PyList :: empty ( py ) . unbind ( )
162+ final_list . unbind ( )
151163}
152164
153165#[ allow( clippy:: too_many_lines) ]
0 commit comments