Don't flatten the rustobject module + started implementing the py_class!() macro.
This commit is contained in:
parent
506443210a
commit
acc5712536
|
@ -51,6 +51,13 @@ stamps/test-custom_type: custom_type.out
|
||||||
@grep "a() was called with self=42" custom_type.out >/dev/null
|
@grep "a() was called with self=42" custom_type.out >/dev/null
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
custom_class.out: custom_class.so
|
||||||
|
python$(PY) -c "import custom_class; custom_class.MyType(42).a()" 2>&1 | tee $@
|
||||||
|
|
||||||
|
all: stamps/test-custom_class
|
||||||
|
stamps/test-custom_class: custom_class.out
|
||||||
|
@grep "a() was called with self=42" custom_class.out >/dev/null
|
||||||
|
|
||||||
all: inheritance.so
|
all: inheritance.so
|
||||||
|
|
||||||
|
|
||||||
|
|
33
extensions/custom_class.rs
Normal file
33
extensions/custom_class.rs
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
#![crate_type = "dylib"]
|
||||||
|
#![feature(const_fn)]
|
||||||
|
|
||||||
|
#![feature(trace_macros)]
|
||||||
|
|
||||||
|
#[macro_use] extern crate cpython;
|
||||||
|
|
||||||
|
use cpython::{Python, PyObject, PyRustObject, PyRustType, PyResult, GILProtected};
|
||||||
|
use std::cell::RefCell;
|
||||||
|
|
||||||
|
static MY_TYPE: GILProtected<RefCell<Option<PyRustType<i32>>>> = GILProtected::new(RefCell::new(None));
|
||||||
|
|
||||||
|
py_module_initializer!(custom_type, initcustom_type, PyInit_custom_type, |py, m| {
|
||||||
|
try!(m.add(py, "__doc__", "Module documentation string"));
|
||||||
|
try!(m.add_class::<MyType>(py));
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
|
||||||
|
trace_macros!(true);
|
||||||
|
|
||||||
|
py_class!(class MyType, data: i32, |py| {
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
fn new(py: Python, arg: i32) -> PyResult<PyRustObject<i32>> {
|
||||||
|
Ok(MY_TYPE.get(py).borrow().as_ref().unwrap().create_instance(py, arg, ()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn a(py: Python, slf: &PyRustObject<i32>) -> PyResult<PyObject> {
|
||||||
|
println!("a() was called with self={:?}", slf.get(py));
|
||||||
|
Ok(py.None())
|
||||||
|
}
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
|
|
||||||
#[macro_use] extern crate cpython;
|
#[macro_use] extern crate cpython;
|
||||||
|
|
||||||
use cpython::{Python, PyObject, PyRustObject, PyRustType, PyResult, GILProtected};
|
use cpython::{Python, PyObject, PyResult, GILProtected};
|
||||||
|
use cpython::rustobject::{PyRustType, PyRustObject};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
|
||||||
static MY_TYPE: GILProtected<RefCell<Option<PyRustType<i32>>>> = GILProtected::new(RefCell::new(None));
|
static MY_TYPE: GILProtected<RefCell<Option<PyRustType<i32>>>> = GILProtected::new(RefCell::new(None));
|
||||||
|
|
|
@ -20,7 +20,7 @@ use std::{mem, ptr};
|
||||||
use python::{Python, PythonObject};
|
use python::{Python, PythonObject};
|
||||||
use objects::{PyObject, PyTuple, PyDict, PyString, exc};
|
use objects::{PyObject, PyTuple, PyDict, PyString, exc};
|
||||||
use conversion::ToPyObject;
|
use conversion::ToPyObject;
|
||||||
use rustobject::typebuilder;
|
use rustobject::{PyRustTypeBuilder, TypeConstructor};
|
||||||
use ffi;
|
use ffi;
|
||||||
use err::{self, PyResult};
|
use err::{self, PyResult};
|
||||||
|
|
||||||
|
@ -173,7 +173,7 @@ impl ToPyObject for PyFn {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl typebuilder::TypeConstructor for PyFn {
|
unsafe impl TypeConstructor for PyFn {
|
||||||
fn tp_new(&self) -> ffi::newfunc {
|
fn tp_new(&self) -> ffi::newfunc {
|
||||||
unsafe {
|
unsafe {
|
||||||
mem::transmute::<ffi::PyCFunction, ffi::newfunc>((*self.0).ml_meth.unwrap())
|
mem::transmute::<ffi::PyCFunction, ffi::newfunc>((*self.0).ml_meth.unwrap())
|
||||||
|
|
|
@ -93,12 +93,10 @@ extern crate python3_sys as ffi;
|
||||||
pub use ffi::Py_ssize_t;
|
pub use ffi::Py_ssize_t;
|
||||||
pub use err::{PyErr, PyResult};
|
pub use err::{PyErr, PyResult};
|
||||||
pub use objects::*;
|
pub use objects::*;
|
||||||
pub use python::{Python, PythonObject, PythonObjectWithCheckedDowncast, PythonObjectWithTypeObject, PyClone, PyDrop};
|
pub use python::{Python, PythonObject, PythonObjectWithCheckedDowncast, PythonObjectDowncastError, PythonObjectWithTypeObject, PyClone, PyDrop};
|
||||||
pub use pythonrun::{GILGuard, GILProtected, prepare_freethreaded_python};
|
pub use pythonrun::{GILGuard, GILProtected, prepare_freethreaded_python};
|
||||||
pub use conversion::{ExtractPyObject, ToPyObject};
|
pub use conversion::{ExtractPyObject, ToPyObject};
|
||||||
pub use objectprotocol::{ObjectProtocol};
|
pub use objectprotocol::{ObjectProtocol};
|
||||||
pub use rustobject::{PyRustType, PyRustObject};
|
|
||||||
pub use rustobject::typebuilder::PyRustTypeBuilder;
|
|
||||||
|
|
||||||
#[cfg(feature="python27-sys")]
|
#[cfg(feature="python27-sys")]
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
|
@ -128,7 +126,7 @@ mod objectprotocol;
|
||||||
mod pythonrun;
|
mod pythonrun;
|
||||||
pub mod argparse;
|
pub mod argparse;
|
||||||
mod function;
|
mod function;
|
||||||
mod rustobject;
|
pub mod rustobject;
|
||||||
|
|
||||||
/// Private re-exports for macros. Do not use.
|
/// Private re-exports for macros. Do not use.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
@ -142,7 +140,6 @@ pub mod _detail {
|
||||||
pub use abort_on_panic::PanicGuard;
|
pub use abort_on_panic::PanicGuard;
|
||||||
pub use err::from_owned_ptr_or_panic;
|
pub use err::from_owned_ptr_or_panic;
|
||||||
pub use function::{get_kwargs, result_to_ptr, py_fn_impl};
|
pub use function::{get_kwargs, result_to_ptr, py_fn_impl};
|
||||||
pub use rustobject::method::{py_method_impl, py_class_method_impl};
|
|
||||||
|
|
||||||
/// assume_gil_acquired(), but the returned Python<'p> is bounded by the scope
|
/// assume_gil_acquired(), but the returned Python<'p> is bounded by the scope
|
||||||
/// of the referenced variable.
|
/// of the referenced variable.
|
||||||
|
|
|
@ -109,9 +109,9 @@ impl PyModule {
|
||||||
/// This is a convenience function that creates a new `PyRustTypeBuilder` and
|
/// This is a convenience function that creates a new `PyRustTypeBuilder` and
|
||||||
/// sets `new_type.__module__` to this module's name.
|
/// sets `new_type.__module__` to this module's name.
|
||||||
/// The new type will be added to this module when `finish()` is called on the builder.
|
/// The new type will be added to this module when `finish()` is called on the builder.
|
||||||
pub fn add_type<'p, T>(&self, py: Python<'p>, name: &str) -> ::rustobject::typebuilder::PyRustTypeBuilder<'p, T>
|
pub fn add_type<'p, T>(&self, py: Python<'p>, name: &str) -> ::rustobject::PyRustTypeBuilder<'p, T>
|
||||||
where T: 'static + Send {
|
where T: 'static + Send {
|
||||||
::rustobject::typebuilder::new_typebuilder_for_module(py, self, name)
|
::rustobject::new_typebuilder_for_module(py, self, name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
235
src/rustobject/class.rs
Normal file
235
src/rustobject/class.rs
Normal file
|
@ -0,0 +1,235 @@
|
||||||
|
// Copyright (c) 2016 Daniel Grunwald
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||||
|
// software and associated documentation files (the "Software"), to deal in the Software
|
||||||
|
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
||||||
|
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
||||||
|
// to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in all copies or
|
||||||
|
// substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||||
|
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||||
|
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||||
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
use python::{self, Python};
|
||||||
|
use objects::PyType;
|
||||||
|
use err::PyResult;
|
||||||
|
|
||||||
|
/// Trait implemented by the types produced by the `py_class!()` macro.
|
||||||
|
pub trait PythonObjectFromPyClassMacro : python::PythonObjectWithTypeObject {
|
||||||
|
fn initialize(py: Python) -> PyResult<PyType>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
# Example
|
||||||
|
```
|
||||||
|
#[macro_use] extern crate cpython;
|
||||||
|
use cpython::Python;
|
||||||
|
|
||||||
|
py_class!(pub class MyType, data: i32, |py| {
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let gil = Python::acquire_gil();
|
||||||
|
let py = gil.python();
|
||||||
|
let type_obj = py.get_type::<MyType>();
|
||||||
|
MyType::create_instance(py, 42);
|
||||||
|
}
|
||||||
|
``` */
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! py_class {
|
||||||
|
(pub class $name:ident, $data_name:ident : $data_ty:ty, |$py: ident| { $( $body:tt )* }) => (
|
||||||
|
pub struct $name($crate::rustobject::PyRustObject<$data_ty>);
|
||||||
|
py_class_impl!($name, $data_name: $data_ty,
|
||||||
|
($data_name: $data_ty),
|
||||||
|
($data_name, ()),
|
||||||
|
|$py| { $( $body )* });
|
||||||
|
);
|
||||||
|
(pub class $name:ident($base:ty), $data_name:ident : $data_ty:ty, |$py: ident| { $( $body:tt )* }) => (
|
||||||
|
pub struct $name($crate::rustobject::PyRustObject<$data_ty, $base>);
|
||||||
|
py_class_impl!($name, $data_name: $data_ty,
|
||||||
|
($data_name: $data_ty, base_data: <$base as $crate::rustobject::BaseObject>::InitType),
|
||||||
|
($data_name, base_data),
|
||||||
|
|$py| { $( $body )* });
|
||||||
|
);
|
||||||
|
(class $name:ident, $data_name:ident : $data_ty:ty, |$py: ident| { $( $body:tt )* }) => (
|
||||||
|
struct $name($crate::rustobject::PyRustObject<$data_ty>);
|
||||||
|
py_class_impl!($name, $data_name: $data_ty,
|
||||||
|
($data_name: $data_ty),
|
||||||
|
($data_name, ()),
|
||||||
|
|$py| { $( $body )* });
|
||||||
|
);
|
||||||
|
(class $name:ident($base:ty), $data_name:ident : $data_ty:ty, |$py: ident| { $( $body:tt )* }) => (
|
||||||
|
struct $name($crate::rustobject::PyRustObject<$data_ty, $base>);
|
||||||
|
py_class_impl!($name, $data_name: $data_ty,
|
||||||
|
($data_name: $data_ty, base_data: <$base as $crate::rustobject::BaseObject>::InitType),
|
||||||
|
($data_name, base_data),
|
||||||
|
|$py| { $( $body )* });
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
#[doc(hidden)]
|
||||||
|
macro_rules! py_class_impl {
|
||||||
|
(
|
||||||
|
$name:ident,
|
||||||
|
$data_name:ident : $data_ty:ty,
|
||||||
|
( $( $param_name:ident : $param_ty:ty ),* ),
|
||||||
|
$init_val:expr,
|
||||||
|
|$py: ident| { $( $body:tt )* }
|
||||||
|
) => (
|
||||||
|
impl $name {
|
||||||
|
pub fn $data_name<'a>(&'a self, py: $crate::Python<'a>) -> &'a $data_ty {
|
||||||
|
self.0.get(py)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_instance(py: $crate::Python, $( $param_name : $param_ty ),* ) -> $name {
|
||||||
|
// hide statics in create_instance to avoid name conflicts
|
||||||
|
static mut type_ptr: *mut $crate::_detail::ffi::PyTypeObject = 0 as *mut _;
|
||||||
|
static mut init_active: bool = false;
|
||||||
|
py_class_impl_py_object!($name, type_ptr);
|
||||||
|
|
||||||
|
impl $crate::rustobject::PythonObjectFromPyClassMacro for $name {
|
||||||
|
fn initialize(py: Python) -> $crate::PyResult<$crate::PyType> {
|
||||||
|
unsafe {
|
||||||
|
if !type_ptr.is_null() {
|
||||||
|
return Ok(py.get_type::<$name>());
|
||||||
|
}
|
||||||
|
assert!(!init_active, "Reentrancy detected: already initializing class $name");
|
||||||
|
init_active = true;
|
||||||
|
let result = init(py);
|
||||||
|
if let Ok(ref ty) = result {
|
||||||
|
type_ptr = ty.as_type_ptr();
|
||||||
|
}
|
||||||
|
init_active = false;
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn init($py: Python) -> $crate::PyResult<$crate::PyType> {
|
||||||
|
let b = $crate::rustobject::PyRustTypeBuilder::<$name>::new(
|
||||||
|
$py, stringify!($name));
|
||||||
|
//let b = b.base(); TODO inheritance
|
||||||
|
//py_class_parse_body!($py, b, $( $body )* );
|
||||||
|
///b.finish()
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
py_class_create_instance_impl!(py, $name, $init_val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
#[doc(hidden)]
|
||||||
|
macro_rules! py_class_create_instance_impl {
|
||||||
|
($py: expr, $name: ident, $data: expr) => {{
|
||||||
|
let type_obj = $py.get_type::<$name>();
|
||||||
|
let obj = unsafe { $crate::rustobject::BaseObject::alloc($py, &type_obj, $data) };
|
||||||
|
$crate::PyDrop::release_ref(type_obj, $py);
|
||||||
|
$name(obj.expect("Allocation failed"))
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
#[doc(hidden)]
|
||||||
|
macro_rules! py_class_impl_py_object {
|
||||||
|
($name:ident, $type_obj:expr) => (
|
||||||
|
impl $crate::PythonObject for $name {
|
||||||
|
#[inline]
|
||||||
|
fn as_object(&self) -> &$crate::PyObject {
|
||||||
|
$crate::PythonObject::as_object(&self.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn into_object(self) -> $crate::PyObject {
|
||||||
|
$crate::PythonObject::into_object(self.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unchecked downcast from PyObject to Self.
|
||||||
|
/// Undefined behavior if the input object does not have the expected type.
|
||||||
|
#[inline]
|
||||||
|
unsafe fn unchecked_downcast_from(obj: $crate::PyObject) -> Self {
|
||||||
|
$name($crate::PythonObject::unchecked_downcast_from(obj))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unchecked downcast from PyObject to Self.
|
||||||
|
/// Undefined behavior if the input object does not have the expected type.
|
||||||
|
#[inline]
|
||||||
|
unsafe fn unchecked_downcast_borrow_from<'a>(obj: &'a $crate::PyObject) -> &'a Self {
|
||||||
|
::std::mem::transmute(obj)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl $crate::PythonObjectWithCheckedDowncast for $name {
|
||||||
|
fn downcast_from<'p>(py: $crate::Python<'p>, obj: $crate::PyObject) -> Result<$name, $crate::PythonObjectDowncastError<'p>> {
|
||||||
|
unsafe {
|
||||||
|
if $crate::_detail::ffi::PyObject_TypeCheck(obj.as_ptr(), type_ptr) != 0 {
|
||||||
|
Ok($name($crate::PythonObject::unchecked_downcast_from(obj)))
|
||||||
|
} else {
|
||||||
|
Err($crate::PythonObjectDowncastError(py))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn downcast_borrow_from<'a, 'p>(py: $crate::Python<'p>, obj: &'a $crate::PyObject) -> Result<&'a $name, $crate::PythonObjectDowncastError<'p>> {
|
||||||
|
unsafe {
|
||||||
|
if $crate::_detail::ffi::PyObject_TypeCheck(obj.as_ptr(), type_ptr) != 0 {
|
||||||
|
Ok(::std::mem::transmute(obj))
|
||||||
|
} else {
|
||||||
|
Err($crate::PythonObjectDowncastError(py))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl $crate::PythonObjectWithTypeObject for $name {
|
||||||
|
fn type_object(py: $crate::Python) -> $crate::PyType {
|
||||||
|
unsafe {
|
||||||
|
if type_ptr.is_null() {
|
||||||
|
// automatically initialize the class on-demand
|
||||||
|
<$name as $crate::rustobject::PythonObjectFromPyClassMacro>::initialize(py).unwrap()
|
||||||
|
} else {
|
||||||
|
$crate::PyType::from_type_ptr(py, type_ptr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl $crate::ToPyObject for $name {
|
||||||
|
type ObjectType = $name;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn to_py_object(&self, py: $crate::Python) -> $name {
|
||||||
|
$crate::PyClone::clone_ref(self, py)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn into_py_object(self, _py: $crate::Python) -> $name {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn with_borrowed_ptr<F, R>(&self, _py: $crate::Python, f: F) -> R
|
||||||
|
where F: FnOnce(*mut $crate::_detail::ffi::PyObject) -> R
|
||||||
|
{
|
||||||
|
f($crate::PythonObject::as_object(&self.0).as_ptr())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
#[doc(hidden)]
|
||||||
|
macro_rules! py_class_parse_body {
|
||||||
|
() => (
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -76,9 +76,9 @@ macro_rules! py_method_wrap {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// #[macro_use] extern crate cpython;
|
/// #[macro_use] extern crate cpython;
|
||||||
/// use cpython::{Python, PythonObject, PyResult, PyErr, ObjectProtocol,
|
/// use cpython::{Python, PythonObject, PyResult, PyErr, ObjectProtocol};
|
||||||
/// PyRustObject, PyRustTypeBuilder};
|
|
||||||
/// use cpython::{exc};
|
/// use cpython::{exc};
|
||||||
|
/// use cpython::rustobject::{PyRustObject, PyRustTypeBuilder};
|
||||||
///
|
///
|
||||||
/// fn mul(py: Python, slf: &PyRustObject<i32>, arg: i32) -> PyResult<i32> {
|
/// fn mul(py: Python, slf: &PyRustObject<i32>, arg: i32) -> PyResult<i32> {
|
||||||
/// match slf.get(py).checked_mul(arg) {
|
/// match slf.get(py).checked_mul(arg) {
|
||||||
|
@ -106,7 +106,7 @@ macro_rules! py_method {
|
||||||
$f(py, slf, args, kwargs)
|
$f(py, slf, args, kwargs)
|
||||||
});
|
});
|
||||||
unsafe {
|
unsafe {
|
||||||
$crate::_detail::py_method_impl::py_method_impl(
|
$crate::rustobject::py_method_impl::py_method_impl(
|
||||||
py_method_def!($f, 0, wrap), $f)
|
py_method_def!($f, 0, wrap), $f)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -124,6 +124,7 @@ macro_rules! py_method {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return value of `py_method!()` macro.
|
||||||
pub struct MethodDescriptor<T>(*mut ffi::PyMethodDef, marker::PhantomData<fn(&T)>);
|
pub struct MethodDescriptor<T>(*mut ffi::PyMethodDef, marker::PhantomData<fn(&T)>);
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
@ -148,15 +149,15 @@ pub mod py_method_impl {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
macro_rules! py_method_call_impl {
|
macro_rules! py_method_call_impl {
|
||||||
( $def:expr, $f:ident ( ) )
|
( $def:expr, $f:ident ( ) )
|
||||||
=> { $crate::_detail::py_method_impl::py_method_impl_0($def, $f) };
|
=> { $crate::rustobject::py_method_impl::py_method_impl_0($def, $f) };
|
||||||
( $def:expr, $f:ident ( $n1:ident : $t1:ty ) )
|
( $def:expr, $f:ident ( $n1:ident : $t1:ty ) )
|
||||||
=> { $crate::_detail::py_method_impl::py_method_impl_1($def, $f) };
|
=> { $crate::rustobject::py_method_impl::py_method_impl_1($def, $f) };
|
||||||
( $def:expr, $f:ident ( $n1:ident : $t1:ty, $n2:ident : $t2:ty ) )
|
( $def:expr, $f:ident ( $n1:ident : $t1:ty, $n2:ident : $t2:ty ) )
|
||||||
=> { $crate::_detail::py_method_impl::py_method_impl_2($def, $f) };
|
=> { $crate::rustobject::py_method_impl::py_method_impl_2($def, $f) };
|
||||||
( $def:expr, $f:ident ( $n1:ident : $t1:ty, $n2:ident : $t2:ty, $n3:ident : $t3:ty ) )
|
( $def:expr, $f:ident ( $n1:ident : $t1:ty, $n2:ident : $t2:ty, $n3:ident : $t3:ty ) )
|
||||||
=> { $crate::_detail::py_method_impl::py_method_impl_3($def, $f) };
|
=> { $crate::rustobject::py_method_impl::py_method_impl_3($def, $f) };
|
||||||
( $def:expr, $f:ident ( $n1:ident : $t1:ty, $n2:ident : $t2:ty, $n3:ident : $t3:ty, $n4:ident : $t4:ty ) )
|
( $def:expr, $f:ident ( $n1:ident : $t1:ty, $n2:ident : $t2:ty, $n3:ident : $t3:ty, $n4:ident : $t4:ty ) )
|
||||||
=> { $crate::_detail::py_method_impl::py_method_impl_4($def, $f) };
|
=> { $crate::rustobject::py_method_impl::py_method_impl_4($def, $f) };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn py_method_impl_0<T, R>(
|
pub unsafe fn py_method_impl_0<T, R>(
|
||||||
|
@ -258,8 +259,8 @@ macro_rules! py_class_method_wrap {
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// #[macro_use] extern crate cpython;
|
/// #[macro_use] extern crate cpython;
|
||||||
/// use cpython::{Python, PythonObject, PyResult, ObjectProtocol, PyType,
|
/// use cpython::{Python, PythonObject, PyResult, ObjectProtocol, PyType, NoArgs};
|
||||||
/// PyRustTypeBuilder, NoArgs};
|
/// use cpython::rustobject::PyRustTypeBuilder;
|
||||||
///
|
///
|
||||||
/// fn method(py: Python, cls: &PyType) -> PyResult<i32> {
|
/// fn method(py: Python, cls: &PyType) -> PyResult<i32> {
|
||||||
/// Ok(42)
|
/// Ok(42)
|
||||||
|
@ -282,7 +283,7 @@ macro_rules! py_class_method {
|
||||||
$f(py, cls, args, kwargs)
|
$f(py, cls, args, kwargs)
|
||||||
});
|
});
|
||||||
unsafe {
|
unsafe {
|
||||||
$crate::_detail::py_class_method_impl(
|
$crate::rustobject::py_class_method_impl(
|
||||||
py_method_def!($f, $crate::_detail::ffi::METH_CLASS, wrap))
|
py_method_def!($f, $crate::_detail::ffi::METH_CLASS, wrap))
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -292,15 +293,17 @@ macro_rules! py_class_method {
|
||||||
( $($pname : $ptype),* ) { $f( py, cls, $($pname),* ) })
|
( $($pname : $ptype),* ) { $f( py, cls, $($pname),* ) })
|
||||||
});
|
});
|
||||||
unsafe {
|
unsafe {
|
||||||
$crate::_detail::py_class_method_impl(
|
$crate::rustobject::py_class_method_impl(
|
||||||
py_method_def!($f, $crate::_detail::ffi::METH_CLASS, wrap))
|
py_method_def!($f, $crate::_detail::ffi::METH_CLASS, wrap))
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The return type of the `py_class_method!()` macro.
|
||||||
pub struct ClassMethodDescriptor(*mut ffi::PyMethodDef);
|
pub struct ClassMethodDescriptor(*mut ffi::PyMethodDef);
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[doc(hidden)]
|
||||||
pub unsafe fn py_class_method_impl(def: *mut ffi::PyMethodDef) -> ClassMethodDescriptor {
|
pub unsafe fn py_class_method_impl(def: *mut ffi::PyMethodDef) -> ClassMethodDescriptor {
|
||||||
ClassMethodDescriptor(def)
|
ClassMethodDescriptor(def)
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,15 +24,18 @@ use objects::{PyObject, PyType};
|
||||||
use std::{mem, ops, ptr, marker};
|
use std::{mem, ops, ptr, marker};
|
||||||
use err::{self, PyResult};
|
use err::{self, PyResult};
|
||||||
|
|
||||||
// note: because rustobject isn't public, these modules aren't visible
|
mod typebuilder;
|
||||||
// outside the crate
|
mod method;
|
||||||
pub mod typebuilder;
|
mod class;
|
||||||
pub mod method;
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
/// A PythonObject that is usable as a base type with PyTypeBuilder::base().
|
pub use self::typebuilder::*;
|
||||||
pub trait PythonBaseObject : PythonObject {
|
pub use self::method::*;
|
||||||
|
pub use self::class::*;
|
||||||
|
|
||||||
|
/// A PythonObject that is usable as a base type with `PyRustTypeBuilder::base()`.
|
||||||
|
pub trait BaseObject : PythonObject {
|
||||||
/// Gets the size of the object, in bytes.
|
/// Gets the size of the object, in bytes.
|
||||||
fn size() -> usize;
|
fn size() -> usize;
|
||||||
|
|
||||||
|
@ -50,7 +53,7 @@ pub trait PythonBaseObject : PythonObject {
|
||||||
unsafe fn dealloc(py: Python, ptr: *mut ffi::PyObject);
|
unsafe fn dealloc(py: Python, ptr: *mut ffi::PyObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PythonBaseObject for PyObject {
|
impl BaseObject for PyObject {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn size() -> usize {
|
fn size() -> usize {
|
||||||
mem::size_of::<ffi::PyObject>()
|
mem::size_of::<ffi::PyObject>()
|
||||||
|
@ -85,13 +88,13 @@ impl PythonBaseObject for PyObject {
|
||||||
/// Note that this type effectively acts like `Rc<T>`,
|
/// Note that this type effectively acts like `Rc<T>`,
|
||||||
/// except that the reference counting is done by the Python runtime.
|
/// except that the reference counting is done by the Python runtime.
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct PyRustObject<T, B = PyObject> where T: 'static + Send, B: PythonBaseObject {
|
pub struct PyRustObject<T, B = PyObject> where T: 'static + Send, B: BaseObject {
|
||||||
obj: PyObject,
|
obj: PyObject,
|
||||||
/// The PyRustObject acts like a shared reference to the contained T.
|
/// The PyRustObject acts like a shared reference to the contained T.
|
||||||
t: marker::PhantomData<&'static (T, B)>
|
t: marker::PhantomData<&'static (T, B)>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <T, B> PyRustObject<T, B> where T: 'static + Send, B: PythonBaseObject {
|
impl <T, B> PyRustObject<T, B> where T: 'static + Send, B: BaseObject {
|
||||||
#[inline] // this function can usually be reduced to a compile-time constant
|
#[inline] // this function can usually be reduced to a compile-time constant
|
||||||
fn offset() -> usize {
|
fn offset() -> usize {
|
||||||
let align = mem::align_of::<T>();
|
let align = mem::align_of::<T>();
|
||||||
|
@ -124,7 +127,7 @@ impl <T, B> PyRustObject<T, B> where T: 'static + Send, B: PythonBaseObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <T, B> PythonBaseObject for PyRustObject<T, B> where T: 'static + Send, B: PythonBaseObject {
|
impl <T, B> BaseObject for PyRustObject<T, B> where T: 'static + Send, B: BaseObject {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn size() -> usize {
|
fn size() -> usize {
|
||||||
PyRustObject::<T, B>::offset() + mem::size_of::<T>()
|
PyRustObject::<T, B>::offset() + mem::size_of::<T>()
|
||||||
|
@ -153,7 +156,7 @@ impl <T, B> PythonBaseObject for PyRustObject<T, B> where T: 'static + Send, B:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <T, B> ToPyObject for PyRustObject<T, B> where T: 'static + Send, B: PythonBaseObject {
|
impl <T, B> ToPyObject for PyRustObject<T, B> where T: 'static + Send, B: BaseObject {
|
||||||
type ObjectType = PyObject;
|
type ObjectType = PyObject;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -173,7 +176,7 @@ impl <T, B> ToPyObject for PyRustObject<T, B> where T: 'static + Send, B: Python
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <T, B> PythonObject for PyRustObject<T, B> where T: 'static + Send, B: PythonBaseObject {
|
impl <T, B> PythonObject for PyRustObject<T, B> where T: 'static + Send, B: BaseObject {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn as_object(&self) -> &PyObject {
|
fn as_object(&self) -> &PyObject {
|
||||||
&self.obj
|
&self.obj
|
||||||
|
@ -206,21 +209,22 @@ impl <T, B> PythonObject for PyRustObject<T, B> where T: 'static + Send, B: Pyth
|
||||||
/// Serves as a Python type object, and can be used to construct
|
/// Serves as a Python type object, and can be used to construct
|
||||||
/// `PyRustObject<T>` instances.
|
/// `PyRustObject<T>` instances.
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct PyRustType<T, B = PyObject> where T: 'static + Send, B: PythonBaseObject {
|
pub struct PyRustType<T, B = PyObject> where T: 'static + Send, B: BaseObject {
|
||||||
type_obj: PyType,
|
type_obj: PyType,
|
||||||
phantom: marker::PhantomData<&'static (B, T)>
|
phantom: marker::PhantomData<&'static (B, T)>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <T, B> PyRustType<T, B> where T: 'static + Send, B: PythonBaseObject {
|
impl <T, B> PyRustType<T, B> where T: 'static + Send, B: BaseObject {
|
||||||
/// Creates a PyRustObject instance from a value.
|
/// Creates a PyRustObject instance from a value.
|
||||||
pub fn create_instance(&self, py: Python, val: T, base_val: B::InitType) -> PyRustObject<T, B> {
|
pub fn create_instance(&self, py: Python, val: T, base_val: B::InitType) -> PyRustObject<T, B> {
|
||||||
unsafe {
|
unsafe {
|
||||||
PythonBaseObject::alloc(py, &self.type_obj, (val, base_val)).unwrap()
|
BaseObject::alloc(py, &self.type_obj, (val, base_val))
|
||||||
|
.expect("Allocation failure")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <T, B> ops::Deref for PyRustType<T, B> where T: 'static + Send, B: PythonBaseObject {
|
impl <T, B> ops::Deref for PyRustType<T, B> where T: 'static + Send, B: BaseObject {
|
||||||
type Target = PyType;
|
type Target = PyType;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -229,7 +233,7 @@ impl <T, B> ops::Deref for PyRustType<T, B> where T: 'static + Send, B: PythonBa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <T, B> ToPyObject for PyRustType<T, B> where T: 'static + Send, B: PythonBaseObject {
|
impl <T, B> ToPyObject for PyRustType<T, B> where T: 'static + Send, B: BaseObject {
|
||||||
type ObjectType = PyType;
|
type ObjectType = PyType;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -249,7 +253,7 @@ impl <T, B> ToPyObject for PyRustType<T, B> where T: 'static + Send, B: PythonBa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <T, B> PythonObject for PyRustType<T, B> where T: 'static + Send, B: PythonBaseObject {
|
impl <T, B> PythonObject for PyRustType<T, B> where T: 'static + Send, B: BaseObject {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn as_object(&self) -> &PyObject {
|
fn as_object(&self) -> &PyObject {
|
||||||
self.type_obj.as_object()
|
self.type_obj.as_object()
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use {Python, NoArgs, PythonObject, PyRustTypeBuilder};
|
use {Python, NoArgs, PythonObject, rustobject};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn rustobject_calls_drop() {
|
fn rustobject_calls_drop() {
|
||||||
|
@ -34,7 +34,8 @@ fn rustobject_calls_drop() {
|
||||||
|
|
||||||
let gil = Python::acquire_gil();
|
let gil = Python::acquire_gil();
|
||||||
let py = gil.python();
|
let py = gil.python();
|
||||||
let t = PyRustTypeBuilder::<MyObj>::new(py, "TypeWithDrop").finish().unwrap();
|
let t = rustobject::PyRustTypeBuilder::<MyObj>::new(py, "TypeWithDrop")
|
||||||
|
.finish().unwrap();
|
||||||
|
|
||||||
let drop_called = Arc::new(AtomicBool::new(false));
|
let drop_called = Arc::new(AtomicBool::new(false));
|
||||||
let inst = t.create_instance(py, MyObj { drop_called: drop_called.clone() }, ());
|
let inst = t.create_instance(py, MyObj { drop_called: drop_called.clone() }, ());
|
||||||
|
@ -48,7 +49,8 @@ fn rustobject_calls_drop() {
|
||||||
fn no_init_from_python() {
|
fn no_init_from_python() {
|
||||||
let gil = Python::acquire_gil();
|
let gil = Python::acquire_gil();
|
||||||
let py = gil.python();
|
let py = gil.python();
|
||||||
let t = PyRustTypeBuilder::<i32>::new(py, "MyType").finish().unwrap();
|
let t = rustobject::PyRustTypeBuilder::<i32>::new(py, "MyType")
|
||||||
|
.finish().unwrap();
|
||||||
assert!(t.call(py, &NoArgs, None).is_err());
|
assert!(t.call(py, &NoArgs, None).is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,7 +59,8 @@ fn no_init_from_python() {
|
||||||
fn heaptype_refcount() {
|
fn heaptype_refcount() {
|
||||||
let gil = Python::acquire_gil();
|
let gil = Python::acquire_gil();
|
||||||
let py = gil.python();
|
let py = gil.python();
|
||||||
let t = PyRustTypeBuilder::<i32>::new(py, "MyType").finish().unwrap();
|
let t = rustobject::PyRustTypeBuilder::<i32>::new(py, "MyType")
|
||||||
|
.finish().unwrap();
|
||||||
// TODO: investigate why the refcnt isn't 1.
|
// TODO: investigate why the refcnt isn't 1.
|
||||||
//assert_eq!(1, t.as_object().get_refcnt());
|
//assert_eq!(1, t.as_object().get_refcnt());
|
||||||
let old_refcnt = t.as_object().get_refcnt(py);
|
let old_refcnt = t.as_object().get_refcnt(py);
|
||||||
|
|
|
@ -20,16 +20,16 @@ use std::{ptr, mem, marker};
|
||||||
use std::ffi::{CStr, CString};
|
use std::ffi::{CStr, CString};
|
||||||
use libc;
|
use libc;
|
||||||
use ffi;
|
use ffi;
|
||||||
use python::{Python, ToPythonPointer, PythonObject, PyClone};
|
use python::{self, Python, ToPythonPointer, PythonObject, PyClone};
|
||||||
use conversion::ToPyObject;
|
use conversion::ToPyObject;
|
||||||
use objects::{PyObject, PyType, PyString, PyModule, PyDict};
|
use objects::{PyObject, PyType, PyString, PyModule, PyDict};
|
||||||
use err::{self, PyResult};
|
use err::{self, PyResult};
|
||||||
use objectprotocol::ObjectProtocol;
|
use objectprotocol::ObjectProtocol;
|
||||||
use super::{PythonBaseObject, PyRustObject, PyRustType, method};
|
use super::{BaseObject, PyRustObject, PyRustType, method};
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub struct PyRustTypeBuilder<'p, T, B = PyObject> where T: 'static + Send, B: PythonBaseObject {
|
pub struct PyRustTypeBuilder<'p, T, B = PyObject> where T: 'static + Send, B: BaseObject {
|
||||||
// In Python 2.7, we can create a new PyHeapTypeObject and fill it.
|
// In Python 2.7, we can create a new PyHeapTypeObject and fill it.
|
||||||
|
|
||||||
/// The python type object under construction.
|
/// The python type object under construction.
|
||||||
|
@ -84,7 +84,7 @@ unsafe extern "C" fn disabled_tp_new_callback
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe extern "C" fn tp_dealloc_callback<T, B>(obj: *mut ffi::PyObject)
|
unsafe extern "C" fn tp_dealloc_callback<T, B>(obj: *mut ffi::PyObject)
|
||||||
where T: 'static + Send, B: PythonBaseObject {
|
where T: 'static + Send, B: BaseObject {
|
||||||
abort_on_panic!({
|
abort_on_panic!({
|
||||||
let py = Python::assume_gil_acquired();
|
let py = Python::assume_gil_acquired();
|
||||||
PyRustObject::<T, B>::dealloc(py, obj)
|
PyRustObject::<T, B>::dealloc(py, obj)
|
||||||
|
@ -147,7 +147,7 @@ impl <'p, T> PyRustTypeBuilder<'p, T> where T: 'static + Send {
|
||||||
/// Sets the base class that this type is inheriting from.
|
/// Sets the base class that this type is inheriting from.
|
||||||
pub fn base<T2, B2>(self, base_type: &PyRustType<T2, B2>)
|
pub fn base<T2, B2>(self, base_type: &PyRustType<T2, B2>)
|
||||||
-> PyRustTypeBuilder<'p, T, PyRustObject<T2, B2>>
|
-> PyRustTypeBuilder<'p, T, PyRustObject<T2, B2>>
|
||||||
where T2: 'static + Send, B2: PythonBaseObject
|
where T2: 'static + Send, B2: BaseObject
|
||||||
{
|
{
|
||||||
// Ensure we can't change the base after any callbacks are registered.
|
// Ensure we can't change the base after any callbacks are registered.
|
||||||
assert!(self.can_change_base,
|
assert!(self.can_change_base,
|
||||||
|
@ -155,7 +155,7 @@ impl <'p, T> PyRustTypeBuilder<'p, T> where T: 'static + Send {
|
||||||
#[cfg(feature="python27-sys")]
|
#[cfg(feature="python27-sys")]
|
||||||
fn base_impl<'p, T, T2, B2>(slf: PyRustTypeBuilder<'p, T>, base_type: &PyRustType<T2, B2>)
|
fn base_impl<'p, T, T2, B2>(slf: PyRustTypeBuilder<'p, T>, base_type: &PyRustType<T2, B2>)
|
||||||
-> PyRustTypeBuilder<'p, T, PyRustObject<T2, B2>>
|
-> PyRustTypeBuilder<'p, T, PyRustObject<T2, B2>>
|
||||||
where T: 'static + Send, T2: 'static + Send, B2: PythonBaseObject
|
where T: 'static + Send, T2: 'static + Send, B2: BaseObject
|
||||||
{
|
{
|
||||||
unsafe {
|
unsafe {
|
||||||
ffi::Py_XDECREF((*slf.ht).ht_type.tp_base as *mut ffi::PyObject);
|
ffi::Py_XDECREF((*slf.ht).ht_type.tp_base as *mut ffi::PyObject);
|
||||||
|
@ -175,7 +175,7 @@ impl <'p, T> PyRustTypeBuilder<'p, T> where T: 'static + Send {
|
||||||
#[cfg(feature="python3-sys")]
|
#[cfg(feature="python3-sys")]
|
||||||
fn base_impl<'p, T, T2, B2>(slf: PyRustTypeBuilder<'p, T>, base_type: &PyRustType<T2, B2>)
|
fn base_impl<'p, T, T2, B2>(slf: PyRustTypeBuilder<'p, T>, base_type: &PyRustType<T2, B2>)
|
||||||
-> PyRustTypeBuilder<'p, T, PyRustObject<T2, B2>>
|
-> PyRustTypeBuilder<'p, T, PyRustObject<T2, B2>>
|
||||||
where T: 'static + Send, T2: 'static + Send, B2: PythonBaseObject
|
where T: 'static + Send, T2: 'static + Send, B2: BaseObject
|
||||||
{
|
{
|
||||||
let base_type_obj: &PyType = base_type;
|
let base_type_obj: &PyType = base_type;
|
||||||
return PyRustTypeBuilder {
|
return PyRustTypeBuilder {
|
||||||
|
@ -195,7 +195,7 @@ impl <'p, T> PyRustTypeBuilder<'p, T> where T: 'static + Send {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <'p, T, B> PyRustTypeBuilder<'p, T, B> where T: 'static + Send, B: PythonBaseObject {
|
impl <'p, T, B> PyRustTypeBuilder<'p, T, B> where T: 'static + Send, B: BaseObject {
|
||||||
|
|
||||||
/// Retrieves the type dictionary of the type being built.
|
/// Retrieves the type dictionary of the type being built.
|
||||||
#[cfg(feature="python27-sys")]
|
#[cfg(feature="python27-sys")]
|
||||||
|
|
Loading…
Reference in a new issue