types: refactor native_type macros

This commit is contained in:
David Hewitt 2020-11-15 18:58:46 +00:00
parent ff5e2d0856
commit f8d408f3b5
4 changed files with 99 additions and 143 deletions

View file

@ -12,8 +12,6 @@ use std::os::raw::c_char;
#[macro_export] #[macro_export]
macro_rules! impl_exception_boilerplate { macro_rules! impl_exception_boilerplate {
($name: ident) => { ($name: ident) => {
$crate::pyobject_native_type_fmt!($name);
impl std::convert::From<&$name> for $crate::PyErr { impl std::convert::From<&$name> for $crate::PyErr {
fn from(err: &$name) -> $crate::PyErr { fn from(err: &$name) -> $crate::PyErr {
$crate::PyErr::from_instance(err) $crate::PyErr::from_instance(err)
@ -88,22 +86,10 @@ macro_rules! import_exception {
$name, $name,
$crate::ffi::PyBaseExceptionObject, $crate::ffi::PyBaseExceptionObject,
*$name::type_object_raw($crate::Python::assume_gil_acquired()), *$name::type_object_raw($crate::Python::assume_gil_acquired()),
Some(stringify!($module)), Some(stringify!($module))
$name::check
); );
impl $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 {
$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 { fn type_object_raw(py: $crate::Python) -> *mut $crate::ffi::PyTypeObject {
use $crate::once_cell::GILOnceCell; use $crate::once_cell::GILOnceCell;
use $crate::AsPyPointer; use $crate::AsPyPointer;
@ -191,22 +177,10 @@ macro_rules! create_exception_type_object {
$name, $name,
$crate::ffi::PyBaseExceptionObject, $crate::ffi::PyBaseExceptionObject,
*$name::type_object_raw($crate::Python::assume_gil_acquired()), *$name::type_object_raw($crate::Python::assume_gil_acquired()),
Some(stringify!($module)), Some(stringify!($module))
$name::check
); );
impl $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 {
$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 { fn type_object_raw(py: $crate::Python) -> *mut $crate::ffi::PyTypeObject {
use $crate::once_cell::GILOnceCell; use $crate::once_cell::GILOnceCell;
use $crate::AsPyPointer; use $crate::AsPyPointer;
@ -240,18 +214,7 @@ macro_rules! impl_native_exception (
pub type $legacy_name = $crate::Py<$name>; pub type $legacy_name = $crate::Py<$name>;
$crate::impl_exception_boilerplate!($name); $crate::impl_exception_boilerplate!($name);
$crate::pyobject_native_type_core!($name, $layout, *(ffi::$exc_name as *mut ffi::PyTypeObject), Some("builtins"));
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);
); );
($name:ident, $legacy_name:ident, $exc_name:ident) => ( ($name:ident, $legacy_name:ident, $exc_name:ident) => (
impl_native_exception!($name, $legacy_name, $exc_name, ffi::PyBaseExceptionObject); impl_native_exception!($name, $legacy_name, $exc_name, ffi::PyBaseExceptionObject);

View file

@ -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<PyAny> for ffi::PyObject {} unsafe impl crate::type_object::PyLayout<PyAny> for ffi::PyObject {}
impl crate::type_object::PySizedLayout<PyAny> for ffi::PyObject {} impl crate::type_object::PySizedLayout<PyAny> for ffi::PyObject {}
pyobject_native_type_convert!( pyobject_native_type_info!(
PyAny, PyAny,
ffi::PyObject, ffi::PyObject,
ffi::PyBaseObject_Type, ffi::PyBaseObject_Type,
@ -66,7 +58,7 @@ pyobject_native_type_convert!(
pyobject_native_type_extract!(PyAny); pyobject_native_type_extract!(PyAny);
pyobject_native_type_fmt!(PyAny); pyobject_native_type_base!(PyAny);
impl PyAny { impl PyAny {
/// Convert this PyAny to a concrete Python type. /// Convert this PyAny to a concrete Python type.

View file

@ -24,7 +24,6 @@ use crate::{PyDowncastError, PyTryFrom};
/// # Ok(()) /// # Ok(())
/// # } /// # }
/// ``` /// ```
#[derive(Debug)]
#[repr(transparent)] #[repr(transparent)]
pub struct PyIterator(PyAny); pub struct PyIterator(PyAny);
pyobject_native_type_named!(PyIterator); pyobject_native_type_named!(PyIterator);

View file

@ -27,17 +27,65 @@ pub use self::string::{PyString, PyString as PyUnicode};
pub use self::tuple::PyTuple; pub use self::tuple::PyTuple;
pub use self::typeobject::PyType; 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_export]
macro_rules! pyobject_native_type_named ( macro_rules! pyobject_native_type_named (
($name: ty $(,$type_param: ident)*) => { ($name: ty $(,generics: <$($generics:ident),+>)?) => {
impl<$($type_param,)*> ::std::convert::AsRef<$crate::PyAny> for $name { $crate::pyobject_native_type_base!($name $(,generics: <$($generics),+>)?);
impl<$($($generics),+)?> ::std::convert::AsRef<$crate::PyAny> for $name {
#[inline] #[inline]
fn as_ref(&self) -> &$crate::PyAny { fn as_ref(&self) -> &$crate::PyAny {
&self.0 &self.0
} }
} }
impl<$($type_param,)*> ::std::ops::Deref for $name { impl<$($($generics),+)?> ::std::ops::Deref for $name {
type Target = $crate::PyAny; type Target = $crate::PyAny;
#[inline] #[inline]
@ -46,9 +94,7 @@ macro_rules! pyobject_native_type_named (
} }
} }
unsafe impl<$($type_param,)*> $crate::PyNativeType for $name {} impl<$($($generics),+)?> $crate::AsPyPointer for $name {
impl<$($type_param,)*> $crate::AsPyPointer for $name {
/// Gets the underlying FFI pointer, returns a borrowed pointer. /// Gets the underlying FFI pointer, returns a borrowed pointer.
#[inline] #[inline]
fn as_ptr(&self) -> *mut $crate::ffi::PyObject { fn as_ptr(&self) -> *mut $crate::ffi::PyObject {
@ -56,43 +102,15 @@ macro_rules! pyobject_native_type_named (
} }
} }
impl<$($type_param,)*> PartialEq for $name { impl<$($($generics),+)?> $crate::IntoPy<$crate::Py<$name>> 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 {
#[inline] #[inline]
fn into_py(self, py: $crate::Python) -> $crate::Py<$name> { fn into_py(self, py: $crate::Python) -> $crate::Py<$name> {
use $crate::AsPyPointer; use $crate::AsPyPointer;
unsafe { $crate::Py::from_borrowed_ptr(py, self.as_ptr()) } unsafe { $crate::Py::from_borrowed_ptr(py, self.as_ptr()) }
} }
} }
};
);
#[macro_export] impl<$($($generics),+)?> From<&'_ $name> for $crate::Py<$name> {
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> {
#[inline] #[inline]
fn from(other: &$name) -> Self { fn from(other: &$name) -> Self {
use $crate::AsPyPointer; use $crate::AsPyPointer;
@ -100,16 +118,32 @@ macro_rules! pyobject_native_type_core {
unsafe { $crate::Py::from_borrowed_ptr(other.py(), other.as_ptr()) } 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_export]
macro_rules! pyobject_native_type_sized { 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 // To prevent inheriting native types with ABI3
#[cfg(not(Py_LIMITED_API))] #[cfg(not(Py_LIMITED_API))]
impl $crate::type_object::PySizedLayout<$name> for $layout {} 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 Dict = $crate::pyclass_slots::PyClassDummySlot;
type WeakRef = $crate::pyclass_slots::PyClassDummySlot; type WeakRef = $crate::pyclass_slots::PyClassDummySlot;
type LayoutAsBase = $crate::pycell::PyCellBase<$name>; type LayoutAsBase = $crate::pycell::PyCellBase<$name>;
@ -121,38 +155,36 @@ macro_rules! pyobject_native_type_sized {
#[macro_export] #[macro_export]
macro_rules! pyobject_native_type { macro_rules! pyobject_native_type {
($name: ty, $layout: path, $typeobject: expr, $module: expr, $checkfunction: path $(,$type_param: ident)*) => { ($name: ty, $layout: path, $typeobject: expr, $module: expr, $checkfunction:path $(,generics: <$($generics:ident),+>)?) => {
$crate::pyobject_native_type_core!($name, $layout, $typeobject, $module, $checkfunction $(,$type_param)*); $crate::pyobject_native_type_core!($name, $layout, $typeobject, $module, $checkfunction $(,generics: <$($generics),+>)?);
$crate::pyobject_native_type_sized!($name, $layout $(,$type_param)*); $crate::pyobject_native_type_sized!($name, $layout $(,generics: <$($generics),+>)?);
$crate::pyobject_native_type_fmt!($name $(,$type_param)*);
}; };
($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! { $crate::pyobject_native_type! {
$name, $layout, $typeobject, Some("builtins"), $checkfunction $(,$type_param)* $name, $layout, $typeobject, Some("builtins"), $checkfunction $(,generics: <$($generics),+>)?
} }
}; };
} }
#[macro_export] #[macro_export]
macro_rules! pyobject_native_var_type { 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!( $crate::pyobject_native_type_core!(
$name, $crate::ffi::PyObject, $typeobject, Some("builtins"), $checkfunction $(,$type_param)*); $name, $crate::ffi::PyObject, $typeobject, Some("builtins"), $checkfunction $(,generics: <$($generics),+>)?);
$crate::pyobject_native_type_fmt!($name $(,$type_param)*);
}; };
($name: ty, $typeobject: expr, $checkfunction: path $(,$type_param: ident)*) => { ($name: ty, $typeobject: expr, $checkfunction: path $(,generics: <$($generics:ident),+>)?) => {
$crate::pyobject_native_var_type! { $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. // because rust-numpy has a special implementation.
#[macro_export] #[macro_export]
macro_rules! pyobject_native_type_extract { macro_rules! pyobject_native_type_extract {
($name: ty $(,$type_param: ident)*) => { ($name: ty $(,generics: <$($generics:ident),+>)?) => {
impl<'py, $($type_param,)*> $crate::FromPyObject<'py> for &'py $name { impl<'py, $($($generics),+)?> $crate::FromPyObject<'py> for &'py $name {
fn extract(obj: &'py $crate::PyAny) -> $crate::PyResult<Self> { fn extract(obj: &'py $crate::PyAny) -> $crate::PyResult<Self> {
$crate::PyTryFrom::try_from(obj).map_err(Into::into) $crate::PyTryFrom::try_from(obj).map_err(Into::into)
} }
@ -161,10 +193,10 @@ macro_rules! pyobject_native_type_extract {
} }
#[macro_export] #[macro_export]
macro_rules! pyobject_native_type_convert( macro_rules! pyobject_native_type_info(
($name: ty, $layout: path, $typeobject: expr, ($name: ty, $layout: path, $typeobject: expr,
$module: expr, $checkfunction: path $(,$type_param: ident)*) => { $module: expr $(, $checkfunction:path)? $(,generics: <$($generics:ident),+>)?) => {
unsafe impl<$($type_param,)*> $crate::type_object::PyTypeInfo for $name { unsafe impl<$($($generics),+)?> $crate::type_object::PyTypeInfo for $name {
type Type = (); type Type = ();
type BaseType = $crate::PyAny; type BaseType = $crate::PyAny;
type Layout = $layout; type Layout = $layout;
@ -183,43 +215,13 @@ macro_rules! pyobject_native_type_convert(
unsafe { &mut $typeobject } unsafe { &mut $typeobject }
} }
#[allow(unused_unsafe)] $(
fn is_type_of(ptr: &$crate::PyAny) -> bool { fn is_type_of(ptr: &$crate::PyAny) -> bool {
use $crate::AsPyPointer; use $crate::AsPyPointer;
#[allow(unused_unsafe)]
unsafe { $checkfunction(ptr.as_ptr()) > 0 } 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())
}
} }
}; };
); );