@@ -259,48 +259,50 @@ impl<'s> From<TextInputSequence<'s>> for tk::InputSequence<'s> {
259
259
struct PyArrayUnicode ( Vec < String > ) ;
260
260
impl FromPyObject < ' _ > for PyArrayUnicode {
261
261
fn extract ( ob : & PyAny ) -> PyResult < Self > {
262
+ // SAFETY Making sure the pointer is a valid numpy array requires calling numpy C code
262
263
if unsafe { npyffi:: PyArray_Check ( ob. py ( ) , ob. as_ptr ( ) ) } == 0 {
263
264
return Err ( exceptions:: PyTypeError :: new_err ( "Expected an np.array" ) ) ;
264
265
}
265
266
let arr = ob. as_ptr ( ) as * mut npyffi:: PyArrayObject ;
266
- if unsafe { ( * arr) . nd } != 1 {
267
- return Err ( exceptions:: PyTypeError :: new_err (
268
- "Expected a 1 dimensional np.array" ,
269
- ) ) ;
270
- }
271
- if unsafe { ( * arr) . flags }
272
- & ( npyffi:: NPY_ARRAY_C_CONTIGUOUS | npyffi:: NPY_ARRAY_F_CONTIGUOUS )
273
- == 0
274
- {
275
- return Err ( exceptions:: PyTypeError :: new_err (
276
- "Expected a contiguous np.array" ,
277
- ) ) ;
278
- }
279
- let n_elem = unsafe { * ( * arr) . dimensions } as usize ;
280
- let ( type_num, elsize, alignment, data) = unsafe {
267
+ // SAFETY Getting all the metadata about the numpy array to check its sanity
268
+ let ( type_num, elsize, alignment, data, nd, flags) = unsafe {
281
269
let desc = ( * arr) . descr ;
282
270
(
283
271
( * desc) . type_num ,
284
272
( * desc) . elsize as usize ,
285
273
( * desc) . alignment as usize ,
286
274
( * arr) . data ,
275
+ ( * arr) . nd ,
276
+ ( * arr) . flags ,
287
277
)
288
278
} ;
289
279
280
+ if nd != 1 {
281
+ return Err ( exceptions:: PyTypeError :: new_err (
282
+ "Expected a 1 dimensional np.array" ,
283
+ ) ) ;
284
+ }
285
+ if flags & ( npyffi:: NPY_ARRAY_C_CONTIGUOUS | npyffi:: NPY_ARRAY_F_CONTIGUOUS ) == 0 {
286
+ return Err ( exceptions:: PyTypeError :: new_err (
287
+ "Expected a contiguous np.array" ,
288
+ ) ) ;
289
+ }
290
290
if type_num != npyffi:: types:: NPY_TYPES :: NPY_UNICODE as i32 {
291
291
return Err ( exceptions:: PyTypeError :: new_err (
292
292
"Expected a np.array[dtype='U']" ,
293
293
) ) ;
294
294
}
295
295
296
+ // SAFETY Looking at the raw numpy data to create new owned Rust strings via copies (so it's safe afterwards).
296
297
unsafe {
298
+ let n_elem = * ( * arr) . dimensions as usize ;
297
299
let all_bytes = std:: slice:: from_raw_parts ( data as * const u8 , elsize * n_elem) ;
298
300
299
301
let seq = ( 0 ..n_elem)
300
302
. map ( |i| {
301
303
let bytes = & all_bytes[ i * elsize..( i + 1 ) * elsize] ;
302
- # [ allow ( deprecated ) ]
303
- let unicode = pyo3:: ffi:: PyUnicode_FromUnicode (
304
+ let unicode = pyo3 :: ffi :: PyUnicode_FromKindAndData (
305
+ pyo3:: ffi:: PyUnicode_4BYTE_KIND as _ ,
304
306
bytes. as_ptr ( ) as * const _ ,
305
307
elsize as isize / alignment as isize ,
306
308
) ;
0 commit comments