2017-05-16 18:58:18 +00:00
|
|
|
// Copyright (c) 2017-present PyO3 Project and Contributors
|
|
|
|
|
2017-05-25 03:31:51 +00:00
|
|
|
use std;
|
2017-05-16 18:58:18 +00:00
|
|
|
use std::mem;
|
|
|
|
use std::ffi::CString;
|
|
|
|
use std::collections::HashMap;
|
|
|
|
|
2017-05-25 03:31:51 +00:00
|
|
|
use {ffi, class};
|
|
|
|
use err::{PyErr, PyResult};
|
|
|
|
use pyptr::Py;
|
|
|
|
use python::Python;
|
2017-05-19 04:35:08 +00:00
|
|
|
use objects::PyType;
|
2017-05-17 06:43:39 +00:00
|
|
|
use callback::AbortOnDrop;
|
2017-05-25 03:31:51 +00:00
|
|
|
use class::methods::PyMethodDefType;
|
2017-05-16 18:58:18 +00:00
|
|
|
|
|
|
|
|
2017-05-23 06:53:14 +00:00
|
|
|
/// Basic python type information
|
|
|
|
/// Implementing this trait for custom struct is enough to make it compatible with
|
|
|
|
/// python object system
|
2017-05-23 06:45:28 +00:00
|
|
|
pub trait PyTypeInfo {
|
2017-05-23 06:53:14 +00:00
|
|
|
/// Type of objects to store in PyObject struct
|
2017-05-23 06:19:14 +00:00
|
|
|
type Type;
|
2017-05-19 04:35:08 +00:00
|
|
|
|
2017-05-23 06:53:14 +00:00
|
|
|
/// Size of the PyObject structure
|
2017-05-22 05:22:45 +00:00
|
|
|
fn size() -> usize;
|
|
|
|
|
2017-05-23 06:53:14 +00:00
|
|
|
/// `Type` instance offset inside PyObject structure
|
2017-05-23 06:45:28 +00:00
|
|
|
fn offset() -> isize;
|
2017-05-22 05:22:45 +00:00
|
|
|
|
2017-05-23 06:53:14 +00:00
|
|
|
/// Type name
|
2017-05-19 04:35:08 +00:00
|
|
|
fn type_name() -> &'static str;
|
|
|
|
|
2017-05-23 06:53:14 +00:00
|
|
|
/// PyTypeObject instance for this type
|
2017-05-19 04:35:08 +00:00
|
|
|
fn type_object() -> &'static mut ffi::PyTypeObject;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-05-23 06:45:28 +00:00
|
|
|
impl<'a, T: ?Sized> PyTypeInfo for &'a T where T: PyTypeInfo {
|
2017-05-23 06:19:14 +00:00
|
|
|
type Type = T::Type;
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
default fn size() -> usize {
|
2017-05-23 06:45:28 +00:00
|
|
|
<T as PyTypeInfo>::size()
|
2017-05-23 06:19:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
2017-05-23 06:45:28 +00:00
|
|
|
default fn offset() -> isize {
|
|
|
|
<T as PyTypeInfo>::offset()
|
2017-05-23 06:19:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
default fn type_name() -> &'static str {
|
2017-05-23 06:45:28 +00:00
|
|
|
<T as PyTypeInfo>::type_name()
|
2017-05-23 06:19:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
default fn type_object() -> &'static mut ffi::PyTypeObject {
|
2017-05-23 06:45:28 +00:00
|
|
|
<T as PyTypeInfo>::type_object()
|
2017-05-23 06:19:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-05-23 06:45:28 +00:00
|
|
|
impl<'a, T> PyTypeInfo for Py<'a, T> where T: PyTypeInfo {
|
2017-05-23 06:19:14 +00:00
|
|
|
type Type = T::Type;
|
2017-05-22 05:22:45 +00:00
|
|
|
|
|
|
|
#[inline]
|
|
|
|
default fn size() -> usize {
|
2017-05-23 06:45:28 +00:00
|
|
|
<T as PyTypeInfo>::size()
|
2017-05-22 05:22:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
2017-05-23 06:45:28 +00:00
|
|
|
default fn offset() -> isize {
|
|
|
|
<T as PyTypeInfo>::offset()
|
2017-05-22 05:22:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
default fn type_name() -> &'static str {
|
2017-05-23 06:45:28 +00:00
|
|
|
<T as PyTypeInfo>::type_name()
|
2017-05-22 05:22:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
default fn type_object() -> &'static mut ffi::PyTypeObject {
|
2017-05-23 06:45:28 +00:00
|
|
|
<T as PyTypeInfo>::type_object()
|
2017-05-22 05:22:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-25 03:31:51 +00:00
|
|
|
pub trait PyObjectAlloc {
|
|
|
|
type Type;
|
|
|
|
|
|
|
|
/// Allocates a new object (usually by calling ty->tp_alloc),
|
|
|
|
/// and initializes it using init_val.
|
|
|
|
/// `ty` must be derived from the Self type, and the resulting object
|
|
|
|
/// must be of type `ty`.
|
|
|
|
unsafe fn alloc(_py: &Python, value: Self::Type) -> PyResult<*mut ffi::PyObject>;
|
|
|
|
|
|
|
|
/// Calls the rust destructor for the object and frees the memory
|
|
|
|
/// (usually by calling ptr->ob_type->tp_free).
|
|
|
|
/// This function is used as tp_dealloc implementation.
|
|
|
|
unsafe fn dealloc(_py: &Python, obj: *mut ffi::PyObject);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A PythonObject that is usable as a base type for #[class]
|
|
|
|
impl<T> PyObjectAlloc for T where T : PyTypeInfo {
|
|
|
|
type Type = T::Type;
|
|
|
|
|
|
|
|
/// Allocates a new object (usually by calling ty->tp_alloc),
|
|
|
|
/// and initializes it using init_val.
|
|
|
|
/// `ty` must be derived from the Self type, and the resulting object
|
|
|
|
/// must be of type `ty`.
|
|
|
|
unsafe fn alloc(_py: &Python, value: T::Type) -> PyResult<*mut ffi::PyObject> {
|
|
|
|
let obj = ffi::PyType_GenericAlloc(
|
|
|
|
<Self as PyTypeInfo>::type_object(), 0);
|
|
|
|
|
|
|
|
let offset = <Self as PyTypeInfo>::offset();
|
|
|
|
let ptr = (obj as *mut u8).offset(offset) as *mut Self::Type;
|
|
|
|
std::ptr::write(ptr, value);
|
|
|
|
|
|
|
|
Ok(obj)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Calls the rust destructor for the object and frees the memory
|
|
|
|
/// (usually by calling ptr->ob_type->tp_free).
|
|
|
|
/// This function is used as tp_dealloc implementation.
|
|
|
|
unsafe fn dealloc(_py: &Python, obj: *mut ffi::PyObject) {
|
|
|
|
let ptr = (obj as *mut u8).offset(
|
|
|
|
<Self as PyTypeInfo>::offset() as isize) as *mut Self::Type;
|
|
|
|
std::ptr::drop_in_place(ptr);
|
|
|
|
|
|
|
|
let ty = ffi::Py_TYPE(obj);
|
|
|
|
if ffi::PyType_IS_GC(ty) != 0 {
|
|
|
|
ffi::PyObject_GC_Del(obj as *mut ::c_void);
|
|
|
|
} else {
|
|
|
|
ffi::PyObject_Free(obj as *mut ::c_void);
|
|
|
|
}
|
|
|
|
// For heap types, PyType_GenericAlloc calls INCREF on the type objects,
|
|
|
|
// so we need to call DECREF here:
|
|
|
|
if ffi::PyType_HasFeature(ty, ffi::Py_TPFLAGS_HEAPTYPE) != 0 {
|
|
|
|
ffi::Py_DECREF(ty as *mut ffi::PyObject);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-05-22 05:22:45 +00:00
|
|
|
|
2017-05-23 06:53:14 +00:00
|
|
|
/// Trait implemented by Python object types that have a corresponding type object.
|
|
|
|
pub trait PyTypeObject {
|
|
|
|
|
|
|
|
/// Retrieves the type object for this Python object type.
|
2017-05-25 03:31:51 +00:00
|
|
|
fn type_object<'p>(py: Python<'p>) -> Py<'p, PyType>;
|
2017-05-23 06:53:14 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2017-05-25 03:31:51 +00:00
|
|
|
impl<T> PyTypeObject for T where T: PyObjectAlloc + PyTypeInfo {
|
2017-05-16 18:58:18 +00:00
|
|
|
|
2017-05-19 04:35:08 +00:00
|
|
|
#[inline]
|
2017-05-25 03:31:51 +00:00
|
|
|
fn type_object<'p>(py: Python<'p>) -> Py<'p, PyType> {
|
2017-05-23 06:45:28 +00:00
|
|
|
let mut ty = <T as PyTypeInfo>::type_object();
|
2017-05-16 18:58:18 +00:00
|
|
|
|
2017-05-19 04:35:08 +00:00
|
|
|
if (ty.tp_flags & ffi::Py_TPFLAGS_READY) != 0 {
|
|
|
|
unsafe { PyType::from_type_ptr(py, ty) }
|
|
|
|
} else {
|
|
|
|
// automatically initialize the class on-demand
|
2017-05-23 06:45:28 +00:00
|
|
|
initialize_type::<T>(py, None, <T as PyTypeInfo>::type_name(), ty).expect(
|
2017-05-19 04:35:08 +00:00
|
|
|
format!("An error occurred while initializing class {}",
|
2017-05-23 06:45:28 +00:00
|
|
|
<T as PyTypeInfo>::type_name()).as_ref());
|
2017-05-19 04:35:08 +00:00
|
|
|
unsafe { PyType::from_type_ptr(py, ty) }
|
|
|
|
}
|
|
|
|
}
|
2017-05-16 18:58:18 +00:00
|
|
|
}
|
|
|
|
|
2017-05-25 03:31:51 +00:00
|
|
|
pub fn initialize_type<'p, T>(py: Python<'p>, module_name: Option<&str>, type_name: &str,
|
|
|
|
type_object: &mut ffi::PyTypeObject) -> PyResult<Py<'p, PyType>>
|
|
|
|
where T: PyObjectAlloc + PyTypeInfo
|
2017-05-17 06:43:39 +00:00
|
|
|
{
|
|
|
|
// type name
|
|
|
|
let name = match module_name {
|
2017-05-18 23:57:39 +00:00
|
|
|
Some(module_name) => CString::new(format!("{}.{}", module_name, type_name)),
|
2017-05-20 06:14:59 +00:00
|
|
|
None => CString::new(type_name)
|
2017-05-17 06:43:39 +00:00
|
|
|
};
|
|
|
|
let name = name.expect(
|
|
|
|
"Module name/type name must not contain NUL byte").into_raw();
|
|
|
|
|
|
|
|
type_object.tp_name = name;
|
|
|
|
|
|
|
|
// dealloc
|
|
|
|
type_object.tp_dealloc = Some(tp_dealloc_callback::<T>);
|
|
|
|
|
|
|
|
// type size
|
2017-05-23 06:45:28 +00:00
|
|
|
type_object.tp_basicsize = <T as PyTypeInfo>::size() as ffi::Py_ssize_t;
|
2017-05-17 06:43:39 +00:00
|
|
|
|
2017-05-22 05:22:45 +00:00
|
|
|
// GC support
|
2017-05-26 21:43:28 +00:00
|
|
|
//<T as class::gc::PyGCProtocolImpl>::update_type_object(type_object);
|
2017-05-22 05:22:45 +00:00
|
|
|
|
2017-05-17 06:43:39 +00:00
|
|
|
// descriptor protocol
|
2017-05-26 21:43:28 +00:00
|
|
|
//<T as class::descr::PyDescrProtocolImpl>::tp_as_descr(type_object);
|
2017-05-17 06:43:39 +00:00
|
|
|
|
2017-05-18 22:57:38 +00:00
|
|
|
// iterator methods
|
2017-05-22 05:22:45 +00:00
|
|
|
// <T as class::iter::PyIterProtocolImpl>::tp_as_iter(type_object);
|
2017-05-18 22:57:38 +00:00
|
|
|
|
2017-05-21 05:18:31 +00:00
|
|
|
// basic methods
|
2017-05-26 21:43:28 +00:00
|
|
|
//<T as class::basic::PyObjectProtocolImpl>::tp_as_object(type_object);
|
2017-05-21 05:18:31 +00:00
|
|
|
|
2017-05-17 06:43:39 +00:00
|
|
|
// number methods
|
2017-05-26 21:43:28 +00:00
|
|
|
/*if let Some(meth) = <T as class::number::PyNumberProtocolImpl>::tp_as_number() {
|
2017-05-17 06:43:39 +00:00
|
|
|
static mut NB_METHODS: ffi::PyNumberMethods = ffi::PyNumberMethods_INIT;
|
|
|
|
*(unsafe { &mut NB_METHODS }) = meth;
|
|
|
|
type_object.tp_as_number = unsafe { &mut NB_METHODS };
|
2017-05-18 22:57:38 +00:00
|
|
|
mem::forget(meth);
|
2017-05-17 06:43:39 +00:00
|
|
|
} else {
|
|
|
|
type_object.tp_as_number = 0 as *mut ffi::PyNumberMethods;
|
2017-05-26 21:43:28 +00:00
|
|
|
}*/
|
2017-05-16 18:58:18 +00:00
|
|
|
|
2017-05-17 06:43:39 +00:00
|
|
|
// mapping methods
|
2017-05-17 23:33:18 +00:00
|
|
|
if let Some(meth) = <T as class::mapping::PyMappingProtocolImpl>::tp_as_mapping() {
|
2017-05-17 06:43:39 +00:00
|
|
|
static mut MP_METHODS: ffi::PyMappingMethods = ffi::PyMappingMethods_INIT;
|
|
|
|
*(unsafe { &mut MP_METHODS }) = meth;
|
|
|
|
type_object.tp_as_mapping = unsafe { &mut MP_METHODS };
|
2017-05-18 22:57:38 +00:00
|
|
|
mem::forget(meth);
|
2017-05-17 06:43:39 +00:00
|
|
|
} else {
|
|
|
|
type_object.tp_as_mapping = 0 as *mut ffi::PyMappingMethods;
|
2017-05-25 03:31:51 +00:00
|
|
|
}
|
2017-05-16 18:58:18 +00:00
|
|
|
|
2017-05-17 06:43:39 +00:00
|
|
|
// sequence methods
|
2017-05-26 21:43:28 +00:00
|
|
|
/*if let Some(meth) = <T as class::sequence::PySequenceProtocolImpl>::tp_as_sequence() {
|
2017-05-17 06:43:39 +00:00
|
|
|
static mut SQ_METHODS: ffi::PySequenceMethods = ffi::PySequenceMethods_INIT;
|
|
|
|
*(unsafe { &mut SQ_METHODS }) = meth;
|
|
|
|
type_object.tp_as_sequence = unsafe { &mut SQ_METHODS };
|
2017-05-18 22:57:38 +00:00
|
|
|
mem::forget(meth);
|
2017-05-17 06:43:39 +00:00
|
|
|
} else {
|
|
|
|
type_object.tp_as_sequence = 0 as *mut ffi::PySequenceMethods;
|
|
|
|
}
|
2017-05-16 18:58:18 +00:00
|
|
|
|
2017-05-17 06:43:39 +00:00
|
|
|
// async methods
|
2017-05-18 01:25:26 +00:00
|
|
|
if let Some(meth) = <T as class::async::PyAsyncProtocolImpl>::tp_as_async() {
|
2017-05-17 06:43:39 +00:00
|
|
|
static mut ASYNC_METHODS: ffi::PyAsyncMethods = ffi::PyAsyncMethods_INIT;
|
|
|
|
*(unsafe { &mut ASYNC_METHODS }) = meth;
|
|
|
|
type_object.tp_as_async = unsafe { &mut ASYNC_METHODS };
|
2017-05-18 22:57:38 +00:00
|
|
|
mem::forget(meth);
|
2017-05-17 06:43:39 +00:00
|
|
|
} else {
|
|
|
|
type_object.tp_as_async = 0 as *mut ffi::PyAsyncMethods;
|
|
|
|
}
|
2017-05-16 18:58:18 +00:00
|
|
|
|
2017-05-17 06:43:39 +00:00
|
|
|
// buffer protocol
|
2017-05-25 05:43:07 +00:00
|
|
|
if let Some(meth) = ffi::PyBufferProcs::new::<T>() {
|
2017-05-17 06:43:39 +00:00
|
|
|
static mut BUFFER_PROCS: ffi::PyBufferProcs = ffi::PyBufferProcs_INIT;
|
|
|
|
*(unsafe { &mut BUFFER_PROCS }) = meth;
|
|
|
|
type_object.tp_as_buffer = unsafe { &mut BUFFER_PROCS };
|
2017-05-18 22:57:38 +00:00
|
|
|
mem::forget(meth);
|
2017-05-17 06:43:39 +00:00
|
|
|
} else {
|
|
|
|
type_object.tp_as_buffer = 0 as *mut ffi::PyBufferProcs;
|
|
|
|
}
|
2017-05-16 18:58:18 +00:00
|
|
|
|
2017-05-17 06:43:39 +00:00
|
|
|
// normal methods
|
2017-05-20 06:14:59 +00:00
|
|
|
let (new, call, mut methods) = py_class_method_defs::<T>();
|
2017-05-17 06:43:39 +00:00
|
|
|
if !methods.is_empty() {
|
|
|
|
methods.push(ffi::PyMethodDef_INIT);
|
|
|
|
type_object.tp_methods = methods.as_ptr() as *mut _;
|
2017-05-16 18:58:18 +00:00
|
|
|
|
2017-05-17 06:43:39 +00:00
|
|
|
static mut METHODS: *const ffi::PyMethodDef = 0 as *const _;
|
|
|
|
*(unsafe { &mut METHODS }) = methods.as_ptr();
|
2017-05-18 22:57:38 +00:00
|
|
|
|
|
|
|
mem::forget(methods);
|
2017-05-17 06:43:39 +00:00
|
|
|
}
|
2017-05-20 06:14:59 +00:00
|
|
|
// __new__ method
|
|
|
|
type_object.tp_new = new;
|
|
|
|
// __call__ method
|
|
|
|
type_object.tp_call = call;
|
2017-05-16 18:58:18 +00:00
|
|
|
|
2017-05-17 06:43:39 +00:00
|
|
|
// properties
|
|
|
|
let mut props = py_class_properties::<T>();
|
|
|
|
if !props.is_empty() {
|
|
|
|
props.push(ffi::PyGetSetDef_INIT);
|
|
|
|
let props = props.into_boxed_slice();
|
|
|
|
type_object.tp_getset = props.as_ptr() as *mut _;
|
2017-05-16 18:58:18 +00:00
|
|
|
|
2017-05-17 06:43:39 +00:00
|
|
|
static mut PROPS: *const ffi::PyGetSetDef = 0 as *const _;
|
|
|
|
*(unsafe { &mut PROPS }) = props.as_ptr();
|
2017-05-16 18:58:18 +00:00
|
|
|
|
2017-05-17 06:43:39 +00:00
|
|
|
// strange
|
|
|
|
mem::forget(props);
|
2017-05-26 21:43:28 +00:00
|
|
|
}*/
|
2017-05-16 18:58:18 +00:00
|
|
|
|
2017-05-17 06:43:39 +00:00
|
|
|
// register type object
|
|
|
|
unsafe {
|
|
|
|
if ffi::PyType_Ready(type_object) == 0 {
|
|
|
|
Ok(PyType::from_type_ptr(py, type_object))
|
|
|
|
} else {
|
|
|
|
Err(PyErr::fetch(py))
|
2017-05-16 18:58:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-25 03:31:51 +00:00
|
|
|
|
2017-05-22 05:22:45 +00:00
|
|
|
unsafe extern "C" fn tp_dealloc_callback<T>(obj: *mut ffi::PyObject)
|
2017-05-23 06:45:28 +00:00
|
|
|
where T: PyTypeInfo
|
2017-05-16 18:58:18 +00:00
|
|
|
{
|
2017-05-25 03:31:51 +00:00
|
|
|
println!("DEALLOC: {:?}", obj);
|
2017-05-16 18:58:18 +00:00
|
|
|
let guard = AbortOnDrop("Cannot unwind out of tp_dealloc");
|
|
|
|
let py = Python::assume_gil_acquired();
|
2017-05-25 03:31:51 +00:00
|
|
|
let r = <T as PyObjectAlloc>::dealloc(&py, obj);
|
2017-05-16 18:58:18 +00:00
|
|
|
mem::forget(guard);
|
|
|
|
r
|
|
|
|
}
|
|
|
|
|
2017-05-20 06:14:59 +00:00
|
|
|
fn py_class_method_defs<T>() -> (Option<ffi::newfunc>,
|
|
|
|
Option<ffi::PyCFunctionWithKeywords>,
|
|
|
|
Vec<ffi::PyMethodDef>) {
|
2017-05-16 18:58:18 +00:00
|
|
|
let mut defs = Vec::new();
|
2017-05-20 06:14:59 +00:00
|
|
|
let mut call = None;
|
|
|
|
let mut new = None;
|
2017-05-16 18:58:18 +00:00
|
|
|
|
|
|
|
for def in <T as class::methods::PyMethodsProtocolImpl>::py_methods() {
|
|
|
|
match def {
|
2017-05-20 06:14:59 +00:00
|
|
|
&PyMethodDefType::New(ref def) => {
|
|
|
|
if let class::methods::PyMethodType::PyNewFunc(meth) = def.ml_meth {
|
|
|
|
new = Some(meth)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
&PyMethodDefType::Call(ref def) => {
|
|
|
|
if let class::methods::PyMethodType::PyCFunctionWithKeywords(meth) = def.ml_meth {
|
|
|
|
call = Some(meth)
|
|
|
|
} else {
|
|
|
|
panic!("Method type is not supoorted by tp_call slot")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
&PyMethodDefType::Method(ref def) => {
|
|
|
|
defs.push(def.as_method_def())
|
|
|
|
}
|
2017-05-16 18:58:18 +00:00
|
|
|
_ => (),
|
|
|
|
}
|
|
|
|
}
|
2017-05-26 21:43:28 +00:00
|
|
|
/*
|
2017-05-21 05:18:31 +00:00
|
|
|
for def in <T as class::basic::PyObjectProtocolImpl>::methods() {
|
|
|
|
defs.push(def.as_method_def())
|
|
|
|
}
|
2017-05-19 18:48:05 +00:00
|
|
|
for def in <T as class::async::PyAsyncProtocolImpl>::methods() {
|
|
|
|
defs.push(def.as_method_def())
|
|
|
|
}
|
2017-05-20 06:14:59 +00:00
|
|
|
for def in <T as class::context::PyContextProtocolImpl>::methods() {
|
|
|
|
defs.push(def.as_method_def())
|
2017-05-20 19:15:28 +00:00
|
|
|
}
|
|
|
|
for def in <T as class::mapping::PyMappingProtocolImpl>::methods() {
|
|
|
|
defs.push(def.as_method_def())
|
2017-05-21 05:18:31 +00:00
|
|
|
}
|
|
|
|
for def in <T as class::number::PyNumberProtocolImpl>::methods() {
|
|
|
|
defs.push(def.as_method_def())
|
|
|
|
}
|
|
|
|
for def in <T as class::descr::PyDescrProtocolImpl>::methods() {
|
|
|
|
defs.push(def.as_method_def())
|
2017-05-26 21:43:28 +00:00
|
|
|
}*/
|
2017-05-16 18:58:18 +00:00
|
|
|
|
2017-05-20 06:14:59 +00:00
|
|
|
(new, call, defs)
|
2017-05-16 18:58:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn py_class_properties<T>() -> Vec<ffi::PyGetSetDef> {
|
|
|
|
let mut defs = HashMap::new();
|
|
|
|
|
|
|
|
for def in <T as class::methods::PyMethodsProtocolImpl>::py_methods() {
|
|
|
|
match def {
|
|
|
|
&PyMethodDefType::Getter(ref getter) => {
|
|
|
|
let name = getter.name.to_string();
|
|
|
|
if !defs.contains_key(&name) {
|
|
|
|
let _ = defs.insert(name.clone(), ffi::PyGetSetDef_INIT);
|
|
|
|
}
|
|
|
|
let def = defs.get_mut(&name).unwrap();
|
|
|
|
getter.copy_to(def);
|
|
|
|
},
|
|
|
|
&PyMethodDefType::Setter(ref setter) => {
|
|
|
|
let name = setter.name.to_string();
|
|
|
|
if !defs.contains_key(&name) {
|
|
|
|
let _ = defs.insert(name.clone(), ffi::PyGetSetDef_INIT);
|
|
|
|
}
|
|
|
|
let def = defs.get_mut(&name).unwrap();
|
|
|
|
setter.copy_to(def);
|
|
|
|
},
|
|
|
|
_ => (),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
defs.values().map(|i| i.clone()).collect()
|
2017-05-25 05:43:07 +00:00
|
|
|
}
|