Merge pull request #778 from c410-f3r/array-impls
Implement `FromPyObject` and `IntoPy<PyObject>` traits for arrays (up to 32)
This commit is contained in:
commit
f470154cdf
|
@ -28,6 +28,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|||
* `#[setter]` functions may now take an argument of `Pyo3::Python`. [#760](https://github.com/PyO3/pyo3/pull/760)
|
||||
* `PyTypeInfo::BaseLayout` and `PyClass::BaseNativeType`. [#770](https://github.com/PyO3/pyo3/pull/770)
|
||||
* `PyDowncastImpl`. [#770](https://github.com/PyO3/pyo3/pull/770)
|
||||
* Implement `FromPyObject` and `IntoPy<PyObject>` traits for arrays (up to 32). [#778](https://github.com/PyO3/pyo3/pull/778)
|
||||
|
||||
### Fixed
|
||||
|
||||
|
|
|
@ -178,6 +178,26 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
macro_rules! array_impls {
|
||||
($($N:expr),+) => {
|
||||
$(
|
||||
impl<T> IntoPy<PyObject> for [T; $N]
|
||||
where
|
||||
T: ToPyObject
|
||||
{
|
||||
fn into_py(self, py: Python) -> PyObject {
|
||||
self.as_ref().to_object(py)
|
||||
}
|
||||
}
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
array_impls!(
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
|
||||
26, 27, 28, 29, 30, 31, 32
|
||||
);
|
||||
|
||||
impl<T> ToPyObject for Vec<T>
|
||||
where
|
||||
T: ToPyObject,
|
||||
|
@ -209,7 +229,7 @@ mod test {
|
|||
use crate::objectprotocol::ObjectProtocol;
|
||||
use crate::types::PyList;
|
||||
use crate::Python;
|
||||
use crate::{PyTryFrom, ToPyObject};
|
||||
use crate::{IntoPy, PyObject, PyTryFrom, ToPyObject};
|
||||
|
||||
#[test]
|
||||
fn test_new() {
|
||||
|
@ -423,4 +443,14 @@ mod test {
|
|||
assert_eq!(3, list.get_item(2).extract::<i32>().unwrap());
|
||||
assert_eq!(2, list.get_item(3).extract::<i32>().unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_array_into_py() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
let array: PyObject = [1, 2].into_py(py);
|
||||
let list = <PyList as PyTryFrom>::try_from(array.as_ref(py)).unwrap();
|
||||
assert_eq!(1, list.get_item(0).extract::<i32>().unwrap());
|
||||
assert_eq!(2, list.get_item(1).extract::<i32>().unwrap());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
use crate::buffer;
|
||||
use crate::err::{self, PyDowncastError, PyErr, PyResult};
|
||||
use crate::exceptions;
|
||||
use crate::ffi::{self, Py_ssize_t};
|
||||
use crate::instance::PyNativeType;
|
||||
use crate::internal_tricks::Unsendable;
|
||||
|
@ -241,6 +242,48 @@ impl PySequence {
|
|||
}
|
||||
}
|
||||
|
||||
macro_rules! array_impls {
|
||||
($($N:expr),+) => {
|
||||
$(
|
||||
impl<'a, T> FromPyObject<'a> for [T; $N]
|
||||
where
|
||||
T: Copy + Default + FromPyObject<'a>,
|
||||
{
|
||||
default fn extract(obj: &'a PyAny) -> PyResult<Self> {
|
||||
let mut array = [T::default(); $N];
|
||||
extract_sequence_into_slice(obj, &mut array)?;
|
||||
Ok(array)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'source, T> FromPyObject<'source> for [T; $N]
|
||||
where
|
||||
for<'a> T: Copy + Default + FromPyObject<'a> + buffer::Element,
|
||||
{
|
||||
fn extract(obj: &'source PyAny) -> PyResult<Self> {
|
||||
let mut array = [T::default(); $N];
|
||||
// first try buffer protocol
|
||||
if let Ok(buf) = buffer::PyBuffer::get(obj.py(), obj) {
|
||||
if buf.dimensions() == 1 && buf.copy_to_slice(obj.py(), &mut array).is_ok() {
|
||||
buf.release(obj.py());
|
||||
return Ok(array);
|
||||
}
|
||||
buf.release(obj.py());
|
||||
}
|
||||
// fall back to sequence protocol
|
||||
extract_sequence_into_slice(obj, &mut array)?;
|
||||
Ok(array)
|
||||
}
|
||||
}
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
array_impls!(
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
|
||||
26, 27, 28, 29, 30, 31, 32
|
||||
);
|
||||
|
||||
impl<'a, T> FromPyObject<'a> for Vec<T>
|
||||
where
|
||||
T: FromPyObject<'a>,
|
||||
|
@ -282,6 +325,22 @@ where
|
|||
Ok(v)
|
||||
}
|
||||
|
||||
fn extract_sequence_into_slice<'s, T>(obj: &'s PyAny, slice: &mut [T]) -> PyResult<()>
|
||||
where
|
||||
T: FromPyObject<'s>,
|
||||
{
|
||||
let seq = <PySequence as PyTryFrom>::try_from(obj)?;
|
||||
if seq.len()? as usize != slice.len() {
|
||||
return Err(exceptions::BufferError::py_err(
|
||||
"Slice length does not match buffer length.",
|
||||
));
|
||||
}
|
||||
for (value, item) in slice.iter_mut().zip(seq.iter()?) {
|
||||
*value = item?.extract::<T>()?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl<'v> PyTryFrom<'v> for PySequence {
|
||||
fn try_from<V: Into<&'v PyAny>>(value: V) -> Result<&'v PySequence, PyDowncastError> {
|
||||
let value = value.into();
|
||||
|
@ -617,6 +676,18 @@ mod test {
|
|||
assert!(v == [1, 2, 3, 4]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_extract_bytearray_to_array() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
let v: [u8; 3] = py
|
||||
.eval("bytearray(b'abc')", None, None)
|
||||
.unwrap()
|
||||
.extract()
|
||||
.unwrap();
|
||||
assert!(&v == b"abc");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_extract_bytearray_to_vec() {
|
||||
let gil = Python::acquire_gil();
|
||||
|
|
Loading…
Reference in New Issue