1use std::marker;
20
21use crate::conversion::ToPyObject;
22use crate::err::{self, PyResult};
23use crate::ffi;
24use crate::objects::PyObject;
25use crate::python::{Python, PythonObject};
26
27pub trait TypeMember<T>
31where
32 T: PythonObject,
33{
34 unsafe fn into_descriptor(self, py: Python, ty: *mut ffi::PyTypeObject) -> PyResult<PyObject>;
41}
42
43impl<T, S> TypeMember<T> for S
44where
45 T: PythonObject,
46 S: ToPyObject,
47{
48 #[inline]
49 unsafe fn into_descriptor(self, py: Python, _ty: *mut ffi::PyTypeObject) -> PyResult<PyObject> {
50 Ok(self.into_py_object(py).into_object())
51 }
52}
53
54#[macro_export]
55#[doc(hidden)]
56macro_rules! py_class_init_members {
57 ($class:ident, $py:ident, $type_object: ident, { }) => {{}};
58 ($class:ident, $py:ident, $type_object: ident, { $( $name:ident = $init:expr; )+ }) => {{
59 let dict = $crate::PyDict::new($py);
60 $( {
61 let init = $init;
63 let descriptor = unsafe {
64 $crate::py_class::members::TypeMember::<$class>::into_descriptor(init, $py, &mut $type_object)
65 }?;
66 let name = $crate::strip_raw!(stringify!($name));
67 dict.set_item($py, name, descriptor)?;
68 })*
69 unsafe {
70 assert!($type_object.tp_dict.is_null());
71 $type_object.tp_dict = $crate::PythonObject::into_object(dict).steal_ptr();
72 }
73 }};
74}
75
76#[macro_export]
77#[doc(hidden)]
78macro_rules! py_class_instance_method {
79 ($py:ident, $class:ident :: $f:ident [ $( { $pname:ident : $ptype:ty = $detail:tt } )* ]) => {{
80 $crate::py_class_instance_method!($py, $class::$f, { "" } [ $( { $pname : $ptype = $detail } )* ])
81 }};
82
83 ($py:ident, $class:ident :: $f:ident, { $doc:expr } [ $( { $pname:ident : $ptype:ty = $detail:tt } )* ]) => {{
84 unsafe extern "C" fn wrap_instance_method(
85 slf: *mut $crate::_detail::ffi::PyObject,
86 args: *mut $crate::_detail::ffi::PyObject,
87 kwargs: *mut $crate::_detail::ffi::PyObject)
88 -> *mut $crate::_detail::ffi::PyObject
89 {
90 const LOCATION: &'static str = concat!(stringify!($class), ".", stringify!($f), "()");
91 $crate::_detail::handle_callback(
92 LOCATION, $crate::_detail::PyObjectCallbackConverter,
93 |py| {
94 $crate::py_argparse_raw!(py, Some(LOCATION), args, kwargs,
95 [ $( { $pname : $ptype = $detail } )* ]
96 {
97 let slf = $crate::PyObject::from_borrowed_ptr(py, slf).unchecked_cast_into::<$class>();
98 let ret = slf.$f(py $(, $pname )* );
99 $crate::PyDrop::release_ref(slf, py);
100 ret
101 })
102 })
103 }
104 unsafe {
105 let method_def = $crate::py_method_def!(stringify!($f), 0, wrap_instance_method, $doc);
106 $crate::py_class::members::create_instance_method_descriptor::<$class>(method_def)
107 }
108 }}
109}
110
111pub struct InstanceMethodDescriptor<T>(*mut ffi::PyMethodDef, marker::PhantomData<fn(&T)>);
112
113#[inline]
114pub unsafe fn create_instance_method_descriptor<T>(
115 method_def: *mut ffi::PyMethodDef,
116) -> InstanceMethodDescriptor<T> {
117 InstanceMethodDescriptor(method_def, marker::PhantomData)
118}
119
120impl<T> TypeMember<T> for InstanceMethodDescriptor<T>
121where
122 T: PythonObject,
123{
124 #[inline]
125 unsafe fn into_descriptor(self, py: Python, ty: *mut ffi::PyTypeObject) -> PyResult<PyObject> {
126 err::result_from_owned_ptr(py, ffi::PyDescr_NewMethod(ty, self.0))
127 }
128}
129
130#[macro_export]
131#[doc(hidden)]
132macro_rules! py_class_class_method {
133 ($py:ident, $class:ident :: $f:ident [ $( { $pname:ident : $ptype:ty = $detail:tt } )* ]) => {{
134 $crate::py_class_class_method!($py, $class::$f, { "" } [ $( { $pname : $ptype = $detail } )* ])
135 }};
136
137 ($py:ident, $class:ident :: $f:ident, { $doc:expr } [ $( { $pname:ident : $ptype:ty = $detail:tt } )* ]) => {{
138 unsafe extern "C" fn wrap_class_method(
139 cls: *mut $crate::_detail::ffi::PyObject,
140 args: *mut $crate::_detail::ffi::PyObject,
141 kwargs: *mut $crate::_detail::ffi::PyObject)
142 -> *mut $crate::_detail::ffi::PyObject
143 {
144 const LOCATION: &'static str = concat!(stringify!($class), ".", stringify!($f), "()");
145 $crate::_detail::handle_callback(
146 LOCATION, $crate::_detail::PyObjectCallbackConverter,
147 |py| {
148 $crate::py_argparse_raw!(py, Some(LOCATION), args, kwargs,
149 [ $( { $pname : $ptype = $detail } )* ]
150 {
151 let cls = $crate::PyObject::from_borrowed_ptr(py, cls).unchecked_cast_into::<$crate::PyType>();
152 let ret = $class::$f(&cls, py $(, $pname )* );
153 $crate::PyDrop::release_ref(cls, py);
154 ret
155 })
156 })
157 }
158 unsafe {
159 let method_def = $crate::py_method_def!(stringify!($f),
160 $crate::_detail::ffi::METH_CLASS,
161 wrap_class_method,
162 $doc);
163 $crate::py_class::members::create_class_method_descriptor(method_def)
164 }
165 }}
166}
167
168pub struct ClassMethodDescriptor(*mut ffi::PyMethodDef);
169
170#[inline]
171pub unsafe fn create_class_method_descriptor(
172 method_def: *mut ffi::PyMethodDef,
173) -> ClassMethodDescriptor {
174 ClassMethodDescriptor(method_def)
175}
176
177impl<T> TypeMember<T> for ClassMethodDescriptor
178where
179 T: PythonObject,
180{
181 #[inline]
182 unsafe fn into_descriptor(self, py: Python, ty: *mut ffi::PyTypeObject) -> PyResult<PyObject> {
183 err::result_from_owned_ptr(py, ffi::PyDescr_NewClassMethod(ty, self.0))
184 }
185}
186
187#[macro_export]
188#[doc(hidden)]
189macro_rules! py_class_static_method {
190 ($py:ident, $class:ident :: $f:ident [ $( { $pname:ident : $ptype:ty = $detail:tt } )* ]) => {{
191 $crate::py_class_static_method!($py, $class::$f, { "" } [ $( { $pname : $ptype = $detail } )* ])
192 }};
193
194 ($py:ident, $class:ident :: $f:ident, { $doc:expr } [ $( { $pname:ident : $ptype:ty = $detail:tt } )* ]) => {{
195 unsafe extern "C" fn wrap_static_method(
196 _slf: *mut $crate::_detail::ffi::PyObject,
197 args: *mut $crate::_detail::ffi::PyObject,
198 kwargs: *mut $crate::_detail::ffi::PyObject)
199 -> *mut $crate::_detail::ffi::PyObject
200 {
201 const LOCATION: &'static str = concat!(stringify!($class), ".", stringify!($f), "()");
202 $crate::_detail::handle_callback(
203 LOCATION, $crate::_detail::PyObjectCallbackConverter,
204 |py| {
205 $crate::py_argparse_raw!(py, Some(LOCATION), args, kwargs,
206 [ $( { $pname : $ptype = $detail } )* ]
207 {
208 $class::$f(py $(, $pname )* )
209 })
210 })
211 }
212 unsafe {
213 let method_def = $crate::py_method_def!(stringify!($f),
214 $crate::_detail::ffi::METH_STATIC,
215 wrap_static_method,
216 $doc);
217 $crate::_detail::py_fn_impl($py, method_def)
218 }
219 }}
220}