@@ -3,70 +3,6 @@ use crate::{
3
3
ToPyObject ,
4
4
} ;
5
5
6
- #[ cfg( not( min_const_generics) ) ]
7
- macro_rules! array_impls {
8
- ( $( $N: expr) ,+) => {
9
- $(
10
- impl <T > IntoPy <PyObject > for [ T ; $N]
11
- where
12
- T : ToPyObject
13
- {
14
- fn into_py( self , py: Python ) -> PyObject {
15
- self . as_ref( ) . to_object( py)
16
- }
17
- }
18
-
19
- impl <' a, T > FromPyObject <' a> for [ T ; $N]
20
- where
21
- T : Copy + Default + FromPyObject <' a>,
22
- {
23
- #[ cfg( not( feature = "nightly" ) ) ]
24
- fn extract( obj: & ' a PyAny ) -> PyResult <Self > {
25
- let mut array = [ T :: default ( ) ; $N] ;
26
- _extract_sequence_into_slice( obj, & mut array) ?;
27
- Ok ( array)
28
- }
29
-
30
- #[ cfg( feature = "nightly" ) ]
31
- default fn extract( obj: & ' a PyAny ) -> PyResult <Self > {
32
- let mut array = [ T :: default ( ) ; $N] ;
33
- _extract_sequence_into_slice( obj, & mut array) ?;
34
- Ok ( array)
35
- }
36
- }
37
-
38
- #[ cfg( feature = "nightly" ) ]
39
- impl <' source, T > FromPyObject <' source> for [ T ; $N]
40
- where
41
- for <' a> T : Default + FromPyObject <' a> + crate :: buffer:: Element ,
42
- {
43
- fn extract( obj: & ' source PyAny ) -> PyResult <Self > {
44
- let mut array = [ T :: default ( ) ; $N] ;
45
- // first try buffer protocol
46
- if unsafe { crate :: ffi:: PyObject_CheckBuffer ( obj. as_ptr( ) ) } == 1 {
47
- if let Ok ( buf) = crate :: buffer:: PyBuffer :: get( obj) {
48
- if buf. dimensions( ) == 1 && buf. copy_to_slice( obj. py( ) , & mut array) . is_ok( ) {
49
- buf. release( obj. py( ) ) ;
50
- return Ok ( array) ;
51
- }
52
- buf. release( obj. py( ) ) ;
53
- }
54
- }
55
- // fall back to sequence protocol
56
- _extract_sequence_into_slice( obj, & mut array) ?;
57
- Ok ( array)
58
- }
59
- }
60
- ) +
61
- }
62
- }
63
-
64
- #[ cfg( not( min_const_generics) ) ]
65
- array_impls ! (
66
- 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 ,
67
- 26 , 27 , 28 , 29 , 30 , 31 , 32
68
- ) ;
69
-
70
6
#[ cfg( min_const_generics) ]
71
7
impl < T , const N : usize > IntoPy < PyObject > for [ T ; N ]
72
8
where
@@ -100,20 +36,18 @@ where
100
36
{
101
37
fn extract ( obj : & ' source PyAny ) -> PyResult < Self > {
102
38
use crate :: { AsPyPointer , PyNativeType } ;
103
- let mut array = [ T :: default ( ) ; N ] ;
104
39
// first try buffer protocol
105
40
if unsafe { crate :: ffi:: PyObject_CheckBuffer ( obj. as_ptr ( ) ) } == 1 {
106
41
if let Ok ( buf) = crate :: buffer:: PyBuffer :: get ( obj) {
42
+ let mut array = [ T :: default ( ) ; N ] ;
107
43
if buf. dimensions ( ) == 1 && buf. copy_to_slice ( obj. py ( ) , & mut array) . is_ok ( ) {
108
44
buf. release ( obj. py ( ) ) ;
109
45
return Ok ( array) ;
110
46
}
111
47
buf. release ( obj. py ( ) ) ;
112
48
}
113
49
}
114
- // fall back to sequence protocol
115
- _extract_sequence_into_slice ( obj, & mut array) ?;
116
- Ok ( array)
50
+ create_array_from_obj ( obj)
117
51
}
118
52
}
119
53
@@ -123,12 +57,11 @@ where
123
57
T : FromPyObject < ' s > ,
124
58
{
125
59
let seq = <crate :: types:: PySequence as PyTryFrom >:: try_from ( obj) ?;
126
- let expected_len = seq. len ( ) ? as usize ;
127
- array_try_from_fn ( |idx| {
128
- seq. get_item ( idx as isize )
129
- . map_err ( |_| invalid_sequence_length ( expected_len, idx + 1 ) ) ?
130
- . extract :: < T > ( )
131
- } )
60
+ let seq_len = seq. len ( ) ? as usize ;
61
+ if seq_len != N {
62
+ return Err ( invalid_sequence_length ( N , seq_len) ) ;
63
+ }
64
+ array_try_from_fn ( |idx| seq. get_item ( idx as isize ) . and_then ( PyAny :: extract) )
132
65
}
133
66
134
67
// TODO use std::array::try_from_fn, if that stabilises:
@@ -174,7 +107,72 @@ where
174
107
}
175
108
}
176
109
177
- fn _extract_sequence_into_slice < ' s , T > ( obj : & ' s PyAny , slice : & mut [ T ] ) -> PyResult < ( ) >
110
+ #[ cfg( not( min_const_generics) ) ]
111
+ macro_rules! array_impls {
112
+ ( $( $N: expr) ,+) => {
113
+ $(
114
+ impl <T > IntoPy <PyObject > for [ T ; $N]
115
+ where
116
+ T : ToPyObject
117
+ {
118
+ fn into_py( self , py: Python ) -> PyObject {
119
+ self . as_ref( ) . to_object( py)
120
+ }
121
+ }
122
+
123
+ impl <' a, T > FromPyObject <' a> for [ T ; $N]
124
+ where
125
+ T : Copy + Default + FromPyObject <' a>,
126
+ {
127
+ #[ cfg( not( feature = "nightly" ) ) ]
128
+ fn extract( obj: & ' a PyAny ) -> PyResult <Self > {
129
+ let mut array = [ T :: default ( ) ; $N] ;
130
+ extract_sequence_into_slice( obj, & mut array) ?;
131
+ Ok ( array)
132
+ }
133
+
134
+ #[ cfg( feature = "nightly" ) ]
135
+ default fn extract( obj: & ' a PyAny ) -> PyResult <Self > {
136
+ let mut array = [ T :: default ( ) ; $N] ;
137
+ extract_sequence_into_slice( obj, & mut array) ?;
138
+ Ok ( array)
139
+ }
140
+ }
141
+
142
+ #[ cfg( feature = "nightly" ) ]
143
+ impl <' source, T > FromPyObject <' source> for [ T ; $N]
144
+ where
145
+ for <' a> T : Default + FromPyObject <' a> + crate :: buffer:: Element ,
146
+ {
147
+ fn extract( obj: & ' source PyAny ) -> PyResult <Self > {
148
+ let mut array = [ T :: default ( ) ; $N] ;
149
+ // first try buffer protocol
150
+ if unsafe { crate :: ffi:: PyObject_CheckBuffer ( obj. as_ptr( ) ) } == 1 {
151
+ if let Ok ( buf) = crate :: buffer:: PyBuffer :: get( obj) {
152
+ if buf. dimensions( ) == 1 && buf. copy_to_slice( obj. py( ) , & mut array) . is_ok( ) {
153
+ buf. release( obj. py( ) ) ;
154
+ return Ok ( array) ;
155
+ }
156
+ buf. release( obj. py( ) ) ;
157
+ }
158
+ }
159
+ // fall back to sequence protocol
160
+ extract_sequence_into_slice( obj, & mut array) ?;
161
+ Ok ( array)
162
+ }
163
+ }
164
+ ) +
165
+ }
166
+ }
167
+
168
+ #[ cfg( not( min_const_generics) ) ]
169
+ array_impls ! (
170
+ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 ,
171
+ 26 , 27 , 28 , 29 , 30 , 31 , 32
172
+ ) ;
173
+
174
+ #[ cfg( not( min_const_generics) ) ]
175
+ fn extract_sequence_into_slice < ' s , T > ( obj : & ' s PyAny , slice : & mut [ T ] ) -> PyResult < ( ) >
178
176
where
179
177
T : FromPyObject < ' s > ,
180
178
{
@@ -189,7 +187,7 @@ where
189
187
Ok ( ( ) )
190
188
}
191
189
192
- pub fn invalid_sequence_length ( expected : usize , actual : usize ) -> PyErr {
190
+ fn invalid_sequence_length ( expected : usize , actual : usize ) -> PyErr {
193
191
exceptions:: PyValueError :: new_err ( format ! (
194
192
"expected a sequence of length {} (got {})" ,
195
193
expected, actual
@@ -198,7 +196,7 @@ pub fn invalid_sequence_length(expected: usize, actual: usize) -> PyErr {
198
196
199
197
#[ cfg( test) ]
200
198
mod test {
201
- use crate :: Python ;
199
+ use crate :: { PyResult , Python } ;
202
200
#[ cfg( min_const_generics) ]
203
201
use std:: {
204
202
panic,
@@ -238,6 +236,20 @@ mod test {
238
236
assert ! ( & v == b"abc" ) ;
239
237
}
240
238
239
+ #[ test]
240
+ fn test_extract_invalid_sequence_length ( ) {
241
+ let gil = Python :: acquire_gil ( ) ;
242
+ let py = gil. python ( ) ;
243
+ let v: PyResult < [ u8 ; 3 ] > = py
244
+ . eval ( "bytearray(b'abcdefg')" , None , None )
245
+ . unwrap ( )
246
+ . extract ( ) ;
247
+ assert_eq ! (
248
+ v. unwrap_err( ) . to_string( ) ,
249
+ "ValueError: expected a sequence of length 3 (got 7)"
250
+ ) ;
251
+ }
252
+
241
253
#[ cfg( min_const_generics) ]
242
254
#[ test]
243
255
fn test_extract_bytearray_to_array ( ) {
0 commit comments