Skip to content

Commit

Permalink
[RFC] standardize PyBytes <-> Vec<u8> or &[u8] or Cow<[u8]>
Browse files Browse the repository at this point in the history
  • Loading branch information
diliop committed May 13, 2024
1 parent 10152a7 commit 59119db
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 9 deletions.
11 changes: 11 additions & 0 deletions src/conversion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
Expand Down Expand Up @@ -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.
Expand Down
35 changes: 34 additions & 1 deletion src/conversions/std/num.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -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<PyObject> 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<Self> {
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);
Expand Down
12 changes: 9 additions & 3 deletions src/conversions/std/slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,19 @@ impl<'a> crate::conversion::FromPyObjectBound<'a, '_> for Cow<'a, [u8]> {
}
}

impl ToPyObject for Cow<'_, [u8]> {
impl<T> ToPyObject for Cow<'_, [T]>
where
T: ToPyObject + Clone,
{
fn to_object(&self, py: Python<'_>) -> Py<PyAny> {
PyBytes::new_bound(py, self.as_ref()).into()
T::slice_to_object(self, py)
}
}

impl IntoPy<Py<PyAny>> for Cow<'_, [u8]> {
impl<T> IntoPy<Py<PyAny>> for Cow<'_, [T]>
where
T: ToPyObject + Clone,
{
fn into_py(self, py: Python<'_>) -> Py<PyAny> {
self.to_object(py)
}
Expand Down
6 changes: 2 additions & 4 deletions src/conversions/std/vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}

Expand All @@ -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)
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/types/any.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<PyList>()).unwrap());
});
}
Expand Down

0 comments on commit 59119db

Please # to comment.