# PyO3-ArrayLike
This crate provides a single struct `PyArrayLike<T,D>` which can be used for extracting an array from any Python object which can be regarded as an array of type `T` and dimension `D` in a reasonable way.
## How it works
`PyArrayLike<T,D>` is basically an enum consisting of either a `PyReadonlyArray<T,D>` from the [rust-numpy](https://github.com/PyO3/rust-numpy) project (i.e. a readonly reference to an actual numpy array on the Python heap), or of an owned `Array<T,D>` from the [ndarray](https://github.com/rust-ndarray/ndarray) project. When calling `pyobject.extract::<PyArrayLike<T,D>>()` it immediately checks whether `pyobject` is already a numpy array of the right type and dimension by calling `pyobject.downcast::<PyReadonlyArray<T,D>>()` internally. Only if this fails, it will try to construct an owned array from `pyobject` by iterating over its elements and trying to convert them into the right type recursively.
## Example
Consider the following function. It takes anything which "looks like" an array of dimension two consisting of integers bewteen 0 and 4294967295. It computes the sum of the array's rows and returns a one dimensional numpy array.
```rust
#[pyfunction]
fn sum_of_rows<'py>(py: Python<'py>, ar: PyArrayLike2<'py, u32>) -> &'py PyArray1<u32> {
ar.view().sum_axis(Axis(0)).into_pyarray(py)
}
```
You can call this function from Python in the following ways. The first two functions will succeed, the latter two will raise an error.
```python
def call1():
"""Succeeds by passing a reference of the input array to the rust component."""
return sum_of_rows(np.array([[1,2,3],[4,5,6]], dtype='uint32'))
def call2():
"""Succeeds but allocates extra memory for rebuilding the input array inside the rust component."""
return sum_of_rows([[1,2,3], iter([4,5,6]), np.array([7,8,9], dtype='int64')])
def call3():
"""Raises an error since the input array is expected to be two dimensional."""
return sum_of_rows([1,2,3])
def call4():
"""Raises an error since the input array contains a value which cannot be safely casted to u32."""
return sum_of_rows([[2**32,0,0], [0,0,0]])
```