You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Safely access Numpy v2 StringDType array data #505
Numpy v2 added a new variable-width string data type. This is much more performant than variable-width string arrays in Numpy v1 because those stored a Python str for every element.
It would be great to have a safe way to access this data. It looks like currently the only APIs are in the unsafe npyffi module.
Perhaps this is slightly more difficult than I expected because of the presence of the na_object, which can be any PyObject, and is not limited just to a &str.
Also in the future there might be different encodings besides UTF-8, so maybe &[u8] isn't the right type but also UTF-8 encoded bytes is all numpy supports right now, so going further is probably overkill.
How would the const generic work in practice? The size of the string could be anything, right? How would we know at compile time how large the string buffer will be?
I guess you could add e.g. a wrapper for the npy_static_string struct, which right now is just 16 opaque bytes (on 64 bit architectures) and then make the npy_static_string wrapper expose an acquire() method that returns an RAII guard wrapper abound a &str. So something like this:
// NBYTES is 16 on 64 bit architectures and 8 on 32 bit architecturespubstructNpyPackedString([u8;NBYTES])pubstructNpyStringGuard(&str)implDropforNpyStringGuard{fndrop(&mutself){unsafe{npy_ffi::NpyString_release_allocator(...)};}}implNpyPackedString{fnacquire(&mutself){NpyStringGuard{
let data:&[u8] = unsafe{self.get_utf8_data()}
str::from_utf8(data)}}}
Just a sketch, but that's probably the best way to do it and better reflects how the NpyString C API works. It's probably best to force users to explicitly acquire the allocator lock and also provide methods to acquire the allocator lock only once if you have a collection of &NpyPackedString references that share the same array descriptor.
Activity
kylebarron commentedon Aug 22, 2025
Perhaps this is slightly more difficult than I expected because of the presence of the
na_object, which can be anyPyObject, and is not limited just to a&str.ngoldbaum commentedon Aug 22, 2025
I think we'd need a struct like this:
T_NAwould parameterize over the Python type of thena_object.There might also need to be an RAII guard object we expose to make sure the allocator lock is always released, even if there's a panic.
EDIT: deleted incorrect const parameter
ngoldbaum commentedon Aug 22, 2025
Also in the future there might be different encodings besides UTF-8, so maybe &[u8] isn't the right type but also UTF-8 encoded bytes is all numpy supports right now, so going further is probably overkill.
kylebarron commentedon Aug 22, 2025
How would the const generic work in practice? The size of the string could be anything, right? How would we know at compile time how large the string buffer will be?
ngoldbaum commentedon Aug 22, 2025
Oh wait, you're totally right. That only makes sense for the fixed-width DTypes. Sorry...
I edited the posts above.
ngoldbaum commentedon Aug 22, 2025
Maybe actually this is better, since we know it's valid UTF-8:
I'm not sure if there are subtleties around a &str which is actually owned outside the Rust runtime. Might need another wrapper type...
ngoldbaum commentedon Aug 22, 2025
I guess you could add e.g. a wrapper for the
npy_static_stringstruct, which right now is just 16 opaque bytes (on 64 bit architectures) and then make thenpy_static_stringwrapper expose anacquire()method that returns an RAII guard wrapper abound a &str. So something like this:Just a sketch, but that's probably the best way to do it and better reflects how the NpyString C API works. It's probably best to force users to explicitly acquire the allocator lock and also provide methods to acquire the allocator lock only once if you have a collection of
&NpyPackedStringreferences that share the same array descriptor.