diff --git a/src/exceptions.rs b/src/exceptions.rs index 9bbb2e63..d55f74f1 100644 --- a/src/exceptions.rs +++ b/src/exceptions.rs @@ -12,8 +12,6 @@ use std::os::raw::c_char; #[macro_export] macro_rules! impl_exception_boilerplate { ($name: ident) => { - $crate::pyobject_native_type_fmt!($name); - impl std::convert::From<&$name> for $crate::PyErr { fn from(err: &$name) -> $crate::PyErr { $crate::PyErr::from_instance(err) @@ -88,22 +86,10 @@ macro_rules! import_exception { $name, $crate::ffi::PyBaseExceptionObject, *$name::type_object_raw($crate::Python::assume_gil_acquired()), - Some(stringify!($module)), - $name::check + Some(stringify!($module)) ); impl $name { - /// Check if a python object is an instance of this exception. - /// - /// # Safety - /// `ptr` must be a valid pointer to a Python object - unsafe fn check(ptr: *mut $crate::ffi::PyObject) -> $crate::libc::c_int { - $crate::ffi::PyObject_TypeCheck( - ptr, - Self::type_object_raw($crate::Python::assume_gil_acquired()) as *mut _, - ) - } - fn type_object_raw(py: $crate::Python) -> *mut $crate::ffi::PyTypeObject { use $crate::once_cell::GILOnceCell; use $crate::AsPyPointer; @@ -191,22 +177,10 @@ macro_rules! create_exception_type_object { $name, $crate::ffi::PyBaseExceptionObject, *$name::type_object_raw($crate::Python::assume_gil_acquired()), - Some(stringify!($module)), - $name::check + Some(stringify!($module)) ); impl $name { - /// Check if a python object is an instance of this exception. - /// - /// # Safety - /// `ptr` must be a valid pointer to a Python object - unsafe fn check(ptr: *mut $crate::ffi::PyObject) -> $crate::libc::c_int { - $crate::ffi::PyObject_TypeCheck( - ptr, - Self::type_object_raw($crate::Python::assume_gil_acquired()) as *mut _, - ) - } - fn type_object_raw(py: $crate::Python) -> *mut $crate::ffi::PyTypeObject { use $crate::once_cell::GILOnceCell; use $crate::AsPyPointer; @@ -240,18 +214,7 @@ macro_rules! impl_native_exception ( pub type $legacy_name = $crate::Py<$name>; $crate::impl_exception_boilerplate!($name); - - impl $name { - /// Check if a python object is an instance of this exception. - /// - /// # Safety - /// `ptr` must be a valid pointer to a Python object - unsafe fn check(ptr: *mut $crate::ffi::PyObject) -> $crate::libc::c_int { - ffi::PyObject_TypeCheck(ptr, ffi::$exc_name as *mut _) - } - } - - $crate::pyobject_native_type_core!($name, $layout, *(ffi::$exc_name as *mut ffi::PyTypeObject), Some("builtins"), $name::check); + $crate::pyobject_native_type_core!($name, $layout, *(ffi::$exc_name as *mut ffi::PyTypeObject), Some("builtins")); ); ($name:ident, $legacy_name:ident, $exc_name:ident) => ( impl_native_exception!($name, $legacy_name, $exc_name, ffi::PyBaseExceptionObject); diff --git a/src/types/any.rs b/src/types/any.rs index 5e8c2ff1..c50e7401 100644 --- a/src/types/any.rs +++ b/src/types/any.rs @@ -45,18 +45,10 @@ impl crate::AsPyPointer for PyAny { } } -impl PartialEq for PyAny { - #[inline] - fn eq(&self, o: &PyAny) -> bool { - self.as_ptr() == o.as_ptr() - } -} - -unsafe impl crate::PyNativeType for PyAny {} unsafe impl crate::type_object::PyLayout for ffi::PyObject {} impl crate::type_object::PySizedLayout for ffi::PyObject {} -pyobject_native_type_convert!( +pyobject_native_type_info!( PyAny, ffi::PyObject, ffi::PyBaseObject_Type, @@ -66,7 +58,7 @@ pyobject_native_type_convert!( pyobject_native_type_extract!(PyAny); -pyobject_native_type_fmt!(PyAny); +pyobject_native_type_base!(PyAny); impl PyAny { /// Convert this PyAny to a concrete Python type. diff --git a/src/types/iterator.rs b/src/types/iterator.rs index ea0f2dc9..e9c0a674 100644 --- a/src/types/iterator.rs +++ b/src/types/iterator.rs @@ -24,7 +24,6 @@ use crate::{PyDowncastError, PyTryFrom}; /// # Ok(()) /// # } /// ``` -#[derive(Debug)] #[repr(transparent)] pub struct PyIterator(PyAny); pyobject_native_type_named!(PyIterator); diff --git a/src/types/mod.rs b/src/types/mod.rs index fbd01e41..9c5cae92 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -27,17 +27,65 @@ pub use self::string::{PyString, PyString as PyUnicode}; pub use self::tuple::PyTuple; pub use self::typeobject::PyType; +// Implementations core to all native types +#[macro_export] +macro_rules! pyobject_native_type_base( + ($name: ty $(,generics: <$($generics:ident),+>)?) => { + unsafe impl<$($($generics),+)?> $crate::PyNativeType for $name {} + + impl<$($($generics),+)?> ::std::fmt::Debug for $name { + fn fmt(&self, f: &mut ::std::fmt::Formatter) + -> Result<(), ::std::fmt::Error> + { + let s = self.repr().map_err(|_| ::std::fmt::Error)?; + f.write_str(&s.to_string_lossy()) + } + } + + impl<$($($generics),+)?> ::std::fmt::Display for $name { + fn fmt(&self, f: &mut ::std::fmt::Formatter) + -> Result<(), ::std::fmt::Error> + { + let s = self.str().map_err(|_| ::std::fmt::Error)?; + f.write_str(&s.to_string_lossy()) + } + } + + impl<$($($generics),+)?> $crate::ToPyObject for $name + { + #[inline] + fn to_object(&self, py: $crate::Python) -> $crate::PyObject { + use $crate::AsPyPointer; + unsafe { $crate::PyObject::from_borrowed_ptr(py, self.as_ptr()) } + } + } + + impl<$($($generics),+)?> PartialEq for $name { + #[inline] + fn eq(&self, o: &$name) -> bool { + use $crate::AsPyPointer; + + self.as_ptr() == o.as_ptr() + } + } + }; +); + +// Implementations core to all native types except for PyAny (because they don't +// make sense on PyAny / have different implementations). #[macro_export] macro_rules! pyobject_native_type_named ( - ($name: ty $(,$type_param: ident)*) => { - impl<$($type_param,)*> ::std::convert::AsRef<$crate::PyAny> for $name { + ($name: ty $(,generics: <$($generics:ident),+>)?) => { + $crate::pyobject_native_type_base!($name $(,generics: <$($generics),+>)?); + + impl<$($($generics),+)?> ::std::convert::AsRef<$crate::PyAny> for $name { #[inline] fn as_ref(&self) -> &$crate::PyAny { &self.0 } } - impl<$($type_param,)*> ::std::ops::Deref for $name { + impl<$($($generics),+)?> ::std::ops::Deref for $name { type Target = $crate::PyAny; #[inline] @@ -46,9 +94,7 @@ macro_rules! pyobject_native_type_named ( } } - unsafe impl<$($type_param,)*> $crate::PyNativeType for $name {} - - impl<$($type_param,)*> $crate::AsPyPointer for $name { + impl<$($($generics),+)?> $crate::AsPyPointer for $name { /// Gets the underlying FFI pointer, returns a borrowed pointer. #[inline] fn as_ptr(&self) -> *mut $crate::ffi::PyObject { @@ -56,43 +102,15 @@ macro_rules! pyobject_native_type_named ( } } - impl<$($type_param,)*> PartialEq for $name { - #[inline] - fn eq(&self, o: &$name) -> bool { - use $crate::AsPyPointer; - - self.as_ptr() == o.as_ptr() - } - } - - impl<$($type_param,)*> $crate::IntoPy<$crate::Py<$name>> for &'_ $name { + impl<$($($generics),+)?> $crate::IntoPy<$crate::Py<$name>> for &'_ $name { #[inline] fn into_py(self, py: $crate::Python) -> $crate::Py<$name> { use $crate::AsPyPointer; unsafe { $crate::Py::from_borrowed_ptr(py, self.as_ptr()) } } } - }; -); -#[macro_export] -macro_rules! pyobject_native_type_core { - ($name: ty, $layout: path, $typeobject: expr, $module: expr, $checkfunction: path $(,$type_param: ident)*) => { - unsafe impl $crate::type_object::PyLayout<$name> for $layout {} - $crate::pyobject_native_type_named!($name $(,$type_param)*); - $crate::pyobject_native_type_convert!($name, $layout, $typeobject, $module, $checkfunction $(,$type_param)*); - $crate::pyobject_native_type_extract!($name $(,$type_param)*); - - impl<'a, $($type_param,)*> ::std::convert::From<&'a $name> for &'a $crate::PyAny { - fn from(ob: &'a $name) -> Self { - unsafe{&*(ob as *const $name as *const $crate::PyAny)} - } - } - - - // TODO: Rust>=1.40 allows this impl for rust-numpy. - // So we should move this to `named` or `convert` when we bump MSRV. - impl<$($type_param,)*> From<&'_ $name> for $crate::Py<$name> { + impl<$($($generics),+)?> From<&'_ $name> for $crate::Py<$name> { #[inline] fn from(other: &$name) -> Self { use $crate::AsPyPointer; @@ -100,16 +118,32 @@ macro_rules! pyobject_native_type_core { unsafe { $crate::Py::from_borrowed_ptr(other.py(), other.as_ptr()) } } } + + impl<'a, $($($generics),+)?> ::std::convert::From<&'a $name> for &'a $crate::PyAny { + fn from(ob: &'a $name) -> Self { + unsafe{&*(ob as *const $name as *const $crate::PyAny)} + } + } + }; +); + +#[macro_export] +macro_rules! pyobject_native_type_core { + ($name: ty, $layout: path, $typeobject: expr, $module: expr $(, $checkfunction:path)? $(,generics: <$($generics:ident),+>)? ) => { + unsafe impl $crate::type_object::PyLayout<$name> for $layout {} + $crate::pyobject_native_type_named!($name $(,generics: <$($generics),+>)?); + $crate::pyobject_native_type_info!($name, $layout, $typeobject, $module $(, $checkfunction)? $(,generics: <$($generics),+>)?); + $crate::pyobject_native_type_extract!($name $(,generics: <$($generics),+>)?); } } #[macro_export] macro_rules! pyobject_native_type_sized { - ($name: ty, $layout: path $(,$type_param: ident)*) => { + ($name: ty, $layout: path $(,generics: <$($generics:ident),+>)?) => { // To prevent inheriting native types with ABI3 #[cfg(not(Py_LIMITED_API))] impl $crate::type_object::PySizedLayout<$name> for $layout {} - impl<'a, $($type_param,)*> $crate::derive_utils::PyBaseTypeUtils for $name { + impl<'a, $($($generics),+)?> $crate::derive_utils::PyBaseTypeUtils for $name { type Dict = $crate::pyclass_slots::PyClassDummySlot; type WeakRef = $crate::pyclass_slots::PyClassDummySlot; type LayoutAsBase = $crate::pycell::PyCellBase<$name>; @@ -121,38 +155,36 @@ macro_rules! pyobject_native_type_sized { #[macro_export] macro_rules! pyobject_native_type { - ($name: ty, $layout: path, $typeobject: expr, $module: expr, $checkfunction: path $(,$type_param: ident)*) => { - $crate::pyobject_native_type_core!($name, $layout, $typeobject, $module, $checkfunction $(,$type_param)*); - $crate::pyobject_native_type_sized!($name, $layout $(,$type_param)*); - $crate::pyobject_native_type_fmt!($name $(,$type_param)*); + ($name: ty, $layout: path, $typeobject: expr, $module: expr, $checkfunction:path $(,generics: <$($generics:ident),+>)?) => { + $crate::pyobject_native_type_core!($name, $layout, $typeobject, $module, $checkfunction $(,generics: <$($generics),+>)?); + $crate::pyobject_native_type_sized!($name, $layout $(,generics: <$($generics),+>)?); }; - ($name: ty, $layout: path, $typeobject: expr, $checkfunction: path $(,$type_param: ident)*) => { + ($name: ty, $layout: path, $typeobject: expr, $checkfunction:path $(,generics: <$($generics:ident),+>)?) => { $crate::pyobject_native_type! { - $name, $layout, $typeobject, Some("builtins"), $checkfunction $(,$type_param)* + $name, $layout, $typeobject, Some("builtins"), $checkfunction $(,generics: <$($generics),+>)? } }; } #[macro_export] macro_rules! pyobject_native_var_type { - ($name: ty, $typeobject: expr, $module: expr, $checkfunction: path $(,$type_param: ident)*) => { + ($name: ty, $typeobject: expr, $module: expr, $checkfunction:path $(,generics: <$($generics:ident),+>)?) => { $crate::pyobject_native_type_core!( - $name, $crate::ffi::PyObject, $typeobject, Some("builtins"), $checkfunction $(,$type_param)*); - $crate::pyobject_native_type_fmt!($name $(,$type_param)*); + $name, $crate::ffi::PyObject, $typeobject, Some("builtins"), $checkfunction $(,generics: <$($generics),+>)?); }; - ($name: ty, $typeobject: expr, $checkfunction: path $(,$type_param: ident)*) => { + ($name: ty, $typeobject: expr, $checkfunction: path $(,generics: <$($generics:ident),+>)?) => { $crate::pyobject_native_var_type! { - $name, $typeobject, Some("builtins"), $checkfunction $(,$type_param)* + $name, $typeobject, Some("builtins"), $checkfunction $(,generics: <$($generics),+>)? } }; } -// NOTE: This macro is not included in pyobject_native_type_convert! +// NOTE: This macro is not included in pyobject_native_type_base! // because rust-numpy has a special implementation. #[macro_export] macro_rules! pyobject_native_type_extract { - ($name: ty $(,$type_param: ident)*) => { - impl<'py, $($type_param,)*> $crate::FromPyObject<'py> for &'py $name { + ($name: ty $(,generics: <$($generics:ident),+>)?) => { + impl<'py, $($($generics),+)?> $crate::FromPyObject<'py> for &'py $name { fn extract(obj: &'py $crate::PyAny) -> $crate::PyResult { $crate::PyTryFrom::try_from(obj).map_err(Into::into) } @@ -161,10 +193,10 @@ macro_rules! pyobject_native_type_extract { } #[macro_export] -macro_rules! pyobject_native_type_convert( +macro_rules! pyobject_native_type_info( ($name: ty, $layout: path, $typeobject: expr, - $module: expr, $checkfunction: path $(,$type_param: ident)*) => { - unsafe impl<$($type_param,)*> $crate::type_object::PyTypeInfo for $name { + $module: expr $(, $checkfunction:path)? $(,generics: <$($generics:ident),+>)?) => { + unsafe impl<$($($generics),+)?> $crate::type_object::PyTypeInfo for $name { type Type = (); type BaseType = $crate::PyAny; type Layout = $layout; @@ -183,43 +215,13 @@ macro_rules! pyobject_native_type_convert( unsafe { &mut $typeobject } } - #[allow(unused_unsafe)] - fn is_type_of(ptr: &$crate::PyAny) -> bool { - use $crate::AsPyPointer; - unsafe { $checkfunction(ptr.as_ptr()) > 0 } - } - } - - impl<$($type_param,)*> $crate::ToPyObject for $name - { - #[inline] - fn to_object(&self, py: $crate::Python) -> $crate::PyObject { - use $crate::AsPyPointer; - unsafe { $crate::PyObject::from_borrowed_ptr(py, self.as_ptr()) } - } - } - }; -); - -#[macro_export] -macro_rules! pyobject_native_type_fmt( - ($name: ty $(,$type_param: ident)*) => { - impl<$($type_param,)*> ::std::fmt::Debug for $name { - fn fmt(&self, f: &mut ::std::fmt::Formatter) - -> Result<(), ::std::fmt::Error> - { - let s = self.repr().map_err(|_| ::std::fmt::Error)?; - f.write_str(&s.to_string_lossy()) - } - } - - impl<$($type_param,)*> ::std::fmt::Display for $name { - fn fmt(&self, f: &mut ::std::fmt::Formatter) - -> Result<(), ::std::fmt::Error> - { - let s = self.str().map_err(|_| ::std::fmt::Error)?; - f.write_str(&s.to_string_lossy()) - } + $( + fn is_type_of(ptr: &$crate::PyAny) -> bool { + use $crate::AsPyPointer; + #[allow(unused_unsafe)] + unsafe { $checkfunction(ptr.as_ptr()) > 0 } + } + )? } }; );