@@ -262,8 +262,70 @@ pyarray_typestrdescr_to_type(ts::String, descr::Py) = begin
262262 return Utils. StaticString{UInt32,sz}
263263 elseif etc == ' O'
264264 return UnsafePyObject
265+ elseif etc == ' V'
266+ pyisnull (descr) && error (" not supported: void dtype with null descr" )
267+ sz = parse (Int, ts[3 : end ])
268+ T = pyarray_descr_to_type (descr)
269+ sizeof (T) == sz || error (" size mismatch: itemsize=$sz but sizeof(descr)=$(sizeof (T)) " )
270+ return T
271+ else
272+ error (" not supported: dtype of kind: $(repr (etc)) " )
273+ end
274+ end
275+
276+ function pyarray_descr_to_type (descr:: Py )
277+ fnames = Symbol[]
278+ foffsets = Int[]
279+ ftypes = DataType[]
280+ curoffset = 0
281+ for item in descr
282+ # get the name
283+ name = item[0 ]
284+ if pyistuple (name)
285+ name = name[0 ]
286+ end
287+ fname = Symbol (pyconvert (String, name))
288+ # get the shape
289+ if length (item) > 2
290+ shape = pyconvert (Vector{Int}, item[2 ])
291+ else
292+ shape = Int[]
293+ end
294+ # get the type
295+ descr2 = item[1 ]
296+ if pyisstr (descr2)
297+ typestr = pyconvert (String, descr2)
298+ # void entries are just padding to ignore
299+ if typestr[2 ] == ' V'
300+ curoffset += parse (Int, typestr[3 : end ]) * prod (shape)
301+ continue
302+ end
303+ ftype = pyarray_typestrdescr_to_type (typestr, PyNULL)
304+ else
305+ ftype = pyarray_descr_to_type (descr2)
306+ end
307+ # apply the shape
308+ for n in reverse (shape)
309+ ftype = NTuple{n,ftype}
310+ end
311+ # save the field
312+ push! (fnames, fname)
313+ push! (foffsets, curoffset)
314+ push! (ftypes, ftype)
315+ curoffset += sizeof (ftype)
316+ end
317+ # construct the tuple type and check its offsets and size
318+ # TODO : support non-aligned dtypes by packing them into a custom type and reinterpreting
319+ T = Tuple{ftypes... }
320+ for (i, o) in pairs (foffsets)
321+ fieldoffset (T, i) == o || error (" not supported: dtype that is not aligned: $descr " )
322+ end
323+ sizeof (T) == curoffset || error (" not supported: dtype with end padding: $descr " )
324+ # return the tuple type if the field names are f0, f1, ..., else return a named tuple
325+ if fnames == [Symbol (:f , i- 1 ) for i in 1 : length (fnames)]
326+ return T
265327 else
266- error ( " type not supported: $ts " )
328+ return NamedTuple{ Tuple (fnames), T}
267329 end
268330end
269331
@@ -380,9 +442,13 @@ function pyarray_get_R(src::PyArraySource_ArrayStruct)
380442 mod (size, 4 ) == 0 || error (" unicode size must be a multiple of 4: $size " )
381443 return Utils. StaticString{UInt32,div (size, 4 )}
382444 elseif kind == 86 # V = void (should have descr)
383- error (" dtype not supported" )
445+ hasdescr || error (" not supported: void dtype with no descr" )
446+ descr = pynew (incref (src. info. descr))
447+ T = pyarray_descr_to_type (descr)
448+ sizeof (T) == size || error (" size mismatch: itemsize=$size but sizeof(descr)=$(sizeof (T)) " )
449+ return T
384450 else
385- error (" unexpected kind ( $(Char (kind) ) )" )
451+ error (" not supported: dtype of kind: $(Char (kind)) " )
386452 end
387453 @assert false
388454end
0 commit comments