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_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);

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 {}
impl crate::type_object::PySizedLayout<PyAny> 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.

View file

@ -24,7 +24,6 @@ use crate::{PyDowncastError, PyTryFrom};
/// # Ok(())
/// # }
/// ```
#[derive(Debug)]
#[repr(transparent)]
pub struct PyIterator(PyAny);
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::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<Self> {
$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 }
}
)?
}
};
);