@@ -95,13 +95,9 @@ fn postgres_array_to_py<'py, T: IntoPyObject<'py> + Clone>(
95
95
array : Option < Array < T > > ,
96
96
) -> Option < Py < PyList > > {
97
97
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 )
105
101
} )
106
102
}
107
103
@@ -110,44 +106,60 @@ fn postgres_array_to_py<'py, T: IntoPyObject<'py> + Clone>(
110
106
fn inner_postgres_array_to_py < ' py , T > (
111
107
py : Python < ' py > ,
112
108
dimensions : & [ Dimension ] ,
113
- data : Vec < T > ,
109
+ data : & [ T ] ,
114
110
dimension_index : usize ,
115
- mut lower_bound : usize ,
111
+ data_offset : usize ,
116
112
) -> Py < PyList >
117
113
where
118
114
T : IntoPyObject < ' py > + Clone ,
119
115
{
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 ;
147
150
}
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;
148
160
}
149
161
150
- PyList :: empty ( py ) . unbind ( )
162
+ final_list . unbind ( )
151
163
}
152
164
153
165
#[ allow( clippy:: too_many_lines) ]
0 commit comments