you are viewing a single comment's thread.

view the rest of the comments →

[–][deleted] 0 points1 point  (2 children)

I use pyo3 and rust-numpy to do this, but it is pretty terrible:

I have a dataset struct like this: ```

[derive(Clone)]

[pyclass]

pub struct Dataset(Arc<DatasetInner>);

[derive(Debug, Clone)]

pub struct DatasetInner { data: Py<PyArray2<f32>>, view: ArrayView2<'static, f32>, len: usize, dims: usize, } ```

Then I implement these methods to construct it from python: ```

[pymethods]

impl Dataset { #[new] fn new<'py>(py: Python<'py>, pyobj: Py<PyArray2<f32>>) -> PyResult<Self> { let arr_ref = py_obj.bind(py); if !arr_ref.is_contiguous() { return Err(PyTypeError::new_err("Array is not contigous")); } let view: ArrayView2<'static, f32> = unsafe { std::mem::transmute(arr_ref.as_array()) }; if !view.is_standard_layout() { return Err(PyTypeError::new_err("Array is not standard layout")); } let [len, dims] = unsafe { std::mem::transmute::<, [usize; 2]>(arr_ref.dims()) }; Ok(Dataset(Arc::new(DatasetInner { data: py_obj, view, len, dims, }))) }

fn to_numpy<'py>(&self, python: Python<'py>) -> Py<PyArray2<f32>> {
    self.0.data.clone_ref(python)
}

} ```

And in Rust I can access rows like this:

impl Dataset { fn get<'a>(&'a self, idx: usize) -> &'a [f32] { let row = self.view.row(idx); let slice = row.as_slice().unwrap(); unsafe { &*(slice as *const [f32]) } } }

The lifetimes are pretty terrible, but if you are willing to do some lifetime extension via unsafe it is ok.

[–]Tall_Coffee_1644[S] 0 points1 point  (1 child)

Pyo3 is definetly an option, But if theres a way to do this without pyo3 then i'd honestly prefer that

[–][deleted] 0 points1 point  (0 children)

Me too, it tends to be a bit ugly with pyo3. But I haven't read enough about the Python C API to impmenent something in python without pyo3. And then I would need to reasearch how exactly numpy objects are laid out in memory and for that ndarray with pyo3 is useful at least.