From 279d4ca2094b62d21b6b4faac2d219630f35993f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Fri, 1 Jul 2022 13:54:00 +0200 Subject: [PATCH] Declare the Python type of Rust primitives --- src/inspect/types.rs | 68 ++++++++++++++++++++++++++++++++++++++++- src/types/boolobject.rs | 9 ++++++ src/types/bytes.rs | 10 ++++++ src/types/floatob.rs | 17 +++++++++++ src/types/num.rs | 41 +++++++++++++++++++++++++ src/types/string.rs | 37 ++++++++++++++++++++++ 6 files changed, 181 insertions(+), 1 deletion(-) diff --git a/src/inspect/types.rs b/src/inspect/types.rs index 3d11bec7d3b..6dfe88477f8 100644 --- a/src/inspect/types.rs +++ b/src/inspect/types.rs @@ -272,7 +272,7 @@ impl Display for TypeInfo { mod test { use crate::inspect::types::{ModuleName, TypeInfo}; - fn assert_display(t: &TypeInfo, expected: &str) { + pub fn assert_display(t: &TypeInfo, expected: &str) { assert_eq!(format!("{}", t), expected) } @@ -394,3 +394,69 @@ mod test { ); } } + +#[cfg(test)] +mod conversion { + use crate::inspect::types::test::assert_display; + use crate::{FromPyObject, IntoPy}; + + #[test] + fn unsigned_int() { + assert_display(&usize::type_output(), "int"); + assert_display(&usize::type_input(), "int"); + + assert_display(&u8::type_output(), "int"); + assert_display(&u8::type_input(), "int"); + + assert_display(&u16::type_output(), "int"); + assert_display(&u16::type_input(), "int"); + + assert_display(&u32::type_output(), "int"); + assert_display(&u32::type_input(), "int"); + + assert_display(&u64::type_output(), "int"); + assert_display(&u64::type_input(), "int"); + } + + #[test] + fn signed_int() { + assert_display(&isize::type_output(), "int"); + assert_display(&isize::type_input(), "int"); + + assert_display(&i8::type_output(), "int"); + assert_display(&i8::type_input(), "int"); + + assert_display(&i16::type_output(), "int"); + assert_display(&i16::type_input(), "int"); + + assert_display(&i32::type_output(), "int"); + assert_display(&i32::type_input(), "int"); + + assert_display(&i64::type_output(), "int"); + assert_display(&i64::type_input(), "int"); + } + + #[test] + fn float() { + assert_display(&f32::type_output(), "float"); + assert_display(&f32::type_input(), "float"); + + assert_display(&f64::type_output(), "float"); + assert_display(&f64::type_input(), "float"); + } + + #[test] + fn bool() { + assert_display(&bool::type_output(), "bool"); + assert_display(&bool::type_input(), "bool"); + } + + #[test] + fn text() { + assert_display(&String::type_output(), "str"); + assert_display(&String::type_input(), "str"); + + assert_display(&<&[u8]>::type_output(), "bytes"); + assert_display(&<&[u8]>::type_input(), "bytes"); + } +} diff --git a/src/types/boolobject.rs b/src/types/boolobject.rs index b7126bc044c..af7de4fb958 100644 --- a/src/types/boolobject.rs +++ b/src/types/boolobject.rs @@ -1,4 +1,5 @@ // Copyright (c) 2017-present PyO3 Project and Contributors +use crate::inspect::types::TypeInfo; use crate::{ ffi, AsPyPointer, FromPyObject, IntoPy, PyAny, PyObject, PyResult, PyTryFrom, Python, ToPyObject, @@ -46,6 +47,10 @@ impl IntoPy for bool { fn into_py(self, py: Python<'_>) -> PyObject { PyBool::new(py, self).into() } + + fn type_output() -> TypeInfo { + TypeInfo::builtin("bool") + } } /// Converts a Python `bool` to a Rust `bool`. @@ -55,6 +60,10 @@ impl<'source> FromPyObject<'source> for bool { fn extract(obj: &'source PyAny) -> PyResult { Ok(::try_from(obj)?.is_true()) } + + fn type_input() -> TypeInfo { + Self::type_output() + } } #[cfg(test)] diff --git a/src/types/bytes.rs b/src/types/bytes.rs index 44bb2fd90b3..4ba195d157f 100644 --- a/src/types/bytes.rs +++ b/src/types/bytes.rs @@ -1,3 +1,4 @@ +use crate::inspect::types::TypeInfo; use crate::{ ffi, AsPyPointer, FromPyObject, IntoPy, Py, PyAny, PyObject, PyResult, PyTryFrom, Python, ToPyObject, @@ -128,13 +129,22 @@ impl<'a> IntoPy for &'a [u8] { fn into_py(self, py: Python<'_>) -> PyObject { PyBytes::new(py, self).to_object(py) } + + fn type_output() -> TypeInfo { + TypeInfo::builtin("bytes") + } } impl<'a> FromPyObject<'a> for &'a [u8] { fn extract(obj: &'a PyAny) -> PyResult { Ok(::try_from(obj)?.as_bytes()) } + + fn type_input() -> TypeInfo { + Self::type_output() + } } + #[cfg(test)] mod tests { use super::PyBytes; diff --git a/src/types/floatob.rs b/src/types/floatob.rs index 3079c61bbb8..31511d909a4 100644 --- a/src/types/floatob.rs +++ b/src/types/floatob.rs @@ -1,6 +1,7 @@ // Copyright (c) 2017-present PyO3 Project and Contributors // // based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython +use crate::inspect::types::TypeInfo; use crate::{ ffi, AsPyPointer, FromPyObject, IntoPy, PyAny, PyErr, PyObject, PyResult, Python, ToPyObject, }; @@ -44,6 +45,10 @@ impl IntoPy for f64 { fn into_py(self, py: Python<'_>) -> PyObject { PyFloat::new(py, self).into() } + + fn type_output() -> TypeInfo { + TypeInfo::builtin("float") + } } impl<'source> FromPyObject<'source> for f64 { @@ -60,6 +65,10 @@ impl<'source> FromPyObject<'source> for f64 { Ok(v) } + + fn type_input() -> TypeInfo { + Self::type_output() + } } impl ToPyObject for f32 { @@ -72,12 +81,20 @@ impl IntoPy for f32 { fn into_py(self, py: Python<'_>) -> PyObject { PyFloat::new(py, f64::from(self)).into() } + + fn type_output() -> TypeInfo { + TypeInfo::builtin("float") + } } impl<'source> FromPyObject<'source> for f32 { fn extract(obj: &'source PyAny) -> PyResult { Ok(obj.extract::()? as f32) } + + fn type_input() -> TypeInfo { + Self::type_output() + } } #[cfg(test)] diff --git a/src/types/num.rs b/src/types/num.rs index 75af9a19193..e28b795b263 100644 --- a/src/types/num.rs +++ b/src/types/num.rs @@ -2,6 +2,7 @@ // // based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython +use crate::inspect::types::TypeInfo; use crate::{ exceptions, ffi, AsPyPointer, FromPyObject, IntoPy, PyAny, PyErr, PyObject, PyResult, Python, ToPyObject, @@ -22,6 +23,10 @@ macro_rules! int_fits_larger_int { fn into_py(self, py: Python<'_>) -> PyObject { (self as $larger_type).into_py(py) } + + fn type_output() -> TypeInfo { + <$larger_type>::type_output() + } } impl<'source> FromPyObject<'source> for $rust_type { @@ -30,6 +35,10 @@ macro_rules! int_fits_larger_int { <$rust_type>::try_from(val) .map_err(|e| exceptions::PyOverflowError::new_err(e.to_string())) } + + fn type_input() -> TypeInfo { + <$larger_type>::type_input() + } } }; } @@ -56,6 +65,10 @@ macro_rules! int_fits_c_long { fn into_py(self, py: Python<'_>) -> PyObject { unsafe { PyObject::from_owned_ptr(py, ffi::PyLong_FromLong(self as c_long)) } } + + fn type_output() -> TypeInfo { + TypeInfo::builtin("int") + } } impl<'source> FromPyObject<'source> for $rust_type { @@ -74,6 +87,10 @@ macro_rules! int_fits_c_long { <$rust_type>::try_from(val) .map_err(|e| exceptions::PyOverflowError::new_err(e.to_string())) } + + fn type_input() -> TypeInfo { + Self::type_output() + } } }; } @@ -91,6 +108,10 @@ macro_rules! int_convert_u64_or_i64 { fn into_py(self, py: Python<'_>) -> PyObject { unsafe { PyObject::from_owned_ptr(py, $pylong_from_ll_or_ull(self)) } } + + fn type_output() -> TypeInfo { + TypeInfo::builtin("int") + } } impl<'source> FromPyObject<'source> for $rust_type { fn extract(ob: &'source PyAny) -> PyResult<$rust_type> { @@ -106,6 +127,10 @@ macro_rules! int_convert_u64_or_i64 { } } } + + fn type_input() -> TypeInfo { + Self::type_output() + } } }; } @@ -170,6 +195,10 @@ mod fast_128bit_int_conversion { PyObject::from_owned_ptr(py, obj) } } + + fn type_output() -> TypeInfo { + TypeInfo::builtin("int") + } } impl<'source> FromPyObject<'source> for $rust_type { @@ -192,6 +221,10 @@ mod fast_128bit_int_conversion { Ok(<$rust_type>::from_le_bytes(buffer)) } } + + fn type_input() -> TypeInfo { + Self::type_output() + } } }; } @@ -234,6 +267,10 @@ mod slow_128bit_int_conversion { ) } } + + fn type_output() -> TypeInfo { + TypeInfo::builtin("int") + } } impl<'source> FromPyObject<'source> for $rust_type { @@ -253,6 +290,10 @@ mod slow_128bit_int_conversion { Ok((<$rust_type>::from(upper) << SHIFT) | lower) } } + + fn type_input() -> TypeInfo { + Self::type_output() + } } }; } diff --git a/src/types/string.rs b/src/types/string.rs index 1cd7a1499a6..37911232257 100644 --- a/src/types/string.rs +++ b/src/types/string.rs @@ -2,6 +2,7 @@ #[cfg(all(not(Py_LIMITED_API), target_endian = "little"))] use crate::exceptions::PyUnicodeDecodeError; +use crate::inspect::types::TypeInfo; use crate::types::PyBytes; use crate::{ ffi, AsPyPointer, FromPyObject, IntoPy, Py, PyAny, PyObject, PyResult, PyTryFrom, Python, @@ -296,6 +297,10 @@ impl<'a> IntoPy for &'a str { fn into_py(self, py: Python<'_>) -> PyObject { PyString::new(py, self).into() } + + fn type_output() -> TypeInfo { + ::type_output() + } } impl<'a> IntoPy> for &'a str { @@ -303,6 +308,10 @@ impl<'a> IntoPy> for &'a str { fn into_py(self, py: Python<'_>) -> Py { PyString::new(py, self).into() } + + fn type_output() -> TypeInfo { + ::type_output() + } } /// Converts a Rust `Cow<'_, str>` to a Python object. @@ -319,6 +328,10 @@ impl IntoPy for Cow<'_, str> { fn into_py(self, py: Python<'_>) -> PyObject { self.to_object(py) } + + fn type_output() -> TypeInfo { + ::type_output() + } } /// Converts a Rust `String` to a Python object. @@ -341,12 +354,20 @@ impl IntoPy for char { let mut bytes = [0u8; 4]; PyString::new(py, self.encode_utf8(&mut bytes)).into() } + + fn type_output() -> TypeInfo { + ::type_output() + } } impl IntoPy for String { fn into_py(self, py: Python<'_>) -> PyObject { PyString::new(py, &self).into() } + + fn type_output() -> TypeInfo { + TypeInfo::builtin("str") + } } impl<'a> IntoPy for &'a String { @@ -354,6 +375,10 @@ impl<'a> IntoPy for &'a String { fn into_py(self, py: Python<'_>) -> PyObject { PyString::new(py, self).into() } + + fn type_output() -> TypeInfo { + ::type_output() + } } /// Allows extracting strings from Python objects. @@ -362,6 +387,10 @@ impl<'source> FromPyObject<'source> for &'source str { fn extract(ob: &'source PyAny) -> PyResult { ::try_from(ob)?.to_str() } + + fn type_input() -> TypeInfo { + ::type_input() + } } /// Allows extracting strings from Python objects. @@ -372,6 +401,10 @@ impl FromPyObject<'_> for String { .to_str() .map(ToOwned::to_owned) } + + fn type_input() -> TypeInfo { + Self::type_output() + } } impl FromPyObject<'_> for char { @@ -386,6 +419,10 @@ impl FromPyObject<'_> for char { )) } } + + fn type_input() -> TypeInfo { + ::type_input() + } } #[cfg(test)]