stopping point

This commit is contained in:
Nikolay Kim 2017-05-21 22:22:45 -07:00
parent 56d93249ab
commit d6fb90bdc2
17 changed files with 583 additions and 254 deletions

View file

@ -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,

View file

@ -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;
}

View file

@ -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,

View file

@ -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!();
}
}
}

View file

@ -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)),

View file

@ -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);
}
}

View file

@ -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>
{

View file

@ -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> {

View file

@ -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 {

View file

@ -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) {

View file

@ -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
}

View file

@ -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 {

View file

@ -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,

View file

@ -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)

View file

@ -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) }

View file

@ -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)
}
}

View file

@ -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)