introduce PythonToken; cleanup number protocol

This commit is contained in:
Nikolay Kim 2017-05-27 10:49:38 -07:00
parent 467cce6c6d
commit 6205be98b8
21 changed files with 693 additions and 388 deletions

View file

@ -439,68 +439,68 @@ pub const NUM: Proto = Proto {
MethodProto::Binary { MethodProto::Binary {
name: "__iadd__", name: "__iadd__",
arg: "Other", arg: "Other",
pyres: true, pyres: false,
proto: "::pyo3::class::number::PyNumberIAddProtocol"}, proto: "::pyo3::class::number::PyNumberIAddProtocol"},
MethodProto::Binary { MethodProto::Binary {
name: "__isub__", name: "__isub__",
arg: "Other", arg: "Other",
pyres: true, pyres: false,
proto: "::pyo3::class::number::PyNumberISubProtocol"}, proto: "::pyo3::class::number::PyNumberISubProtocol"},
MethodProto::Binary { MethodProto::Binary {
name: "__imul__", name: "__imul__",
arg: "Other", arg: "Other",
pyres: true, pyres: false,
proto: "::pyo3::class::number::PyNumberIMulProtocol"}, proto: "::pyo3::class::number::PyNumberIMulProtocol"},
MethodProto::Binary { MethodProto::Binary {
name: "__imatmul__", name: "__imatmul__",
arg: "Other", arg: "Other",
pyres: true, pyres: false,
proto: "::pyo3::class::number::PyNumberIMatmulProtocol"}, proto: "::pyo3::class::number::PyNumberIMatmulProtocol"},
MethodProto::Binary { MethodProto::Binary {
name: "__itruediv__", name: "__itruediv__",
arg: "Other", arg: "Other",
pyres: true, pyres: false,
proto: "::pyo3::class::number::PyNumberITruedivProtocol"}, proto: "::pyo3::class::number::PyNumberITruedivProtocol"},
MethodProto::Binary { MethodProto::Binary {
name: "__ifloordiv__", name: "__ifloordiv__",
arg: "Other", arg: "Other",
pyres: true, pyres: false,
proto: "::pyo3::class::number::PyNumberIFloordivProtocol"}, proto: "::pyo3::class::number::PyNumberIFloordivProtocol"},
MethodProto::Binary { MethodProto::Binary {
name: "__imod__", name: "__imod__",
arg: "Other", arg: "Other",
pyres: true, pyres: false,
proto: "::pyo3::class::number::PyNumberIModProtocol"}, proto: "::pyo3::class::number::PyNumberIModProtocol"},
MethodProto::Ternary { MethodProto::Ternary {
name: "__ipow__", name: "__ipow__",
arg1: "Other", arg1: "Other",
arg2: "Modulo", arg2: "Modulo",
pyres: true, pyres: false,
proto: "::pyo3::class::number::PyNumberIPowProtocol"}, proto: "::pyo3::class::number::PyNumberIPowProtocol"},
MethodProto::Binary { MethodProto::Binary {
name: "__ilshift__", name: "__ilshift__",
arg: "Other", arg: "Other",
pyres: true, pyres: false,
proto: "::pyo3::class::number::PyNumberILShiftProtocol"}, proto: "::pyo3::class::number::PyNumberILShiftProtocol"},
MethodProto::Binary { MethodProto::Binary {
name: "__irshift__", name: "__irshift__",
arg: "Other", arg: "Other",
pyres: true, pyres: false,
proto: "::pyo3::class::number::PyNumberIRShiftProtocol"}, proto: "::pyo3::class::number::PyNumberIRShiftProtocol"},
MethodProto::Binary { MethodProto::Binary {
name: "__iand__", name: "__iand__",
arg: "Other", arg: "Other",
pyres: true, pyres: false,
proto: "::pyo3::class::number::PyNumberIAndProtocol"}, proto: "::pyo3::class::number::PyNumberIAndProtocol"},
MethodProto::Binary { MethodProto::Binary {
name: "__ixor__", name: "__ixor__",
arg: "Other", arg: "Other",
pyres: true, pyres: false,
proto: "::pyo3::class::number::PyNumberIXorProtocol"}, proto: "::pyo3::class::number::PyNumberIXorProtocol"},
MethodProto::Binary { MethodProto::Binary {
name: "__ior__", name: "__ior__",
arg: "Other", arg: "Other",
pyres: true, pyres: false,
proto: "::pyo3::class::number::PyNumberIOrProtocol"}, proto: "::pyo3::class::number::PyNumberIOrProtocol"},
MethodProto::Unary { MethodProto::Unary {

View file

@ -42,12 +42,14 @@ pub fn impl_method_proto(cls: &Box<syn::Ty>,
match *meth { match *meth {
MethodProto::Unary{name: _, pyres, proto} => { MethodProto::Unary{name: _, pyres, proto} => {
let p = syn::Ident::from(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( let tmp = extract_decl(syn::parse_item(
quote! {fn test(&self) quote! {fn test(&self)
-> <#cls as #p<'p>>::Result {}}.as_str()).unwrap()); -> <#cls as #p<'p>>::Result {}}.as_str()).unwrap());
sig.decl.output = tmp.output.clone(); sig.decl.output = tmp.output.clone();
modify_self_ty(sig);
modify_py_ty(sig);
if pyres { if pyres {
quote! { quote! {
@ -65,14 +67,14 @@ pub fn impl_method_proto(cls: &Box<syn::Ty>,
} }
}, },
MethodProto::Binary{name: n, arg, pyres, proto} => { 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); println!("Not enough arguments for {}", n);
return Tokens::new(); return Tokens::new();
} }
let p = syn::Ident::from(proto); let p = syn::Ident::from(proto);
let arg_name = syn::Ident::from(arg); let arg_name = syn::Ident::from(arg);
let arg_ty = get_arg_ty(sig, 2); 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( let tmp = extract_decl(syn::parse_item(
quote! {fn test( quote! {fn test(
@ -85,6 +87,8 @@ pub fn impl_method_proto(cls: &Box<syn::Ty>,
arg: Option<<#cls as #p<'p>>::#arg_name>) arg: Option<<#cls as #p<'p>>::#arg_name>)
-> <#cls as #p<'p>>::Result {}}.as_str()).unwrap()); -> <#cls as #p<'p>>::Result {}}.as_str()).unwrap());
modify_arg_ty(sig, 2, &tmp, &tmp2); modify_arg_ty(sig, 2, &tmp, &tmp2);
modify_self_ty(sig);
modify_py_ty(sig);
if pyres { if pyres {
quote! { quote! {
@ -104,7 +108,7 @@ pub fn impl_method_proto(cls: &Box<syn::Ty>,
} }
}, },
MethodProto::Ternary{name: n, arg1, arg2, pyres, proto} => { 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)); print_err(format!("Not enough arguments {}", n), quote!(sig));
return Tokens::new(); return Tokens::new();
} }
@ -113,7 +117,7 @@ pub fn impl_method_proto(cls: &Box<syn::Ty>,
let arg1_ty = get_arg_ty(sig, 2); let arg1_ty = get_arg_ty(sig, 2);
let arg2_name = syn::Ident::from(arg2); let arg2_name = syn::Ident::from(arg2);
let arg2_ty = get_arg_ty(sig, 3); let arg2_ty = get_arg_ty(sig, 3);
let succ = get_res_success(ty); let (ty, succ) = get_res_success(ty);
// rewrite ty // rewrite ty
let tmp = extract_decl(syn::parse_item( let tmp = extract_decl(syn::parse_item(
@ -130,6 +134,8 @@ pub fn impl_method_proto(cls: &Box<syn::Ty>,
-> <#cls as #p<'p>>::Result {}}.as_str()).unwrap()); -> <#cls as #p<'p>>::Result {}}.as_str()).unwrap());
modify_arg_ty(sig, 2, &tmp, &tmp2); modify_arg_ty(sig, 2, &tmp, &tmp2);
modify_arg_ty(sig, 3, &tmp, &tmp2); modify_arg_ty(sig, 3, &tmp, &tmp2);
modify_self_ty(sig);
modify_py_ty(sig);
if pyres { if pyres {
quote! { quote! {
@ -151,7 +157,7 @@ pub fn impl_method_proto(cls: &Box<syn::Ty>,
} }
}, },
MethodProto::Quaternary{name: n, arg1, arg2, arg3, proto} => { 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)); print_err(format!("Not enough arguments {}", n), quote!(sig));
return Tokens::new(); return Tokens::new();
} }
@ -162,7 +168,7 @@ pub fn impl_method_proto(cls: &Box<syn::Ty>,
let arg2_ty = get_arg_ty(sig, 3); let arg2_ty = get_arg_ty(sig, 3);
let arg3_name = syn::Ident::from(arg3); let arg3_name = syn::Ident::from(arg3);
let arg3_ty = get_arg_ty(sig, 4); let arg3_ty = get_arg_ty(sig, 4);
let succ = get_res_success(ty); let (ty, succ) = get_res_success(ty);
// rewrite ty // rewrite ty
let tmp = extract_decl(syn::parse_item( let tmp = extract_decl(syn::parse_item(
@ -182,6 +188,8 @@ pub fn impl_method_proto(cls: &Box<syn::Ty>,
modify_arg_ty(sig, 2, &tmp, &tmp2); modify_arg_ty(sig, 2, &tmp, &tmp2);
modify_arg_ty(sig, 3, &tmp, &tmp2); modify_arg_ty(sig, 3, &tmp, &tmp2);
modify_arg_ty(sig, 4, &tmp, &tmp2); modify_arg_ty(sig, 4, &tmp, &tmp2);
modify_self_ty(sig);
modify_py_ty(sig);
quote! { quote! {
impl<'p> #p<'p> for #cls { impl<'p> #p<'p> for #cls {
@ -202,7 +210,7 @@ pub fn impl_method_proto(cls: &Box<syn::Ty>,
// TODO: better arg ty detection // TODO: better arg ty detection
fn get_arg_ty(sig: &syn::MethodSig, idx: usize) -> syn::Ty { 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) => { syn::FnArg::Captured(_, ref arg_ty) => {
match arg_ty { match arg_ty {
&syn::Ty::Path(_, ref path) => { &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()
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 // Success
fn get_res_success(ty: &syn::Ty) -> syn::Ty { fn get_res_success(ty: &syn::Ty) -> (Tokens, syn::Ty) {
match ty { let result;
let mut succ = match ty {
&syn::Ty::Path(_, ref path) => { &syn::Ty::Path(_, ref path) => {
if let Some(segment) = path.segments.last() { if let Some(segment) = path.segments.last() {
match segment.ident.as_ref() { match segment.ident.as_ref() {
// check result type // check result type
"PyResult" => match segment.parameters { "PyResult" => match segment.parameters {
syn::PathParameters::AngleBracketed(ref data) => { syn::PathParameters::AngleBracketed(ref data) => {
result = true;
data.types[0].clone() data.types[0].clone()
}, },
_ => panic!("fn result type is not supported"), _ => panic!("fn result type is not supported"),
@ -253,7 +274,40 @@ fn get_res_success(ty: &syn::Ty) -> syn::Ty {
} }
} }
_ => panic!("not supported: {:?}", ty), _ => panic!("not supported: {:?}", ty),
};
// add lifetime to Py<T>
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(); 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 { fn fix_name(pat: &syn::Pat, arg: &syn::FnArg) -> syn::FnArg {
match arg { match arg {
&syn::FnArg::Captured(_, ref arg_ty) => &syn::FnArg::Captured(_, ref arg_ty) =>

View file

@ -8,7 +8,8 @@ pub fn build_py_class(ast: &mut syn::DeriveInput) -> Tokens {
let base = syn::Ident::from("_pyo3::PyObject"); let base = syn::Ident::from("_pyo3::PyObject");
match ast.body { match ast.body {
syn::Body::Struct(syn::VariantData::Struct(_)) => (), syn::Body::Struct(syn::VariantData::Struct(_)) => {
},
_ => panic!("#[class] can only be used with notmal structs"), _ => 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: () = { const #dummy_const: () = {
extern crate pyo3 as _pyo3; extern crate pyo3 as _pyo3;
use std; use std;
use pyo3::python::IntoPythonPointer;
#tokens #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 { 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(); let cls_name = quote! { #cls }.as_str().to_string();
quote! { 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] #[inline]
fn into_object<'p>(self, py: Python<'p>) -> Py<'p, PyObject> where Self: Sized fn as_ptr(&self) -> *mut ffi::PyObject {
{ let offset = <#cls as _pyo3::typeob::PyTypeInfo>::offset();
let ptr = py.init(self).into_ptr(); unsafe {
_pyo3::PyObject::from_owned_ptr(py, ptr) {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)
}
} }
} }
} }

View file

@ -47,7 +47,7 @@ pub fn impl_wrap(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec) -> Tokens
kwargs: *mut _pyo3::ffi::PyObject) -> *mut _pyo3::ffi::PyObject kwargs: *mut _pyo3::ffi::PyObject) -> *mut _pyo3::ffi::PyObject
{ {
const LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#name),"()"); 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 mut slf: Py<#cls> = Py::from_borrowed_ptr(py, slf);
let args: _pyo3::Py<_pyo3::PyTuple> = _pyo3::Py::from_borrowed_ptr(py, args); let args: _pyo3::Py<_pyo3::PyTuple> = _pyo3::Py::from_borrowed_ptr(py, args);
@ -70,18 +70,24 @@ pub fn impl_proto_wrap(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec) ->
let body = impl_arg_params(&spec, cb); let body = impl_arg_params(&spec, cb);
quote! { quote! {
unsafe extern "C" fn wrap<'p>( #[allow(unused_mut)]
slf: *mut _pyo3::ffi::PyObject, unsafe extern "C" fn wrap(slf: *mut _pyo3::ffi::PyObject,
args: *mut _pyo3::ffi::PyObject, args: *mut _pyo3::ffi::PyObject,
kwargs: *mut _pyo3::ffi::PyObject) -> *mut _pyo3::ffi::PyObject kwargs: *mut _pyo3::ffi::PyObject) -> *mut _pyo3::ffi::PyObject
{ {
const LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#name),"()"); 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 args: _pyo3::Py<_pyo3::PyTuple> = _pyo3::Py::from_borrowed_ptr(py, args);
let kwargs: Option<_pyo3::Py<_pyo3::PyDict>> = let kwargs: Option<_pyo3::Py<_pyo3::PyDict>> =
_pyo3::argparse::get_kwargs(py, kwargs); _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<syn::Ty>, name: &syn::Ident, spec: &FnSpec) ->
pub fn impl_wrap_new(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec) -> Tokens { pub fn impl_wrap_new(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec) -> Tokens {
let cb = impl_class_new(cls, name, spec); let cb = impl_class_new(cls, name, spec);
let body = impl_arg_params(spec, cb); let body = impl_arg_params(spec, cb);
let output = &spec.output;
quote! { quote! {
#[allow(unused_mut)]
unsafe extern "C" fn wrap(cls: *mut _pyo3::ffi::PyTypeObject, unsafe extern "C" fn wrap(cls: *mut _pyo3::ffi::PyTypeObject,
args: *mut _pyo3::ffi::PyObject, args: *mut _pyo3::ffi::PyObject,
kwargs: *mut _pyo3::ffi::PyObject) -> *mut _pyo3::ffi::PyObject kwargs: *mut _pyo3::ffi::PyObject) -> *mut _pyo3::ffi::PyObject
{ {
const LOCATION: &'static str = concat!( const LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#name), "()");
stringify!(#cls), ".", stringify!(#name), "()");
_pyo3::callback::handle(LOCATION, _pyo3::callback::PyObjectCallbackConverter, |py| { _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 args: _pyo3::Py<_pyo3::PyTuple> = _pyo3::Py::from_borrowed_ptr(py, args);
let kwargs: Option<_pyo3::Py<_pyo3::PyDict>> = let kwargs: Option<_pyo3::Py<_pyo3::PyDict>> =
_pyo3::argparse::get_kwargs(py, kwargs); _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<syn::Ty>, name: &syn::Ident, _spec: &FnSpec) -> To
{ {
const LOCATION: &'static str = concat!( const LOCATION: &'static str = concat!(
stringify!(#cls), ".getter_", stringify!(#name), "()"); stringify!(#cls), ".getter_", stringify!(#name), "()");
_pyo3::callback::handle(LOCATION, _pyo3::callback::PyObjectCallbackConverter, |py| { _pyo3::callback::cb_unary::<#cls, _, _, _>(
let slf: _pyo3::Py<#cls> = _pyo3::Py::from_borrowed_ptr(py, slf); LOCATION, slf, _pyo3::callback::PyObjectCallbackConverter, |py, slf| {
slf.#name(py) slf.#name(py)
}) })
} }
@ -130,25 +144,33 @@ fn impl_wrap_getter(cls: &Box<syn::Ty>, name: &syn::Ident, _spec: &FnSpec) -> To
/// Generate functiona wrapper (PyCFunction, PyCFunctionWithKeywords) /// Generate functiona wrapper (PyCFunction, PyCFunctionWithKeywords)
fn impl_wrap_setter(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec) -> Tokens { fn impl_wrap_setter(cls: &Box<syn::Ty>, 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; let val_ty = spec.args[0].ty;
quote! { quote! {
#[allow(unused_mut)]
unsafe extern "C" fn wrap(slf: *mut _pyo3::ffi::PyObject, unsafe extern "C" fn wrap(slf: *mut _pyo3::ffi::PyObject,
value: *mut _pyo3::ffi::PyObject, value: *mut _pyo3::ffi::PyObject,
_: *mut _pyo3::c_void) -> _pyo3::c_int _: *mut _pyo3::c_void) -> _pyo3::c_int
{ {
const LOCATION: &'static str = concat!( const LOCATION: &'static str = concat!(
stringify!(#cls), ".setter", stringify!(#name), "()"); stringify!(#cls), ".setter", stringify!(#name), "()");
_pyo3::callback::handle(LOCATION, _pyo3::callback::UnitCallbackConverter, |py| { _pyo3::callback::cb_setter(LOCATION, |py| {
let slf: _pyo3::Py<#cls> = _pyo3::Py::from_borrowed_ptr(py, slf); let mut slf = _pyo3::Py::<#cls>::from_borrowed_ptr(py, slf);
let value = _pyo3::PyObject::from_borrowed_ptr(py, value); let value = _pyo3::PyObject::from_borrowed_ptr(py, value);
match <#val_ty as _pyo3::FromPyObject>::extract(&value) { let result = match <#val_ty as _pyo3::FromPyObject>::extract(&value) {
Ok(val) => { Ok(val) => slf.#name(py, val),
let ret = slf.#name(val);
ret.map(|o| ())
}
Err(e) => Err(e) Err(e) => Err(e)
};
match result {
Ok(_) => 0,
Err(e) => {
e.restore(py);
-1
}
} }
}) })
} }
@ -156,19 +178,17 @@ fn impl_wrap_setter(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec) -> Tok
} }
fn impl_call(cls: &Box<syn::Ty>, fname: &syn::Ident, spec: &FnSpec) -> Tokens { fn impl_call(_cls: &Box<syn::Ty>, fname: &syn::Ident, spec: &FnSpec) -> Tokens {
let names: Vec<&syn::Ident> = spec.args.iter().map(|item| item.name).collect(); let names: Vec<&syn::Ident> = spec.args.iter().map(|item| item.name).collect();
quote! {{ quote! {{
slf.#fname(py, #(#names),*) slf.as_mut().#fname(py, #(#names),*)
}} }}
} }
fn impl_class_new(cls: &Box<syn::Ty>, fname: &syn::Ident, spec: &FnSpec) -> Tokens { fn impl_class_new(cls: &Box<syn::Ty>, fname: &syn::Ident, spec: &FnSpec) -> Tokens {
let names: Vec<&syn::Ident> = spec.args.iter().map(|item| item.name).collect(); let names: Vec<&syn::Ident> = spec.args.iter().map(|item| item.name).collect();
quote! {{ quote! {{
let cls: _pyo3::Py<_pyo3::PyType> = _pyo3::Py::from_borrowed_ptr( #cls::#fname(&cls, py, #(#names),*)
py, cls as *mut _pyo3::ffi::PyObject);
#cls::#fname(&cls, #(#names),*)
}} }}
} }

View file

@ -95,8 +95,7 @@ fn impl_proto_impl(ty: &Box<syn::Ty>, impls: &mut Vec<syn::ImplItem>, proto: &de
let name = syn::Ident::from(m.name); let name = syn::Ident::from(m.name);
let proto = syn::Ident::from(m.proto); let proto = syn::Ident::from(m.proto);
let fn_spec = FnSpec::parse( let fn_spec = FnSpec::parse(&iimpl.ident, sig, &mut iimpl.attrs);
&iimpl.ident, sig, &mut iimpl.attrs);
let meth = py_method::impl_proto_wrap(ty, &iimpl.ident, &fn_spec); let meth = py_method::impl_proto_wrap(ty, &iimpl.ident, &fn_spec);
py_methods.push( py_methods.push(

View file

@ -21,7 +21,7 @@ pub trait CallbackConverter<S> {
pub struct PyObjectCallbackConverter; pub struct PyObjectCallbackConverter;
impl <S> CallbackConverter<S> for PyObjectCallbackConverter impl<S> CallbackConverter<S> for PyObjectCallbackConverter
where S: IntoPyObject where S: IntoPyObject
{ {
type R = *mut ffi::PyObject; type R = *mut ffi::PyObject;
@ -90,7 +90,7 @@ impl CallbackConverter<()> for UnitCallbackConverter {
} }
} }
pub struct IterNextResultConverter; /*pub struct IterNextResultConverter;
impl <T> CallbackConverter<Option<T>> impl <T> CallbackConverter<Option<T>>
for IterNextResultConverter for IterNextResultConverter
@ -112,7 +112,7 @@ impl <T> CallbackConverter<Option<T>>
fn error_value() -> *mut ffi::PyObject { fn error_value() -> *mut ffi::PyObject {
ptr::null_mut() ptr::null_mut()
} }
} }*/
pub trait WrappingCastTo<T> { pub trait WrappingCastTo<T> {
fn wrapping_cast(self) -> T; fn wrapping_cast(self) -> T;
@ -250,7 +250,7 @@ pub unsafe fn cb_unary_unit<Slf, F>(location: &str, slf: *mut ffi::PyObject, f:
ret ret
} }
pub unsafe fn cb_meth<F, R>(location: &str, f: F) -> *mut ffi::PyObject pub unsafe fn cb_meth<F>(location: &str, f: F) -> *mut ffi::PyObject
where F: for<'p> FnOnce(Python<'p>) -> *mut ffi::PyObject, where F: for<'p> FnOnce(Python<'p>) -> *mut ffi::PyObject,
F: panic::UnwindSafe F: panic::UnwindSafe
{ {
@ -270,6 +270,26 @@ pub unsafe fn cb_meth<F, R>(location: &str, f: F) -> *mut ffi::PyObject
ret ret
} }
pub unsafe fn cb_setter<F>(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] #[inline]
pub unsafe fn cb_convert<C, T>(_c: C, py: Python, value: PyResult<T>) -> C::R pub unsafe fn cb_convert<C, T>(_c: C, py: Python, value: PyResult<T>) -> C::R
where C: CallbackConverter<T> where C: CallbackConverter<T>

View file

@ -24,13 +24,13 @@ pub trait PyAsyncProtocol<'p>: PyTypeInfo + Sized + 'static {
fn __aiter__(&'p self, py: Python<'p>) fn __aiter__(&'p self, py: Python<'p>)
-> Self::Result where Self: PyAsyncAiterProtocol<'p> { unimplemented!() } -> 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!() } -> 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!() } -> 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<Self::ExcType>, exc_type: Option<Self::ExcType>,
exc_value: Option<Self::ExcValue>, exc_value: Option<Self::ExcValue>,
traceback: Option<Self::Traceback>) traceback: Option<Self::Traceback>)

View file

@ -31,10 +31,10 @@ pub trait PyObjectProtocol<'p>: PyTypeInfo + Sized + 'static {
fn __getattr__(&'p self, py: Python<'p>, name: Self::Name) fn __getattr__(&'p self, py: Python<'p>, name: Self::Name)
-> Self::Result where Self: PyObjectGetAttrProtocol<'p> {unimplemented!()} -> 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!()} -> 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!()} -> Self::Result where Self: PyObjectDelAttrProtocol<'p> {unimplemented!()}
fn __str__(&'p self, py: Python<'p>) fn __str__(&'p self, py: Python<'p>)

View file

@ -16,10 +16,10 @@ use callback::PyObjectCallbackConverter;
/// Iterator protocol /// Iterator protocol
#[allow(unused_variables)] #[allow(unused_variables)]
pub trait PyIterProtocol<'p> : PyTypeInfo { 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!() } -> 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!() } -> Self::Result where Self: PyIterNextProtocol<'p> { unimplemented!() }
} }

View file

@ -17,7 +17,7 @@ macro_rules! py_unary_func {
let ret = $crate::std::panic::catch_unwind(|| { let ret = $crate::std::panic::catch_unwind(|| {
let py = $crate::Python::assume_gil_acquired(); let py = $crate::Python::assume_gil_acquired();
let mut slf = $crate::Py::<T>::from_borrowed_ptr(py, slf); let mut slf = $crate::Py::<T>::from_borrowed_ptr(py, slf);
let res = slf.$f(py).into(); let res = slf.as_mut().$f(py).into();
match res { match res {
Ok(val) => { Ok(val) => {
@ -131,7 +131,7 @@ macro_rules! py_binary_func{
let result = match arg.extract() { let result = match arg.extract() {
Ok(arg) => { Ok(arg) => {
slf.$f(py, arg).into() slf.as_mut().$f(py, arg).into()
} }
Err(e) => Err(e.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<T>(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::<T>::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] #[macro_export]
#[doc(hidden)] #[doc(hidden)]
macro_rules! py_ssizearg_func { macro_rules! py_ssizearg_func {
@ -180,7 +230,7 @@ macro_rules! py_ssizearg_func {
let py = $crate::Python::assume_gil_acquired(); let py = $crate::Python::assume_gil_acquired();
let mut slf = $crate::Py::<T>::from_borrowed_ptr(py, slf); let mut slf = $crate::Py::<T>::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 { match result {
Ok(val) => { Ok(val) => {
<$conv as $crate::callback::CallbackConverter<$res_type>> <$conv as $crate::callback::CallbackConverter<$res_type>>
@ -232,7 +282,7 @@ macro_rules! py_ternary_func{
let result = match arg1.extract() { let result = match arg1.extract() {
Ok(arg1) => match arg2.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())
}, },
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<T>(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::<T>::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::<T>)
}}
}
#[macro_export] #[macro_export]
#[doc(hidden)] #[doc(hidden)]
@ -336,7 +438,7 @@ macro_rules! py_func_del{
let name = PyObject::from_borrowed_ptr(py, name); let name = PyObject::from_borrowed_ptr(py, name);
let result = match name.extract() { let result = match name.extract() {
Ok(name) => Ok(name) =>
slf.$f(py, name).into(), slf.as_mut().$f(py, name).into(),
Err(e) => Err(e.into()), Err(e) => Err(e.into()),
}; };
match result { match result {
@ -394,7 +496,7 @@ macro_rules! py_func_set_del{
if value.is_null() { if value.is_null() {
let result = match name.extract() { let result = match name.extract() {
Ok(name) => Ok(name) =>
slf.$f2(py, name).into(), slf.as_mut().$f2(py, name).into(),
Err(e) => Err(e.into()), Err(e) => Err(e.into()),
}; };
match result { match result {
@ -410,7 +512,7 @@ macro_rules! py_func_set_del{
let result = match name.extract() { let result = match name.extract() {
Ok(name) => match value.extract() { Ok(name) => match value.extract() {
Ok(value) => { Ok(value) => {
slf.$f(py, name, value).into() slf.as_mut().$f(py, name, value).into()
}, },
Err(e) => Err(e.into()), Err(e) => Err(e.into()),
}, },

View file

@ -23,10 +23,10 @@ pub trait PyMappingProtocol<'p>: PyTypeInfo + Sized + 'static {
fn __getitem__(&'p self, py: Python<'p>, key: Self::Key) fn __getitem__(&'p self, py: Python<'p>, key: Self::Key)
-> Self::Result where Self: PyMappingGetItemProtocol<'p> {unimplemented!()} -> 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!()} -> 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!()} -> Self::Result where Self: PyMappingDelItemProtocol<'p> {unimplemented!()}
fn __iter__(&'p self, py: Python<'p>) fn __iter__(&'p self, py: Python<'p>)

View file

@ -74,31 +74,31 @@ pub trait PyNumberProtocol<'p>: PyTypeInfo {
fn __ror__(&'p self, py: Python<'p>, other: Self::Other) fn __ror__(&'p self, py: Python<'p>, other: Self::Other)
-> Self::Result where Self: PyNumberROrProtocol<'p> { unimplemented!() } -> 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!() } -> 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!() } -> 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!() } -> 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!() } -> 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!()} -> 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!() } -> 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!() } -> 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!() } -> 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!() } -> 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!() } -> 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!() } -> 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!() } -> 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!() } -> Self::Result where Self: PyNumberIOrProtocol<'p> { unimplemented!() }
// Unary arithmetic // Unary arithmetic
@ -124,12 +124,12 @@ pub trait PyNumberProtocol<'p>: PyTypeInfo {
pub trait PyNumberAddProtocol<'p>: PyNumberProtocol<'p> { pub trait PyNumberAddProtocol<'p>: PyNumberProtocol<'p> {
type Other: for<'a> FromPyObject<'a>; type Other: FromPyObject<'p>;
type Success: ToPyObject; type Success: ToPyObject;
type Result: Into<PyResult<Self::Success>>; type Result: Into<PyResult<Self::Success>>;
} }
pub trait PyNumberSubProtocol<'p>: PyNumberProtocol<'p> { pub trait PyNumberSubProtocol<'p>: PyNumberProtocol<'p> {
type Other: for<'a> FromPyObject<'a>; type Other: FromPyObject<'p>;
type Success: ToPyObject; type Success: ToPyObject;
type Result: Into<PyResult<Self::Success>>; type Result: Into<PyResult<Self::Success>>;
} }
@ -270,74 +270,60 @@ pub trait PyNumberROrProtocol<'p>: PyNumberProtocol<'p> {
pub trait PyNumberIAddProtocol<'p>: PyNumberProtocol<'p> { pub trait PyNumberIAddProtocol<'p>: PyNumberProtocol<'p> {
type Other: FromPyObject<'p>; type Other: FromPyObject<'p>;
type Success: ToPyObject; type Result: Into<PyResult<()>>;
type Result: Into<PyResult<Self::Success>>;
} }
pub trait PyNumberISubProtocol<'p>: PyNumberProtocol<'p> { pub trait PyNumberISubProtocol<'p>: PyNumberProtocol<'p> {
type Other: FromPyObject<'p>; type Other: FromPyObject<'p>;
type Success: ToPyObject; type Result: Into<PyResult<()>>;
type Result: Into<PyResult<Self::Success>>;
} }
pub trait PyNumberIMulProtocol<'p>: PyNumberProtocol<'p> { pub trait PyNumberIMulProtocol<'p>: PyNumberProtocol<'p> {
type Other: FromPyObject<'p>; type Other: FromPyObject<'p>;
type Success: ToPyObject; type Result: Into<PyResult<()>>;
type Result: Into<PyResult<Self::Success>>;
} }
pub trait PyNumberIMatmulProtocol<'p>: PyNumberProtocol<'p> { pub trait PyNumberIMatmulProtocol<'p>: PyNumberProtocol<'p> {
type Other: FromPyObject<'p>; type Other: FromPyObject<'p>;
type Success: ToPyObject; type Result: Into<PyResult<()>>;
type Result: Into<PyResult<Self::Success>>;
} }
pub trait PyNumberITruedivProtocol<'p>: PyNumberProtocol<'p> { pub trait PyNumberITruedivProtocol<'p>: PyNumberProtocol<'p> {
type Other: FromPyObject<'p>; type Other: FromPyObject<'p>;
type Success: ToPyObject; type Result: Into<PyResult<()>>;
type Result: Into<PyResult<Self::Success>>;
} }
pub trait PyNumberIFloordivProtocol<'p>: PyNumberProtocol<'p> { pub trait PyNumberIFloordivProtocol<'p>: PyNumberProtocol<'p> {
type Other: FromPyObject<'p>; type Other: FromPyObject<'p>;
type Success: ToPyObject; type Result: Into<PyResult<()>>;
type Result: Into<PyResult<Self::Success>>;
} }
pub trait PyNumberIModProtocol<'p>: PyNumberProtocol<'p> { pub trait PyNumberIModProtocol<'p>: PyNumberProtocol<'p> {
type Other: FromPyObject<'p>; type Other: FromPyObject<'p>;
type Success: ToPyObject; type Result: Into<PyResult<()>>;
type Result: Into<PyResult<Self::Success>>;
} }
pub trait PyNumberIDivmodProtocol<'p>: PyNumberProtocol<'p> { pub trait PyNumberIDivmodProtocol<'p>: PyNumberProtocol<'p> {
type Other: FromPyObject<'p>; type Other: FromPyObject<'p>;
type Success: ToPyObject; type Result: Into<PyResult<()>>;
type Result: Into<PyResult<Self::Success>>;
} }
pub trait PyNumberIPowProtocol<'p>: PyNumberProtocol<'p> { pub trait PyNumberIPowProtocol<'p>: PyNumberProtocol<'p> {
type Other: FromPyObject<'p>; type Other: FromPyObject<'p>;
type Modulo: FromPyObject<'p>; type Modulo: FromPyObject<'p>;
type Success: ToPyObject; type Result: Into<PyResult<()>>;
type Result: Into<PyResult<Self::Success>>;
} }
pub trait PyNumberILShiftProtocol<'p>: PyNumberProtocol<'p> { pub trait PyNumberILShiftProtocol<'p>: PyNumberProtocol<'p> {
type Other: FromPyObject<'p>; type Other: FromPyObject<'p>;
type Success: ToPyObject; type Result: Into<PyResult<()>>;
type Result: Into<PyResult<Self::Success>>;
} }
pub trait PyNumberIRShiftProtocol<'p>: PyNumberProtocol<'p> { pub trait PyNumberIRShiftProtocol<'p>: PyNumberProtocol<'p> {
type Other: FromPyObject<'p>; type Other: FromPyObject<'p>;
type Success: ToPyObject; type Result: Into<PyResult<()>>;
type Result: Into<PyResult<Self::Success>>;
} }
pub trait PyNumberIAndProtocol<'p>: PyNumberProtocol<'p> { pub trait PyNumberIAndProtocol<'p>: PyNumberProtocol<'p> {
type Other: FromPyObject<'p>; type Other: FromPyObject<'p>;
type Success: ToPyObject; type Result: Into<PyResult<()>>;
type Result: Into<PyResult<Self::Success>>;
} }
pub trait PyNumberIXorProtocol<'p>: PyNumberProtocol<'p> { pub trait PyNumberIXorProtocol<'p>: PyNumberProtocol<'p> {
type Other: FromPyObject<'p>; type Other: FromPyObject<'p>;
type Success: ToPyObject; type Result: Into<PyResult<()>>;
type Result: Into<PyResult<Self::Success>>;
} }
pub trait PyNumberIOrProtocol<'p>: PyNumberProtocol<'p> { pub trait PyNumberIOrProtocol<'p>: PyNumberProtocol<'p> {
type Other: FromPyObject<'p>; type Other: FromPyObject<'p>;
type Success: ToPyObject; type Result: Into<PyResult<()>>;
type Result: Into<PyResult<Self::Success>>;
} }
pub trait PyNumberNegProtocol<'p>: PyNumberProtocol<'p> { pub trait PyNumberNegProtocol<'p>: PyNumberProtocol<'p> {
@ -689,8 +675,7 @@ impl<'p, T> PyNumberIAddProtocolImpl for T where T: PyNumberProtocol<'p> {
} }
impl<T> PyNumberIAddProtocolImpl for T where T: for<'p> PyNumberIAddProtocol<'p> { impl<T> PyNumberIAddProtocolImpl for T where T: for<'p> PyNumberIAddProtocol<'p> {
fn nb_inplace_add() -> Option<ffi::binaryfunc> { fn nb_inplace_add() -> Option<ffi::binaryfunc> {
py_binary_func!(PyNumberIAddProtocol, py_binary_self_func!(PyNumberIAddProtocol, T::__iadd__)
T::__iadd__, T::Success, PyObjectCallbackConverter)
} }
} }
@ -702,8 +687,7 @@ impl<'p, T> PyNumberISubProtocolImpl for T where T: PyNumberProtocol<'p> {
} }
impl<T> PyNumberISubProtocolImpl for T where T: for<'p> PyNumberISubProtocol<'p> { impl<T> PyNumberISubProtocolImpl for T where T: for<'p> PyNumberISubProtocol<'p> {
fn nb_inplace_subtract() -> Option<ffi::binaryfunc> { fn nb_inplace_subtract() -> Option<ffi::binaryfunc> {
py_binary_func!(PyNumberISubProtocol, py_binary_self_func!(PyNumberISubProtocol, T::__isub__)
T::__isub__, T::Success, PyObjectCallbackConverter)
} }
} }
@ -715,8 +699,7 @@ impl<'p, T> PyNumberIMulProtocolImpl for T where T: PyNumberProtocol<'p> {
} }
impl<T> PyNumberIMulProtocolImpl for T where T: for<'p> PyNumberIMulProtocol<'p> { impl<T> PyNumberIMulProtocolImpl for T where T: for<'p> PyNumberIMulProtocol<'p> {
fn nb_inplace_multiply() -> Option<ffi::binaryfunc> { fn nb_inplace_multiply() -> Option<ffi::binaryfunc> {
py_binary_func!(PyNumberIMulProtocol, py_binary_self_func!(PyNumberIMulProtocol, T::__imul__)
T::__imul__, T::Success, PyObjectCallbackConverter)
} }
} }
@ -728,8 +711,7 @@ impl<'p, T> PyNumberIMatmulProtocolImpl for T where T: PyNumberProtocol<'p> {
} }
impl<T> PyNumberIMatmulProtocolImpl for T where T: for<'p> PyNumberIMatmulProtocol<'p> { impl<T> PyNumberIMatmulProtocolImpl for T where T: for<'p> PyNumberIMatmulProtocol<'p> {
fn nb_inplace_matrix_multiply() -> Option<ffi::binaryfunc> { fn nb_inplace_matrix_multiply() -> Option<ffi::binaryfunc> {
py_binary_func!(PyNumberIMatmulProtocol, py_binary_self_func!(PyNumberIMatmulProtocol, T::__imatmul__)
T::__imatmul__, T::Success, PyObjectCallbackConverter)
} }
} }
@ -741,8 +723,7 @@ impl<'p, T> PyNumberITruedivProtocolImpl for T where T: PyNumberProtocol<'p> {
} }
impl<T> PyNumberITruedivProtocolImpl for T where T: for<'p> PyNumberITruedivProtocol<'p> { impl<T> PyNumberITruedivProtocolImpl for T where T: for<'p> PyNumberITruedivProtocol<'p> {
fn nb_inplace_true_divide() -> Option<ffi::binaryfunc> { fn nb_inplace_true_divide() -> Option<ffi::binaryfunc> {
py_binary_func!(PyNumberITruedivProtocol, py_binary_self_func!(PyNumberITruedivProtocol, T::__itruediv__)
T::__itruediv__, T::Success, PyObjectCallbackConverter)
} }
} }
@ -754,8 +735,7 @@ impl<'p, T> PyNumberIFloordivProtocolImpl for T where T: PyNumberProtocol<'p> {
} }
impl<T> PyNumberIFloordivProtocolImpl for T where T: for<'p> PyNumberIFloordivProtocol<'p> { impl<T> PyNumberIFloordivProtocolImpl for T where T: for<'p> PyNumberIFloordivProtocol<'p> {
fn nb_inplace_floor_divide() -> Option<ffi::binaryfunc> { fn nb_inplace_floor_divide() -> Option<ffi::binaryfunc> {
py_binary_func!(PyNumberIFloordivProtocol, py_binary_self_func!(PyNumberIFloordivProtocol, T::__ifloordiv__)
T::__ifloordiv__, T::Success, PyObjectCallbackConverter)
} }
} }
@ -767,8 +747,7 @@ impl<'p, T> PyNumberIModProtocolImpl for T where T: PyNumberProtocol<'p> {
} }
impl<T> PyNumberIModProtocolImpl for T where T: for<'p> PyNumberIModProtocol<'p> { impl<T> PyNumberIModProtocolImpl for T where T: for<'p> PyNumberIModProtocol<'p> {
fn nb_inplace_remainder() -> Option<ffi::binaryfunc> { fn nb_inplace_remainder() -> Option<ffi::binaryfunc> {
py_binary_func!(PyNumberIModProtocol, py_binary_self_func!(PyNumberIModProtocol, T::__imod__)
T::__imod__, T::Success, PyObjectCallbackConverter)
} }
} }
@ -780,8 +759,7 @@ impl<'p, T> PyNumberIPowProtocolImpl for T where T: PyNumberProtocol<'p> {
} }
impl<T> PyNumberIPowProtocolImpl for T where T: for<'p> PyNumberIPowProtocol<'p> { impl<T> PyNumberIPowProtocolImpl for T where T: for<'p> PyNumberIPowProtocol<'p> {
fn nb_inplace_power() -> Option<ffi::ternaryfunc> { fn nb_inplace_power() -> Option<ffi::ternaryfunc> {
py_ternary_func!(PyNumberIPowProtocol, py_ternary_self_func!(PyNumberIPowProtocol, T::__ipow__)
T::__ipow__, T::Success, PyObjectCallbackConverter)
} }
} }
@ -793,8 +771,7 @@ impl<'p, T> PyNumberILShiftProtocolImpl for T where T: PyNumberProtocol<'p> {
} }
impl<T> PyNumberILShiftProtocolImpl for T where T: for<'p> PyNumberILShiftProtocol<'p> { impl<T> PyNumberILShiftProtocolImpl for T where T: for<'p> PyNumberILShiftProtocol<'p> {
fn nb_inplace_lshift() -> Option<ffi::binaryfunc> { fn nb_inplace_lshift() -> Option<ffi::binaryfunc> {
py_binary_func!(PyNumberILShiftProtocol, py_binary_self_func!(PyNumberILShiftProtocol, T::__ilshift__)
T::__ilshift__, T::Success, PyObjectCallbackConverter)
} }
} }
@ -806,8 +783,7 @@ impl<'p, T> PyNumberIRShiftProtocolImpl for T where T: PyNumberProtocol<'p> {
} }
impl<T> PyNumberIRShiftProtocolImpl for T where T: for<'p> PyNumberIRShiftProtocol<'p> { impl<T> PyNumberIRShiftProtocolImpl for T where T: for<'p> PyNumberIRShiftProtocol<'p> {
fn nb_inplace_rshift() -> Option<ffi::binaryfunc> { fn nb_inplace_rshift() -> Option<ffi::binaryfunc> {
py_binary_func!(PyNumberIRShiftProtocol, py_binary_self_func!(PyNumberIRShiftProtocol, T::__irshift__)
T::__irshift__, T::Success, PyObjectCallbackConverter)
} }
} }
@ -820,8 +796,7 @@ impl<'p, T> PyNumberIAndProtocolImpl for T where T: PyNumberProtocol<'p> {
} }
impl<T> PyNumberIAndProtocolImpl for T where T: for<'p> PyNumberIAndProtocol<'p> { impl<T> PyNumberIAndProtocolImpl for T where T: for<'p> PyNumberIAndProtocol<'p> {
fn nb_inplace_and() -> Option<ffi::binaryfunc> { fn nb_inplace_and() -> Option<ffi::binaryfunc> {
py_binary_func!(PyNumberIAndProtocol, py_binary_self_func!(PyNumberIAndProtocol, T::__iand__)
T::__iand__, T::Success, PyObjectCallbackConverter)
} }
} }
@ -833,8 +808,7 @@ impl<'p, T> PyNumberIXorProtocolImpl for T where T: PyNumberProtocol<'p> {
} }
impl<T> PyNumberIXorProtocolImpl for T where T: for<'p> PyNumberIXorProtocol<'p> { impl<T> PyNumberIXorProtocolImpl for T where T: for<'p> PyNumberIXorProtocol<'p> {
fn nb_inplace_xor() -> Option<ffi::binaryfunc> { fn nb_inplace_xor() -> Option<ffi::binaryfunc> {
py_binary_func!(PyNumberIXorProtocol, py_binary_self_func!(PyNumberIXorProtocol, T::__ixor__)
T::__ixor__, T::Success, PyObjectCallbackConverter)
} }
} }
@ -846,8 +820,7 @@ impl<'p, T> PyNumberIOrProtocolImpl for T where T: PyNumberProtocol<'p> {
} }
impl<T> PyNumberIOrProtocolImpl for T where T: for<'p> PyNumberIOrProtocol<'p> { impl<T> PyNumberIOrProtocolImpl for T where T: for<'p> PyNumberIOrProtocol<'p> {
fn nb_inplace_or() -> Option<ffi::binaryfunc> { fn nb_inplace_or() -> Option<ffi::binaryfunc> {
py_binary_func!(PyNumberIOrProtocol, py_binary_self_func!(PyNumberIOrProtocol, T::__ior__)
T::__ior__, T::Success, PyObjectCallbackConverter)
} }
} }

View file

@ -23,10 +23,10 @@ pub trait PySequenceProtocol<'p>: PyTypeInfo + Sized + 'static {
fn __getitem__(&'p self, py: Python<'p>, key: isize) -> Self::Result fn __getitem__(&'p self, py: Python<'p>, key: isize) -> Self::Result
where Self: PySequenceGetItemProtocol<'p> { unimplemented!() } 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!() } 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!() } where Self: PySequenceDelItemProtocol<'p> { unimplemented!() }
fn __contains__(&'p self, py: Python<'p>, item: Self::Item) -> Self::Result 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 fn __repeat__(&'p self, py: Python<'p>, count: isize) -> Self::Result
where Self: PySequenceRepeatProtocol<'p> { unimplemented!() } 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!() } 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!() } where Self: PySequenceInplaceRepeatProtocol<'p> { unimplemented!() }
} }

View file

@ -32,7 +32,6 @@ pub trait IntoPyObject {
#[inline] #[inline]
fn into_object<'p>(self, py: Python<'p>) -> Py<'p, PyObject> fn into_object<'p>(self, py: Python<'p>) -> Py<'p, PyObject>
where Self: Sized; where Self: Sized;
} }
@ -100,7 +99,7 @@ impl <'p, T: ?Sized> RefFromPyObject<'p> for T
} }
// Default IntoPyObject implementation // Default IntoPyObject implementation
impl <T> IntoPyObject for T where T: ToPyObject impl<T> IntoPyObject for T where T: ToPyObject
{ {
#[inline] #[inline]
default fn into_object<'p>(self, py: Python<'p>) -> Py<'p, PyObject> where Self: Sized default fn into_object<'p>(self, py: Python<'p>) -> Py<'p, PyObject> where Self: Sized
@ -139,7 +138,7 @@ impl <T> ToPyObject for Option<T> where T: ToPyObject {
} }
} }
impl <T> IntoPyObject for Option<T> where T: IntoPyObject { impl<T> IntoPyObject for Option<T> where T: IntoPyObject {
fn into_object<'p>(self, py: Python<'p>) -> Py<'p, PyObject> { fn into_object<'p>(self, py: Python<'p>) -> Py<'p, PyObject> {
match self { match self {

View file

@ -69,9 +69,9 @@ pub use pyptr::{Py, PyPtr};
pub use err::{PyErr, PyResult, PyDowncastError}; pub use err::{PyErr, PyResult, PyDowncastError};
pub use objects::*; pub use objects::*;
pub use python::{AsPy, Python}; pub use python::{AsPy, Python, PythonToken};
pub use pythonrun::{GILGuard, GILProtected, prepare_freethreaded_python}; 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 use class::{CompareOp};
pub mod class; pub mod class;
pub use class::*; pub use class::*;

View file

@ -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 // based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
use std::fmt; use std::fmt;
use std::cmp::Ordering; use std::cmp::Ordering;
@ -303,7 +289,6 @@ impl<T> fmt::Display for PyPtr<T> {
} }
} }
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use std; use std;

View file

@ -22,22 +22,22 @@ macro_rules! pyobject_newtype(
impl<'p> $crate::python::AsPy<'p> for &'p $name { impl<'p> $crate::python::AsPy<'p> for &'p $name {
#[inline] #[inline]
fn py<'a>(&'a self) -> Python<'p> { fn py<'a>(&'a self) -> $crate::Python<'p> {
unsafe { $crate::python::Python::assume_gil_acquired() } unsafe { $crate::python::Python::assume_gil_acquired() }
} }
} }
impl $crate::python::ToPythonPointer for $name { impl $crate::python::ToPythonPointer for $name {
#[inline] #[inline]
fn as_ptr(&self) -> *mut ffi::PyObject { fn as_ptr(&self) -> *mut $crate::ffi::PyObject {
self as *const _ as *mut ffi::PyObject self as *const _ as *mut $crate::ffi::PyObject
} }
} }
impl<'a> $crate::python::ToPythonPointer for &'a $name { impl<'a> $crate::python::ToPythonPointer for &'a $name {
#[inline] #[inline]
fn as_ptr(&self) -> *mut ffi::PyObject { fn as_ptr(&self) -> *mut $crate::ffi::PyObject {
self as *const _ as *mut ffi::PyObject self as *const _ as *mut $crate::ffi::PyObject
} }
} }
@ -63,6 +63,32 @@ macro_rules! pyobject_newtype(
unsafe { &mut $crate::ffi::$typeobject } 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())
}
}
); );
); );

View file

@ -20,6 +20,26 @@ pub struct PyPtr<T> {
} }
impl<T> PyPtr<T> { impl<T> PyPtr<T> {
/// 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<T> {
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<T> {
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> { pub fn as_ref<'p>(&self, _py: Python<'p>) -> Py<'p, T> {
Py{inner: self.inner, _t: PhantomData, _py: PhantomData} Py{inner: self.inner, _t: PhantomData, _py: PhantomData}
} }
@ -56,7 +76,6 @@ impl<T> IntoPythonPointer for PyPtr<T> {
#[inline] #[inline]
#[must_use] #[must_use]
fn into_ptr(self) -> *mut ffi::PyObject { fn into_ptr(self) -> *mut ffi::PyObject {
println!("INTO PTR: {:?}", self.inner);
let ptr = self.inner; let ptr = self.inner;
std::mem::forget(self); std::mem::forget(self);
ptr ptr
@ -206,7 +225,7 @@ impl<'p, T> Py<'p, T>
impl<'p, T> Py<'p, T> where T: PyTypeInfo impl<'p, T> Py<'p, T> where T: PyTypeInfo
{ {
/// Create new python object and move T instance under python management /// Create new python object and move T instance under python management
pub fn new(py: &Python<'p>, value: T) -> PyResult<Py<'p, T>> where T: PyObjectAlloc<Type=T> pub fn new(py: Python<'p>, value: T) -> PyResult<Py<'p, T>> where T: PyObjectAlloc<Type=T>
{ {
let ob = unsafe { let ob = unsafe {
try!(<T as PyObjectAlloc>::alloc(py, value)) try!(<T as PyObjectAlloc>::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] #[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) PyObject::from_borrowed_ptr(py, self.inner)
} }
} }

View file

@ -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 // based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
use std; use std;
use std::ffi::CString; use std::ffi::CString;
@ -42,11 +28,19 @@ use pythonrun::GILGuard;
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct Python<'p>(PhantomData<&'p GILGuard>); pub struct Python<'p>(PhantomData<&'p GILGuard>);
pub struct PythonToken<T>(PhantomData<T>);
pub trait AsPy<'p> { pub trait AsPy<'p> {
fn py<'a>(&'a self) -> Python<'p>; fn py<'a>(&'a self) -> Python<'p>;
} }
pub trait PyClone : Sized {
fn clone_ref(&self) -> PyPtr<Self>;
}
/// This trait allows retrieving the underlying FFI pointer from Python objects. /// This trait allows retrieving the underlying FFI pointer from Python objects.
pub trait ToPythonPointer { pub trait ToPythonPointer {
/// Retrieves the underlying FFI pointer (as a borrowed pointer). /// 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. /// This trait allows retrieving the underlying FFI pointer from Python objects.
pub trait IntoPythonPointer { 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; fn into_ptr(self) -> *mut ffi::PyObject;
} }
@ -82,6 +77,7 @@ impl <T> IntoPythonPointer for Option<T> where T: IntoPythonPointer {
} }
} }
impl<'p> Python<'p> { impl<'p> Python<'p> {
/// Retrieve Python instance under the assumption that the GIL is already acquired at this point, /// Retrieve Python instance under the assumption that the GIL is already acquired at this point,
/// and stays acquired for the lifetime `'p`. /// and stays acquired for the lifetime `'p`.
@ -169,14 +165,6 @@ impl<'p> Python<'p> {
} }
} }
/// Create new PyObject instance
#[inline]
pub fn init<T>(&'p self, value: T) -> Py<'p, T>
where T: PyTypeInfo + PyObjectAlloc<Type=T>
{
Py::new(self, value).unwrap()
}
/// Gets the Python builtin value `None`. /// Gets the Python builtin value `None`.
#[allow(non_snake_case)] // the Python keyword starts with uppercase #[allow(non_snake_case)] // the Python keyword starts with uppercase
#[inline] #[inline]
@ -219,8 +207,69 @@ impl<'p> Python<'p> {
pub fn import(self, name : &str) -> PyResult<Py<'p, PyModule>> { pub fn import(self, name : &str) -> PyResult<Py<'p, PyModule>> {
PyModule::import(self, name) PyModule::import(self, name)
} }
pub fn with_token<T, F>(self, f: F) -> Py<'p, T>
where F: FnOnce(PythonToken<T>) -> T,
T: PyTypeInfo + PyObjectAlloc<Type=T>
{
let value = f(PythonToken(PhantomData));
Py::new(self, value).unwrap()
}
} }
impl<T> PythonToken<T> {
/// Gets the Python builtin value `None`.
#[allow(non_snake_case)] // the Python keyword starts with uppercase
#[inline]
pub fn None(self) -> PyPtr<PyObject> {
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<PyBool> {
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<PyBool> {
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<PyObject> {
unsafe { PyPtr::from_borrowed_ptr(ffi::Py_NotImplemented()) }
}
/// Gets the Python type object for type T.
pub fn get_type<U>(self) -> PyPtr<PyType> 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<P, F>(self, f: F) -> PyPtr<P>
where F: FnOnce(PythonToken<P>) -> P,
P: PyTypeInfo + PyObjectAlloc<Type=P>
{
let value = f(PythonToken(PhantomData));
Py::new(Python(PhantomData), value).unwrap().into_pptr()
}
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use {Python, PyDict}; use {Python, PyDict};

View file

@ -92,12 +92,12 @@ pub trait PyObjectAlloc {
/// and initializes it using init_val. /// and initializes it using init_val.
/// `ty` must be derived from the Self type, and the resulting object /// `ty` must be derived from the Self type, and the resulting object
/// must be of type `ty`. /// 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 /// Calls the rust destructor for the object and frees the memory
/// (usually by calling ptr->ob_type->tp_free). /// (usually by calling ptr->ob_type->tp_free).
/// This function is used as tp_dealloc implementation. /// 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] /// A PythonObject that is usable as a base type for #[class]
@ -108,7 +108,7 @@ impl<T> PyObjectAlloc for T where T : PyTypeInfo {
/// and initializes it using init_val. /// and initializes it using init_val.
/// `ty` must be derived from the Self type, and the resulting object /// `ty` must be derived from the Self type, and the resulting object
/// must be of type `ty`. /// 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( let obj = ffi::PyType_GenericAlloc(
<Self as PyTypeInfo>::type_object(), 0); <Self as PyTypeInfo>::type_object(), 0);
@ -122,7 +122,7 @@ impl<T> PyObjectAlloc for T where T : PyTypeInfo {
/// Calls the rust destructor for the object and frees the memory /// Calls the rust destructor for the object and frees the memory
/// (usually by calling ptr->ob_type->tp_free). /// (usually by calling ptr->ob_type->tp_free).
/// This function is used as tp_dealloc implementation. /// 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( let ptr = (obj as *mut u8).offset(
<Self as PyTypeInfo>::offset() as isize) as *mut Self::Type; <Self as PyTypeInfo>::offset() as isize) as *mut Self::Type;
std::ptr::drop_in_place(ptr); std::ptr::drop_in_place(ptr);
@ -296,7 +296,7 @@ unsafe extern "C" fn tp_dealloc_callback<T>(obj: *mut ffi::PyObject)
println!("DEALLOC: {:?}", obj); println!("DEALLOC: {:?}", obj);
let guard = AbortOnDrop("Cannot unwind out of tp_dealloc"); let guard = AbortOnDrop("Cannot unwind out of tp_dealloc");
let py = Python::assume_gil_acquired(); let py = Python::assume_gil_acquired();
let r = <T as PyObjectAlloc>::dealloc(&py, obj); let r = <T as PyObjectAlloc>::dealloc(py, obj);
mem::forget(guard); mem::forget(guard);
r r
} }
@ -329,24 +329,24 @@ fn py_class_method_defs<T>() -> (Option<ffi::newfunc>,
} }
} }
for def in <T as class::basic::PyObjectProtocolImpl>::methods() { //for def in <T as class::basic::PyObjectProtocolImpl>::methods() {
defs.push(def.as_method_def()) // defs.push(def.as_method_def())
} //}
for def in <T as class::async::PyAsyncProtocolImpl>::methods() { //for def in <T as class::async::PyAsyncProtocolImpl>::methods() {
defs.push(def.as_method_def()) // defs.push(def.as_method_def())
} //}
for def in <T as class::context::PyContextProtocolImpl>::methods() { //for def in <T as class::context::PyContextProtocolImpl>::methods() {
defs.push(def.as_method_def()) // defs.push(def.as_method_def())
} //}
for def in <T as class::mapping::PyMappingProtocolImpl>::methods() { //for def in <T as class::mapping::PyMappingProtocolImpl>::methods() {
defs.push(def.as_method_def()) //defs.push(def.as_method_def())
} //}
for def in <T as class::number::PyNumberProtocolImpl>::methods() { //for def in <T as class::number::PyNumberProtocolImpl>::methods() {
defs.push(def.as_method_def()) // defs.push(def.as_method_def())
} //}
for def in <T as class::descr::PyDescrProtocolImpl>::methods() { //for def in <T as class::descr::PyDescrProtocolImpl>::methods() {
defs.push(def.as_method_def()) // defs.push(def.as_method_def())
} //}
(new, call, defs) (new, call, defs)
} }

View file

@ -9,6 +9,8 @@ use std::cell::RefCell;
use std::sync::Arc; use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use pyo3::ffi; use pyo3::ffi;
use pyo3::python::ToPythonPointer;
macro_rules! py_run { macro_rules! py_run {
($py:expr, $val:ident, $code:expr) => {{ ($py:expr, $val:ident, $code:expr) => {{
@ -26,7 +28,7 @@ macro_rules! py_assert {
macro_rules! py_expect_exception { macro_rules! py_expect_exception {
($py:expr, $val:ident, $code:expr, $err:ident) => {{ ($py:expr, $val:ident, $code:expr, $err:ident) => {{
let d = PyDict::new($py); 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 res = $py.run($code, None, Some(&d));
let err = res.unwrap_err(); let err = res.unwrap_err();
if !err.matches($py, $py.get_type::<exc::$err>()) { if !err.matches($py, $py.get_type::<exc::$err>()) {
@ -71,7 +73,7 @@ struct EmptyClassWithNew { }
#[py::methods] #[py::methods]
impl EmptyClassWithNew { impl EmptyClassWithNew {
#[__new__] #[__new__]
fn __new__(cls: &PyType) -> PyResult<EmptyClassWithNew> { fn __new__(cls: &PyType, py: Python) -> PyResult<EmptyClassWithNew> {
Ok(EmptyClassWithNew{}) Ok(EmptyClassWithNew{})
} }
} }
@ -91,7 +93,7 @@ struct NewWithOneArg {
#[py::methods] #[py::methods]
impl NewWithOneArg { impl NewWithOneArg {
#[new] #[new]
fn __new__(_cls: &PyType, arg: i32) -> PyResult<NewWithOneArg> { fn __new__(_cls: &PyType, py: Python, arg: i32) -> PyResult<NewWithOneArg> {
Ok(NewWithOneArg{_data: arg}) Ok(NewWithOneArg{_data: arg})
} }
} }
@ -114,7 +116,7 @@ struct NewWithTwoArgs {
#[py::methods] #[py::methods]
impl NewWithTwoArgs { impl NewWithTwoArgs {
#[new] #[new]
fn __new__(_cls: &PyType, arg1: i32, arg2: i32) -> PyResult<NewWithTwoArgs> { fn __new__(_cls: &PyType, py: Python, arg1: i32, arg2: i32) -> PyResult<NewWithTwoArgs> {
Ok(NewWithTwoArgs{_data1: arg1, _data2: arg2}) Ok(NewWithTwoArgs{_data1: arg1, _data2: arg2})
} }
} }
@ -169,7 +171,7 @@ struct InstanceMethod {
#[py::methods] #[py::methods]
impl InstanceMethod { impl InstanceMethod {
fn method(&self) -> PyResult<i32> { fn method(&self, py: Python) -> PyResult<i32> {
Ok(self.member) Ok(self.member)
} }
} }
@ -180,7 +182,7 @@ fn instance_method() {
let py = gil.python(); let py = gil.python();
let obj = py.init(InstanceMethod{member: 42}); let obj = py.init(InstanceMethod{member: 42});
assert!(obj.method().unwrap() == 42); assert!(obj.method(py).unwrap() == 42);
let d = PyDict::new(py); let d = PyDict::new(py);
d.set_item("obj", obj).unwrap(); d.set_item("obj", obj).unwrap();
py.run("assert obj.method() == 42", None, Some(&d)).unwrap(); py.run("assert obj.method() == 42", None, Some(&d)).unwrap();
@ -192,7 +194,7 @@ struct InstanceMethodWithArgs {
} }
#[py::methods] #[py::methods]
impl InstanceMethodWithArgs { impl InstanceMethodWithArgs {
fn method(&self, multiplier: i32) -> PyResult<i32> { fn method(&self, py: Python, multiplier: i32) -> PyResult<i32> {
Ok(self.member * multiplier) Ok(self.member * multiplier)
} }
} }
@ -203,7 +205,7 @@ fn instance_method_with_args() {
let py = gil.python(); let py = gil.python();
let obj = py.init(InstanceMethodWithArgs{member: 7}); 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); let d = PyDict::new(py);
d.set_item("obj", obj).unwrap(); d.set_item("obj", obj).unwrap();
py.run("assert obj.method(3) == 21", None, Some(&d)).unwrap(); py.run("assert obj.method(3) == 21", None, Some(&d)).unwrap();
@ -261,7 +263,7 @@ struct StaticMethod {}
impl StaticMethod { impl StaticMethod {
#[new] #[new]
fn __new__(cls: &PyType, py: Python) -> PyResult<StaticMethod> { fn __new__(cls: &PyType, py: Python) -> PyResult<StaticMethod> {
StaticMethod::create_instance(py) Ok(StaticMethod{}.into_object(py))
} }
//#[staticmethod] //#[staticmethod]
@ -303,18 +305,18 @@ impl StaticMethod {
#[py::class] #[py::class]
struct GCIntegration { struct GCIntegration {
self_ref: RefCell<PyObject>, self_ref: RefCell<PyPtr<PyObject>>,
dropped: TestDropCall, dropped: TestDropCall,
} }
#[py::proto] #[py::proto]
impl PyGCProtocol for GCIntegration { impl PyGCProtocol for GCIntegration {
fn __traverse__(&self, py: Python, visit: PyVisit) -> Result<(), PyTraverseError> { 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) { fn __clear__(&mut self, py: Python) {
let old_ref = mem::replace(&mut *self.self_ref(py).borrow_mut(), py.None()); let old_ref = mem::replace(&mut *self.self_ref.borrow_mut(), py.None());
// Release reference only after the mutable borrow has expired. // Release reference only after the mutable borrow has expired.
old_ref.release_ref(py); old_ref.release_ref(py);
} }
@ -326,12 +328,12 @@ fn gc_integration() {
let py = gil.python(); let py = gil.python();
let drop_called = Arc::new(AtomicBool::new(false)); let drop_called = Arc::new(AtomicBool::new(false));
let inst = GCIntegration::create_instance(py, let inst = py.init(GCIntegration{
RefCell::new(py.None()), self_ref: RefCell::new(py.None()),
TestDropCall { drop_called: drop_called.clone() } dropped: TestDropCall { drop_called: drop_called.clone() }});
).unwrap();
*inst.self_ref(py).borrow_mut() = inst.as_object().clone_ref(py); *inst.self_ref.borrow_mut() = inst.clone_ref().into_object().into_pptr();
inst.release_ref(py); drop(inst);
py.run("import gc; gc.collect()", None, None).unwrap(); py.run("import gc; gc.collect()", None, None).unwrap();
assert!(drop_called.load(Ordering::Relaxed)); assert!(drop_called.load(Ordering::Relaxed));
@ -345,7 +347,7 @@ pub struct Len {
#[py::proto] #[py::proto]
impl PyMappingProtocol for Len { impl PyMappingProtocol for Len {
fn __len__(&self, py: Python) -> PyResult<usize> { fn __len__(&self, py: Python) -> PyResult<usize> {
Ok(*self.l(py)) Ok(self.l)
} }
} }
@ -354,14 +356,14 @@ fn len() {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
let py = gil.python(); 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"); py_assert!(py, inst, "len(inst) == 10");
unsafe { unsafe {
assert_eq!(ffi::PyObject_Size(inst.as_object().as_ptr()), 10); assert_eq!(ffi::PyObject_Size(inst.as_ptr()), 10);
assert_eq!(ffi::PyMapping_Size(inst.as_object().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); py_expect_exception!(py, inst, "len(inst)", OverflowError);
} }
@ -391,16 +393,16 @@ fn iterator() {
struct StringMethods {} struct StringMethods {}
#[py::proto] #[py::proto]
impl PyObjectProtocol for StringMethods { impl<'p> PyObjectProtocol<'p> for StringMethods {
fn __str__(&self) -> PyResult<&'static str> { fn __str__(&self, py: Python) -> PyResult<&'static str> {
Ok("str") Ok("str")
} }
fn __repr__(&self) -> PyResult<&'static str> { fn __repr__(&self, py: Python) -> PyResult<&'static str> {
Ok("repr") Ok("repr")
} }
fn __format__(&self, format_spec: String) -> PyResult<String> { fn __format__(&self, py: Python, format_spec: String) -> PyResult<String> {
Ok(format!("format({})", format_spec)) Ok(format!("format({})", format_spec))
} }
@ -408,7 +410,7 @@ impl PyObjectProtocol for StringMethods {
// Ok(PyString::new(py, "unicode")) // Ok(PyString::new(py, "unicode"))
//} //}
fn __bytes__(&self) -> PyResult<PyBytes> { fn __bytes__(&self, py: Python) -> PyResult<Py<PyBytes>> {
Ok(PyBytes::new(py, b"bytes")) Ok(PyBytes::new(py, b"bytes"))
} }
} }
@ -418,7 +420,7 @@ fn string_methods() {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
let py = gil.python(); 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, "str(obj) == 'str'");
py_assert!(py, obj, "repr(obj) == 'repr'"); py_assert!(py, obj, "repr(obj) == 'repr'");
py_assert!(py, obj, "'{0:x}'.format(obj) == 'format(x)'"); py_assert!(py, obj, "'{0:x}'.format(obj) == 'format(x)'");
@ -433,12 +435,12 @@ struct Comparisons {
#[py::proto] #[py::proto]
impl PyObjectProtocol for Comparisons { impl PyObjectProtocol for Comparisons {
fn __hash__(&self) -> PyResult<usize> { fn __hash__(&self, py: Python) -> PyResult<usize> {
Ok(*self.val(py) as usize) Ok(self.val as usize)
} }
fn __bool__(&self) -> PyResult<bool> { fn __bool__(&self, py: Python) -> PyResult<bool> {
Ok(*self.val(py) != 0) Ok(self.val != 0)
} }
} }
@ -448,10 +450,10 @@ fn comparisons() {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
let py = gil.python(); let py = gil.python();
let zero = Comparisons::create_instance(py, 0).unwrap(); let zero = Comparisons{val: 0}.into_object(py);
let one = Comparisons::create_instance(py, 1).unwrap(); let one = Comparisons{val: 1}.into_object(py);
let ten = Comparisons::create_instance(py, 10).unwrap(); let ten = Comparisons{val: 10}.into_object(py);
let minus_one = Comparisons::create_instance(py, -1).unwrap(); let minus_one = Comparisons{val: -1}.into_object(py);
py_assert!(py, one, "hash(one) == 1"); py_assert!(py, one, "hash(one) == 1");
py_assert!(py, ten, "hash(ten) == 10"); py_assert!(py, ten, "hash(ten) == 10");
py_assert!(py, minus_one, "hash(minus_one) == -2"); py_assert!(py, minus_one, "hash(minus_one) == -2");
@ -466,11 +468,11 @@ struct Sequence {}
#[py::proto] #[py::proto]
impl PySequenceProtocol for Sequence { impl PySequenceProtocol for Sequence {
fn __len__(&self) -> PyResult<usize> { fn __len__(&self, py: Python) -> PyResult<usize> {
Ok(5) Ok(5)
} }
fn __getitem__(&self, key: isize) -> PyResult<isize> { fn __getitem__(&self, py: Python, key: isize) -> PyResult<isize> {
if key == 5 { if key == 5 {
return Err(PyErr::new::<exc::IndexError, NoArgs>(py, NoArgs)); return Err(PyErr::new::<exc::IndexError, NoArgs>(py, NoArgs));
} }
@ -483,7 +485,7 @@ fn sequence() {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
let py = gil.python(); 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_assert!(py, c, "list(c) == [0, 1, 2, 3, 4]");
py_expect_exception!(py, c, "c['abc']", TypeError); py_expect_exception!(py, c, "c['abc']", TypeError);
} }
@ -496,7 +498,7 @@ struct Callable {}
impl Callable { impl Callable {
#[__call__] #[__call__]
fn __call__(&self, arg: i32) -> PyResult<i32> { fn __call__(&self, py: Python, arg: i32) -> PyResult<i32> {
Ok(arg * 6) Ok(arg * 6)
} }
} }
@ -506,11 +508,11 @@ fn callable() {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
let py = gil.python(); 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, "callable(c)");
py_assert!(py, c, "c(7) == 42"); 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)"); py_assert!(py, nc, "not callable(nc)");
} }
@ -522,9 +524,9 @@ struct SetItem {
#[py::proto] #[py::proto]
impl PyMappingProtocol<'a> for SetItem { impl PyMappingProtocol<'a> for SetItem {
fn __setitem__(&self, key: i32, val: i32) -> PyResult<()> { fn __setitem__(&mut self, py: Python, key: i32, val: i32) -> PyResult<()> {
*self.key_mut(py) = key; self.key = key;
*self.val_mut(py) = val; self.val = val;
Ok(()) Ok(())
} }
} }
@ -534,7 +536,7 @@ fn setitem() {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
let py = gil.python(); 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"); py_run!(py, c, "c[1] = 2");
assert_eq!(c.key, 1); assert_eq!(c.key, 1);
assert_eq!(c.val, 2); assert_eq!(c.val, 2);
@ -548,8 +550,8 @@ struct DelItem {
#[py::proto] #[py::proto]
impl PyMappingProtocol<'a> for DelItem { impl PyMappingProtocol<'a> for DelItem {
fn __delitem__(&self, key: i32) -> PyResult<()> { fn __delitem__(&mut self, py: Python, key: i32) -> PyResult<()> {
*self.key_mut(py) = key; self.key = key;
Ok(()) Ok(())
} }
} }
@ -559,9 +561,9 @@ fn delitem() {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
let py = gil.python(); 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]"); 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); py_expect_exception!(py, c, "c[1] = 2", NotImplementedError);
} }
@ -572,13 +574,13 @@ struct SetDelItem {
#[py::proto] #[py::proto]
impl PyMappingProtocol for SetDelItem { impl PyMappingProtocol for SetDelItem {
fn __setitem__(&self, key: i32, val: i32) -> PyResult<()> { fn __setitem__(&mut self, py: Python, key: i32, val: i32) -> PyResult<()> {
*self.val_mut(py) = Some(val); self.val = Some(val);
Ok(()) Ok(())
} }
fn __delitem__(&self, key: i32) -> PyResult<()> { fn __delitem__(&mut self, py: Python, key: i32) -> PyResult<()> {
*self.val_mut(py) = None; self.val = None;
Ok(()) Ok(())
} }
} }
@ -588,11 +590,11 @@ fn setdelitem() {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
let py = gil.python(); 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"); 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]"); py_run!(py, c, "del c[1]");
assert_eq!(*c.val(py), None); assert_eq!(c.val, None);
} }
#[py::class] #[py::class]
@ -600,7 +602,7 @@ struct Reversed {}
#[py::proto] #[py::proto]
impl PyMappingProtocol for Reversed{ impl PyMappingProtocol for Reversed{
fn __reversed__(&self) -> PyResult<&'static str> { fn __reversed__(&self, py: Python) -> PyResult<&'static str> {
println!("__reversed__"); println!("__reversed__");
Ok("I am reversed") Ok("I am reversed")
} }
@ -611,7 +613,7 @@ fn reversed() {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
let py = gil.python(); 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'"); py_run!(py, c, "assert reversed(c) == 'I am reversed'");
} }
@ -620,7 +622,7 @@ struct Contains {}
#[py::proto] #[py::proto]
impl PySequenceProtocol for Contains { impl PySequenceProtocol for Contains {
fn __contains__(&self, item: i32) -> PyResult<bool> { fn __contains__(&self, py: Python, item: i32) -> PyResult<bool> {
Ok(item >= 0) Ok(item >= 0)
} }
} }
@ -630,7 +632,7 @@ fn contains() {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
let py = gil.python(); 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 in c");
py_run!(py, c, "assert -1 not in c"); py_run!(py, c, "assert -1 not in c");
py_expect_exception!(py, c, "assert 'wrong type' not in c", TypeError); py_expect_exception!(py, c, "assert 'wrong type' not in c", TypeError);
@ -644,19 +646,19 @@ struct UnaryArithmetic {}
#[py::proto] #[py::proto]
impl PyNumberProtocol for UnaryArithmetic { impl PyNumberProtocol for UnaryArithmetic {
fn __neg__(&self) -> PyResult<&'static str> { fn __neg__(&self, py: Python) -> PyResult<&'static str> {
Ok("neg") Ok("neg")
} }
fn __pos__(&self) -> PyResult<&'static str> { fn __pos__(&self, py: Python) -> PyResult<&'static str> {
Ok("pos") Ok("pos")
} }
fn __abs__(&self) -> PyResult<&'static str> { fn __abs__(&self, py: Python) -> PyResult<&'static str> {
Ok("abs") Ok("abs")
} }
fn __invert__(&self) -> PyResult<&'static str> { fn __invert__(&self, py: Python) -> PyResult<&'static str> {
Ok("invert") Ok("invert")
} }
} }
@ -666,7 +668,7 @@ fn unary_arithmetic() {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
let py = gil.python(); 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 == 'neg'");
py_run!(py, c, "assert +c == 'pos'"); py_run!(py, c, "assert +c == 'pos'");
py_run!(py, c, "assert abs(c) == 'abs'"); py_run!(py, c, "assert abs(c) == 'abs'");
@ -679,43 +681,43 @@ struct BinaryArithmetic {}
#[py::proto] #[py::proto]
impl PyObjectProtocol for BinaryArithmetic { impl PyObjectProtocol for BinaryArithmetic {
fn __repr__(&self) -> PyResult<&'static str> { fn __repr__(&self, py: Python) -> PyResult<&'static str> {
Ok("BA") Ok("BA")
} }
} }
#[py::proto] #[py::proto]
impl PyNumberProtocol for BinaryArithmetic { impl PyNumberProtocol for BinaryArithmetic {
fn __add__(&self, rhs: PyObject) -> PyResult<String> { fn __add__(&self, py: Python, rhs: &PyObject) -> PyResult<String> {
Ok(format!("{:?} + {:?}", self.as_object(), rhs)) Ok(format!("{:?} + {:?}", self, rhs))
} }
fn __sub__(&self, rhs: PyObject) -> PyResult<String> { fn __sub__(&self, py: Python, rhs: &PyObject) -> PyResult<String> {
Ok(format!("{:?} - {:?}", self.as_object(), rhs)) Ok(format!("{:?} - {:?}", self, rhs))
} }
fn __mul__(&self, rhs: PyObject) -> PyResult<String> { fn __mul__(&self, py: Python, rhs: &PyObject) -> PyResult<String> {
Ok(format!("{:?} * {:?}", self.as_object(), rhs)) Ok(format!("{:?} * {:?}", self, rhs))
} }
fn __lshift__(&self, rhs: PyObject) -> PyResult<String> { fn __lshift__(&self, py: Python, rhs: &PyObject) -> PyResult<String> {
Ok(format!("{:?} << {:?}", self.as_object(), rhs)) Ok(format!("{:?} << {:?}", self, rhs))
} }
fn __rshift__(&self, rhs: PyObject) -> PyResult<String> { fn __rshift__(&self, py: Python, rhs: &PyObject) -> PyResult<String> {
Ok(format!("{:?} >> {:?}", self.as_object(), rhs)) Ok(format!("{:?} >> {:?}", self, rhs))
} }
fn __and__(&self, rhs: PyObject) -> PyResult<String> { fn __and__(&self, py: Python, rhs: &PyObject) -> PyResult<String> {
Ok(format!("{:?} & {:?}", self.as_object(), rhs)) Ok(format!("{:?} & {:?}", self, rhs))
} }
fn __xor__(&self, rhs: PyObject) -> PyResult<String> { fn __xor__(&self, py: Python, rhs: &PyObject) -> PyResult<String> {
Ok(format!("{:?} ^ {:?}", self.as_object(), rhs)) Ok(format!("{:?} ^ {:?}", self, rhs))
} }
fn __or__(&self, rhs: PyObject) -> PyResult<String> { fn __or__(&self, py: Python, rhs: &PyObject) -> PyResult<String> {
Ok(format!("{:?} | {:?}", self.as_object(), rhs)) Ok(format!("{:?} | {:?}", self, rhs))
} }
} }
@ -724,7 +726,7 @@ fn binary_arithmetic() {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
let py = gil.python(); 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 + c == 'BA + BA'");
py_run!(py, c, "assert c + 1 == 'BA + 1'"); py_run!(py, c, "assert c + 1 == 'BA + 1'");
py_run!(py, c, "assert 1 + c == '1 + BA'"); py_run!(py, c, "assert 1 + c == '1 + BA'");
@ -751,35 +753,38 @@ struct RichComparisons {}
#[py::proto] #[py::proto]
impl PyObjectProtocol for RichComparisons { impl PyObjectProtocol for RichComparisons {
fn __repr__(&self) -> PyResult<&'static str> { fn __repr__(&self, py: Python) -> PyResult<&'static str> {
Ok("RC") Ok("RC")
} }
fn __richcmp__(&self, other: PyObject, op: CompareOp) -> PyResult<String> { fn __richcmp__(&self, py: Python, other: &PyObject, op: CompareOp) -> PyResult<String> {
match op { match op {
CompareOp::Lt => Ok(format!("{:?} < {:?}", self.as_object(), other)), CompareOp::Lt => Ok(format!("{:?} < {:?}", self.__repr__(py), other)),
CompareOp::Le => Ok(format!("{:?} <= {:?}", self.as_object(), other)), CompareOp::Le => Ok(format!("{:?} <= {:?}", self.__repr__(py), other)),
CompareOp::Eq => Ok(format!("{:?} == {:?}", self.as_object(), other)), CompareOp::Eq => Ok(format!("{:?} == {:?}", self.__repr__(py), other)),
CompareOp::Ne => Ok(format!("{:?} != {:?}", self.as_object(), other)), CompareOp::Ne => Ok(format!("{:?} != {:?}", self.__repr__(py), other)),
CompareOp::Gt => Ok(format!("{:?} > {:?}", self.as_object(), other)), CompareOp::Gt => Ok(format!("{:?} > {:?}", self.__repr__(py), other)),
CompareOp::Ge => Ok(format!("{:?} >= {:?}", self.as_object(), other)) CompareOp::Ge => Ok(format!("{:?} >= {:?}", self.__repr__(py), other))
} }
} }
} }
#[py::class] #[py::class]
struct RichComparisons2 {} struct RichComparisons2 {
py: PythonToken<RichComparisons2>
}
#[py::proto] #[py::proto]
impl PyObjectProtocol for RichComparisons2 { impl PyObjectProtocol for RichComparisons2 {
fn __repr__(&self) -> PyResult<&'static str> { fn __repr__(&self, py: Python) -> PyResult<&'static str> {
Ok("RC2") Ok("RC2")
} }
fn __richcmp__(&self, other: PyObject, op: CompareOp) -> PyResult<PyObject> { fn __richcmp__(&self, py: Python,
other: &PyObject, op: CompareOp) -> PyResult<Py<PyObject>> {
match op { match op {
CompareOp::Eq => Ok(true.to_py_object(py).into_object()), CompareOp::Eq => Ok(true.to_object(py).into_object()),
CompareOp::Ne => Ok(false.to_py_object(py).into_object()), CompareOp::Ne => Ok(false.to_object(py).into_object()),
_ => Ok(py.NotImplemented()) _ => Ok(py.NotImplemented())
} }
} }
@ -790,7 +795,7 @@ fn rich_comparisons() {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
let py = gil.python(); 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 < c) == 'RC < RC'");
py_run!(py, c, "assert (c < 1) == 'RC < 1'"); py_run!(py, c, "assert (c < 1) == 'RC < 1'");
py_run!(py, c, "assert (1 < c) == '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 gil = Python::acquire_gil();
let py = gil.python(); 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 < c2", TypeError);
py_expect_exception!(py, c2, "c2 < 1", TypeError); py_expect_exception!(py, c2, "c2 < 1", TypeError);
py_expect_exception!(py, c2, "1 < c2", TypeError); py_expect_exception!(py, c2, "1 < c2", TypeError);
@ -844,51 +849,51 @@ struct InPlaceOperations {
#[py::proto] #[py::proto]
impl PyObjectProtocol for InPlaceOperations { impl PyObjectProtocol for InPlaceOperations {
fn __repr__(&self) -> PyResult<String> { fn __repr__(&self, py: Python) -> PyResult<String> {
Ok(format!("IPO({:?})", self.value(py))) Ok(format!("IPO({:?})", self.value))
} }
} }
#[py::proto] #[py::proto]
impl PyNumberProtocol for InPlaceOperations { impl PyNumberProtocol for InPlaceOperations {
fn __iadd__(&self, other: u32) -> PyResult<Self> { fn __iadd__(&mut self, py: Python, other: u32) -> PyResult<()> {
*self.value_mut(py) = *self.value(py) + other; self.value = self.value + other;
Ok(self.clone_ref(py)) Ok(())
} }
fn __isub__(&self, other: u32) -> PyResult<Self> { fn __isub__(&mut self, py: Python, other: u32) -> PyResult<()> {
*self.value_mut(py) = *self.value(py) - other; self.value = self.value - other;
Ok(self.clone_ref(py)) Ok(())
} }
fn __imul__(&self, other: u32) -> PyResult<Self> { fn __imul__(&mut self, py: Python, other: u32) -> PyResult<()> {
*self.value_mut(py) = *self.value(py) * other; self.value = self.value * other;
Ok(self.clone_ref(py)) Ok(())
} }
fn __ilshift__(&self, other: u32) -> PyResult<Self> { fn __ilshift__(&mut self, py: Python, other: u32) -> PyResult<()> {
*self.value_mut(py) = *self.value(py) << other; self.value = self.value << other;
Ok(self.clone_ref(py)) Ok(())
} }
fn __irshift__(&self, other: u32) -> PyResult<Self> { fn __irshift__(&mut self, py: Python, other: u32) -> PyResult<()> {
*self.value_mut(py) = *self.value(py) >> other; self.value = self.value >> other;
Ok(self.clone_ref(py)) Ok(())
} }
fn __iand__(&self, other: u32) -> PyResult<Self> { fn __iand__(&mut self, py: Python, other: u32) -> PyResult<()> {
*self.value_mut(py) = *self.value(py) & other; self.value = self.value & other;
Ok(self.clone_ref(py)) Ok(())
} }
fn __ixor__(&self, other: u32) -> PyResult<Self> { fn __ixor__(&mut self, py: Python, other: u32) -> PyResult<()> {
*self.value_mut(py) = *self.value(py) ^ other; self.value = self.value ^ other;
Ok(self.clone_ref(py)) Ok(())
} }
fn __ior__(&self, other: u32) -> PyResult<Self> { fn __ior__(&mut self, py: Python, other: u32) -> PyResult<()> {
*self.value_mut(py) = *self.value(py) | other; self.value = self.value | other;
Ok(self.clone_ref(py)) Ok(())
} }
} }
@ -897,28 +902,28 @@ fn inplace_operations() {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
let py = gil.python(); 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)'"); 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)'"); 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)'"); 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)'"); 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)'"); 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)'"); 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)'"); 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)'"); py_run!(py, c, "d = c; c ^= 5; assert repr(c) == repr(d) == 'IPO(9)'");
} }
@ -930,11 +935,11 @@ struct ContextManager {
#[py::proto] #[py::proto]
impl<'p> PyContextProtocol<'p> for ContextManager { impl<'p> PyContextProtocol<'p> for ContextManager {
fn __enter__(&self) -> PyResult<i32> { fn __enter__(&mut self, py: Python) -> PyResult<i32> {
Ok(42) Ok(42)
} }
fn __exit__(&mut self, fn __exit__(&mut self, py: Python,
ty: Option<&'p PyType>, ty: Option<&'p PyType>,
value: Option<&'p PyObject>, value: Option<&'p PyObject>,
traceback: Option<&'p PyObject>) -> PyResult<bool> { traceback: Option<&'p PyObject>) -> PyResult<bool> {
@ -952,17 +957,19 @@ fn context_manager() {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
let py = gil.python(); 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"); 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"); 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; c.exit_called = false;
py_expect_exception!(py, c, "with c as x:\n raise NotImplementedError", NotImplementedError); py_expect_exception!(
assert!(*c.exit_called(py)); py, c, "with c as x:\n raise NotImplementedError",
NotImplementedError);
assert!(c.exit_called);
} }
@ -974,17 +981,17 @@ struct ClassWithProperties {
#[py::methods] #[py::methods]
impl ClassWithProperties { impl ClassWithProperties {
fn get_num(&self) -> PyResult<i32> { fn get_num(&self, py: Python) -> PyResult<i32> {
Ok(*self.num(py)) Ok(self.num)
} }
#[getter(DATA)] #[getter(DATA)]
fn get_data(&self) -> PyResult<i32> { fn get_data(&self, py: Python) -> PyResult<i32> {
Ok(*self.num(py)) Ok(self.num)
} }
#[setter(DATA)] #[setter(DATA)]
fn set(&self, value: i32) -> PyResult<()> { fn set(&self, py: Python, value: i32) -> PyResult<()> {
*self.num_mut(py) = value; self.num = value;
Ok(()) Ok(())
} }
} }
@ -995,7 +1002,7 @@ fn class_with_properties() {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
let py = gil.python(); 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() == 10");
py_run!(py, inst, "assert inst.get_num() == inst.DATA"); py_run!(py, inst, "assert inst.get_num() == inst.DATA");