stopping point
This commit is contained in:
parent
56d93249ab
commit
d6fb90bdc2
|
@ -17,10 +17,11 @@ pub const OBJECT: Proto = Proto {
|
|||
MethodProto::Binary {
|
||||
name: "__getattr__",
|
||||
arg: "Name",
|
||||
pyres: true,
|
||||
//pyres: true,
|
||||
pyres: false,
|
||||
proto: "_pyo3::class::basic::PyObjectGetAttrProtocol"},
|
||||
MethodProto::Ternary {
|
||||
name: "__getattr__",
|
||||
name: "__setattr__",
|
||||
arg1: "Name",
|
||||
arg2: "Value",
|
||||
pyres: true,
|
||||
|
|
|
@ -4,6 +4,7 @@ use quote::Tokens;
|
|||
// TODO:
|
||||
// Add lifetime support for args with Rptr
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum MethodProto {
|
||||
Unary{name: &'static str, pyres: bool, proto: &'static str, },
|
||||
Binary{name: &'static str, arg: &'static str, pyres: bool, proto: &'static str},
|
||||
|
@ -58,12 +59,13 @@ pub fn impl_method_proto(cls: &Box<syn::Ty>,
|
|||
MethodProto::Binary{name: _, arg, pyres, proto} => {
|
||||
let p = syn::Ident::from(proto);
|
||||
let arg_name = syn::Ident::from(arg);
|
||||
let arg_ty = get_arg_ty(sig, 2);
|
||||
//let arg_ty = get_arg_ty(sig, 2);
|
||||
let arg_ty = get_arg_ty(sig, 1);
|
||||
let succ = get_res_success(ty);
|
||||
|
||||
if pyres {
|
||||
quote! {
|
||||
impl #p for #cls {
|
||||
impl<'a'> #p<'a> for #cls {
|
||||
type #arg_name = #arg_ty;
|
||||
type Success = #succ;
|
||||
type Result = #ty;
|
||||
|
@ -71,7 +73,7 @@ pub fn impl_method_proto(cls: &Box<syn::Ty>,
|
|||
}
|
||||
} else {
|
||||
quote! {
|
||||
impl #p for #cls {
|
||||
impl<'a> #p<'a> for #cls {
|
||||
type #arg_name = #arg_ty;
|
||||
type Result = #ty;
|
||||
}
|
||||
|
|
|
@ -43,7 +43,8 @@ impl<'a> FnSpec<'a> {
|
|||
let (fn_type, fn_attrs) = parse_attributes(meth_attrs);
|
||||
|
||||
//let mut has_self = false;
|
||||
let mut py = false;
|
||||
//let mut py = false;
|
||||
let mut py = true;
|
||||
let mut arguments = Vec::new();
|
||||
|
||||
for input in sig.decl.inputs[1..].iter() {
|
||||
|
@ -74,7 +75,6 @@ impl<'a> FnSpec<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
FnSpec {
|
||||
tp: fn_type,
|
||||
attrs: fn_attrs,
|
||||
|
|
|
@ -10,22 +10,8 @@ pub fn build_py_class(ast: &mut syn::DeriveInput) -> Tokens {
|
|||
let mut tokens = Tokens::new();
|
||||
|
||||
match ast.body {
|
||||
syn::Body::Struct(syn::VariantData::Struct(ref mut data)) => {
|
||||
impl_storage(&ast.ident, &base, data).to_tokens(&mut tokens);
|
||||
|
||||
let tt = quote! {
|
||||
struct Test {
|
||||
_unsafe_inner: PyObject
|
||||
}
|
||||
};
|
||||
let t = syn::parse_item(tt.as_str()).unwrap();
|
||||
match t.node {
|
||||
syn::ItemKind::Struct(syn::VariantData::Struct(fields), _) => {
|
||||
data.clear();
|
||||
data.extend(fields);
|
||||
}
|
||||
_ => panic!("something is worng"),
|
||||
}
|
||||
syn::Body::Struct(syn::VariantData::Struct(_)) => {
|
||||
impl_storage(&ast.ident, &base).to_tokens(&mut tokens);
|
||||
},
|
||||
_ =>
|
||||
panic!("#[class] can only be used with notmal structs"),
|
||||
|
@ -49,63 +35,25 @@ pub fn build_py_class(ast: &mut syn::DeriveInput) -> Tokens {
|
|||
}
|
||||
}
|
||||
|
||||
fn impl_storage(cls: &syn::Ident, base: &syn::Ident, fields: &Vec<syn::Field>) -> Tokens {
|
||||
let names: Vec<syn::Ident> = fields.iter()
|
||||
.map(|f| f.ident.as_ref().unwrap().clone()).collect();
|
||||
let values: Vec<syn::Ident> = fields.iter()
|
||||
.map(|f| f.ident.as_ref().unwrap().clone()).collect();
|
||||
//let types: Vec<syn::Ty> = fields.iter().map(|f| f.ty.clone()).collect();
|
||||
|
||||
let storage = syn::Ident::from(format!("{}_Storage", cls).as_str());
|
||||
|
||||
let mut accessors = Tokens::new();
|
||||
for field in fields.iter() {
|
||||
let name = &field.ident.as_ref().unwrap();
|
||||
let name_mut = syn::Ident::from(format!("{}_mut", name.as_ref()));
|
||||
let ty = &field.ty;
|
||||
|
||||
let accessor = quote!{
|
||||
impl #cls {
|
||||
fn #name<'a>(&'a self, py: _pyo3::Python<'a>) -> &'a #ty {
|
||||
unsafe {
|
||||
let ptr = (self._unsafe_inner.as_ptr() as *const u8)
|
||||
.offset(base_offset() as isize) as *const #storage;
|
||||
&(*ptr).#name
|
||||
}
|
||||
}
|
||||
fn #name_mut<'a>(&'a self, py: _pyo3::Python<'a>) -> &'a mut #ty {
|
||||
unsafe {
|
||||
let ptr = (self._unsafe_inner.as_ptr() as *const u8)
|
||||
.offset(base_offset() as isize) as *mut #storage;
|
||||
&mut (*ptr).#name
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
accessor.to_tokens(&mut accessors);
|
||||
}
|
||||
|
||||
fn impl_storage(cls: &syn::Ident, base: &syn::Ident) -> Tokens {
|
||||
let cls_name = quote! { #cls }.as_str().to_string();
|
||||
|
||||
quote! {
|
||||
pub struct #storage {
|
||||
#(#fields),*
|
||||
}
|
||||
|
||||
impl #cls {
|
||||
fn create_instance(py: _pyo3::Python, #(#fields),*) -> _pyo3::PyResult<#cls> {
|
||||
let obj = try!(unsafe {
|
||||
<#cls as _pyo3::class::BaseObject>::alloc(
|
||||
py, &py.get_type::<#cls>(),
|
||||
#storage { #(#names: #values),*})});
|
||||
|
||||
return Ok(#cls { _unsafe_inner: obj });
|
||||
}
|
||||
}
|
||||
|
||||
#accessors
|
||||
|
||||
impl _pyo3::class::typeob::PyTypeObjectInfo for #cls {
|
||||
#[inline]
|
||||
fn size() -> usize {
|
||||
Self::offset() + std::mem::size_of::<#cls>()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn offset() -> usize {
|
||||
let align = std::mem::align_of::<#cls>();
|
||||
let bs = <#base as _pyo3::class::BaseObject>::size();
|
||||
|
||||
// round base_size up to next multiple of align
|
||||
(bs + align - 1) / align * align
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn type_name() -> &'static str { #cls_name }
|
||||
|
||||
|
@ -117,8 +65,8 @@ fn impl_storage(cls: &syn::Ident, base: &syn::Ident, fields: &Vec<syn::Field>) -
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn base_offset() -> usize {
|
||||
let align = std::mem::align_of::<#storage>();
|
||||
fn offset() -> usize {
|
||||
let align = std::mem::align_of::<#cls>();
|
||||
let bs = <#base as _pyo3::class::BaseObject>::size();
|
||||
|
||||
// round base_size up to next multiple of align
|
||||
|
@ -126,30 +74,46 @@ fn impl_storage(cls: &syn::Ident, base: &syn::Ident, fields: &Vec<syn::Field>) -
|
|||
}
|
||||
|
||||
impl _pyo3::class::BaseObject for #cls {
|
||||
type Type = #storage;
|
||||
type Type = #cls;
|
||||
|
||||
#[inline]
|
||||
fn size() -> usize {
|
||||
base_offset() + std::mem::size_of::<Self::Type>()
|
||||
offset() + std::mem::size_of::<Self::Type>()
|
||||
}
|
||||
|
||||
unsafe fn alloc(py: _pyo3::Python, ty: &_pyo3::PyType,
|
||||
value: Self::Type) -> _pyo3::PyResult<_pyo3::PyObject>
|
||||
unsafe fn alloc(py: _pyo3::Python,
|
||||
value: Self::Type) -> _pyo3::PyResult<*mut _pyo3::ffi::PyObject>
|
||||
{
|
||||
let obj = try!(<#base as _pyo3::class::BaseObject>::alloc(py, ty, ()));
|
||||
let ty = py.get_type::<Self::Type>();
|
||||
let obj = ffi::PyType_GenericAlloc(ty.as_type_ptr(), 0);
|
||||
|
||||
let ptr = (obj.as_ptr() as *mut u8)
|
||||
.offset(base_offset() as isize) as *mut Self::Type;
|
||||
if obj.is_null() {
|
||||
return Err(PyErr::fetch(py))
|
||||
}
|
||||
|
||||
let ptr = (obj as *mut u8).offset(offset() as isize) as *mut Self::Type;
|
||||
std::ptr::write(ptr, value);
|
||||
|
||||
Ok(obj)
|
||||
}
|
||||
|
||||
unsafe fn dealloc(py: _pyo3::Python, obj: *mut _pyo3::ffi::PyObject) {
|
||||
let ptr = (obj as *mut u8).offset(base_offset() as isize) as *mut Self::Type;
|
||||
let ptr = (obj as *mut u8).offset(offset() as isize) as *mut Self::Type;
|
||||
std::ptr::drop_in_place(ptr);
|
||||
|
||||
<#base as _pyo3::class::BaseObject>::dealloc(py, obj)
|
||||
// Unfortunately, there is no PyType_GenericFree, so
|
||||
// we have to manually un-do the work of PyType_GenericAlloc:
|
||||
let ty = _pyo3::ffi::Py_TYPE(obj);
|
||||
if _pyo3::ffi::PyType_IS_GC(ty) != 0 {
|
||||
_pyo3::ffi::PyObject_GC_Del(obj as *mut c_void);
|
||||
} else {
|
||||
_pyo3::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 _pyo3::ffi::PyType_HasFeature(ty, _pyo3::ffi::Py_TPFLAGS_HEAPTYPE) != 0 {
|
||||
_pyo3::ffi::Py_DECREF(ty as *mut _pyo3::ffi::PyObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -182,19 +146,12 @@ fn impl_to_py_object(cls: &syn::Ident) -> Tokens {
|
|||
|
||||
fn impl_from_py_object(cls: &syn::Ident) -> Tokens {
|
||||
quote! {
|
||||
impl <'source> _pyo3::FromPyObject<'source> for #cls {
|
||||
impl <'source> _pyo3::FromPyObj<'source> for &'source #cls {
|
||||
#[inline]
|
||||
fn extract(py: _pyo3::Python, obj: &'source _pyo3::PyObject)
|
||||
-> _pyo3::PyResult<#cls> {
|
||||
Ok(obj.clone_ref(py).cast_into::<#cls>(py)?)
|
||||
}
|
||||
}
|
||||
|
||||
impl <'source> _pyo3::FromPyObject<'source> for &'source #cls {
|
||||
#[inline]
|
||||
fn extract(py: _pyo3::Python, obj: &'source _pyo3::PyObject)
|
||||
-> _pyo3::PyResult<&'source #cls> {
|
||||
Ok(obj.cast_as::<#cls>(py)?)
|
||||
fn extr<S>(py: &'source _pyo3::Py<'source, S>) -> _pyo3::PyResult<&'source #cls>
|
||||
where S: _pyo3::class::typeob::PyTypeObjectInfo
|
||||
{
|
||||
Ok(py.cast_as::<#cls>()?)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -205,26 +162,54 @@ fn impl_python_object(cls: &syn::Ident) -> Tokens {
|
|||
impl _pyo3::PythonObject for #cls {
|
||||
#[inline]
|
||||
fn as_object(&self) -> &_pyo3::PyObject {
|
||||
&self._unsafe_inner
|
||||
unimplemented!();
|
||||
/*unsafe {
|
||||
let py = Python::assume_gil_acquired();
|
||||
|
||||
let ty = cls::type_object(py);
|
||||
let align = std::mem::align_of::<T>();
|
||||
let bs = <T as BaseObject>::size();
|
||||
|
||||
// round base_size up to next multiple of align
|
||||
let offset = (bs + align - 1) / align * align;
|
||||
|
||||
let ptr = (self as *mut u8).offset(-1(offset as isize)) as *mut ffi::PyObject;
|
||||
|
||||
Ok(PyObject::from_owned_ptr(py, ptr))
|
||||
}*/
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn into_object(self) -> _pyo3::PyObject {
|
||||
self._unsafe_inner
|
||||
unsafe {
|
||||
let py = Python::assume_gil_acquired();
|
||||
|
||||
let ty = #cls::type_object(py);
|
||||
let align = std::mem::align_of::<#cls>();
|
||||
let bs = <#cls as BaseObject>::size();
|
||||
|
||||
// round base_size up to next multiple of align
|
||||
let offset = (bs + align - 1) / align * align;
|
||||
|
||||
let ptr = (&self as *const _ as *mut u8).offset(
|
||||
-(offset as isize)) as *mut ffi::PyObject;
|
||||
|
||||
PyObject::from_borrowed_ptr(py, ptr)
|
||||
}
|
||||
}
|
||||
|
||||
/// 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: _pyo3::PyObject) -> Self {
|
||||
#cls { _unsafe_inner: obj }
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
/// 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 _pyo3::PyObject) -> &'a Self {
|
||||
std::mem::transmute(obj)
|
||||
unsafe fn unchecked_downcast_borrow_from<'b>(obj: &'b _pyo3::PyObject) -> &'b Self {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,9 +9,11 @@ pub fn gen_py_method<'a>(cls: &Box<syn::Ty>, name: &syn::Ident,
|
|||
sig: &mut syn::MethodSig, meth_attrs: &mut Vec<syn::Attribute>) -> Tokens
|
||||
{
|
||||
check_generic(name, sig);
|
||||
println!("====0");
|
||||
|
||||
let spec = FnSpec::parse(name, sig, meth_attrs);
|
||||
|
||||
println!("====1");
|
||||
match spec.tp {
|
||||
FnType::Fn =>
|
||||
impl_py_method_def(name, &impl_wrap(cls, name, &spec)),
|
||||
|
|
|
@ -71,6 +71,7 @@ fn impl_proto_impl(ty: &Box<syn::Ty>, impls: &mut Vec<syn::ImplItem>, proto: &de
|
|||
syn::ImplItemKind::Method(ref mut sig, _) => {
|
||||
for m in proto.methods {
|
||||
if m.eq(iimpl.ident.as_ref()) {
|
||||
println!("test: {:?} {:?}", m, ty);
|
||||
impl_method_proto(ty, sig, m).to_tokens(&mut tokens);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -196,7 +196,36 @@ impl <T> CallbackConverter<T> for HashConverter
|
|||
|
||||
|
||||
pub unsafe fn handle_callback<F, T, C>(location: &str, _c: C, f: F) -> C::R
|
||||
where F: FnOnce(Python) -> PyResult<T>,
|
||||
where F: for<'p> FnOnce(Python<'p>) -> PyResult<T>,
|
||||
F: panic::UnwindSafe,
|
||||
C: CallbackConverter<T>
|
||||
{
|
||||
let guard = AbortOnDrop(location);
|
||||
let ret = panic::catch_unwind(|| {
|
||||
let py = Python::assume_gil_acquired();
|
||||
match f(py) {
|
||||
Ok(val) => {
|
||||
C::convert(val, py)
|
||||
}
|
||||
Err(e) => {
|
||||
e.restore(py);
|
||||
C::error_value()
|
||||
}
|
||||
}
|
||||
});
|
||||
let ret = match ret {
|
||||
Ok(r) => r,
|
||||
Err(ref err) => {
|
||||
handle_panic(Python::assume_gil_acquired(), err);
|
||||
C::error_value()
|
||||
}
|
||||
};
|
||||
mem::forget(guard);
|
||||
ret
|
||||
}
|
||||
|
||||
pub unsafe fn handle_callback2<'p, F, T, C>(location: &str, _c: C, f: F) -> C::R
|
||||
where F: FnOnce(Python<'p>) -> PyResult<T>,
|
||||
F: panic::UnwindSafe,
|
||||
C: CallbackConverter<T>
|
||||
{
|
||||
|
|
|
@ -16,6 +16,7 @@ use conversion::{ToPyObject, FromPyObject};
|
|||
use callback::{handle_callback, PyObjectCallbackConverter,
|
||||
HashConverter, UnitCallbackConverter, BoolCallbackConverter};
|
||||
use class::methods::PyMethodDef;
|
||||
use ::{Py, PyPtr};
|
||||
|
||||
// classmethod
|
||||
// staticmethod
|
||||
|
@ -25,79 +26,84 @@ use class::methods::PyMethodDef;
|
|||
|
||||
/// Object customization
|
||||
#[allow(unused_variables)]
|
||||
pub trait PyObjectProtocol: PythonObject {
|
||||
pub trait PyObjectProtocol<'a>: PythonObject {
|
||||
|
||||
fn __getattr__(&self, py: Python, name: Self::Name)
|
||||
-> Self::Result where Self: PyObjectGetAttrProtocol { unimplemented!() }
|
||||
fn __getattr__(&'a self, name: Self::Name)
|
||||
-> Self::Result where Self: PyObjectGetAttrProtocol<'a>
|
||||
{ unimplemented!() }
|
||||
|
||||
fn __setattr__(&self, py: Python, name: Self::Name, value: Self::Value)
|
||||
-> Self::Result where Self: PyObjectSetAttrProtocol { unimplemented!() }
|
||||
-> Self::Result where Self: PyObjectSetAttrProtocol<'a> { unimplemented!() }
|
||||
|
||||
fn __delattr__(&self, py: Python, name: Self::Name)
|
||||
-> Self::Result where Self: PyObjectDelAttrProtocol { unimplemented!() }
|
||||
-> Self::Result where Self: PyObjectDelAttrProtocol<'a> { unimplemented!() }
|
||||
|
||||
fn __str__(&self, py: Python)
|
||||
-> Self::Result where Self: PyObjectStrProtocol { unimplemented!() }
|
||||
-> Self::Result where Self: PyObjectStrProtocol<'a> { unimplemented!() }
|
||||
|
||||
fn __repr__(&self, py: Python)
|
||||
-> Self::Result where Self: PyObjectReprProtocol { unimplemented!() }
|
||||
-> Self::Result where Self: PyObjectReprProtocol<'a> { unimplemented!() }
|
||||
|
||||
fn __format__(&self, py: Python, format_spec: Self::Format)
|
||||
-> Self::Result where Self: PyObjectFormatProtocol { unimplemented!() }
|
||||
-> Self::Result where Self: PyObjectFormatProtocol<'a> { unimplemented!() }
|
||||
|
||||
fn __hash__(&self, py: Python)
|
||||
-> Self::Result where Self: PyObjectHashProtocol { unimplemented!() }
|
||||
-> Self::Result where Self: PyObjectHashProtocol<'a> { unimplemented!() }
|
||||
|
||||
fn __bool__(&self, py: Python)
|
||||
-> Self::Result where Self: PyObjectBoolProtocol { unimplemented!() }
|
||||
fn __bool__(&self) -> Self::Result where Self: PyObjectBoolProtocol<'a> { unimplemented!() }
|
||||
|
||||
fn __bytes__(&self, py: Python)
|
||||
-> Self::Result where Self: PyObjectBytesProtocol { unimplemented!() }
|
||||
-> Self::Result where Self: PyObjectBytesProtocol<'a> { unimplemented!() }
|
||||
|
||||
fn __richcmp__(&self, py: Python, other: Self::Other, op: CompareOp)
|
||||
-> Self::Result where Self: PyObjectRichcmpProtocol { unimplemented!() }
|
||||
-> Self::Result where Self: PyObjectRichcmpProtocol<'a> { unimplemented!() }
|
||||
}
|
||||
|
||||
|
||||
pub trait PyObjectGetAttrProtocol: PyObjectProtocol {
|
||||
type Name: for<'a> FromPyObject<'a>;
|
||||
type Success: ToPyObject;
|
||||
type Result: Into<PyResult<Self::Success>>;
|
||||
}
|
||||
pub trait PyObjectSetAttrProtocol: PyObjectProtocol {
|
||||
type Name: for<'a> FromPyObject<'a>;
|
||||
type Value: for<'a> FromPyObject<'a>;
|
||||
pub trait PyObjectGetAttrProtocol<'a>: PyObjectProtocol<'a> {
|
||||
type Name: ::FromPyObj<'a> + ::class::typeob::PyTypeObjectInfo;
|
||||
type Result: Into<PyResult<()>>;
|
||||
}
|
||||
pub trait PyObjectDelAttrProtocol: PyObjectProtocol {
|
||||
type Name: for<'a> FromPyObject<'a>;
|
||||
|
||||
//pub trait PyObjectGetAttrProtocol: PyObjectProtocol + ::BaseObject + ::PyTypeObject {
|
||||
// type Name: for<'a> ::FromPyObj<'a>;
|
||||
// type Success: ToPyObject;
|
||||
// type Result: Into<PyResult<Self::Success>>;
|
||||
//}
|
||||
pub trait PyObjectSetAttrProtocol<'a>: PyObjectProtocol<'a> {
|
||||
type Name: FromPyObject<'a> + ::class::typeob::PyTypeObjectInfo + ::class::typeob::PyTypeObject + ::PythonObject;
|
||||
type Value: FromPyObject<'a>;
|
||||
type Result: Into<PyResult<()>>;
|
||||
}
|
||||
pub trait PyObjectStrProtocol: PyObjectProtocol {
|
||||
pub trait PyObjectDelAttrProtocol<'a>: PyObjectProtocol<'a> {
|
||||
type Name: FromPyObject<'a>;
|
||||
type Result: Into<PyResult<()>>;
|
||||
}
|
||||
pub trait PyObjectStrProtocol<'a>: PyObjectProtocol<'a> {
|
||||
type Success: ToPyObject;
|
||||
type Result: Into<PyResult<Self::Success>>;
|
||||
}
|
||||
pub trait PyObjectReprProtocol: PyObjectProtocol {
|
||||
pub trait PyObjectReprProtocol<'a>: PyObjectProtocol<'a> {
|
||||
type Success: ToPyObject;
|
||||
type Result: Into<PyResult<Self::Success>>;
|
||||
}
|
||||
pub trait PyObjectFormatProtocol: PyObjectProtocol {
|
||||
type Format: for<'a> FromPyObject<'a>;
|
||||
pub trait PyObjectFormatProtocol<'a>: PyObjectProtocol<'a> {
|
||||
type Format: FromPyObject<'a>;
|
||||
type Success: ToPyObject;
|
||||
type Result: Into<PyResult<Self::Success>>;
|
||||
}
|
||||
pub trait PyObjectHashProtocol: PyObjectProtocol {
|
||||
pub trait PyObjectHashProtocol<'a>: PyObjectProtocol<'a> {
|
||||
type Result: Into<PyResult<usize>>;
|
||||
}
|
||||
pub trait PyObjectBoolProtocol: PyObjectProtocol {
|
||||
pub trait PyObjectBoolProtocol<'a>: PyObjectProtocol<'a> {
|
||||
type Result: Into<PyResult<bool>>;
|
||||
}
|
||||
pub trait PyObjectBytesProtocol: PyObjectProtocol {
|
||||
pub trait PyObjectBytesProtocol<'a>: PyObjectProtocol<'a> {
|
||||
type Success: ToPyObject;
|
||||
type Result: Into<PyResult<Self::Success>>;
|
||||
}
|
||||
pub trait PyObjectRichcmpProtocol: PyObjectProtocol {
|
||||
type Other: for<'a> FromPyObject<'a>;
|
||||
pub trait PyObjectRichcmpProtocol<'a>: PyObjectProtocol<'a> {
|
||||
type Other: FromPyObject<'a>;
|
||||
type Success: ToPyObject;
|
||||
type Result: Into<PyResult<Self::Success>>;
|
||||
}
|
||||
|
@ -121,7 +127,7 @@ impl<T> PyObjectProtocolImpl for T {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> PyObjectProtocolImpl for T where T: PyObjectProtocol {
|
||||
impl<'a, T> PyObjectProtocolImpl for T where T: PyObjectProtocol<'a> {
|
||||
#[inline]
|
||||
fn methods() -> Vec<PyMethodDef> {
|
||||
let mut methods = Vec::new();
|
||||
|
@ -135,6 +141,8 @@ impl<T> PyObjectProtocolImpl for T where T: PyObjectProtocol {
|
|||
methods
|
||||
}
|
||||
fn tp_as_object(type_object: &mut ffi::PyTypeObject) {
|
||||
println!("getattr: {:?}", Self::tp_getattro());
|
||||
|
||||
type_object.tp_str = Self::tp_str();
|
||||
type_object.tp_repr = Self::tp_repr();
|
||||
type_object.tp_hash = Self::tp_hash();
|
||||
|
@ -156,8 +164,7 @@ trait PyObjectGetAttrProtocolImpl {
|
|||
fn tp_getattro() -> Option<ffi::binaryfunc>;
|
||||
}
|
||||
|
||||
impl<T> PyObjectGetAttrProtocolImpl for T
|
||||
where T: PyObjectProtocol
|
||||
impl<'a, T> PyObjectGetAttrProtocolImpl for T where T: PyObjectProtocol<'a>
|
||||
{
|
||||
#[inline]
|
||||
default fn tp_getattro() -> Option<ffi::binaryfunc> {
|
||||
|
@ -165,11 +172,55 @@ impl<T> PyObjectGetAttrProtocolImpl for T
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> PyObjectGetAttrProtocolImpl for T where T: PyObjectGetAttrProtocol
|
||||
use python::PyClone;
|
||||
use callback::CallbackConverter;
|
||||
|
||||
|
||||
impl<'a, T> PyObjectGetAttrProtocolImpl for T
|
||||
where T: PyObjectGetAttrProtocol<'a> + ::class::typeob::PyTypeObjectInfo
|
||||
{
|
||||
#[inline]
|
||||
fn tp_getattro() -> Option<ffi::binaryfunc> {
|
||||
py_binary_func_!(PyObjectGetAttrProtocol, T::__getattr__, PyObjectCallbackConverter)
|
||||
//py_binary_func_!(PyObjectGetAttrProtocol, T::__getattr__, PyObjectCallbackConverter)
|
||||
unsafe extern "C" fn wrap<'a, T>(slf: *mut ffi::PyObject,
|
||||
arg: *mut ffi::PyObject) -> *mut ffi::PyObject
|
||||
where T: PyObjectGetAttrProtocol<'a> + ::class::typeob::PyTypeObjectInfo
|
||||
{
|
||||
const LOCATION: &'static str = concat!(stringify!($class), ".", stringify!($f), "()");
|
||||
{
|
||||
println!("GETATTRO callback");
|
||||
let py = Python::assume_gil_acquired();
|
||||
|
||||
//::callback::handle_callback2(LOCATION, PyObjectCallbackConverter, |py| {
|
||||
let arg1 = ::pyptr::from_borrowed_ptr(py, arg.clone());
|
||||
let name: &Py<T::Name> = {&arg1 as *const _}.as_ref().unwrap();
|
||||
let ret = match name.extr() {
|
||||
Ok(name) => {
|
||||
let slf: Py<T> = ::pyptr::from_borrowed_ptr(py, slf);
|
||||
let slf1: &Py<T> = {&slf as *const _}.as_ref().unwrap();
|
||||
let res = slf1.as_ref().__getattr__(name).into();
|
||||
res
|
||||
}
|
||||
Err(e) => Err(e),
|
||||
};
|
||||
println!("GETATTRO callback 3 {:?}", ret);
|
||||
|
||||
//$crate::PyDrop::release_ref(arg, py);
|
||||
//$crate::PyDrop::release_ref(slf, py);
|
||||
//res
|
||||
match ret {
|
||||
Ok(val) => {
|
||||
PyObjectCallbackConverter::convert(val, py)
|
||||
}
|
||||
Err(e) => {
|
||||
e.restore(py);
|
||||
//PyObjectCallbackConverter::error_value()
|
||||
::ptr::null_mut()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(wrap::<T>)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -178,7 +229,7 @@ trait PyObjectSetAttrProtocolImpl {
|
|||
fn tp_setattro() -> Option<ffi::setattrofunc>;
|
||||
}
|
||||
|
||||
impl<T> PyObjectSetAttrProtocolImpl for T where T: PyObjectProtocol
|
||||
impl<'a, T> PyObjectSetAttrProtocolImpl for T where T: PyObjectProtocol<'a>
|
||||
{
|
||||
#[inline]
|
||||
default fn tp_setattro() -> Option<ffi::setattrofunc> {
|
||||
|
@ -186,7 +237,7 @@ impl<T> PyObjectSetAttrProtocolImpl for T where T: PyObjectProtocol
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> PyObjectSetAttrProtocolImpl for T where T: PyObjectSetAttrProtocol
|
||||
/*impl<T> PyObjectSetAttrProtocolImpl for T where T: PyObjectSetAttrProtocol
|
||||
{
|
||||
#[inline]
|
||||
fn tp_setattro() -> Option<ffi::setattrofunc> {
|
||||
|
@ -225,14 +276,14 @@ impl<T> PyObjectSetAttrProtocolImpl for T where T: PyObjectSetAttrProtocol
|
|||
}
|
||||
Some(wrap::<T>)
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
trait PyObjectDelAttrProtocolImpl {
|
||||
fn tp_delattro() -> Option<ffi::setattrofunc>;
|
||||
}
|
||||
|
||||
impl<T> PyObjectDelAttrProtocolImpl for T where T: PyObjectProtocol
|
||||
impl<'a, T> PyObjectDelAttrProtocolImpl for T where T: PyObjectProtocol<'a>
|
||||
{
|
||||
#[inline]
|
||||
default fn tp_delattro() -> Option<ffi::setattrofunc> {
|
||||
|
@ -240,7 +291,7 @@ impl<T> PyObjectDelAttrProtocolImpl for T where T: PyObjectProtocol
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> PyObjectDelAttrProtocolImpl for T where T: PyObjectDelAttrProtocol
|
||||
/*impl<T> PyObjectDelAttrProtocolImpl for T where T: PyObjectDelAttrProtocol
|
||||
{
|
||||
#[inline]
|
||||
default fn tp_delattro() -> Option<ffi::setattrofunc> {
|
||||
|
@ -273,10 +324,10 @@ impl<T> PyObjectDelAttrProtocolImpl for T where T: PyObjectDelAttrProtocol
|
|||
}
|
||||
Some(wrap::<T>)
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
impl<T> PyObjectDelAttrProtocolImpl for T
|
||||
/*impl<T> PyObjectDelAttrProtocolImpl for T
|
||||
where T: PyObjectSetAttrProtocol + PyObjectDelAttrProtocol
|
||||
{
|
||||
#[inline]
|
||||
|
@ -318,50 +369,50 @@ impl<T> PyObjectDelAttrProtocolImpl for T
|
|||
}
|
||||
Some(wrap::<T>)
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
trait PyObjectStrProtocolImpl {
|
||||
fn tp_str() -> Option<ffi::unaryfunc>;
|
||||
}
|
||||
impl<T> PyObjectStrProtocolImpl for T where T: PyObjectProtocol
|
||||
impl<'a, T> PyObjectStrProtocolImpl for T where T: PyObjectProtocol<'a>
|
||||
{
|
||||
#[inline]
|
||||
default fn tp_str() -> Option<ffi::unaryfunc> {
|
||||
None
|
||||
}
|
||||
}
|
||||
impl<T> PyObjectStrProtocolImpl for T where T: PyObjectStrProtocol
|
||||
/*impl<T> PyObjectStrProtocolImpl for T where T: PyObjectStrProtocol
|
||||
{
|
||||
#[inline]
|
||||
fn tp_str() -> Option<ffi::unaryfunc> {
|
||||
py_unary_func_!(PyObjectStrProtocol, T::__str__, PyObjectCallbackConverter)
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
trait PyObjectReprProtocolImpl {
|
||||
fn tp_repr() -> Option<ffi::unaryfunc>;
|
||||
}
|
||||
impl<T> PyObjectReprProtocolImpl for T where T: PyObjectProtocol
|
||||
impl<'a, T> PyObjectReprProtocolImpl for T where T: PyObjectProtocol<'a>
|
||||
{
|
||||
#[inline]
|
||||
default fn tp_repr() -> Option<ffi::unaryfunc> {
|
||||
None
|
||||
}
|
||||
}
|
||||
impl<T> PyObjectReprProtocolImpl for T where T: PyObjectReprProtocol
|
||||
/*impl<T> PyObjectReprProtocolImpl for T where T: PyObjectReprProtocol
|
||||
{
|
||||
#[inline]
|
||||
fn tp_repr() -> Option<ffi::unaryfunc> {
|
||||
py_unary_func_!(PyObjectReprProtocol, T::__repr__, PyObjectCallbackConverter)
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
#[doc(hidden)]
|
||||
pub trait PyObjectFormatProtocolImpl {
|
||||
fn __format__() -> Option<PyMethodDef>;
|
||||
}
|
||||
impl<T> PyObjectFormatProtocolImpl for T where T: PyObjectProtocol
|
||||
impl<'a, T> PyObjectFormatProtocolImpl for T where T: PyObjectProtocol<'a>
|
||||
{
|
||||
#[inline]
|
||||
default fn __format__() -> Option<PyMethodDef> {
|
||||
|
@ -370,10 +421,10 @@ impl<T> PyObjectFormatProtocolImpl for T where T: PyObjectProtocol
|
|||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub trait PyObjectBytesProtocolImpl {
|
||||
pub trait PyObjectBytesProtocolImpl {
|
||||
fn __bytes__() -> Option<PyMethodDef>;
|
||||
}
|
||||
impl<T> PyObjectBytesProtocolImpl for T where T: PyObjectProtocol
|
||||
impl<'a, T> PyObjectBytesProtocolImpl for T where T: PyObjectProtocol<'a>
|
||||
{
|
||||
#[inline]
|
||||
default fn __bytes__() -> Option<PyMethodDef> {
|
||||
|
@ -385,50 +436,63 @@ impl<T> PyObjectBytesProtocolImpl for T where T: PyObjectProtocol
|
|||
trait PyObjectHashProtocolImpl {
|
||||
fn tp_hash() -> Option<ffi::hashfunc>;
|
||||
}
|
||||
impl<T> PyObjectHashProtocolImpl for T where T: PyObjectProtocol
|
||||
impl<'a, T> PyObjectHashProtocolImpl for T where T: PyObjectProtocol<'a>
|
||||
{
|
||||
#[inline]
|
||||
default fn tp_hash() -> Option<ffi::hashfunc> {
|
||||
None
|
||||
}
|
||||
}
|
||||
impl<T> PyObjectHashProtocolImpl for T where T: PyObjectHashProtocol
|
||||
/*impl<T> PyObjectHashProtocolImpl for T where T: PyObjectHashProtocol
|
||||
{
|
||||
#[inline]
|
||||
fn tp_hash() -> Option<ffi::hashfunc> {
|
||||
py_unary_func_!(PyObjectHashProtocol, T::__hash__, HashConverter, ffi::Py_hash_t)
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
trait PyObjectBoolProtocolImpl {
|
||||
fn nb_bool() -> Option<ffi::inquiry>;
|
||||
}
|
||||
impl<T> PyObjectBoolProtocolImpl for T where T: PyObjectProtocol
|
||||
impl<'a, T> PyObjectBoolProtocolImpl for T where T: PyObjectProtocol<'a>
|
||||
{
|
||||
#[inline]
|
||||
default fn nb_bool() -> Option<ffi::inquiry> {
|
||||
None
|
||||
}
|
||||
}
|
||||
impl<T> PyObjectBoolProtocolImpl for T where T: PyObjectBoolProtocol
|
||||
/*impl<T> PyObjectBoolProtocolImpl for T
|
||||
where T: PyObjectBoolProtocol + ::BaseObject<Type=T> + ::PyTypeObject
|
||||
{
|
||||
#[inline]
|
||||
fn nb_bool() -> Option<ffi::inquiry> {
|
||||
py_unary_func_!(PyObjectBoolProtocol, T::__bool__, BoolCallbackConverter, c_int)
|
||||
//py_unary_func_2!(PyObjectBoolProtocol, T::__bool__, BoolCallbackConverter, c_int)
|
||||
unsafe extern "C" fn wrap<T>(slf: *mut ffi::PyObject) -> c_int
|
||||
where T: PyObjectBoolProtocol
|
||||
{
|
||||
const LOCATION: &'static str = concat!(stringify!(T), ".", stringify!($f), "()");
|
||||
::callback::handle_callback(LOCATION, BoolCallbackConverter, |py| {
|
||||
let slf: Py<T> = ::pyptr::from_borrowed_ptr(py, slf);
|
||||
let ret = slf.__bool__().into();
|
||||
//$crate::PyDrop::release_ref(slf, py);
|
||||
ret
|
||||
})
|
||||
}
|
||||
Some(wrap::<T>)
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
trait PyObjectRichcmpProtocolImpl {
|
||||
fn tp_richcompare() -> Option<ffi::richcmpfunc>;
|
||||
}
|
||||
impl<T> PyObjectRichcmpProtocolImpl for T where T: PyObjectProtocol
|
||||
impl<'a, T> PyObjectRichcmpProtocolImpl for T where T: PyObjectProtocol<'a>
|
||||
{
|
||||
#[inline]
|
||||
default fn tp_richcompare() -> Option<ffi::richcmpfunc> {
|
||||
None
|
||||
}
|
||||
}
|
||||
impl<T> PyObjectRichcmpProtocolImpl for T where T: PyObjectRichcmpProtocol
|
||||
/*impl<T> PyObjectRichcmpProtocolImpl for T where T: PyObjectRichcmpProtocol
|
||||
{
|
||||
#[inline]
|
||||
fn tp_richcompare() -> Option<ffi::richcmpfunc> {
|
||||
|
@ -456,7 +520,7 @@ impl<T> PyObjectRichcmpProtocolImpl for T where T: PyObjectRichcmpProtocol
|
|||
}
|
||||
Some(wrap::<T>)
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
fn extract_op(py: Python, op: c_int) -> PyResult<CompareOp> {
|
||||
|
|
|
@ -44,6 +44,28 @@ macro_rules! py_unary_func_ {
|
|||
}}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! py_unary_func_2 {
|
||||
($trait:ident, $class:ident :: $f:ident, $conv:expr) => {
|
||||
py_unary_func_2!($trait, $class::$f, $conv, *mut $crate::ffi::PyObject);
|
||||
};
|
||||
($trait:ident, $class:ident :: $f:ident, $conv:expr, $res_type:ty) => {{
|
||||
unsafe extern "C" fn wrap<T>(slf: *mut $crate::ffi::PyObject) -> $res_type
|
||||
where T: $trait
|
||||
{
|
||||
const LOCATION: &'static str = concat!(stringify!($class), ".", stringify!($f), "()");
|
||||
$crate::callback::handle_callback(LOCATION, $conv, |py| {
|
||||
let slf: $crate::Py<T> = $crate::Py::from_borrowed_ptr(py, slf);
|
||||
let ret = slf.$f(py).into();
|
||||
//$crate::PyDrop::release_ref(slf, py);
|
||||
ret
|
||||
})
|
||||
}
|
||||
Some(wrap::<$class>)
|
||||
}}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! py_len_func {
|
||||
|
|
|
@ -37,9 +37,9 @@ pub static NO_METHODS: &'static [&'static str] = &[];
|
|||
pub static NO_PY_METHODS: &'static [PyMethodDefType] = &[];
|
||||
|
||||
use ffi;
|
||||
use err::{self, PyResult};
|
||||
use objects::{PyObject, PyType};
|
||||
use python::{Python, PythonObject};
|
||||
use err::{PyErr, PyResult};
|
||||
use objects::PyObject;
|
||||
use python::Python;
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -54,7 +54,7 @@ pub enum CompareOp {
|
|||
|
||||
|
||||
/// A PythonObject that is usable as a base type for #[class]
|
||||
pub trait BaseObject : PythonObject {
|
||||
pub trait BaseObject {
|
||||
/// Gets the size of the object, in bytes.
|
||||
fn size() -> usize;
|
||||
|
||||
|
@ -64,7 +64,7 @@ pub trait BaseObject : PythonObject {
|
|||
/// 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, ty: &PyType, val: Self::Type) -> PyResult<PyObject>;
|
||||
unsafe fn alloc(py: Python, val: 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).
|
||||
|
@ -81,9 +81,16 @@ impl BaseObject for PyObject {
|
|||
|
||||
type Type = ();
|
||||
|
||||
unsafe fn alloc(py: Python, ty: &PyType, _init_val: ()) -> PyResult<PyObject> {
|
||||
unsafe fn alloc(py: Python, _val: ()) -> PyResult<*mut ffi::PyObject> {
|
||||
let ty = py.get_type::<PyObject>();
|
||||
let ptr = ffi::PyType_GenericAlloc(ty.as_type_ptr(), 0);
|
||||
err::result_from_owned_ptr(py, ptr)
|
||||
println!("alloc PyObject {}", ffi::Py_REFCNT(ptr));
|
||||
//err::result_from_owned_ptr(py, ptr)
|
||||
if ptr.is_null() {
|
||||
return Err(PyErr::fetch(py))
|
||||
} else {
|
||||
Ok(ptr)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn dealloc(_py: Python, obj: *mut ffi::PyObject) {
|
||||
|
|
|
@ -4,7 +4,7 @@ use std::mem;
|
|||
use std::ffi::CString;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use ::{ffi, class, PyErr, Python, PyResult, PythonObject};
|
||||
use ::{ffi, class, PyErr, Python, PyResult, PythonObject, PyPtr, Py};
|
||||
use objects::PyType;
|
||||
use callback::AbortOnDrop;
|
||||
use class::{BaseObject, PyMethodDefType};
|
||||
|
@ -21,6 +21,10 @@ pub trait PyTypeObject {
|
|||
/// Trait implemented by object that generated by py::class macro
|
||||
pub trait PyTypeObjectInfo {
|
||||
|
||||
fn size() -> usize;
|
||||
|
||||
fn offset() -> usize;
|
||||
|
||||
fn type_name() -> &'static str;
|
||||
|
||||
fn type_object() -> &'static mut ffi::PyTypeObject;
|
||||
|
@ -28,7 +32,31 @@ pub trait PyTypeObjectInfo {
|
|||
}
|
||||
|
||||
|
||||
impl<T> PyTypeObject for T where T: BaseObject + PythonObject + PyTypeObjectInfo {
|
||||
impl<'a, T: ?Sized> PyTypeObjectInfo for &'a T where T: PyTypeObjectInfo {
|
||||
|
||||
#[inline]
|
||||
default fn size() -> usize {
|
||||
<T as PyTypeObjectInfo>::size()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
default fn offset() -> usize {
|
||||
<T as PyTypeObjectInfo>::offset()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
default fn type_name() -> &'static str {
|
||||
<T as PyTypeObjectInfo>::type_name()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
default fn type_object() -> &'static mut ffi::PyTypeObject {
|
||||
<T as PyTypeObjectInfo>::type_object()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<T> PyTypeObject for T where T: BaseObject + PyTypeObjectInfo {
|
||||
|
||||
#[inline]
|
||||
fn type_object(py: Python) -> PyType {
|
||||
|
@ -48,7 +76,7 @@ impl<T> PyTypeObject for T where T: BaseObject + PythonObject + PyTypeObjectInfo
|
|||
|
||||
pub fn initialize_type<T>(py: Python, module_name: Option<&str>, type_name: &str,
|
||||
type_object: &mut ffi::PyTypeObject) -> PyResult<PyType>
|
||||
where T: BaseObject + PythonObject
|
||||
where T: BaseObject + PyTypeObjectInfo
|
||||
{
|
||||
// type name
|
||||
let name = match module_name {
|
||||
|
@ -63,23 +91,23 @@ pub fn initialize_type<T>(py: Python, module_name: Option<&str>, type_name: &str
|
|||
// dealloc
|
||||
type_object.tp_dealloc = Some(tp_dealloc_callback::<T>);
|
||||
|
||||
// GC support
|
||||
<T as class::gc::PyGCProtocolImpl>::update_type_object(type_object);
|
||||
|
||||
// type size
|
||||
type_object.tp_basicsize = <T as BaseObject>::size() as ffi::Py_ssize_t;
|
||||
|
||||
// GC support
|
||||
// <T as class::gc::PyGCProtocolImpl>::update_type_object(type_object);
|
||||
|
||||
// descriptor protocol
|
||||
<T as class::descr::PyDescrProtocolImpl>::tp_as_descr(type_object);
|
||||
// <T as class::descr::PyDescrProtocolImpl>::tp_as_descr(type_object);
|
||||
|
||||
// iterator methods
|
||||
<T as class::iter::PyIterProtocolImpl>::tp_as_iter(type_object);
|
||||
// <T as class::iter::PyIterProtocolImpl>::tp_as_iter(type_object);
|
||||
|
||||
// basic methods
|
||||
<T as class::basic::PyObjectProtocolImpl>::tp_as_object(type_object);
|
||||
|
||||
// number methods
|
||||
if let Some(meth) = <T as class::number::PyNumberProtocolImpl>::tp_as_number() {
|
||||
/*if let Some(meth) = <T as class::number::PyNumberProtocolImpl>::tp_as_number() {
|
||||
static mut NB_METHODS: ffi::PyNumberMethods = ffi::PyNumberMethods_INIT;
|
||||
*(unsafe { &mut NB_METHODS }) = meth;
|
||||
type_object.tp_as_number = unsafe { &mut NB_METHODS };
|
||||
|
@ -156,7 +184,7 @@ pub fn initialize_type<T>(py: Python, module_name: Option<&str>, type_name: &str
|
|||
|
||||
// strange
|
||||
mem::forget(props);
|
||||
}
|
||||
}*/
|
||||
|
||||
// register type object
|
||||
unsafe {
|
||||
|
@ -168,11 +196,12 @@ pub fn initialize_type<T>(py: Python, module_name: Option<&str>, type_name: &str
|
|||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn tp_dealloc_callback<T>(obj: *mut ffi::PyObject) where T: BaseObject
|
||||
unsafe extern "C" fn tp_dealloc_callback<T>(obj: *mut ffi::PyObject)
|
||||
where T: BaseObject + PyTypeObjectInfo
|
||||
{
|
||||
let guard = AbortOnDrop("Cannot unwind out of tp_dealloc");
|
||||
let py = Python::assume_gil_acquired();
|
||||
let r = T::dealloc(py, obj);
|
||||
let r = <T as BaseObject>::dealloc(py, obj);
|
||||
mem::forget(guard);
|
||||
r
|
||||
}
|
||||
|
|
|
@ -20,6 +20,8 @@ use ffi;
|
|||
use python::{Python, PythonObject};
|
||||
use objects::{PyObject, PyTuple};
|
||||
use err::PyResult;
|
||||
use pyptr::{Py, PyPtr};
|
||||
|
||||
|
||||
/// Conversion trait that allows various objects to be converted into Python objects.
|
||||
pub trait ToPyObject {
|
||||
|
@ -112,6 +114,12 @@ pub trait FromPyObject<'source> : Sized {
|
|||
fn extract(py: Python, obj: &'source PyObject) -> PyResult<Self>;
|
||||
}
|
||||
|
||||
pub trait FromPyObj<'source> : Sized {
|
||||
/// Extracts `Self` from the source `PyObject`.
|
||||
fn extr<S>(py: &'source Py<'source, S>) -> PyResult<Self>
|
||||
where S: ::class::typeob::PyTypeObjectInfo;
|
||||
}
|
||||
|
||||
pub trait RefFromPyObject {
|
||||
fn with_extracted<F, R>(py: Python, obj: &PyObject, f: F) -> PyResult<R>
|
||||
where F: FnOnce(&Self) -> R;
|
||||
|
@ -133,25 +141,6 @@ impl <T: ?Sized> RefFromPyObject for T
|
|||
|
||||
/// Identity conversion: allows using existing `PyObject` instances where
|
||||
/// `T: ToPyObject` is expected.
|
||||
/*impl<T> ToPyObject for T where T: PythonObject {
|
||||
#[inline]
|
||||
fn to_py_object(&self, py: Python) -> PyObject {
|
||||
PyClone::clone_ref(self, py).into_object()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
default fn into_py_object(self, _py: Python) -> PyObject {
|
||||
self.into_object()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
default fn with_borrowed_ptr<F, R>(&self, _py: Python, f: F) -> R
|
||||
where F: FnOnce(*mut ffi::PyObject) -> R
|
||||
{
|
||||
f(PythonObject::as_object(self).as_ptr())
|
||||
}
|
||||
}*/
|
||||
|
||||
// ToPyObject for references
|
||||
impl <'a, T: ?Sized> ToPyObject for &'a T where T: ToPyObject {
|
||||
|
||||
|
|
|
@ -90,8 +90,12 @@ pub use pyo3cls::*;
|
|||
|
||||
pub mod ffi;
|
||||
pub use ffi::{Py_ssize_t, Py_hash_t};
|
||||
mod pyptr;
|
||||
|
||||
pub mod pyptr;
|
||||
pub use pyptr::{Py, PyPtr};
|
||||
pub use python::PyWithCheckedDowncast;
|
||||
pub use conversion::FromPyObj;
|
||||
|
||||
pub use err::{PyErr, PyResult};
|
||||
pub use objects::*;
|
||||
pub use python::{Python, PythonObject,
|
||||
|
|
|
@ -108,6 +108,16 @@ macro_rules! pyobject_newtype(
|
|||
pyobject_newtype!($name, $checkfunction);
|
||||
|
||||
impl $crate::class::typeob::PyTypeObjectInfo for $name {
|
||||
#[inline]
|
||||
fn size() -> usize {
|
||||
Self::offset() + $crate::std::mem::size_of::<$name>()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn offset() -> usize {
|
||||
0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn type_name() -> &'static str {
|
||||
stringify!($name)
|
||||
|
|
|
@ -144,6 +144,7 @@ impl PyObject {
|
|||
/// Undefined behavior if the pointer is NULL or invalid.
|
||||
#[inline]
|
||||
pub unsafe fn from_borrowed_ptr(_py : Python, ptr : *mut ffi::PyObject) -> PyObject {
|
||||
println!("from_borrowed_ptr: {} {:?} {}", ptr.is_null(), ptr, ffi::Py_REFCNT(ptr));
|
||||
debug_assert!(!ptr.is_null() && ffi::Py_REFCNT(ptr) > 0);
|
||||
ffi::Py_INCREF(ptr);
|
||||
PyObject { ptr: make_shared(ptr) }
|
||||
|
|
262
src/pyptr.rs
262
src/pyptr.rs
|
@ -2,19 +2,22 @@
|
|||
|
||||
use std;
|
||||
use std::marker::PhantomData;
|
||||
use std::os::raw::c_int;
|
||||
use std::os::raw::{c_int, c_void};
|
||||
use std::ops::Deref;
|
||||
|
||||
use ffi;
|
||||
use err::PyResult;
|
||||
use err::{PyErr, PyResult};
|
||||
use python::Python;
|
||||
use class::{BaseObject, PyTypeObject};
|
||||
|
||||
use objects::{PyObject, PyType};
|
||||
use ::ToPyObject;
|
||||
use class::typeob::PyTypeObjectInfo;
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PyPtr<T> {
|
||||
inner: *mut ffi::PyObject,
|
||||
pub inner: *mut ffi::PyObject,
|
||||
_t: PhantomData<T>,
|
||||
}
|
||||
|
||||
|
@ -28,57 +31,80 @@ impl<T> PyPtr<T> {
|
|||
}
|
||||
}
|
||||
|
||||
// PyObject is thread-safe, because all operations on it require a Python<'p> token.
|
||||
unsafe impl<T> Send for PyPtr<T> {}
|
||||
unsafe impl<T> Sync for PyPtr<T> {}
|
||||
|
||||
/// Dropping a `PyPtr` decrements the reference count on the object by 1.
|
||||
impl<T> Drop for PyPtr<T> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
println!("drop PyPtr: {:?} {}", self.inner, ffi::Py_REFCNT(self.inner));
|
||||
}
|
||||
|
||||
let _gil_guard = Python::acquire_gil();
|
||||
unsafe { ffi::Py_DECREF(self.inner); }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub struct Py<'p, T> {
|
||||
inner: *mut ffi::PyObject,
|
||||
pub inner: *mut ffi::PyObject,
|
||||
_t: PhantomData<T>,
|
||||
_py: PhantomData<Python<'p>>,
|
||||
}
|
||||
|
||||
impl<'p, T> Py<'p, T> where T: BaseObject + PyTypeObject {
|
||||
/// Creates a Py instance for the given FFI pointer.
|
||||
/// Calls Py_INCREF() on the ptr.
|
||||
/// Undefined behavior if the pointer is NULL or invalid.
|
||||
#[inline]
|
||||
pub unsafe fn from_borrowed_ptr<'p, T>(_py: Python<'p>, ptr: *mut ffi::PyObject) -> Py<'p, T> {
|
||||
debug_assert!(!ptr.is_null() && ffi::Py_REFCNT(ptr) > 0);
|
||||
ffi::Py_INCREF(ptr);
|
||||
Py {inner: ptr, _t: PhantomData, _py: PhantomData}
|
||||
}
|
||||
|
||||
fn new(py: Python<'p>, value: T) -> PyResult<Py<'p, T>> {
|
||||
unsafe {
|
||||
let obj = try!(Py::<T>::alloc(py, value));
|
||||
pub fn new<'p, T>(py: Python<'p>, value: T) -> PyResult<Py<'p, T>> where T: BaseObject<Type=T>
|
||||
{
|
||||
unsafe {
|
||||
let obj = try!(<T as BaseObject>::alloc(py, value));
|
||||
|
||||
Ok(Py{inner: obj, _t: PhantomData, _py: PhantomData})
|
||||
}
|
||||
Ok(Py{inner: obj, _t: PhantomData, _py: PhantomData})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<'p, T> Py<'p, T> where T: PyTypeObjectInfo
|
||||
{
|
||||
/// Creates a Py instance for the given FFI pointer.
|
||||
/// This moves ownership over the pointer into the Py.
|
||||
/// Undefined behavior if the pointer is NULL or invalid.
|
||||
#[inline]
|
||||
pub unsafe fn from_owned_ptr(_py: Python<'p>, ptr: *mut ffi::PyObject) -> Py<'p, T> {
|
||||
debug_assert!(!ptr.is_null() && ffi::Py_REFCNT(ptr) > 0);
|
||||
Py {inner: ptr, _t: PhantomData, _py: PhantomData}
|
||||
}
|
||||
|
||||
unsafe fn alloc(py: Python, value: T) -> PyResult<*mut ffi::PyObject>
|
||||
{
|
||||
let ty = py.get_type::<T>();
|
||||
let obj = try!(PyObject::alloc(py, &ty, ()));
|
||||
|
||||
let align = std::mem::align_of::<T>();
|
||||
let bs = <T as BaseObject>::size();
|
||||
|
||||
// round base_size up to next multiple of align
|
||||
let offset = (bs + align - 1) / align * align;
|
||||
|
||||
let ptr = (obj.as_ptr() as *mut u8).offset(offset as isize) as *mut T;
|
||||
std::ptr::write(ptr, value);
|
||||
|
||||
Ok(obj.as_ptr())
|
||||
/// Creates a Py instance for the given FFI pointer.
|
||||
/// Calls Py_INCREF() on the ptr.
|
||||
/// Undefined behavior if the pointer is NULL or invalid.
|
||||
#[inline]
|
||||
pub unsafe fn from_borrowed_ptr(_py: Python<'p>, ptr: *mut ffi::PyObject) -> Py<'p, T> {
|
||||
debug_assert!(!ptr.is_null() && ffi::Py_REFCNT(ptr) > 0);
|
||||
ffi::Py_INCREF(ptr);
|
||||
Py {inner: ptr, _t: PhantomData, _py: PhantomData}
|
||||
}
|
||||
|
||||
unsafe fn dealloc(py: Python, obj: *mut ffi::PyObject) {
|
||||
let align = std::mem::align_of::<T>();
|
||||
let bs = <T as BaseObject>::size();
|
||||
|
||||
// round base_size up to next multiple of align
|
||||
let offset = (bs + align - 1) / align * align;
|
||||
|
||||
let ptr = (obj as *mut u8).offset(offset as isize) as *mut T;
|
||||
std::ptr::drop_in_place(ptr);
|
||||
|
||||
PyObject::dealloc(py, obj)
|
||||
/// Gets the reference count of this Py object.
|
||||
#[inline]
|
||||
pub fn get_refcnt(&self, _py: Python) -> usize {
|
||||
unsafe { ffi::Py_REFCNT(self.inner) as usize }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn as_ref(&self) -> &'p T {
|
||||
pub fn as_ref(&self) -> &T {
|
||||
let align = std::mem::align_of::<T>();
|
||||
let bs = <T as BaseObject>::size();
|
||||
let bs = <T as PyTypeObjectInfo>::size();
|
||||
|
||||
// round base_size up to next multiple of align
|
||||
let offset = (bs + align - 1) / align * align;
|
||||
|
@ -90,9 +116,9 @@ impl<'p, T> Py<'p, T> where T: BaseObject + PyTypeObject {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn as_mut(&self) -> &'p mut T {
|
||||
pub fn as_mut(&self) -> &mut T {
|
||||
let align = std::mem::align_of::<T>();
|
||||
let bs = <T as BaseObject>::size();
|
||||
let bs = <T as PyTypeObjectInfo>::size();
|
||||
|
||||
// round base_size up to next multiple of align
|
||||
let offset = (bs + align - 1) / align * align;
|
||||
|
@ -118,21 +144,165 @@ impl<'p, T> Py<'p, T> where T: BaseObject + PyTypeObject {
|
|||
pub fn into_ptr(self) -> PyPtr<T> {
|
||||
PyPtr { inner: self.inner, _t: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'p, T> Deref for Py<'p, T> where T: BaseObject {
|
||||
type Target = T;
|
||||
/// Casts the PyObject to a concrete Python object type.
|
||||
/// Fails with `PythonObjectDowncastError` if the object is not of the expected type.
|
||||
/// This is a wrapper function around `PythonObjectWithCheckedDowncast::downcast_from()`.
|
||||
#[inline]
|
||||
pub fn cast<D>(&self) -> Result<Py<'p, D>, ::PythonObjectDowncastError<'p>>
|
||||
where D: ::PyWithCheckedDowncast<'p>
|
||||
{
|
||||
::PyWithCheckedDowncast::downcast_from(self.clone())
|
||||
}
|
||||
|
||||
fn deref(&self) -> &T {
|
||||
/// Casts the PyObject to a concrete Python object type.
|
||||
/// Fails with `PythonObjectDowncastError` if the object is not of the expected type.
|
||||
/// This is a wrapper function around `PythonObjectWithCheckedDowncast::downcast_from()`.
|
||||
#[inline]
|
||||
pub fn cast_into<D>(self) -> Result<Py<'p, D>, ::PythonObjectDowncastError<'p>>
|
||||
where D: ::PyWithCheckedDowncast<'p>
|
||||
{
|
||||
::PyWithCheckedDowncast::downcast_from(self)
|
||||
}
|
||||
|
||||
/// Casts the PyObject to a concrete Python object type.
|
||||
/// Fails with `PythonObjectDowncastError` if the object is not of the expected type.
|
||||
/// This is a wrapper function around
|
||||
/// `PythonObjectWithCheckedDowncast::downcast_borrow_from()`.
|
||||
#[inline]
|
||||
pub fn cast_as<D>(&'p self) -> Result<&'p D, ::PythonObjectDowncastError<'p>>
|
||||
where D: ::PyWithCheckedDowncast<'p>
|
||||
{
|
||||
::PyWithCheckedDowncast::downcast_borrow_from(&self)
|
||||
}
|
||||
|
||||
/// Unchecked downcast from other Py<> to Self.
|
||||
/// Undefined behavior if the input object does not have the expected type.
|
||||
#[inline]
|
||||
pub unsafe fn unchecked_downcast_from<'a, S>(py: Py<'a, S>) -> Py<'a, T>
|
||||
{
|
||||
let res = Py {inner: py.inner, _t: PhantomData, _py: PhantomData};
|
||||
std::mem::forget(py);
|
||||
res
|
||||
}
|
||||
|
||||
/// Unchecked downcast from Py<'p, S> to &'p S.
|
||||
/// Undefined behavior if the input object does not have the expected type.
|
||||
#[inline]
|
||||
pub unsafe fn unchecked_downcast_borrow_from<'a, S>(py: &'a Py<'a, S>) -> &'a T {
|
||||
let align = std::mem::align_of::<T>();
|
||||
let bs = <T as BaseObject>::size();
|
||||
let bs = <T as PyTypeObjectInfo>::size();
|
||||
|
||||
// round base_size up to next multiple of align
|
||||
let offset = (bs + align - 1) / align * align;
|
||||
|
||||
unsafe {
|
||||
let ptr = (self.inner as *mut u8).offset(offset as isize) as *mut T;
|
||||
let ptr = (py.inner as *mut u8).offset(offset as isize) as *mut T;
|
||||
ptr.as_ref().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
/// Extracts some type from the Python object.
|
||||
/// This is a wrapper function around `FromPyObject::from_py_object()`.
|
||||
#[inline]
|
||||
pub fn extr<D>(&'p self) -> PyResult<D>
|
||||
where D: ::conversion::FromPyObj<'p>
|
||||
{
|
||||
::conversion::FromPyObj::extr(&self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'p, T> Clone for Py<'p, T> {
|
||||
fn clone(&self) -> Self {
|
||||
unsafe {
|
||||
debug_assert!(!self.inner.is_null() && ffi::Py_REFCNT(self.inner) > 0);
|
||||
ffi::Py_INCREF(self.inner);
|
||||
Py {inner: self.inner, _t: PhantomData, _py: PhantomData}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'p, T> Deref for Py<'p, T> where T: PyTypeObjectInfo + PyTypeObject + ::PythonObject {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &T {
|
||||
self.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'p, T> ::PyWithCheckedDowncast<'p> for T where T: PyTypeObjectInfo
|
||||
{
|
||||
#[inline]
|
||||
default fn downcast_from<S>(ob: Py<'p, S>)
|
||||
-> Result<Py<'p, T>, ::PythonObjectDowncastError<'p>>
|
||||
{
|
||||
let checked = unsafe { ffi::PyObject_TypeCheck(ob.inner, T::type_object()) != 0 };
|
||||
|
||||
if checked {
|
||||
Ok( unsafe { Py::<T>::unchecked_downcast_from(ob) })
|
||||
} else {
|
||||
let py = unsafe {Python::assume_gil_acquired()};
|
||||
Err(::PythonObjectDowncastError(py, None))
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
default fn downcast_borrow_from<'source, S>(
|
||||
ob: &'source Py<'p, S>) -> Result<&'source T, ::PythonObjectDowncastError<'p>>
|
||||
where S: PyTypeObjectInfo
|
||||
{
|
||||
let checked = unsafe { ffi::PyObject_TypeCheck(ob.inner, T::type_object()) != 0 };
|
||||
|
||||
if checked {
|
||||
Ok( unsafe { Py::<T>::unchecked_downcast_borrow_from(ob) })
|
||||
} else {
|
||||
let py = unsafe {Python::assume_gil_acquired()};
|
||||
Err(::PythonObjectDowncastError(py, None))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'source, T> ::FromPyObj<'source> for &'source T
|
||||
where T: PyTypeObjectInfo
|
||||
{
|
||||
#[inline]
|
||||
default fn extr<S>(py: &'source Py<'source, S>) -> PyResult<&'source T>
|
||||
where S: PyTypeObjectInfo
|
||||
{
|
||||
Ok(::PyWithCheckedDowncast::downcast_borrow_from(py)?)
|
||||
//Ok(py.cast_as::<T>()?)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'source, T> ::FromPyObj<'source> for Py<'source, T>
|
||||
where T: PyTypeObjectInfo
|
||||
{
|
||||
#[inline]
|
||||
default fn extr<S>(py: &'source Py<'source, S>) -> PyResult<Py<'source, T>>
|
||||
where S: PyTypeObjectInfo
|
||||
{
|
||||
Ok(::PyWithCheckedDowncast::downcast_from(py.clone())?)
|
||||
}
|
||||
}
|
||||
|
||||
//impl<'p, T> Deref for Py<'p, T> where T: BaseObject {
|
||||
//}
|
||||
|
||||
impl<'p, T> ToPyObject for Py<'p, T> {
|
||||
#[inline]
|
||||
fn to_py_object(&self, py: Python) -> PyObject {
|
||||
unsafe {PyObject::from_owned_ptr(py, self.inner)}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn into_py_object(self, py: Python) -> PyObject {
|
||||
unsafe {PyObject::from_borrowed_ptr(py, self.inner)}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn with_borrowed_ptr<F, R>(&self, _py: Python, f: F) -> R
|
||||
where F: FnOnce(*mut ffi::PyObject) -> R
|
||||
{
|
||||
f(self.inner)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@ use pythonrun::GILGuard;
|
|||
pub struct Python<'p>(PhantomData<&'p GILGuard>);
|
||||
|
||||
/// Trait implemented by all Python object types.
|
||||
|
||||
pub trait PythonObject : Send + Sized + 'static {
|
||||
/// Casts the Python object to PyObject.
|
||||
fn as_object(&self) -> &PyObject;
|
||||
|
@ -73,6 +74,18 @@ pub trait PythonObjectWithCheckedDowncast : PythonObject {
|
|||
fn downcast_borrow_from<'a, 'p>(Python<'p>, &'a PyObject) -> Result<&'a Self, PythonObjectDowncastError<'p>>;
|
||||
}
|
||||
|
||||
/// Trait implemented by Python object types that allow a checked downcast.
|
||||
pub trait PyWithCheckedDowncast<'p> : Sized {
|
||||
|
||||
/// Cast from PyObject to a concrete Python object type.
|
||||
fn downcast_from<S>(::Py<'p, S>) -> Result<::Py<'p, Self>, PythonObjectDowncastError<'p>>;
|
||||
|
||||
/// Cast from PyObject to a concrete Python object type.
|
||||
fn downcast_borrow_from<'source, S>(&'source ::Py<'p, S>)
|
||||
-> Result<&'source Self, PythonObjectDowncastError<'p>>
|
||||
where S: ::class::typeob::PyTypeObjectInfo;
|
||||
}
|
||||
|
||||
impl<T> PythonObjectWithCheckedDowncast for T where T: PyTypeObject + PythonObject {
|
||||
#[inline]
|
||||
default fn downcast_from<'p>(py: Python<'p>, obj: PyObject)
|
||||
|
|
Loading…
Reference in a new issue