diff --git a/pyo3cls/src/defs.rs b/pyo3cls/src/defs.rs index 3aa036ae..53482e16 100644 --- a/pyo3cls/src/defs.rs +++ b/pyo3cls/src/defs.rs @@ -439,68 +439,68 @@ pub const NUM: Proto = Proto { MethodProto::Binary { name: "__iadd__", arg: "Other", - pyres: true, + pyres: false, proto: "::pyo3::class::number::PyNumberIAddProtocol"}, MethodProto::Binary { name: "__isub__", arg: "Other", - pyres: true, + pyres: false, proto: "::pyo3::class::number::PyNumberISubProtocol"}, MethodProto::Binary { name: "__imul__", arg: "Other", - pyres: true, + pyres: false, proto: "::pyo3::class::number::PyNumberIMulProtocol"}, MethodProto::Binary { name: "__imatmul__", arg: "Other", - pyres: true, + pyres: false, proto: "::pyo3::class::number::PyNumberIMatmulProtocol"}, MethodProto::Binary { name: "__itruediv__", arg: "Other", - pyres: true, + pyres: false, proto: "::pyo3::class::number::PyNumberITruedivProtocol"}, MethodProto::Binary { name: "__ifloordiv__", arg: "Other", - pyres: true, + pyres: false, proto: "::pyo3::class::number::PyNumberIFloordivProtocol"}, MethodProto::Binary { name: "__imod__", arg: "Other", - pyres: true, + pyres: false, proto: "::pyo3::class::number::PyNumberIModProtocol"}, MethodProto::Ternary { name: "__ipow__", arg1: "Other", arg2: "Modulo", - pyres: true, + pyres: false, proto: "::pyo3::class::number::PyNumberIPowProtocol"}, MethodProto::Binary { name: "__ilshift__", arg: "Other", - pyres: true, + pyres: false, proto: "::pyo3::class::number::PyNumberILShiftProtocol"}, MethodProto::Binary { name: "__irshift__", arg: "Other", - pyres: true, + pyres: false, proto: "::pyo3::class::number::PyNumberIRShiftProtocol"}, MethodProto::Binary { name: "__iand__", arg: "Other", - pyres: true, + pyres: false, proto: "::pyo3::class::number::PyNumberIAndProtocol"}, MethodProto::Binary { name: "__ixor__", arg: "Other", - pyres: true, + pyres: false, proto: "::pyo3::class::number::PyNumberIXorProtocol"}, MethodProto::Binary { name: "__ior__", arg: "Other", - pyres: true, + pyres: false, proto: "::pyo3::class::number::PyNumberIOrProtocol"}, MethodProto::Unary { diff --git a/pyo3cls/src/func.rs b/pyo3cls/src/func.rs index c6a4af63..7162e4c6 100644 --- a/pyo3cls/src/func.rs +++ b/pyo3cls/src/func.rs @@ -42,12 +42,14 @@ pub fn impl_method_proto(cls: &Box, match *meth { MethodProto::Unary{name: _, pyres, proto} => { let p = syn::Ident::from(proto); - let succ = get_res_success(ty); + let (ty, succ) = get_res_success(ty); let tmp = extract_decl(syn::parse_item( quote! {fn test(&self) -> <#cls as #p<'p>>::Result {}}.as_str()).unwrap()); sig.decl.output = tmp.output.clone(); + modify_self_ty(sig); + modify_py_ty(sig); if pyres { quote! { @@ -65,14 +67,14 @@ pub fn impl_method_proto(cls: &Box, } }, MethodProto::Binary{name: n, arg, pyres, proto} => { - if sig.decl.inputs.len() < 2 { + if sig.decl.inputs.len() <= 2 { println!("Not enough arguments for {}", n); return Tokens::new(); } let p = syn::Ident::from(proto); let arg_name = syn::Ident::from(arg); let arg_ty = get_arg_ty(sig, 2); - let succ = get_res_success(ty); + let (ty, succ) = get_res_success(ty); let tmp = extract_decl(syn::parse_item( quote! {fn test( @@ -85,6 +87,8 @@ pub fn impl_method_proto(cls: &Box, arg: Option<<#cls as #p<'p>>::#arg_name>) -> <#cls as #p<'p>>::Result {}}.as_str()).unwrap()); modify_arg_ty(sig, 2, &tmp, &tmp2); + modify_self_ty(sig); + modify_py_ty(sig); if pyres { quote! { @@ -104,7 +108,7 @@ pub fn impl_method_proto(cls: &Box, } }, MethodProto::Ternary{name: n, arg1, arg2, pyres, proto} => { - if sig.decl.inputs.len() < 3 { + if sig.decl.inputs.len() <= 3 { print_err(format!("Not enough arguments {}", n), quote!(sig)); return Tokens::new(); } @@ -113,7 +117,7 @@ pub fn impl_method_proto(cls: &Box, let arg1_ty = get_arg_ty(sig, 2); let arg2_name = syn::Ident::from(arg2); let arg2_ty = get_arg_ty(sig, 3); - let succ = get_res_success(ty); + let (ty, succ) = get_res_success(ty); // rewrite ty let tmp = extract_decl(syn::parse_item( @@ -130,6 +134,8 @@ pub fn impl_method_proto(cls: &Box, -> <#cls as #p<'p>>::Result {}}.as_str()).unwrap()); modify_arg_ty(sig, 2, &tmp, &tmp2); modify_arg_ty(sig, 3, &tmp, &tmp2); + modify_self_ty(sig); + modify_py_ty(sig); if pyres { quote! { @@ -151,7 +157,7 @@ pub fn impl_method_proto(cls: &Box, } }, MethodProto::Quaternary{name: n, arg1, arg2, arg3, proto} => { - if sig.decl.inputs.len() < 4 { + if sig.decl.inputs.len() <= 4 { print_err(format!("Not enough arguments {}", n), quote!(sig)); return Tokens::new(); } @@ -162,7 +168,7 @@ pub fn impl_method_proto(cls: &Box, let arg2_ty = get_arg_ty(sig, 3); let arg3_name = syn::Ident::from(arg3); let arg3_ty = get_arg_ty(sig, 4); - let succ = get_res_success(ty); + let (ty, succ) = get_res_success(ty); // rewrite ty let tmp = extract_decl(syn::parse_item( @@ -182,6 +188,8 @@ pub fn impl_method_proto(cls: &Box, modify_arg_ty(sig, 2, &tmp, &tmp2); modify_arg_ty(sig, 3, &tmp, &tmp2); modify_arg_ty(sig, 4, &tmp, &tmp2); + modify_self_ty(sig); + modify_py_ty(sig); quote! { impl<'p> #p<'p> for #cls { @@ -202,7 +210,7 @@ pub fn impl_method_proto(cls: &Box, // TODO: better arg ty detection fn get_arg_ty(sig: &syn::MethodSig, idx: usize) -> syn::Ty { - match sig.decl.inputs[idx] { + let mut ty = match sig.decl.inputs[idx] { syn::FnArg::Captured(_, ref arg_ty) => { match arg_ty { &syn::Ty::Path(_, ref path) => { @@ -220,25 +228,38 @@ fn get_arg_ty(sig: &syn::MethodSig, idx: usize) -> syn::Ty { } arg_ty.clone() }, - _ => { - arg_ty.clone() - } + _ => arg_ty.clone() } }, - _ => - panic!("fn arg type is not supported"), + _ => panic!("fn arg type is not supported"), + }; + + match ty { + syn::Ty::Rptr(ref mut lifetime, _) => { + match lifetime { + &mut None => { + *lifetime = Some(syn::Lifetime {ident: syn::Ident::from("'p")}) + } + _ => (), + } + } + _ => () } + + ty } // Success -fn get_res_success(ty: &syn::Ty) -> syn::Ty { - match ty { +fn get_res_success(ty: &syn::Ty) -> (Tokens, syn::Ty) { + let result; + let mut succ = match ty { &syn::Ty::Path(_, ref path) => { if let Some(segment) = path.segments.last() { match segment.ident.as_ref() { // check result type "PyResult" => match segment.parameters { syn::PathParameters::AngleBracketed(ref data) => { + result = true; data.types[0].clone() }, _ => panic!("fn result type is not supported"), @@ -253,7 +274,40 @@ fn get_res_success(ty: &syn::Ty) -> syn::Ty { } } _ => panic!("not supported: {:?}", ty), + }; + + // add lifetime to Py + match succ { + syn::Ty::Path(_, ref mut path) => { + let last = path.segments.len()-1; + let seg = path.segments[last].clone(); + + if seg.ident.as_ref() == "Py" { + if let syn::PathParameters::AngleBracketed(ref data) = seg.parameters { + path.segments[last] = syn::PathSegment{ + ident: seg.ident.clone(), + parameters: syn::PathParameters::AngleBracketed( + syn::AngleBracketedParameterData{ + lifetimes: vec![syn::Lifetime { + ident: syn::Ident::from("'p")}], + types: data.types.clone(), + bindings: data.bindings.clone(), + }) + } + } + } + } + _ => (), } + + // result + let res = if result { + quote! {PyResult<#succ>} + } else { + quote! {#ty} + }; + + (res, succ) } @@ -285,13 +339,54 @@ fn modify_arg_ty(sig: &mut syn::MethodSig, idx: usize, } } }, - _ => - panic!("not supported"), + _ => panic!("not supported"), } sig.decl.output = decl1.output.clone(); } +fn modify_self_ty(sig: &mut syn::MethodSig) +{ + match sig.decl.inputs[0] { + syn::FnArg::SelfRef(ref mut lifetime, _) => { + *lifetime = Some(syn::Lifetime {ident: syn::Ident::from("'p")}) + }, + _ => panic!("not supported"), + } +} + +// modify Python signature +fn modify_py_ty(sig: &mut syn::MethodSig) +{ + match sig.decl.inputs[1] { + syn::FnArg::Captured(_, ref mut arg_ty) => { + match arg_ty { + &mut syn::Ty::Path(_, ref mut path) => { + let last = path.segments.len()-1; + let seg = path.segments[last].clone(); + if seg.ident.as_ref() == "Python" { + if let syn::PathParameters::AngleBracketed(ref data) = seg.parameters { + path.segments[last] = syn::PathSegment{ + ident: seg.ident.clone(), + parameters: syn::PathParameters::AngleBracketed( + syn::AngleBracketedParameterData{ + lifetimes: vec![syn::Lifetime { + ident: syn::Ident::from("'p")}], + types: data.types.clone(), + bindings: data.bindings.clone(), + }) + } + } + } + }, + _ => (), + } + }, + _ => panic!("not supported"), + } +} + + fn fix_name(pat: &syn::Pat, arg: &syn::FnArg) -> syn::FnArg { match arg { &syn::FnArg::Captured(_, ref arg_ty) => diff --git a/pyo3cls/src/py_class.rs b/pyo3cls/src/py_class.rs index 6a3df929..2162184d 100644 --- a/pyo3cls/src/py_class.rs +++ b/pyo3cls/src/py_class.rs @@ -8,7 +8,8 @@ pub fn build_py_class(ast: &mut syn::DeriveInput) -> Tokens { let base = syn::Ident::from("_pyo3::PyObject"); match ast.body { - syn::Body::Struct(syn::VariantData::Struct(_)) => (), + syn::Body::Struct(syn::VariantData::Struct(_)) => { + }, _ => panic!("#[class] can only be used with notmal structs"), } @@ -22,7 +23,6 @@ pub fn build_py_class(ast: &mut syn::DeriveInput) -> Tokens { const #dummy_const: () = { extern crate pyo3 as _pyo3; use std; - use pyo3::python::IntoPythonPointer; #tokens }; @@ -30,6 +30,7 @@ pub fn build_py_class(ast: &mut syn::DeriveInput) -> Tokens { } fn impl_class(cls: &syn::Ident, base: &syn::Ident) -> Tokens { + let token_name = syn::Ident::from("__py_token"); let cls_name = quote! { #cls }.as_str().to_string(); quote! { @@ -60,12 +61,22 @@ fn impl_class(cls: &syn::Ident, base: &syn::Ident) -> Tokens { } } - impl _pyo3::IntoPyObject for #cls { + impl _pyo3::python::ToPythonPointer for #cls { #[inline] - fn into_object<'p>(self, py: Python<'p>) -> Py<'p, PyObject> where Self: Sized - { - let ptr = py.init(self).into_ptr(); - _pyo3::PyObject::from_owned_ptr(py, ptr) + fn as_ptr(&self) -> *mut ffi::PyObject { + let offset = <#cls as _pyo3::typeob::PyTypeInfo>::offset(); + unsafe { + {self as *const _ as *mut u8}.offset(-offset) as *mut _pyo3::ffi::PyObject + } + } + } + + impl _pyo3::python::PyClone for #cls { + fn clone_ref(&self) -> PyPtr<#cls> { + unsafe { + let ptr = <#cls as _pyo3::python::ToPythonPointer>::as_ptr(self); + _pyo3::PyPtr::from_borrowed_ptr(ptr) + } } } } diff --git a/pyo3cls/src/py_method.rs b/pyo3cls/src/py_method.rs index caa6c53d..ef37166c 100644 --- a/pyo3cls/src/py_method.rs +++ b/pyo3cls/src/py_method.rs @@ -47,7 +47,7 @@ pub fn impl_wrap(cls: &Box, name: &syn::Ident, spec: &FnSpec) -> Tokens kwargs: *mut _pyo3::ffi::PyObject) -> *mut _pyo3::ffi::PyObject { const LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#name),"()"); - _pyo3::callback::cb_meth::<_, *mut _pyo3::ffi::PyObject>(LOCATION, |py| { + _pyo3::callback::cb_meth(LOCATION, |py| { let mut slf: Py<#cls> = Py::from_borrowed_ptr(py, slf); let args: _pyo3::Py<_pyo3::PyTuple> = _pyo3::Py::from_borrowed_ptr(py, args); @@ -70,18 +70,24 @@ pub fn impl_proto_wrap(cls: &Box, name: &syn::Ident, spec: &FnSpec) -> let body = impl_arg_params(&spec, cb); quote! { - unsafe extern "C" fn wrap<'p>( - slf: *mut _pyo3::ffi::PyObject, - args: *mut _pyo3::ffi::PyObject, - kwargs: *mut _pyo3::ffi::PyObject) -> *mut _pyo3::ffi::PyObject + #[allow(unused_mut)] + unsafe extern "C" fn wrap(slf: *mut _pyo3::ffi::PyObject, + args: *mut _pyo3::ffi::PyObject, + kwargs: *mut _pyo3::ffi::PyObject) -> *mut _pyo3::ffi::PyObject { const LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#name),"()"); - _pyo3::callback::handle(LOCATION, _pyo3::callback::PyObjectCallbackConverter, |py| { + _pyo3::callback::cb_meth(LOCATION, |py| { + let mut slf: Py<#cls> = Py::from_borrowed_ptr(py, slf); + let args: _pyo3::Py<_pyo3::PyTuple> = _pyo3::Py::from_borrowed_ptr(py, args); let kwargs: Option<_pyo3::Py<_pyo3::PyDict>> = _pyo3::argparse::get_kwargs(py, kwargs); - #body + let result = { + #body + }; + _pyo3::callback::cb_convert( + _pyo3::callback::PyObjectCallbackConverter, py, result) }) } } @@ -91,20 +97,28 @@ pub fn impl_proto_wrap(cls: &Box, name: &syn::Ident, spec: &FnSpec) -> pub fn impl_wrap_new(cls: &Box, name: &syn::Ident, spec: &FnSpec) -> Tokens { let cb = impl_class_new(cls, name, spec); let body = impl_arg_params(spec, cb); + let output = &spec.output; quote! { + #[allow(unused_mut)] unsafe extern "C" fn wrap(cls: *mut _pyo3::ffi::PyTypeObject, args: *mut _pyo3::ffi::PyObject, kwargs: *mut _pyo3::ffi::PyObject) -> *mut _pyo3::ffi::PyObject { - const LOCATION: &'static str = concat!( - stringify!(#cls), ".", stringify!(#name), "()"); - _pyo3::callback::handle(LOCATION, _pyo3::callback::PyObjectCallbackConverter, |py| { + const LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#name), "()"); + + _pyo3::callback::cb_meth(LOCATION, |py| { + let cls: _pyo3::Py<_pyo3::PyType> = _pyo3::Py::from_borrowed_ptr( + py, cls as *mut _pyo3::ffi::PyObject); let args: _pyo3::Py<_pyo3::PyTuple> = _pyo3::Py::from_borrowed_ptr(py, args); let kwargs: Option<_pyo3::Py<_pyo3::PyDict>> = _pyo3::argparse::get_kwargs(py, kwargs); - #body + let result: #output = { + #body + }; + _pyo3::callback::cb_convert( + _pyo3::callback::PyObjectCallbackConverter, py, result) }) } } @@ -120,8 +134,8 @@ fn impl_wrap_getter(cls: &Box, name: &syn::Ident, _spec: &FnSpec) -> To { const LOCATION: &'static str = concat!( stringify!(#cls), ".getter_", stringify!(#name), "()"); - _pyo3::callback::handle(LOCATION, _pyo3::callback::PyObjectCallbackConverter, |py| { - let slf: _pyo3::Py<#cls> = _pyo3::Py::from_borrowed_ptr(py, slf); + _pyo3::callback::cb_unary::<#cls, _, _, _>( + LOCATION, slf, _pyo3::callback::PyObjectCallbackConverter, |py, slf| { slf.#name(py) }) } @@ -130,25 +144,33 @@ fn impl_wrap_getter(cls: &Box, name: &syn::Ident, _spec: &FnSpec) -> To /// Generate functiona wrapper (PyCFunction, PyCFunctionWithKeywords) fn impl_wrap_setter(cls: &Box, name: &syn::Ident, spec: &FnSpec) -> Tokens { + if spec.args.len() < 1 { + println!("Not enough arguments for setter {}::{}", quote!{#cls}, name); + } let val_ty = spec.args[0].ty; quote! { + #[allow(unused_mut)] unsafe extern "C" fn wrap(slf: *mut _pyo3::ffi::PyObject, value: *mut _pyo3::ffi::PyObject, _: *mut _pyo3::c_void) -> _pyo3::c_int { const LOCATION: &'static str = concat!( stringify!(#cls), ".setter", stringify!(#name), "()"); - _pyo3::callback::handle(LOCATION, _pyo3::callback::UnitCallbackConverter, |py| { - let slf: _pyo3::Py<#cls> = _pyo3::Py::from_borrowed_ptr(py, slf); + _pyo3::callback::cb_setter(LOCATION, |py| { + let mut slf = _pyo3::Py::<#cls>::from_borrowed_ptr(py, slf); let value = _pyo3::PyObject::from_borrowed_ptr(py, value); - match <#val_ty as _pyo3::FromPyObject>::extract(&value) { - Ok(val) => { - let ret = slf.#name(val); - ret.map(|o| ()) - } + let result = match <#val_ty as _pyo3::FromPyObject>::extract(&value) { + Ok(val) => slf.#name(py, val), Err(e) => Err(e) + }; + match result { + Ok(_) => 0, + Err(e) => { + e.restore(py); + -1 + } } }) } @@ -156,19 +178,17 @@ fn impl_wrap_setter(cls: &Box, name: &syn::Ident, spec: &FnSpec) -> Tok } -fn impl_call(cls: &Box, fname: &syn::Ident, spec: &FnSpec) -> Tokens { +fn impl_call(_cls: &Box, fname: &syn::Ident, spec: &FnSpec) -> Tokens { let names: Vec<&syn::Ident> = spec.args.iter().map(|item| item.name).collect(); quote! {{ - slf.#fname(py, #(#names),*) + slf.as_mut().#fname(py, #(#names),*) }} } fn impl_class_new(cls: &Box, fname: &syn::Ident, spec: &FnSpec) -> Tokens { let names: Vec<&syn::Ident> = spec.args.iter().map(|item| item.name).collect(); quote! {{ - let cls: _pyo3::Py<_pyo3::PyType> = _pyo3::Py::from_borrowed_ptr( - py, cls as *mut _pyo3::ffi::PyObject); - #cls::#fname(&cls, #(#names),*) + #cls::#fname(&cls, py, #(#names),*) }} } diff --git a/pyo3cls/src/py_proto.rs b/pyo3cls/src/py_proto.rs index 0b2eb8d7..32e1dd35 100644 --- a/pyo3cls/src/py_proto.rs +++ b/pyo3cls/src/py_proto.rs @@ -95,8 +95,7 @@ fn impl_proto_impl(ty: &Box, impls: &mut Vec, proto: &de let name = syn::Ident::from(m.name); let proto = syn::Ident::from(m.proto); - let fn_spec = FnSpec::parse( - &iimpl.ident, sig, &mut iimpl.attrs); + let fn_spec = FnSpec::parse(&iimpl.ident, sig, &mut iimpl.attrs); let meth = py_method::impl_proto_wrap(ty, &iimpl.ident, &fn_spec); py_methods.push( diff --git a/src/callback.rs b/src/callback.rs index 84a2cc51..71ae74d3 100644 --- a/src/callback.rs +++ b/src/callback.rs @@ -21,7 +21,7 @@ pub trait CallbackConverter { pub struct PyObjectCallbackConverter; -impl CallbackConverter for PyObjectCallbackConverter +impl CallbackConverter for PyObjectCallbackConverter where S: IntoPyObject { type R = *mut ffi::PyObject; @@ -90,7 +90,7 @@ impl CallbackConverter<()> for UnitCallbackConverter { } } -pub struct IterNextResultConverter; +/*pub struct IterNextResultConverter; impl CallbackConverter> for IterNextResultConverter @@ -112,7 +112,7 @@ impl CallbackConverter> fn error_value() -> *mut ffi::PyObject { ptr::null_mut() } -} +}*/ pub trait WrappingCastTo { fn wrapping_cast(self) -> T; @@ -250,7 +250,7 @@ pub unsafe fn cb_unary_unit(location: &str, slf: *mut ffi::PyObject, f: ret } -pub unsafe fn cb_meth(location: &str, f: F) -> *mut ffi::PyObject +pub unsafe fn cb_meth(location: &str, f: F) -> *mut ffi::PyObject where F: for<'p> FnOnce(Python<'p>) -> *mut ffi::PyObject, F: panic::UnwindSafe { @@ -270,6 +270,26 @@ pub unsafe fn cb_meth(location: &str, f: F) -> *mut ffi::PyObject ret } +pub unsafe fn cb_setter(location: &str, f: F) -> c_int + where F: for<'p> FnOnce(Python<'p>) -> c_int, + F: panic::UnwindSafe +{ + let guard = AbortOnDrop(location); + let ret = panic::catch_unwind(|| { + let py = Python::assume_gil_acquired(); + f(py) + }); + let ret = match ret { + Ok(r) => r, + Err(ref err) => { + handle_panic(Python::assume_gil_acquired(), err); + -1 + } + }; + mem::forget(guard); + ret +} + #[inline] pub unsafe fn cb_convert(_c: C, py: Python, value: PyResult) -> C::R where C: CallbackConverter diff --git a/src/class/async.rs b/src/class/async.rs index 4699c71c..90983ed2 100644 --- a/src/class/async.rs +++ b/src/class/async.rs @@ -24,13 +24,13 @@ pub trait PyAsyncProtocol<'p>: PyTypeInfo + Sized + 'static { fn __aiter__(&'p self, py: Python<'p>) -> Self::Result where Self: PyAsyncAiterProtocol<'p> { unimplemented!() } - fn __anext__(&'p self, py: Python<'p>) + fn __anext__(&'p mut self, py: Python<'p>) -> Self::Result where Self: PyAsyncAnextProtocol<'p> { unimplemented!() } - fn __aenter__(&'p self, py: Python<'p>) + fn __aenter__(&'p mut self, py: Python<'p>) -> Self::Result where Self: PyAsyncAenterProtocol<'p> { unimplemented!() } - fn __aexit__(&'p self, py: Python<'p>, + fn __aexit__(&'p mut self, py: Python<'p>, exc_type: Option, exc_value: Option, traceback: Option) diff --git a/src/class/basic.rs b/src/class/basic.rs index 295bd2b2..cdafe434 100644 --- a/src/class/basic.rs +++ b/src/class/basic.rs @@ -31,10 +31,10 @@ pub trait PyObjectProtocol<'p>: PyTypeInfo + Sized + 'static { fn __getattr__(&'p self, py: Python<'p>, name: Self::Name) -> Self::Result where Self: PyObjectGetAttrProtocol<'p> {unimplemented!()} - fn __setattr__(&'p self, py: Python<'p>, name: Self::Name, value: Self::Value) + fn __setattr__(&'p mut self, py: Python<'p>, name: Self::Name, value: Self::Value) -> Self::Result where Self: PyObjectSetAttrProtocol<'p> {unimplemented!()} - fn __delattr__(&'p self, py: Python<'p>, name: Self::Name) + fn __delattr__(&'p mut self, py: Python<'p>, name: Self::Name) -> Self::Result where Self: PyObjectDelAttrProtocol<'p> {unimplemented!()} fn __str__(&'p self, py: Python<'p>) diff --git a/src/class/iter.rs b/src/class/iter.rs index f5e8c6ca..67727594 100644 --- a/src/class/iter.rs +++ b/src/class/iter.rs @@ -16,10 +16,10 @@ use callback::PyObjectCallbackConverter; /// Iterator protocol #[allow(unused_variables)] pub trait PyIterProtocol<'p> : PyTypeInfo { - fn __iter__(&'p self, py: Python<'p>) + fn __iter__(&'p mut self, py: Python<'p>) -> Self::Result where Self: PyIterIterProtocol<'p> { unimplemented!() } - fn __next__(&'p self, py: Python<'p>) + fn __next__(&'p mut self, py: Python<'p>) -> Self::Result where Self: PyIterNextProtocol<'p> { unimplemented!() } } diff --git a/src/class/macros.rs b/src/class/macros.rs index 053220ad..296cd99a 100644 --- a/src/class/macros.rs +++ b/src/class/macros.rs @@ -17,7 +17,7 @@ macro_rules! py_unary_func { let ret = $crate::std::panic::catch_unwind(|| { let py = $crate::Python::assume_gil_acquired(); let mut slf = $crate::Py::::from_borrowed_ptr(py, slf); - let res = slf.$f(py).into(); + let res = slf.as_mut().$f(py).into(); match res { Ok(val) => { @@ -131,7 +131,7 @@ macro_rules! py_binary_func{ let result = match arg.extract() { Ok(arg) => { - slf.$f(py, arg).into() + slf.as_mut().$f(py, arg).into() } Err(e) => Err(e.into()), }; @@ -164,6 +164,56 @@ macro_rules! py_binary_func{ }} } +#[macro_export] +#[doc(hidden)] +macro_rules! py_binary_self_func{ + ($trait:ident, $class:ident :: $f:ident) => {{ + #[allow(unused_mut)] + unsafe extern "C" fn wrap(slf: *mut ffi::PyObject, + arg: *mut ffi::PyObject) -> *mut $crate::ffi::PyObject + where T: for<'p> $trait<'p> + { + const LOCATION: &'static str = concat!(stringify!($class), ".", stringify!($f), "()"); + + let guard = $crate::callback::AbortOnDrop(LOCATION); + let ret = $crate::std::panic::catch_unwind(|| { + let py = $crate::Python::assume_gil_acquired(); + let mut slf1 = $crate::Py::::from_borrowed_ptr(py, slf); + let arg = $crate::PyObject::from_borrowed_ptr(py, arg); + + let result = match arg.extract() { + Ok(arg) => { + slf1.as_mut().$f(py, arg).into() + } + Err(e) => Err(e.into()), + }; + + match result { + Ok(_) => { + slf + } + Err(e) => { + e.restore(py); + $crate::std::ptr::null_mut() + } + } + }); + + let ret = match ret { + Ok(r) => r, + Err(ref err) => { + $crate::callback::handle_panic($crate::Python::assume_gil_acquired(), err); + $crate::std::ptr::null_mut() + } + }; + $crate::mem::forget(guard); + ret + } + Some(wrap::<$class>) + }} +} + + #[macro_export] #[doc(hidden)] macro_rules! py_ssizearg_func { @@ -180,7 +230,7 @@ macro_rules! py_ssizearg_func { let py = $crate::Python::assume_gil_acquired(); let mut slf = $crate::Py::::from_borrowed_ptr(py, slf); - let result = slf.$f(py, arg as isize).into(); + let result = slf.as_mut().$f(py, arg as isize).into(); match result { Ok(val) => { <$conv as $crate::callback::CallbackConverter<$res_type>> @@ -232,7 +282,7 @@ macro_rules! py_ternary_func{ let result = match arg1.extract() { Ok(arg1) => match arg2.extract() { - Ok(arg2) => slf.$f(py, arg1, arg2).into(), + Ok(arg2) => slf.as_mut().$f(py, arg1, arg2).into(), Err(e) => Err(e.into()) }, Err(e) => Err(e.into()), @@ -268,6 +318,58 @@ macro_rules! py_ternary_func{ }} } +#[macro_export] +#[doc(hidden)] +macro_rules! py_ternary_self_func{ + ($trait:ident, $class:ident :: $f:ident) => {{ + #[allow(unused_mut)] + unsafe extern "C" fn wrap(slf: *mut $crate::ffi::PyObject, + arg1: *mut $crate::ffi::PyObject, + arg2: *mut $crate::ffi::PyObject) + -> *mut $crate::ffi::PyObject + where T: for<'p> $trait<'p> + { + const LOCATION: &'static str = concat!(stringify!($class), ".", stringify!($f), "()"); + let guard = $crate::callback::AbortOnDrop(LOCATION); + let ret = $crate::std::panic::catch_unwind(|| { + let py = $crate::Python::assume_gil_acquired(); + let mut slf1 = $crate::Py::::from_borrowed_ptr(py, slf); + let arg1 = $crate::PyObject::from_borrowed_ptr(py, arg1); + let arg2 = $crate::PyObject::from_borrowed_ptr(py, arg2); + + let result = match arg1.extract() { + Ok(arg1) => match arg2.extract() { + Ok(arg2) => slf1.as_mut().$f(py, arg1, arg2).into(), + Err(e) => Err(e.into()) + }, + Err(e) => Err(e.into()), + }; + + match result { + Ok(_) => slf, + Err(e) => { + e.restore(py); + $crate::std::ptr::null_mut() + } + } + }); + + let ret = match ret { + Ok(r) => r, + Err(ref err) => { + $crate::callback::handle_panic( + $crate::Python::assume_gil_acquired(), err); + $crate::std::ptr::null_mut() + } + }; + $crate::mem::forget(guard); + ret + } + + Some(wrap::) + }} +} + #[macro_export] #[doc(hidden)] @@ -336,7 +438,7 @@ macro_rules! py_func_del{ let name = PyObject::from_borrowed_ptr(py, name); let result = match name.extract() { Ok(name) => - slf.$f(py, name).into(), + slf.as_mut().$f(py, name).into(), Err(e) => Err(e.into()), }; match result { @@ -394,7 +496,7 @@ macro_rules! py_func_set_del{ if value.is_null() { let result = match name.extract() { Ok(name) => - slf.$f2(py, name).into(), + slf.as_mut().$f2(py, name).into(), Err(e) => Err(e.into()), }; match result { @@ -410,7 +512,7 @@ macro_rules! py_func_set_del{ let result = match name.extract() { Ok(name) => match value.extract() { Ok(value) => { - slf.$f(py, name, value).into() + slf.as_mut().$f(py, name, value).into() }, Err(e) => Err(e.into()), }, diff --git a/src/class/mapping.rs b/src/class/mapping.rs index be1e6f12..c2357c42 100644 --- a/src/class/mapping.rs +++ b/src/class/mapping.rs @@ -23,10 +23,10 @@ pub trait PyMappingProtocol<'p>: PyTypeInfo + Sized + 'static { fn __getitem__(&'p self, py: Python<'p>, key: Self::Key) -> Self::Result where Self: PyMappingGetItemProtocol<'p> {unimplemented!()} - fn __setitem__(&'p self, py: Python<'p>, key: Self::Key, value: Self::Value) + fn __setitem__(&'p mut self, py: Python<'p>, key: Self::Key, value: Self::Value) -> Self::Result where Self: PyMappingSetItemProtocol<'p> {unimplemented!()} - fn __delitem__(&'p self, py: Python<'p>, key: Self::Key) + fn __delitem__(&'p mut self, py: Python<'p>, key: Self::Key) -> Self::Result where Self: PyMappingDelItemProtocol<'p> {unimplemented!()} fn __iter__(&'p self, py: Python<'p>) diff --git a/src/class/number.rs b/src/class/number.rs index 9f05fb6d..9f82c615 100644 --- a/src/class/number.rs +++ b/src/class/number.rs @@ -74,31 +74,31 @@ pub trait PyNumberProtocol<'p>: PyTypeInfo { fn __ror__(&'p self, py: Python<'p>, other: Self::Other) -> Self::Result where Self: PyNumberROrProtocol<'p> { unimplemented!() } - fn __iadd__(&'p self, py: Python<'p>, other: Self::Other) + fn __iadd__(&'p mut self, py: Python<'p>, other: Self::Other) -> Self::Result where Self: PyNumberIAddProtocol<'p> { unimplemented!() } - fn __isub__(&'p self, py: Python<'p>, other: Self::Other) + fn __isub__(&'p mut self, py: Python<'p>, other: Self::Other) -> Self::Result where Self: PyNumberISubProtocol<'p> { unimplemented!() } - fn __imul__(&'p self, py: Python<'p>, other: Self::Other) + fn __imul__(&'p mut self, py: Python<'p>, other: Self::Other) -> Self::Result where Self: PyNumberIMulProtocol<'p> { unimplemented!() } - fn __imatmul__(&'p self, py: Python<'p>, other: Self::Other) + fn __imatmul__(&'p mut self, py: Python<'p>, other: Self::Other) -> Self::Result where Self: PyNumberIMatmulProtocol<'p> { unimplemented!() } - fn __itruediv__(&'p self, py: Python<'p>, other: Self::Other) + fn __itruediv__(&'p mut self, py: Python<'p>, other: Self::Other) -> Self::Result where Self: PyNumberITruedivProtocol<'p> {unimplemented!()} - fn __ifloordiv__(&'p self, py: Python<'p>, other: Self::Other) + fn __ifloordiv__(&'p mut self, py: Python<'p>, other: Self::Other) -> Self::Result where Self: PyNumberIFloordivProtocol<'p> {unimplemented!() } - fn __imod__(&'p self, py: Python<'p>, other: Self::Other) + fn __imod__(&'p mut self, py: Python<'p>, other: Self::Other) -> Self::Result where Self: PyNumberIModProtocol<'p> { unimplemented!() } - fn __ipow__(&'p self, py: Python<'p>, other: Self::Other, modulo: Self::Modulo) + fn __ipow__(&'p mut self, py: Python<'p>, other: Self::Other, modulo: Self::Modulo) -> Self::Result where Self: PyNumberIPowProtocol<'p> { unimplemented!() } - fn __ilshift__(&'p self, py: Python<'p>, other: Self::Other) + fn __ilshift__(&'p mut self, py: Python<'p>, other: Self::Other) -> Self::Result where Self: PyNumberILShiftProtocol<'p> { unimplemented!() } - fn __irshift__(&'p self, py: Python<'p>, other: Self::Other) + fn __irshift__(&'p mut self, py: Python<'p>, other: Self::Other) -> Self::Result where Self: PyNumberIRShiftProtocol<'p> { unimplemented!() } - fn __iand__(&'p self, py: Python<'p>, other: Self::Other) + fn __iand__(&'p mut self, py: Python<'p>, other: Self::Other) -> Self::Result where Self: PyNumberIAndProtocol<'p> { unimplemented!() } - fn __ixor__(&'p self, py: Python<'p>, other: Self::Other) + fn __ixor__(&'p mut self, py: Python<'p>, other: Self::Other) -> Self::Result where Self: PyNumberIXorProtocol<'p> { unimplemented!() } - fn __ior__(&'p self, py: Python<'p>, other: Self::Other) + fn __ior__(&'p mut self, py: Python<'p>, other: Self::Other) -> Self::Result where Self: PyNumberIOrProtocol<'p> { unimplemented!() } // Unary arithmetic @@ -124,12 +124,12 @@ pub trait PyNumberProtocol<'p>: PyTypeInfo { pub trait PyNumberAddProtocol<'p>: PyNumberProtocol<'p> { - type Other: for<'a> FromPyObject<'a>; + type Other: FromPyObject<'p>; type Success: ToPyObject; type Result: Into>; } pub trait PyNumberSubProtocol<'p>: PyNumberProtocol<'p> { - type Other: for<'a> FromPyObject<'a>; + type Other: FromPyObject<'p>; type Success: ToPyObject; type Result: Into>; } @@ -270,74 +270,60 @@ pub trait PyNumberROrProtocol<'p>: PyNumberProtocol<'p> { pub trait PyNumberIAddProtocol<'p>: PyNumberProtocol<'p> { type Other: FromPyObject<'p>; - type Success: ToPyObject; - type Result: Into>; + type Result: Into>; } pub trait PyNumberISubProtocol<'p>: PyNumberProtocol<'p> { type Other: FromPyObject<'p>; - type Success: ToPyObject; - type Result: Into>; + type Result: Into>; } pub trait PyNumberIMulProtocol<'p>: PyNumberProtocol<'p> { type Other: FromPyObject<'p>; - type Success: ToPyObject; - type Result: Into>; + type Result: Into>; } pub trait PyNumberIMatmulProtocol<'p>: PyNumberProtocol<'p> { type Other: FromPyObject<'p>; - type Success: ToPyObject; - type Result: Into>; + type Result: Into>; } pub trait PyNumberITruedivProtocol<'p>: PyNumberProtocol<'p> { type Other: FromPyObject<'p>; - type Success: ToPyObject; - type Result: Into>; + type Result: Into>; } pub trait PyNumberIFloordivProtocol<'p>: PyNumberProtocol<'p> { type Other: FromPyObject<'p>; - type Success: ToPyObject; - type Result: Into>; + type Result: Into>; } pub trait PyNumberIModProtocol<'p>: PyNumberProtocol<'p> { type Other: FromPyObject<'p>; - type Success: ToPyObject; - type Result: Into>; + type Result: Into>; } pub trait PyNumberIDivmodProtocol<'p>: PyNumberProtocol<'p> { type Other: FromPyObject<'p>; - type Success: ToPyObject; - type Result: Into>; + type Result: Into>; } pub trait PyNumberIPowProtocol<'p>: PyNumberProtocol<'p> { type Other: FromPyObject<'p>; type Modulo: FromPyObject<'p>; - type Success: ToPyObject; - type Result: Into>; + type Result: Into>; } pub trait PyNumberILShiftProtocol<'p>: PyNumberProtocol<'p> { type Other: FromPyObject<'p>; - type Success: ToPyObject; - type Result: Into>; + type Result: Into>; } pub trait PyNumberIRShiftProtocol<'p>: PyNumberProtocol<'p> { type Other: FromPyObject<'p>; - type Success: ToPyObject; - type Result: Into>; + type Result: Into>; } pub trait PyNumberIAndProtocol<'p>: PyNumberProtocol<'p> { type Other: FromPyObject<'p>; - type Success: ToPyObject; - type Result: Into>; + type Result: Into>; } pub trait PyNumberIXorProtocol<'p>: PyNumberProtocol<'p> { type Other: FromPyObject<'p>; - type Success: ToPyObject; - type Result: Into>; + type Result: Into>; } pub trait PyNumberIOrProtocol<'p>: PyNumberProtocol<'p> { type Other: FromPyObject<'p>; - type Success: ToPyObject; - type Result: Into>; + type Result: Into>; } pub trait PyNumberNegProtocol<'p>: PyNumberProtocol<'p> { @@ -689,8 +675,7 @@ impl<'p, T> PyNumberIAddProtocolImpl for T where T: PyNumberProtocol<'p> { } impl PyNumberIAddProtocolImpl for T where T: for<'p> PyNumberIAddProtocol<'p> { fn nb_inplace_add() -> Option { - py_binary_func!(PyNumberIAddProtocol, - T::__iadd__, T::Success, PyObjectCallbackConverter) + py_binary_self_func!(PyNumberIAddProtocol, T::__iadd__) } } @@ -702,8 +687,7 @@ impl<'p, T> PyNumberISubProtocolImpl for T where T: PyNumberProtocol<'p> { } impl PyNumberISubProtocolImpl for T where T: for<'p> PyNumberISubProtocol<'p> { fn nb_inplace_subtract() -> Option { - py_binary_func!(PyNumberISubProtocol, - T::__isub__, T::Success, PyObjectCallbackConverter) + py_binary_self_func!(PyNumberISubProtocol, T::__isub__) } } @@ -715,8 +699,7 @@ impl<'p, T> PyNumberIMulProtocolImpl for T where T: PyNumberProtocol<'p> { } impl PyNumberIMulProtocolImpl for T where T: for<'p> PyNumberIMulProtocol<'p> { fn nb_inplace_multiply() -> Option { - py_binary_func!(PyNumberIMulProtocol, - T::__imul__, T::Success, PyObjectCallbackConverter) + py_binary_self_func!(PyNumberIMulProtocol, T::__imul__) } } @@ -728,8 +711,7 @@ impl<'p, T> PyNumberIMatmulProtocolImpl for T where T: PyNumberProtocol<'p> { } impl PyNumberIMatmulProtocolImpl for T where T: for<'p> PyNumberIMatmulProtocol<'p> { fn nb_inplace_matrix_multiply() -> Option { - py_binary_func!(PyNumberIMatmulProtocol, - T::__imatmul__, T::Success, PyObjectCallbackConverter) + py_binary_self_func!(PyNumberIMatmulProtocol, T::__imatmul__) } } @@ -741,8 +723,7 @@ impl<'p, T> PyNumberITruedivProtocolImpl for T where T: PyNumberProtocol<'p> { } impl PyNumberITruedivProtocolImpl for T where T: for<'p> PyNumberITruedivProtocol<'p> { fn nb_inplace_true_divide() -> Option { - py_binary_func!(PyNumberITruedivProtocol, - T::__itruediv__, T::Success, PyObjectCallbackConverter) + py_binary_self_func!(PyNumberITruedivProtocol, T::__itruediv__) } } @@ -754,8 +735,7 @@ impl<'p, T> PyNumberIFloordivProtocolImpl for T where T: PyNumberProtocol<'p> { } impl PyNumberIFloordivProtocolImpl for T where T: for<'p> PyNumberIFloordivProtocol<'p> { fn nb_inplace_floor_divide() -> Option { - py_binary_func!(PyNumberIFloordivProtocol, - T::__ifloordiv__, T::Success, PyObjectCallbackConverter) + py_binary_self_func!(PyNumberIFloordivProtocol, T::__ifloordiv__) } } @@ -767,8 +747,7 @@ impl<'p, T> PyNumberIModProtocolImpl for T where T: PyNumberProtocol<'p> { } impl PyNumberIModProtocolImpl for T where T: for<'p> PyNumberIModProtocol<'p> { fn nb_inplace_remainder() -> Option { - py_binary_func!(PyNumberIModProtocol, - T::__imod__, T::Success, PyObjectCallbackConverter) + py_binary_self_func!(PyNumberIModProtocol, T::__imod__) } } @@ -780,8 +759,7 @@ impl<'p, T> PyNumberIPowProtocolImpl for T where T: PyNumberProtocol<'p> { } impl PyNumberIPowProtocolImpl for T where T: for<'p> PyNumberIPowProtocol<'p> { fn nb_inplace_power() -> Option { - py_ternary_func!(PyNumberIPowProtocol, - T::__ipow__, T::Success, PyObjectCallbackConverter) + py_ternary_self_func!(PyNumberIPowProtocol, T::__ipow__) } } @@ -793,8 +771,7 @@ impl<'p, T> PyNumberILShiftProtocolImpl for T where T: PyNumberProtocol<'p> { } impl PyNumberILShiftProtocolImpl for T where T: for<'p> PyNumberILShiftProtocol<'p> { fn nb_inplace_lshift() -> Option { - py_binary_func!(PyNumberILShiftProtocol, - T::__ilshift__, T::Success, PyObjectCallbackConverter) + py_binary_self_func!(PyNumberILShiftProtocol, T::__ilshift__) } } @@ -806,8 +783,7 @@ impl<'p, T> PyNumberIRShiftProtocolImpl for T where T: PyNumberProtocol<'p> { } impl PyNumberIRShiftProtocolImpl for T where T: for<'p> PyNumberIRShiftProtocol<'p> { fn nb_inplace_rshift() -> Option { - py_binary_func!(PyNumberIRShiftProtocol, - T::__irshift__, T::Success, PyObjectCallbackConverter) + py_binary_self_func!(PyNumberIRShiftProtocol, T::__irshift__) } } @@ -820,8 +796,7 @@ impl<'p, T> PyNumberIAndProtocolImpl for T where T: PyNumberProtocol<'p> { } impl PyNumberIAndProtocolImpl for T where T: for<'p> PyNumberIAndProtocol<'p> { fn nb_inplace_and() -> Option { - py_binary_func!(PyNumberIAndProtocol, - T::__iand__, T::Success, PyObjectCallbackConverter) + py_binary_self_func!(PyNumberIAndProtocol, T::__iand__) } } @@ -833,8 +808,7 @@ impl<'p, T> PyNumberIXorProtocolImpl for T where T: PyNumberProtocol<'p> { } impl PyNumberIXorProtocolImpl for T where T: for<'p> PyNumberIXorProtocol<'p> { fn nb_inplace_xor() -> Option { - py_binary_func!(PyNumberIXorProtocol, - T::__ixor__, T::Success, PyObjectCallbackConverter) + py_binary_self_func!(PyNumberIXorProtocol, T::__ixor__) } } @@ -846,8 +820,7 @@ impl<'p, T> PyNumberIOrProtocolImpl for T where T: PyNumberProtocol<'p> { } impl PyNumberIOrProtocolImpl for T where T: for<'p> PyNumberIOrProtocol<'p> { fn nb_inplace_or() -> Option { - py_binary_func!(PyNumberIOrProtocol, - T::__ior__, T::Success, PyObjectCallbackConverter) + py_binary_self_func!(PyNumberIOrProtocol, T::__ior__) } } diff --git a/src/class/sequence.rs b/src/class/sequence.rs index 4ba52da0..b41b92ea 100644 --- a/src/class/sequence.rs +++ b/src/class/sequence.rs @@ -23,10 +23,10 @@ pub trait PySequenceProtocol<'p>: PyTypeInfo + Sized + 'static { fn __getitem__(&'p self, py: Python<'p>, key: isize) -> Self::Result where Self: PySequenceGetItemProtocol<'p> { unimplemented!() } - fn __setitem__(&'p self, py: Python<'p>, key: isize, value: Self::Value) -> Self::Result + fn __setitem__(&'p mut self, py: Python<'p>, key: isize, value: Self::Value) -> Self::Result where Self: PySequenceSetItemProtocol<'p> { unimplemented!() } - fn __delitem__(&'p self, py: Python<'p>, key: isize) -> Self::Result + fn __delitem__(&'p mut self, py: Python<'p>, key: isize) -> Self::Result where Self: PySequenceDelItemProtocol<'p> { unimplemented!() } fn __contains__(&'p self, py: Python<'p>, item: Self::Item) -> Self::Result @@ -38,10 +38,10 @@ pub trait PySequenceProtocol<'p>: PyTypeInfo + Sized + 'static { fn __repeat__(&'p self, py: Python<'p>, count: isize) -> Self::Result where Self: PySequenceRepeatProtocol<'p> { unimplemented!() } - fn __inplace_concat__(&'p self, py: Python<'p>, other: Self::Other) -> Self::Result + fn __inplace_concat__(&'p mut self, py: Python<'p>, other: Self::Other) -> Self::Result where Self: PySequenceInplaceConcatProtocol<'p> { unimplemented!() } - fn __inplace_repeat__(&'p self, py: Python<'p>, count: isize) -> Self::Result + fn __inplace_repeat__(&'p mut self, py: Python<'p>, count: isize) -> Self::Result where Self: PySequenceInplaceRepeatProtocol<'p> { unimplemented!() } } diff --git a/src/conversion.rs b/src/conversion.rs index 3e56b521..8cf4790d 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -32,7 +32,6 @@ pub trait IntoPyObject { #[inline] fn into_object<'p>(self, py: Python<'p>) -> Py<'p, PyObject> where Self: Sized; - } @@ -100,7 +99,7 @@ impl <'p, T: ?Sized> RefFromPyObject<'p> for T } // Default IntoPyObject implementation -impl IntoPyObject for T where T: ToPyObject +impl IntoPyObject for T where T: ToPyObject { #[inline] default fn into_object<'p>(self, py: Python<'p>) -> Py<'p, PyObject> where Self: Sized @@ -139,7 +138,7 @@ impl ToPyObject for Option where T: ToPyObject { } } -impl IntoPyObject for Option where T: IntoPyObject { +impl IntoPyObject for Option where T: IntoPyObject { fn into_object<'p>(self, py: Python<'p>) -> Py<'p, PyObject> { match self { diff --git a/src/lib.rs b/src/lib.rs index e7194afc..f229820a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -69,9 +69,9 @@ pub use pyptr::{Py, PyPtr}; pub use err::{PyErr, PyResult, PyDowncastError}; pub use objects::*; -pub use python::{AsPy, Python}; +pub use python::{AsPy, Python, PythonToken}; pub use pythonrun::{GILGuard, GILProtected, prepare_freethreaded_python}; -pub use conversion::{FromPyObject, /*RefFromPyObject,*/ ToPyObject, IntoPyObject, ToPyTuple}; +pub use conversion::{FromPyObject, RefFromPyObject, ToPyObject, IntoPyObject, ToPyTuple}; pub use class::{CompareOp}; pub mod class; pub use class::*; diff --git a/src/objectprotocol.rs b/src/objectprotocol.rs index 21fe2fdb..e9e662e5 100644 --- a/src/objectprotocol.rs +++ b/src/objectprotocol.rs @@ -1,20 +1,6 @@ -// Copyright (c) 2015 Daniel Grunwald +// Copyright (c) 2017-present PyO3 Project and Contributors // -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. +// based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython use std::fmt; use std::cmp::Ordering; @@ -303,7 +289,6 @@ impl fmt::Display for PyPtr { } } - #[cfg(test)] mod test { use std; diff --git a/src/objects/mod.rs b/src/objects/mod.rs index 2b63f003..a80e696d 100644 --- a/src/objects/mod.rs +++ b/src/objects/mod.rs @@ -22,22 +22,22 @@ macro_rules! pyobject_newtype( impl<'p> $crate::python::AsPy<'p> for &'p $name { #[inline] - fn py<'a>(&'a self) -> Python<'p> { + fn py<'a>(&'a self) -> $crate::Python<'p> { unsafe { $crate::python::Python::assume_gil_acquired() } } } impl $crate::python::ToPythonPointer for $name { #[inline] - fn as_ptr(&self) -> *mut ffi::PyObject { - self as *const _ as *mut ffi::PyObject + fn as_ptr(&self) -> *mut $crate::ffi::PyObject { + self as *const _ as *mut $crate::ffi::PyObject } } impl<'a> $crate::python::ToPythonPointer for &'a $name { #[inline] - fn as_ptr(&self) -> *mut ffi::PyObject { - self as *const _ as *mut ffi::PyObject + fn as_ptr(&self) -> *mut $crate::ffi::PyObject { + self as *const _ as *mut $crate::ffi::PyObject } } @@ -63,6 +63,32 @@ macro_rules! pyobject_newtype( unsafe { &mut $crate::ffi::$typeobject } } } + + impl $crate::std::fmt::Debug for $name { + default fn fmt(&self, f: &mut $crate::std::fmt::Formatter) + -> Result<(), $crate::std::fmt::Error> + { + let py = unsafe { $crate::python::Python::assume_gil_acquired() }; + let s = unsafe { $crate::Py::<$crate::PyString>::cast_from_owned_nullptr( + py, $crate::ffi::PyObject_Repr( + $crate::python::ToPythonPointer::as_ptr(self))) }; + let repr_obj = try!(s.map_err(|_| $crate::std::fmt::Error)); + f.write_str(&repr_obj.to_string_lossy()) + } + } + + impl $crate::std::fmt::Display for $name { + fn fmt(&self, f: &mut $crate::std::fmt::Formatter) + -> Result<(), $crate::std::fmt::Error> + { + let py = unsafe { $crate::python::Python::assume_gil_acquired() }; + let s = unsafe { $crate::Py::<$crate::PyString>::cast_from_owned_nullptr( + py, $crate::ffi::PyObject_Str( + $crate::python::ToPythonPointer::as_ptr(self))) }; + let str_obj = try!(s.map_err(|_| $crate::std::fmt::Error)); + f.write_str(&str_obj.to_string_lossy()) + } + } ); ); diff --git a/src/pyptr.rs b/src/pyptr.rs index c09c8c84..d4d32859 100644 --- a/src/pyptr.rs +++ b/src/pyptr.rs @@ -20,6 +20,26 @@ pub struct PyPtr { } impl PyPtr { + /// Creates a PyPtr 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(ptr: *mut ffi::PyObject) -> PyPtr { + debug_assert!(!ptr.is_null() && ffi::Py_REFCNT(ptr) > 0); + PyPtr {inner: ptr, _t: PhantomData} + } + + /// Creates a PyPTr instance for the given FFI pointer. + /// Calls Py_INCREF() on the ptr. + /// Undefined behavior if the pointer is NULL or invalid. + /// Caller of this method has to have valid Py object. + #[inline] + pub unsafe fn from_borrowed_ptr(ptr: *mut ffi::PyObject) -> PyPtr { + debug_assert!(!ptr.is_null() && ffi::Py_REFCNT(ptr) > 0); + ffi::Py_INCREF(ptr); + PyPtr {inner: ptr, _t: PhantomData} + } + pub fn as_ref<'p>(&self, _py: Python<'p>) -> Py<'p, T> { Py{inner: self.inner, _t: PhantomData, _py: PhantomData} } @@ -56,7 +76,6 @@ impl IntoPythonPointer for PyPtr { #[inline] #[must_use] fn into_ptr(self) -> *mut ffi::PyObject { - println!("INTO PTR: {:?}", self.inner); let ptr = self.inner; std::mem::forget(self); ptr @@ -206,7 +225,7 @@ impl<'p, T> Py<'p, T> impl<'p, T> Py<'p, T> where T: PyTypeInfo { /// Create new python object and move T instance under python management - pub fn new(py: &Python<'p>, value: T) -> PyResult> where T: PyObjectAlloc + pub fn new(py: Python<'p>, value: T) -> PyResult> where T: PyObjectAlloc { let ob = unsafe { try!(::alloc(py, value)) @@ -463,10 +482,10 @@ impl <'a, T> ToPyObject for Py<'a, T> { } } -impl <'a, T> IntoPyObject for Py<'a, T> { +impl<'p, T> IntoPyObject for Py<'p, T> { #[inline] - default fn into_object<'p>(self, py: Python<'p>) -> Py<'p, PyObject> { + default fn into_object<'a>(self, py: Python<'a>) -> Py<'a, PyObject> { PyObject::from_borrowed_ptr(py, self.inner) } } diff --git a/src/python.rs b/src/python.rs index fa9562e0..b35a05d0 100644 --- a/src/python.rs +++ b/src/python.rs @@ -1,20 +1,6 @@ -// Copyright (c) 2015 Daniel Grunwald +// Copyright (c) 2017-present PyO3 Project and Contributors // -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. +// based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython use std; use std::ffi::CString; @@ -42,11 +28,19 @@ use pythonrun::GILGuard; #[derive(Copy, Clone)] pub struct Python<'p>(PhantomData<&'p GILGuard>); +pub struct PythonToken(PhantomData); + pub trait AsPy<'p> { fn py<'a>(&'a self) -> Python<'p>; } + +pub trait PyClone : Sized { + fn clone_ref(&self) -> PyPtr; +} + + /// This trait allows retrieving the underlying FFI pointer from Python objects. pub trait ToPythonPointer { /// Retrieves the underlying FFI pointer (as a borrowed pointer). @@ -55,7 +49,8 @@ pub trait ToPythonPointer { /// This trait allows retrieving the underlying FFI pointer from Python objects. pub trait IntoPythonPointer { - /// Retrieves the underlying FFI pointer (as a borrowed pointer). + /// Retrieves the underlying FFI pointer. Whether pointer owned or borrowed + /// depends on implementation. fn into_ptr(self) -> *mut ffi::PyObject; } @@ -82,6 +77,7 @@ impl IntoPythonPointer for Option where T: IntoPythonPointer { } } + impl<'p> Python<'p> { /// Retrieve Python instance under the assumption that the GIL is already acquired at this point, /// and stays acquired for the lifetime `'p`. @@ -169,14 +165,6 @@ impl<'p> Python<'p> { } } - /// Create new PyObject instance - #[inline] - pub fn init(&'p self, value: T) -> Py<'p, T> - where T: PyTypeInfo + PyObjectAlloc - { - Py::new(self, value).unwrap() - } - /// Gets the Python builtin value `None`. #[allow(non_snake_case)] // the Python keyword starts with uppercase #[inline] @@ -219,8 +207,69 @@ impl<'p> Python<'p> { pub fn import(self, name : &str) -> PyResult> { PyModule::import(self, name) } + + pub fn with_token(self, f: F) -> Py<'p, T> + where F: FnOnce(PythonToken) -> T, + T: PyTypeInfo + PyObjectAlloc + { + let value = f(PythonToken(PhantomData)); + Py::new(self, value).unwrap() + } } +impl PythonToken { + + /// Gets the Python builtin value `None`. + #[allow(non_snake_case)] // the Python keyword starts with uppercase + #[inline] + pub fn None(self) -> PyPtr { + unsafe { PyPtr::from_borrowed_ptr(ffi::Py_None()) } + } + + /// Gets the Python builtin value `True`. + #[allow(non_snake_case)] // the Python keyword starts with uppercase + #[inline] + pub fn True(self) -> PyPtr { + unsafe { PyPtr::from_borrowed_ptr(ffi::Py_True()) } + } + + /// Gets the Python builtin value `False`. + #[allow(non_snake_case)] // the Python keyword starts with uppercase + #[inline] + pub fn False(self) -> PyPtr { + unsafe { PyPtr::from_borrowed_ptr(ffi::Py_False()) } + } + + /// Gets the Python builtin value `NotImplemented`. + #[allow(non_snake_case)] // the Python keyword starts with uppercase + #[inline] + pub fn NotImplemented(self) -> PyPtr { + unsafe { PyPtr::from_borrowed_ptr(ffi::Py_NotImplemented()) } + } + + /// Gets the Python type object for type T. + pub fn get_type(self) -> PyPtr where U: PyTypeObject { + U::type_object(Python(PhantomData)).into_pptr() + } + + /// Execute closure `F` with Python instance. + /// Retrieve Python instance under the assumption that the GIL is already acquired + /// at this point, and stays acquired during closure call. + pub fn with_py<'p, F>(self, f: F) where F: FnOnce(Python<'p>) + { + f(Python(PhantomData)) + } + + pub fn with_token(self, f: F) -> PyPtr

+ where F: FnOnce(PythonToken

) -> P, + P: PyTypeInfo + PyObjectAlloc + { + let value = f(PythonToken(PhantomData)); + Py::new(Python(PhantomData), value).unwrap().into_pptr() + } +} + + #[cfg(test)] mod test { use {Python, PyDict}; diff --git a/src/typeob.rs b/src/typeob.rs index 681051ec..4681624d 100644 --- a/src/typeob.rs +++ b/src/typeob.rs @@ -92,12 +92,12 @@ pub trait PyObjectAlloc { /// and initializes it using init_val. /// `ty` must be derived from the Self type, and the resulting object /// must be of type `ty`. - unsafe fn alloc(_py: &Python, value: Self::Type) -> PyResult<*mut ffi::PyObject>; + unsafe fn alloc(_py: Python, value: Self::Type) -> PyResult<*mut ffi::PyObject>; /// Calls the rust destructor for the object and frees the memory /// (usually by calling ptr->ob_type->tp_free). /// This function is used as tp_dealloc implementation. - unsafe fn dealloc(_py: &Python, obj: *mut ffi::PyObject); + unsafe fn dealloc(_py: Python, obj: *mut ffi::PyObject); } /// A PythonObject that is usable as a base type for #[class] @@ -108,7 +108,7 @@ impl PyObjectAlloc for T where T : PyTypeInfo { /// and initializes it using init_val. /// `ty` must be derived from the Self type, and the resulting object /// must be of type `ty`. - unsafe fn alloc(_py: &Python, value: T::Type) -> PyResult<*mut ffi::PyObject> { + unsafe fn alloc(_py: Python, value: T::Type) -> PyResult<*mut ffi::PyObject> { let obj = ffi::PyType_GenericAlloc( ::type_object(), 0); @@ -122,7 +122,7 @@ impl PyObjectAlloc for T where T : PyTypeInfo { /// Calls the rust destructor for the object and frees the memory /// (usually by calling ptr->ob_type->tp_free). /// This function is used as tp_dealloc implementation. - unsafe fn dealloc(_py: &Python, obj: *mut ffi::PyObject) { + unsafe fn dealloc(_py: Python, obj: *mut ffi::PyObject) { let ptr = (obj as *mut u8).offset( ::offset() as isize) as *mut Self::Type; std::ptr::drop_in_place(ptr); @@ -296,7 +296,7 @@ unsafe extern "C" fn tp_dealloc_callback(obj: *mut ffi::PyObject) println!("DEALLOC: {:?}", obj); let guard = AbortOnDrop("Cannot unwind out of tp_dealloc"); let py = Python::assume_gil_acquired(); - let r = ::dealloc(&py, obj); + let r = ::dealloc(py, obj); mem::forget(guard); r } @@ -329,24 +329,24 @@ fn py_class_method_defs() -> (Option, } } - for def in ::methods() { - defs.push(def.as_method_def()) - } - for def in ::methods() { - defs.push(def.as_method_def()) - } - for def in ::methods() { - defs.push(def.as_method_def()) - } - for def in ::methods() { - defs.push(def.as_method_def()) - } - for def in ::methods() { - defs.push(def.as_method_def()) - } - for def in ::methods() { - defs.push(def.as_method_def()) - } + //for def in ::methods() { + // defs.push(def.as_method_def()) + //} + //for def in ::methods() { + // defs.push(def.as_method_def()) + //} + //for def in ::methods() { + // defs.push(def.as_method_def()) + //} + //for def in ::methods() { + //defs.push(def.as_method_def()) + //} + //for def in ::methods() { + // defs.push(def.as_method_def()) + //} + //for def in ::methods() { + // defs.push(def.as_method_def()) + //} (new, call, defs) } diff --git a/tests/test_class.rs b/tests/test_class.rs index cdfa74e4..b8b0ed51 100644 --- a/tests/test_class.rs +++ b/tests/test_class.rs @@ -9,6 +9,8 @@ use std::cell::RefCell; use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering}; use pyo3::ffi; +use pyo3::python::ToPythonPointer; + macro_rules! py_run { ($py:expr, $val:ident, $code:expr) => {{ @@ -26,7 +28,7 @@ macro_rules! py_assert { macro_rules! py_expect_exception { ($py:expr, $val:ident, $code:expr, $err:ident) => {{ let d = PyDict::new($py); - d.set_item($py, stringify!($val), &$val).unwrap(); + d.set_item(stringify!($val), &$val).unwrap(); let res = $py.run($code, None, Some(&d)); let err = res.unwrap_err(); if !err.matches($py, $py.get_type::()) { @@ -71,7 +73,7 @@ struct EmptyClassWithNew { } #[py::methods] impl EmptyClassWithNew { #[__new__] - fn __new__(cls: &PyType) -> PyResult { + fn __new__(cls: &PyType, py: Python) -> PyResult { Ok(EmptyClassWithNew{}) } } @@ -91,7 +93,7 @@ struct NewWithOneArg { #[py::methods] impl NewWithOneArg { #[new] - fn __new__(_cls: &PyType, arg: i32) -> PyResult { + fn __new__(_cls: &PyType, py: Python, arg: i32) -> PyResult { Ok(NewWithOneArg{_data: arg}) } } @@ -114,7 +116,7 @@ struct NewWithTwoArgs { #[py::methods] impl NewWithTwoArgs { #[new] - fn __new__(_cls: &PyType, arg1: i32, arg2: i32) -> PyResult { + fn __new__(_cls: &PyType, py: Python, arg1: i32, arg2: i32) -> PyResult { Ok(NewWithTwoArgs{_data1: arg1, _data2: arg2}) } } @@ -169,7 +171,7 @@ struct InstanceMethod { #[py::methods] impl InstanceMethod { - fn method(&self) -> PyResult { + fn method(&self, py: Python) -> PyResult { Ok(self.member) } } @@ -180,7 +182,7 @@ fn instance_method() { let py = gil.python(); let obj = py.init(InstanceMethod{member: 42}); - assert!(obj.method().unwrap() == 42); + assert!(obj.method(py).unwrap() == 42); let d = PyDict::new(py); d.set_item("obj", obj).unwrap(); py.run("assert obj.method() == 42", None, Some(&d)).unwrap(); @@ -192,7 +194,7 @@ struct InstanceMethodWithArgs { } #[py::methods] impl InstanceMethodWithArgs { - fn method(&self, multiplier: i32) -> PyResult { + fn method(&self, py: Python, multiplier: i32) -> PyResult { Ok(self.member * multiplier) } } @@ -203,7 +205,7 @@ fn instance_method_with_args() { let py = gil.python(); let obj = py.init(InstanceMethodWithArgs{member: 7}); - assert!(obj.method(6).unwrap() == 42); + assert!(obj.method(py, 6).unwrap() == 42); let d = PyDict::new(py); d.set_item("obj", obj).unwrap(); py.run("assert obj.method(3) == 21", None, Some(&d)).unwrap(); @@ -261,7 +263,7 @@ struct StaticMethod {} impl StaticMethod { #[new] fn __new__(cls: &PyType, py: Python) -> PyResult { - StaticMethod::create_instance(py) + Ok(StaticMethod{}.into_object(py)) } //#[staticmethod] @@ -303,18 +305,18 @@ impl StaticMethod { #[py::class] struct GCIntegration { - self_ref: RefCell, + self_ref: RefCell>, dropped: TestDropCall, } #[py::proto] impl PyGCProtocol for GCIntegration { fn __traverse__(&self, py: Python, visit: PyVisit) -> Result<(), PyTraverseError> { - visit.call(&*self.self_ref(py).borrow()) + visit.call(&*self.self_ref.borrow()) } - fn __clear__(&self, py: Python) { - let old_ref = mem::replace(&mut *self.self_ref(py).borrow_mut(), py.None()); + fn __clear__(&mut self, py: Python) { + let old_ref = mem::replace(&mut *self.self_ref.borrow_mut(), py.None()); // Release reference only after the mutable borrow has expired. old_ref.release_ref(py); } @@ -326,12 +328,12 @@ fn gc_integration() { let py = gil.python(); let drop_called = Arc::new(AtomicBool::new(false)); - let inst = GCIntegration::create_instance(py, - RefCell::new(py.None()), - TestDropCall { drop_called: drop_called.clone() } - ).unwrap(); - *inst.self_ref(py).borrow_mut() = inst.as_object().clone_ref(py); - inst.release_ref(py); + let inst = py.init(GCIntegration{ + self_ref: RefCell::new(py.None()), + dropped: TestDropCall { drop_called: drop_called.clone() }}); + + *inst.self_ref.borrow_mut() = inst.clone_ref().into_object().into_pptr(); + drop(inst); py.run("import gc; gc.collect()", None, None).unwrap(); assert!(drop_called.load(Ordering::Relaxed)); @@ -345,7 +347,7 @@ pub struct Len { #[py::proto] impl PyMappingProtocol for Len { fn __len__(&self, py: Python) -> PyResult { - Ok(*self.l(py)) + Ok(self.l) } } @@ -354,14 +356,14 @@ fn len() { let gil = Python::acquire_gil(); let py = gil.python(); - let inst = Len::create_instance(py, 10).unwrap(); + let inst = Len{l: 10}.into_object(py); py_assert!(py, inst, "len(inst) == 10"); unsafe { - assert_eq!(ffi::PyObject_Size(inst.as_object().as_ptr()), 10); - assert_eq!(ffi::PyMapping_Size(inst.as_object().as_ptr()), 10); + assert_eq!(ffi::PyObject_Size(inst.as_ptr()), 10); + assert_eq!(ffi::PyMapping_Size(inst.as_ptr()), 10); } - let inst = Len::create_instance(py, (isize::MAX as usize) + 1).unwrap(); + let inst = Len{l: (isize::MAX as usize) + 1}.into_object(py); py_expect_exception!(py, inst, "len(inst)", OverflowError); } @@ -391,16 +393,16 @@ fn iterator() { struct StringMethods {} #[py::proto] -impl PyObjectProtocol for StringMethods { - fn __str__(&self) -> PyResult<&'static str> { +impl<'p> PyObjectProtocol<'p> for StringMethods { + fn __str__(&self, py: Python) -> PyResult<&'static str> { Ok("str") } - fn __repr__(&self) -> PyResult<&'static str> { + fn __repr__(&self, py: Python) -> PyResult<&'static str> { Ok("repr") } - fn __format__(&self, format_spec: String) -> PyResult { + fn __format__(&self, py: Python, format_spec: String) -> PyResult { Ok(format!("format({})", format_spec)) } @@ -408,7 +410,7 @@ impl PyObjectProtocol for StringMethods { // Ok(PyString::new(py, "unicode")) //} - fn __bytes__(&self) -> PyResult { + fn __bytes__(&self, py: Python) -> PyResult> { Ok(PyBytes::new(py, b"bytes")) } } @@ -418,7 +420,7 @@ fn string_methods() { let gil = Python::acquire_gil(); let py = gil.python(); - let obj = StringMethods::create_instance(py).unwrap(); + let obj = StringMethods{}.into_object(py); py_assert!(py, obj, "str(obj) == 'str'"); py_assert!(py, obj, "repr(obj) == 'repr'"); py_assert!(py, obj, "'{0:x}'.format(obj) == 'format(x)'"); @@ -433,12 +435,12 @@ struct Comparisons { #[py::proto] impl PyObjectProtocol for Comparisons { - fn __hash__(&self) -> PyResult { - Ok(*self.val(py) as usize) + fn __hash__(&self, py: Python) -> PyResult { + Ok(self.val as usize) } - fn __bool__(&self) -> PyResult { - Ok(*self.val(py) != 0) + fn __bool__(&self, py: Python) -> PyResult { + Ok(self.val != 0) } } @@ -448,10 +450,10 @@ fn comparisons() { let gil = Python::acquire_gil(); let py = gil.python(); - let zero = Comparisons::create_instance(py, 0).unwrap(); - let one = Comparisons::create_instance(py, 1).unwrap(); - let ten = Comparisons::create_instance(py, 10).unwrap(); - let minus_one = Comparisons::create_instance(py, -1).unwrap(); + let zero = Comparisons{val: 0}.into_object(py); + let one = Comparisons{val: 1}.into_object(py); + let ten = Comparisons{val: 10}.into_object(py); + let minus_one = Comparisons{val: -1}.into_object(py); py_assert!(py, one, "hash(one) == 1"); py_assert!(py, ten, "hash(ten) == 10"); py_assert!(py, minus_one, "hash(minus_one) == -2"); @@ -466,11 +468,11 @@ struct Sequence {} #[py::proto] impl PySequenceProtocol for Sequence { - fn __len__(&self) -> PyResult { + fn __len__(&self, py: Python) -> PyResult { Ok(5) } - fn __getitem__(&self, key: isize) -> PyResult { + fn __getitem__(&self, py: Python, key: isize) -> PyResult { if key == 5 { return Err(PyErr::new::(py, NoArgs)); } @@ -483,7 +485,7 @@ fn sequence() { let gil = Python::acquire_gil(); let py = gil.python(); - let c = Sequence::create_instance(py).unwrap(); + let c = Sequence{}.into_object(py); py_assert!(py, c, "list(c) == [0, 1, 2, 3, 4]"); py_expect_exception!(py, c, "c['abc']", TypeError); } @@ -496,7 +498,7 @@ struct Callable {} impl Callable { #[__call__] - fn __call__(&self, arg: i32) -> PyResult { + fn __call__(&self, py: Python, arg: i32) -> PyResult { Ok(arg * 6) } } @@ -506,11 +508,11 @@ fn callable() { let gil = Python::acquire_gil(); let py = gil.python(); - let c = Callable::create_instance(py).unwrap(); + let c = Callable{}.into_object(py); py_assert!(py, c, "callable(c)"); py_assert!(py, c, "c(7) == 42"); - let nc = Comparisons::create_instance(py, 0).unwrap(); + let nc = Comparisons{val: 0}.into_object(py); py_assert!(py, nc, "not callable(nc)"); } @@ -522,9 +524,9 @@ struct SetItem { #[py::proto] impl PyMappingProtocol<'a> for SetItem { - fn __setitem__(&self, key: i32, val: i32) -> PyResult<()> { - *self.key_mut(py) = key; - *self.val_mut(py) = val; + fn __setitem__(&mut self, py: Python, key: i32, val: i32) -> PyResult<()> { + self.key = key; + self.val = val; Ok(()) } } @@ -534,7 +536,7 @@ fn setitem() { let gil = Python::acquire_gil(); let py = gil.python(); - let c = SetItem::create_instance(0, 0).unwrap(); + let c = py.init(SetItem{key: 0, val: 0}); py_run!(py, c, "c[1] = 2"); assert_eq!(c.key, 1); assert_eq!(c.val, 2); @@ -548,8 +550,8 @@ struct DelItem { #[py::proto] impl PyMappingProtocol<'a> for DelItem { - fn __delitem__(&self, key: i32) -> PyResult<()> { - *self.key_mut(py) = key; + fn __delitem__(&mut self, py: Python, key: i32) -> PyResult<()> { + self.key = key; Ok(()) } } @@ -559,9 +561,9 @@ fn delitem() { let gil = Python::acquire_gil(); let py = gil.python(); - let c = DelItem::create_instance(py, 0).unwrap(); + let c = py.init(DelItem{key:0}); py_run!(py, c, "del c[1]"); - assert_eq!(*c.key(py), 1); + assert_eq!(c.key, 1); py_expect_exception!(py, c, "c[1] = 2", NotImplementedError); } @@ -572,13 +574,13 @@ struct SetDelItem { #[py::proto] impl PyMappingProtocol for SetDelItem { - fn __setitem__(&self, key: i32, val: i32) -> PyResult<()> { - *self.val_mut(py) = Some(val); + fn __setitem__(&mut self, py: Python, key: i32, val: i32) -> PyResult<()> { + self.val = Some(val); Ok(()) } - fn __delitem__(&self, key: i32) -> PyResult<()> { - *self.val_mut(py) = None; + fn __delitem__(&mut self, py: Python, key: i32) -> PyResult<()> { + self.val = None; Ok(()) } } @@ -588,11 +590,11 @@ fn setdelitem() { let gil = Python::acquire_gil(); let py = gil.python(); - let c = SetDelItem::create_instance(py, None).unwrap(); + let c = py.init(SetDelItem{val: None}); py_run!(py, c, "c[1] = 2"); - assert_eq!(*c.val(py), Some(2)); + assert_eq!(c.val, Some(2)); py_run!(py, c, "del c[1]"); - assert_eq!(*c.val(py), None); + assert_eq!(c.val, None); } #[py::class] @@ -600,7 +602,7 @@ struct Reversed {} #[py::proto] impl PyMappingProtocol for Reversed{ - fn __reversed__(&self) -> PyResult<&'static str> { + fn __reversed__(&self, py: Python) -> PyResult<&'static str> { println!("__reversed__"); Ok("I am reversed") } @@ -611,7 +613,7 @@ fn reversed() { let gil = Python::acquire_gil(); let py = gil.python(); - let c = Reversed::create_instance(py).unwrap(); + let c = Reversed{}.into_object(py); py_run!(py, c, "assert reversed(c) == 'I am reversed'"); } @@ -620,7 +622,7 @@ struct Contains {} #[py::proto] impl PySequenceProtocol for Contains { - fn __contains__(&self, item: i32) -> PyResult { + fn __contains__(&self, py: Python, item: i32) -> PyResult { Ok(item >= 0) } } @@ -630,7 +632,7 @@ fn contains() { let gil = Python::acquire_gil(); let py = gil.python(); - let c = Contains::create_instance(py).unwrap(); + let c = Contains{}.into_object(py); py_run!(py, c, "assert 1 in c"); py_run!(py, c, "assert -1 not in c"); py_expect_exception!(py, c, "assert 'wrong type' not in c", TypeError); @@ -644,19 +646,19 @@ struct UnaryArithmetic {} #[py::proto] impl PyNumberProtocol for UnaryArithmetic { - fn __neg__(&self) -> PyResult<&'static str> { + fn __neg__(&self, py: Python) -> PyResult<&'static str> { Ok("neg") } - fn __pos__(&self) -> PyResult<&'static str> { + fn __pos__(&self, py: Python) -> PyResult<&'static str> { Ok("pos") } - fn __abs__(&self) -> PyResult<&'static str> { + fn __abs__(&self, py: Python) -> PyResult<&'static str> { Ok("abs") } - fn __invert__(&self) -> PyResult<&'static str> { + fn __invert__(&self, py: Python) -> PyResult<&'static str> { Ok("invert") } } @@ -666,7 +668,7 @@ fn unary_arithmetic() { let gil = Python::acquire_gil(); let py = gil.python(); - let c = UnaryArithmetic::create_instance(py).unwrap(); + let c = UnaryArithmetic{}.into_object(py); py_run!(py, c, "assert -c == 'neg'"); py_run!(py, c, "assert +c == 'pos'"); py_run!(py, c, "assert abs(c) == 'abs'"); @@ -679,43 +681,43 @@ struct BinaryArithmetic {} #[py::proto] impl PyObjectProtocol for BinaryArithmetic { - fn __repr__(&self) -> PyResult<&'static str> { + fn __repr__(&self, py: Python) -> PyResult<&'static str> { Ok("BA") } } #[py::proto] impl PyNumberProtocol for BinaryArithmetic { - fn __add__(&self, rhs: PyObject) -> PyResult { - Ok(format!("{:?} + {:?}", self.as_object(), rhs)) + fn __add__(&self, py: Python, rhs: &PyObject) -> PyResult { + Ok(format!("{:?} + {:?}", self, rhs)) } - fn __sub__(&self, rhs: PyObject) -> PyResult { - Ok(format!("{:?} - {:?}", self.as_object(), rhs)) + fn __sub__(&self, py: Python, rhs: &PyObject) -> PyResult { + Ok(format!("{:?} - {:?}", self, rhs)) } - fn __mul__(&self, rhs: PyObject) -> PyResult { - Ok(format!("{:?} * {:?}", self.as_object(), rhs)) + fn __mul__(&self, py: Python, rhs: &PyObject) -> PyResult { + Ok(format!("{:?} * {:?}", self, rhs)) } - fn __lshift__(&self, rhs: PyObject) -> PyResult { - Ok(format!("{:?} << {:?}", self.as_object(), rhs)) + fn __lshift__(&self, py: Python, rhs: &PyObject) -> PyResult { + Ok(format!("{:?} << {:?}", self, rhs)) } - fn __rshift__(&self, rhs: PyObject) -> PyResult { - Ok(format!("{:?} >> {:?}", self.as_object(), rhs)) + fn __rshift__(&self, py: Python, rhs: &PyObject) -> PyResult { + Ok(format!("{:?} >> {:?}", self, rhs)) } - fn __and__(&self, rhs: PyObject) -> PyResult { - Ok(format!("{:?} & {:?}", self.as_object(), rhs)) + fn __and__(&self, py: Python, rhs: &PyObject) -> PyResult { + Ok(format!("{:?} & {:?}", self, rhs)) } - fn __xor__(&self, rhs: PyObject) -> PyResult { - Ok(format!("{:?} ^ {:?}", self.as_object(), rhs)) + fn __xor__(&self, py: Python, rhs: &PyObject) -> PyResult { + Ok(format!("{:?} ^ {:?}", self, rhs)) } - fn __or__(&self, rhs: PyObject) -> PyResult { - Ok(format!("{:?} | {:?}", self.as_object(), rhs)) + fn __or__(&self, py: Python, rhs: &PyObject) -> PyResult { + Ok(format!("{:?} | {:?}", self, rhs)) } } @@ -724,7 +726,7 @@ fn binary_arithmetic() { let gil = Python::acquire_gil(); let py = gil.python(); - let c = BinaryArithmetic::create_instance(py).unwrap(); + let c = BinaryArithmetic{}.into_object(py); py_run!(py, c, "assert c + c == 'BA + BA'"); py_run!(py, c, "assert c + 1 == 'BA + 1'"); py_run!(py, c, "assert 1 + c == '1 + BA'"); @@ -751,35 +753,38 @@ struct RichComparisons {} #[py::proto] impl PyObjectProtocol for RichComparisons { - fn __repr__(&self) -> PyResult<&'static str> { + fn __repr__(&self, py: Python) -> PyResult<&'static str> { Ok("RC") } - fn __richcmp__(&self, other: PyObject, op: CompareOp) -> PyResult { + fn __richcmp__(&self, py: Python, other: &PyObject, op: CompareOp) -> PyResult { match op { - CompareOp::Lt => Ok(format!("{:?} < {:?}", self.as_object(), other)), - CompareOp::Le => Ok(format!("{:?} <= {:?}", self.as_object(), other)), - CompareOp::Eq => Ok(format!("{:?} == {:?}", self.as_object(), other)), - CompareOp::Ne => Ok(format!("{:?} != {:?}", self.as_object(), other)), - CompareOp::Gt => Ok(format!("{:?} > {:?}", self.as_object(), other)), - CompareOp::Ge => Ok(format!("{:?} >= {:?}", self.as_object(), other)) + CompareOp::Lt => Ok(format!("{:?} < {:?}", self.__repr__(py), other)), + CompareOp::Le => Ok(format!("{:?} <= {:?}", self.__repr__(py), other)), + CompareOp::Eq => Ok(format!("{:?} == {:?}", self.__repr__(py), other)), + CompareOp::Ne => Ok(format!("{:?} != {:?}", self.__repr__(py), other)), + CompareOp::Gt => Ok(format!("{:?} > {:?}", self.__repr__(py), other)), + CompareOp::Ge => Ok(format!("{:?} >= {:?}", self.__repr__(py), other)) } } } #[py::class] -struct RichComparisons2 {} +struct RichComparisons2 { + py: PythonToken +} #[py::proto] impl PyObjectProtocol for RichComparisons2 { - fn __repr__(&self) -> PyResult<&'static str> { + fn __repr__(&self, py: Python) -> PyResult<&'static str> { Ok("RC2") } - fn __richcmp__(&self, other: PyObject, op: CompareOp) -> PyResult { + fn __richcmp__(&self, py: Python, + other: &PyObject, op: CompareOp) -> PyResult> { match op { - CompareOp::Eq => Ok(true.to_py_object(py).into_object()), - CompareOp::Ne => Ok(false.to_py_object(py).into_object()), + CompareOp::Eq => Ok(true.to_object(py).into_object()), + CompareOp::Ne => Ok(false.to_object(py).into_object()), _ => Ok(py.NotImplemented()) } } @@ -790,7 +795,7 @@ fn rich_comparisons() { let gil = Python::acquire_gil(); let py = gil.python(); - let c = RichComparisons::create_instance(py).unwrap(); + let c = RichComparisons{}.into_object(py); py_run!(py, c, "assert (c < c) == 'RC < RC'"); py_run!(py, c, "assert (c < 1) == 'RC < 1'"); py_run!(py, c, "assert (1 < c) == 'RC > 1'"); @@ -816,7 +821,7 @@ fn rich_comparisons_python_3_type_error() { let gil = Python::acquire_gil(); let py = gil.python(); - let c2 = RichComparisons2::create_instance(py).unwrap(); + let c2 = RichComparisons2{}.into_object(py); py_expect_exception!(py, c2, "c2 < c2", TypeError); py_expect_exception!(py, c2, "c2 < 1", TypeError); py_expect_exception!(py, c2, "1 < c2", TypeError); @@ -844,51 +849,51 @@ struct InPlaceOperations { #[py::proto] impl PyObjectProtocol for InPlaceOperations { - fn __repr__(&self) -> PyResult { - Ok(format!("IPO({:?})", self.value(py))) + fn __repr__(&self, py: Python) -> PyResult { + Ok(format!("IPO({:?})", self.value)) } } #[py::proto] impl PyNumberProtocol for InPlaceOperations { - fn __iadd__(&self, other: u32) -> PyResult { - *self.value_mut(py) = *self.value(py) + other; - Ok(self.clone_ref(py)) + fn __iadd__(&mut self, py: Python, other: u32) -> PyResult<()> { + self.value = self.value + other; + Ok(()) } - fn __isub__(&self, other: u32) -> PyResult { - *self.value_mut(py) = *self.value(py) - other; - Ok(self.clone_ref(py)) + fn __isub__(&mut self, py: Python, other: u32) -> PyResult<()> { + self.value = self.value - other; + Ok(()) } - fn __imul__(&self, other: u32) -> PyResult { - *self.value_mut(py) = *self.value(py) * other; - Ok(self.clone_ref(py)) + fn __imul__(&mut self, py: Python, other: u32) -> PyResult<()> { + self.value = self.value * other; + Ok(()) } - fn __ilshift__(&self, other: u32) -> PyResult { - *self.value_mut(py) = *self.value(py) << other; - Ok(self.clone_ref(py)) + fn __ilshift__(&mut self, py: Python, other: u32) -> PyResult<()> { + self.value = self.value << other; + Ok(()) } - fn __irshift__(&self, other: u32) -> PyResult { - *self.value_mut(py) = *self.value(py) >> other; - Ok(self.clone_ref(py)) + fn __irshift__(&mut self, py: Python, other: u32) -> PyResult<()> { + self.value = self.value >> other; + Ok(()) } - fn __iand__(&self, other: u32) -> PyResult { - *self.value_mut(py) = *self.value(py) & other; - Ok(self.clone_ref(py)) + fn __iand__(&mut self, py: Python, other: u32) -> PyResult<()> { + self.value = self.value & other; + Ok(()) } - fn __ixor__(&self, other: u32) -> PyResult { - *self.value_mut(py) = *self.value(py) ^ other; - Ok(self.clone_ref(py)) + fn __ixor__(&mut self, py: Python, other: u32) -> PyResult<()> { + self.value = self.value ^ other; + Ok(()) } - fn __ior__(&self, other: u32) -> PyResult { - *self.value_mut(py) = *self.value(py) | other; - Ok(self.clone_ref(py)) + fn __ior__(&mut self, py: Python, other: u32) -> PyResult<()> { + self.value = self.value | other; + Ok(()) } } @@ -897,28 +902,28 @@ fn inplace_operations() { let gil = Python::acquire_gil(); let py = gil.python(); - let c = InPlaceOperations::create_instance(py, 0).unwrap(); + let c = InPlaceOperations{value: 0}.into_object(py); py_run!(py, c, "d = c; c += 1; assert repr(c) == repr(d) == 'IPO(1)'"); - let c = InPlaceOperations::create_instance(py, 10).unwrap(); + let c = InPlaceOperations{value:10}.into_object(py); py_run!(py, c, "d = c; c -= 1; assert repr(c) == repr(d) == 'IPO(9)'"); - let c = InPlaceOperations::create_instance(py, 3).unwrap(); + let c = InPlaceOperations{value: 3}.into_object(py); py_run!(py, c, "d = c; c *= 3; assert repr(c) == repr(d) == 'IPO(9)'"); - let c = InPlaceOperations::create_instance(py, 3).unwrap(); + let c = InPlaceOperations{value: 3}.into_object(py); py_run!(py, c, "d = c; c <<= 2; assert repr(c) == repr(d) == 'IPO(12)'"); - let c = InPlaceOperations::create_instance(py, 12).unwrap(); + let c = InPlaceOperations{value: 12}.into_object(py); py_run!(py, c, "d = c; c >>= 2; assert repr(c) == repr(d) == 'IPO(3)'"); - let c = InPlaceOperations::create_instance(py, 12).unwrap(); + let c = InPlaceOperations{value: 12}.into_object(py); py_run!(py, c, "d = c; c &= 10; assert repr(c) == repr(d) == 'IPO(8)'"); - let c = InPlaceOperations::create_instance(py, 12).unwrap(); + let c = InPlaceOperations{value: 12}.into_object(py); py_run!(py, c, "d = c; c |= 3; assert repr(c) == repr(d) == 'IPO(15)'"); - let c = InPlaceOperations::create_instance(py, 12).unwrap(); + let c = InPlaceOperations{value: 12}.into_object(py); py_run!(py, c, "d = c; c ^= 5; assert repr(c) == repr(d) == 'IPO(9)'"); } @@ -930,11 +935,11 @@ struct ContextManager { #[py::proto] impl<'p> PyContextProtocol<'p> for ContextManager { - fn __enter__(&self) -> PyResult { + fn __enter__(&mut self, py: Python) -> PyResult { Ok(42) } - fn __exit__(&mut self, + fn __exit__(&mut self, py: Python, ty: Option<&'p PyType>, value: Option<&'p PyObject>, traceback: Option<&'p PyObject>) -> PyResult { @@ -952,17 +957,19 @@ fn context_manager() { let gil = Python::acquire_gil(); let py = gil.python(); - let c = ContextManager::create_instance(py, false).unwrap(); + let c = py.init(ContextManager{exit_called: false}); py_run!(py, c, "with c as x:\n assert x == 42"); - assert!(*c.exit_called(py)); + assert!(c.exit_called); - *c.exit_called_mut(py) = false; + c.exit_called = false; py_run!(py, c, "with c as x:\n raise ValueError"); - assert!(*c.exit_called(py)); + assert!(c.exit_called); - *c.exit_called_mut(py) = false; - py_expect_exception!(py, c, "with c as x:\n raise NotImplementedError", NotImplementedError); - assert!(*c.exit_called(py)); + c.exit_called = false; + py_expect_exception!( + py, c, "with c as x:\n raise NotImplementedError", + NotImplementedError); + assert!(c.exit_called); } @@ -974,17 +981,17 @@ struct ClassWithProperties { #[py::methods] impl ClassWithProperties { - fn get_num(&self) -> PyResult { - Ok(*self.num(py)) + fn get_num(&self, py: Python) -> PyResult { + Ok(self.num) } #[getter(DATA)] - fn get_data(&self) -> PyResult { - Ok(*self.num(py)) + fn get_data(&self, py: Python) -> PyResult { + Ok(self.num) } #[setter(DATA)] - fn set(&self, value: i32) -> PyResult<()> { - *self.num_mut(py) = value; + fn set(&self, py: Python, value: i32) -> PyResult<()> { + self.num = value; Ok(()) } } @@ -995,7 +1002,7 @@ fn class_with_properties() { let gil = Python::acquire_gil(); let py = gil.python(); - let inst = ClassWithProperties::create_instance(py, 10).unwrap(); + let inst = ClassWithProperties{num: 10}.into_object(py); py_run!(py, inst, "assert inst.get_num() == 10"); py_run!(py, inst, "assert inst.get_num() == inst.DATA"); @@ -1003,4 +1010,4 @@ fn class_with_properties() { py_run!(py, inst, "assert inst.get_num() == 20"); py_run!(py, inst, "assert inst.get_num() == inst.DATA"); -} \ No newline at end of file +}