Skip to content

Commit

Permalink
pymethods: cleanup macros generating setdel slots
Browse files Browse the repository at this point in the history
  • Loading branch information
davidhewitt committed Sep 17, 2021
1 parent 92e2156 commit 75c0116
Showing 1 changed file with 132 additions and 213 deletions.
345 changes: 132 additions & 213 deletions src/class/impl_.rs
Expand Up @@ -108,229 +108,148 @@ impl<T> PyClassCallImpl<T> for &'_ PyClassImplCollector<T> {
}
}

#[allow(non_camel_case_types)]
pub trait PyClass__setattr__SlotFragment<T>: Sized {
#[inline]
#[allow(non_snake_case)]
fn __setattr__implemented(self) -> bool {
false
}

#[inline]
unsafe fn __setattr__(
self,
_slf: *mut ffi::PyObject,
_attr: *mut ffi::PyObject,
_value: NonNull<ffi::PyObject>,
) -> PyResult<()> {
Err(PyAttributeError::new_err("can't set attribute"))
}
}

impl<T> PyClass__setattr__SlotFragment<T> for &'_ PyClassImplCollector<T> {}

#[allow(non_camel_case_types)]
pub trait PyClass__delattr__SlotFragment<T>: Sized {
#[inline]
#[allow(non_snake_case)]
fn __delattr__implemented(self) -> bool {
false
}

#[inline]
unsafe fn __delattr__(
self,
_slf: *mut ffi::PyObject,
_attr: *mut ffi::PyObject,
) -> PyResult<()> {
Err(PyAttributeError::new_err("can't delete attribute"))
}
}
macro_rules! slot_fragment_trait {
($trait_name:ident, $implemented_name:ident, $($default_method:tt)*) => {
#[allow(non_camel_case_types)]
pub trait $trait_name<T>: Sized {
#[inline]
#[allow(non_snake_case)]
fn $implemented_name(self) -> bool {
false
}

impl<T> PyClass__delattr__SlotFragment<T> for &'_ PyClassImplCollector<T> {}
$($default_method)*
}

#[doc(hidden)]
#[macro_export]
macro_rules! generate_pyclass_setattr_slot {
($cls:ty) => {{
use ::std::option::Option::*;
use $crate::class::impl_::*;
let collector = PyClassImplCollector::<$cls>::new();
if collector.__setattr__implemented() || collector.__delattr__implemented() {
unsafe extern "C" fn __wrap(
_slf: *mut $crate::ffi::PyObject,
attr: *mut $crate::ffi::PyObject,
value: *mut $crate::ffi::PyObject,
) -> ::std::os::raw::c_int {
$crate::callback::handle_panic(|py| {
let collector = PyClassImplCollector::<$cls>::new();
$crate::callback::convert(py, {
if let Some(value) = ::std::ptr::NonNull::new(value) {
collector.__setattr__(_slf, attr, value)
} else {
collector.__delattr__(_slf, attr)
}
})
})
impl<T> $trait_name<T> for &'_ PyClassImplCollector<T> {}
}
}

/// Macro which expands to three items
/// - Trait for a __setitem__ dunder
/// - Trait for the corresponding __delitem__ dunder
/// - A macro which will use dtolnay specialisation to generate the shared slot for the two dunders
macro_rules! define_pyclass_setattr_slot {
(
$set_trait:ident,
$del_trait:ident,
$set_implemented:ident,
$del_implemented:ident,
$set:ident,
$del:ident,
$set_error:expr,
$del_error:expr,
$generate_macro:ident,
$slot:ident,
$func_ty:ident,
) => {
slot_fragment_trait! {
$set_trait,
$set_implemented,

/// # Safety: _slf and _attr must be valid non-null Python objects
#[inline]
unsafe fn $set(
self,
_slf: *mut ffi::PyObject,
_attr: *mut ffi::PyObject,
_value: NonNull<ffi::PyObject>,
) -> PyResult<()> {
$set_error
}
Some($crate::ffi::PyType_Slot {
slot: $crate::ffi::Py_tp_setattro,
pfunc: __wrap as $crate::ffi::setattrofunc as _,
})
} else {
None
}
}};
}

#[allow(non_camel_case_types)]
pub trait PyClass__set__SlotFragment<T>: Sized {
#[inline]
#[allow(non_snake_case)]
fn __set__implemented(self) -> bool {
false
}

#[inline]
unsafe fn __set__(
self,
_slf: *mut ffi::PyObject,
_attr: *mut ffi::PyObject,
_value: NonNull<ffi::PyObject>,
) -> PyResult<()> {
Err(PyNotImplementedError::new_err("can't set descriptor"))
}
}

impl<T> PyClass__set__SlotFragment<T> for &'_ PyClassImplCollector<T> {}

#[allow(non_camel_case_types)]
pub trait PyClass__delete__SlotFragment<T>: Sized {
#[allow(non_snake_case)]
#[inline]
fn __delete__implemented(self) -> bool {
false
}

#[inline]
unsafe fn __delete__(
self,
_slf: *mut ffi::PyObject,
_attr: *mut ffi::PyObject,
) -> PyResult<()> {
Err(PyNotImplementedError::new_err("can't delete descriptor"))
}
}

impl<T> PyClass__delete__SlotFragment<T> for &'_ PyClassImplCollector<T> {}

#[doc(hidden)]
#[macro_export]
macro_rules! generate_pyclass_setdescr_slot {
($cls:ty) => {{
use ::std::option::Option::*;
use $crate::class::impl_::*;
let collector = PyClassImplCollector::<$cls>::new();
if collector.__set__implemented() || collector.__delete__implemented() {
unsafe extern "C" fn __wrap(
_slf: *mut $crate::ffi::PyObject,
attr: *mut $crate::ffi::PyObject,
value: *mut $crate::ffi::PyObject,
) -> ::std::os::raw::c_int {
$crate::callback::handle_panic(|py| {
let collector = PyClassImplCollector::<$cls>::new();
$crate::callback::convert(py, {
if let Some(value) = ::std::ptr::NonNull::new(value) {
collector.__set__(_slf, attr, value)
} else {
collector.__delete__(_slf, attr)
}
})
})
slot_fragment_trait! {
$del_trait,
$del_implemented,

/// # Safety: _slf and _attr must be valid non-null Python objects
#[inline]
unsafe fn $del(
self,
_slf: *mut ffi::PyObject,
_attr: *mut ffi::PyObject,
) -> PyResult<()> {
$del_error
}
Some($crate::ffi::PyType_Slot {
slot: $crate::ffi::Py_tp_descr_set,
pfunc: __wrap as $crate::ffi::descrsetfunc as _,
})
} else {
None
}
}};
}

#[allow(non_camel_case_types)]
pub trait PyClass__setitem__SlotFragment<T>: Sized {
#[inline]
#[allow(non_snake_case)]
fn __setitem__implemented(self) -> bool {
false
}

#[inline]
unsafe fn __setitem__(
self,
_slf: *mut ffi::PyObject,
_attr: *mut ffi::PyObject,
_value: NonNull<ffi::PyObject>,
) -> PyResult<()> {
Err(PyNotImplementedError::new_err("can't set item"))
}
}

impl<T> PyClass__setitem__SlotFragment<T> for &'_ PyClassImplCollector<T> {}

#[allow(non_camel_case_types)]
pub trait PyClass__delitem__SlotFragment<T>: Sized {
#[allow(non_snake_case)]
#[inline]
fn __delitem__implemented(self) -> bool {
false
}

#[inline]
unsafe fn __delitem__(
self,
_slf: *mut ffi::PyObject,
_attr: *mut ffi::PyObject,
) -> PyResult<()> {
Err(PyNotImplementedError::new_err("can't delete item"))
}
}

impl<T> PyClass__delitem__SlotFragment<T> for &'_ PyClassImplCollector<T> {}

#[doc(hidden)]
#[macro_export]
macro_rules! generate_pyclass_setitem_slot {
($cls:ty) => {{
use ::std::option::Option::*;
use $crate::class::impl_::*;
let collector = PyClassImplCollector::<$cls>::new();
if collector.__setitem__implemented() || collector.__delitem__implemented() {
unsafe extern "C" fn __wrap(
_slf: *mut $crate::ffi::PyObject,
attr: *mut $crate::ffi::PyObject,
value: *mut $crate::ffi::PyObject,
) -> ::std::os::raw::c_int {
$crate::callback::handle_panic(|py| {
let collector = PyClassImplCollector::<$cls>::new();
$crate::callback::convert(py, {
if let Some(value) = ::std::ptr::NonNull::new(value) {
collector.__setitem__(_slf, attr, value)
} else {
collector.__delitem__(_slf, attr)
}
#[doc(hidden)]
#[macro_export]
macro_rules! $generate_macro {
($cls:ty) => {{
use ::std::option::Option::*;
use $crate::class::impl_::*;
let collector = PyClassImplCollector::<$cls>::new();
if collector.$set_implemented() || collector.$del_implemented() {
unsafe extern "C" fn __wrap(
_slf: *mut $crate::ffi::PyObject,
attr: *mut $crate::ffi::PyObject,
value: *mut $crate::ffi::PyObject,
) -> ::std::os::raw::c_int {
$crate::callback::handle_panic(|py| {
let collector = PyClassImplCollector::<$cls>::new();
$crate::callback::convert(py, {
if let Some(value) = ::std::ptr::NonNull::new(value) {
collector.$set(_slf, attr, value)
} else {
collector.$del(_slf, attr)
}
})
})
}
Some($crate::ffi::PyType_Slot {
slot: $crate::ffi::$slot,
pfunc: __wrap as $crate::ffi::$func_ty as _,
})
})
}
Some($crate::ffi::PyType_Slot {
slot: $crate::ffi::Py_mp_ass_subscript,
pfunc: __wrap as $crate::ffi::objobjargproc as _,
})
} else {
None
} else {
None
}
}};
}
}};
};
}

define_pyclass_setattr_slot! {
PyClass__setattr__SlotFragment,
PyClass__delattr__SlotFragment,
__setattr__implemented,
__delattr__implemented,
__setattr__,
__delattr__,
Err(PyAttributeError::new_err("can't set attribute")),
Err(PyAttributeError::new_err("can't delete attribute")),
generate_pyclass_setattr_slot,
Py_tp_setattro,
setattrofunc,
}

define_pyclass_setattr_slot! {
PyClass__set__SlotFragment,
PyClass__delete__SlotFragment,
__set__implemented,
__delete__implemented,
__set__,
__delete__,
Err(PyNotImplementedError::new_err("can't set descriptor")),
Err(PyNotImplementedError::new_err("can't delete descriptor")),
generate_pyclass_setdescr_slot,
Py_tp_descr_set,
descrsetfunc,
}

define_pyclass_setattr_slot! {
PyClass__setitem__SlotFragment,
PyClass__delitem__SlotFragment,
__setitem__implemented,
__delitem__implemented,
__setitem__,
__delitem__,
Err(PyNotImplementedError::new_err("can't set item")),
Err(PyNotImplementedError::new_err("can't delete item")),
generate_pyclass_setitem_slot,
Py_mp_ass_subscript,
objobjargproc,
}

pub trait PyClassAllocImpl<T> {
Expand Down

0 comments on commit 75c0116

Please sign in to comment.