diff --git a/src/conversion.rs b/src/conversion.rs index 44dbc3c7eed..3f840524d4b 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -4,6 +4,7 @@ use crate::err::PyResult; use crate::inspect::types::TypeInfo; use crate::pyclass::boolean_struct::False; use crate::types::any::PyAnyMethods; +use crate::types::list::new_from_iter; use crate::types::PyTuple; use crate::{ffi, Borrowed, Bound, Py, PyAny, PyClass, PyObject, PyRef, PyRefMut, Python}; #[cfg(feature = "gil-refs")] @@ -71,6 +72,16 @@ pub unsafe trait AsPyPointer { pub trait ToPyObject { /// Converts self into a Python object. fn to_object(&self, py: Python<'_>) -> PyObject; + + /// Converts slice of self into a Python object + fn slice_to_object(slice: &[Self], py: Python<'_>) -> PyObject + where + Self: Sized, + { + let mut iter = slice.iter().map(|e| e.to_object(py)); + let list = new_from_iter(py, &mut iter); + list.into() + } } /// Defines a conversion from a Rust type to a Python object. diff --git a/src/conversions/std/num.rs b/src/conversions/std/num.rs index e2072d210e0..9a65f76394a 100644 --- a/src/conversions/std/num.rs +++ b/src/conversions/std/num.rs @@ -1,6 +1,7 @@ #[cfg(feature = "experimental-inspect")] use crate::inspect::types::TypeInfo; use crate::types::any::PyAnyMethods; +use crate::types::PyBytes; use crate::{ exceptions, ffi, Bound, FromPyObject, IntoPy, PyAny, PyErr, PyObject, PyResult, Python, ToPyObject, @@ -142,11 +143,43 @@ macro_rules! int_fits_c_long { } int_fits_c_long!(i8); -int_fits_c_long!(u8); int_fits_c_long!(i16); int_fits_c_long!(u16); int_fits_c_long!(i32); +impl ToPyObject for u8 { + fn to_object(&self, py: Python<'_>) -> PyObject { + unsafe { PyObject::from_owned_ptr(py, ffi::PyLong_FromLong(*self as c_long)) } + } + + fn slice_to_object(bytes: &[Self], py: Python<'_>) -> PyObject { + PyBytes::new_bound(py, bytes).into() + } +} + +impl IntoPy for u8 { + fn into_py(self, py: Python<'_>) -> PyObject { + unsafe { PyObject::from_owned_ptr(py, ffi::PyLong_FromLong(self as c_long)) } + } + + #[cfg(feature = "experimental-inspect")] + fn type_output() -> TypeInfo { + TypeInfo::builtin("int") + } +} + +impl<'py> FromPyObject<'py> for u8 { + fn extract_bound(obj: &Bound<'_, PyAny>) -> PyResult { + let val: c_long = extract_int!(obj, -1, ffi::PyLong_AsLong)?; + u8::try_from(val).map_err(|e| exceptions::PyOverflowError::new_err(e.to_string())) + } + + #[cfg(feature = "experimental-inspect")] + fn type_input() -> TypeInfo { + Self::type_output() + } +} + // If c_long is 64-bits, we can use more types with int_fits_c_long!: #[cfg(all(target_pointer_width = "64", not(target_os = "windows")))] int_fits_c_long!(u32); diff --git a/src/conversions/std/slice.rs b/src/conversions/std/slice.rs index 9c9cde06fc7..fc8f72eb9f0 100644 --- a/src/conversions/std/slice.rs +++ b/src/conversions/std/slice.rs @@ -77,13 +77,19 @@ impl<'a> crate::conversion::FromPyObjectBound<'a, '_> for Cow<'a, [u8]> { } } -impl ToPyObject for Cow<'_, [u8]> { +impl ToPyObject for Cow<'_, [T]> +where + T: ToPyObject + Clone, +{ fn to_object(&self, py: Python<'_>) -> Py { - PyBytes::new_bound(py, self.as_ref()).into() + T::slice_to_object(self, py) } } -impl IntoPy> for Cow<'_, [u8]> { +impl IntoPy> for Cow<'_, [T]> +where + T: ToPyObject + Clone, +{ fn into_py(self, py: Python<'_>) -> Py { self.to_object(py) } diff --git a/src/conversions/std/vec.rs b/src/conversions/std/vec.rs index df9e4c4f819..4e50698ea7f 100644 --- a/src/conversions/std/vec.rs +++ b/src/conversions/std/vec.rs @@ -8,9 +8,7 @@ where T: ToPyObject, { fn to_object(&self, py: Python<'_>) -> PyObject { - let mut iter = self.iter().map(|e| e.to_object(py)); - let list = new_from_iter(py, &mut iter); - list.into() + T::slice_to_object(self, py) } } @@ -19,7 +17,7 @@ where T: ToPyObject, { fn to_object(&self, py: Python<'_>) -> PyObject { - self.as_slice().to_object(py) + T::slice_to_object(self, py) } } diff --git a/src/types/any.rs b/src/types/any.rs index ba5ea01b1a3..d192c3a5a21 100644 --- a/src/types/any.rs +++ b/src/types/any.rs @@ -2542,7 +2542,7 @@ class SimpleClass: #[test] fn test_any_is_instance() { Python::with_gil(|py| { - let l = vec![1u8, 2].to_object(py).into_bound(py); + let l = vec![1u16, 2].to_object(py).into_bound(py); assert!(l.is_instance(&py.get_type_bound::()).unwrap()); }); }