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 {
name: "__iadd__",
arg: "Other",
pyres: true,
pyres: false,
proto: "::pyo3::class::number::PyNumberIAddProtocol"},
MethodProto::Binary {
name: "__isub__",
arg: "Other",
pyres: true,
pyres: false,
proto: "::pyo3::class::number::PyNumberISubProtocol"},
MethodProto::Binary {
name: "__imul__",
arg: "Other",
pyres: true,
pyres: false,
proto: "::pyo3::class::number::PyNumberIMulProtocol"},
MethodProto::Binary {
name: "__imatmul__",
arg: "Other",
pyres: true,
pyres: false,
proto: "::pyo3::class::number::PyNumberIMatmulProtocol"},
MethodProto::Binary {
name: "__itruediv__",
arg: "Other",
pyres: true,
pyres: false,
proto: "::pyo3::class::number::PyNumberITruedivProtocol"},
MethodProto::Binary {
name: "__ifloordiv__",
arg: "Other",
pyres: true,
pyres: false,
proto: "::pyo3::class::number::PyNumberIFloordivProtocol"},
MethodProto::Binary {
name: "__imod__",
arg: "Other",
pyres: true,
pyres: false,
proto: "::pyo3::class::number::PyNumberIModProtocol"},
MethodProto::Ternary {
name: "__ipow__",
arg1: "Other",
arg2: "Modulo",
pyres: true,
pyres: false,
proto: "::pyo3::class::number::PyNumberIPowProtocol"},
MethodProto::Binary {
name: "__ilshift__",
arg: "Other",
pyres: true,
pyres: false,
proto: "::pyo3::class::number::PyNumberILShiftProtocol"},
MethodProto::Binary {
name: "__irshift__",
arg: "Other",
pyres: true,
pyres: false,
proto: "::pyo3::class::number::PyNumberIRShiftProtocol"},
MethodProto::Binary {
name: "__iand__",
arg: "Other",
pyres: true,
pyres: false,
proto: "::pyo3::class::number::PyNumberIAndProtocol"},
MethodProto::Binary {
name: "__ixor__",
arg: "Other",
pyres: true,
pyres: false,
proto: "::pyo3::class::number::PyNumberIXorProtocol"},
MethodProto::Binary {
name: "__ior__",
arg: "Other",
pyres: true,
pyres: false,
proto: "::pyo3::class::number::PyNumberIOrProtocol"},
MethodProto::Unary {

View file

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

View file

@ -8,7 +8,8 @@ pub fn build_py_class(ast: &mut syn::DeriveInput) -> Tokens {
let base = syn::Ident::from("_pyo3::PyObject");
match ast.body {
syn::Body::Struct(syn::VariantData::Struct(_)) => (),
syn::Body::Struct(syn::VariantData::Struct(_)) => {
},
_ => panic!("#[class] can only be used with notmal structs"),
}
@ -22,7 +23,6 @@ pub fn build_py_class(ast: &mut syn::DeriveInput) -> Tokens {
const #dummy_const: () = {
extern crate pyo3 as _pyo3;
use std;
use pyo3::python::IntoPythonPointer;
#tokens
};
@ -30,6 +30,7 @@ pub fn build_py_class(ast: &mut syn::DeriveInput) -> Tokens {
}
fn impl_class(cls: &syn::Ident, base: &syn::Ident) -> Tokens {
let token_name = syn::Ident::from("__py_token");
let cls_name = quote! { #cls }.as_str().to_string();
quote! {
@ -60,12 +61,22 @@ fn impl_class(cls: &syn::Ident, base: &syn::Ident) -> Tokens {
}
}
impl _pyo3::IntoPyObject for #cls {
impl _pyo3::python::ToPythonPointer for #cls {
#[inline]
fn into_object<'p>(self, py: Python<'p>) -> Py<'p, PyObject> where Self: Sized
{
let ptr = py.init(self).into_ptr();
_pyo3::PyObject::from_owned_ptr(py, ptr)
fn as_ptr(&self) -> *mut ffi::PyObject {
let offset = <#cls as _pyo3::typeob::PyTypeInfo>::offset();
unsafe {
{self as *const _ as *mut u8}.offset(-offset) as *mut _pyo3::ffi::PyObject
}
}
}
impl _pyo3::python::PyClone for #cls {
fn clone_ref(&self) -> PyPtr<#cls> {
unsafe {
let ptr = <#cls as _pyo3::python::ToPythonPointer>::as_ptr(self);
_pyo3::PyPtr::from_borrowed_ptr(ptr)
}
}
}
}

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

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 proto = syn::Ident::from(m.proto);
let fn_spec = FnSpec::parse(
&iimpl.ident, sig, &mut iimpl.attrs);
let fn_spec = FnSpec::parse(&iimpl.ident, sig, &mut iimpl.attrs);
let meth = py_method::impl_proto_wrap(ty, &iimpl.ident, &fn_spec);
py_methods.push(

View file

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

View file

@ -24,13 +24,13 @@ pub trait PyAsyncProtocol<'p>: PyTypeInfo + Sized + 'static {
fn __aiter__(&'p self, py: Python<'p>)
-> Self::Result where Self: PyAsyncAiterProtocol<'p> { unimplemented!() }
fn __anext__(&'p self, py: Python<'p>)
fn __anext__(&'p mut self, py: Python<'p>)
-> Self::Result where Self: PyAsyncAnextProtocol<'p> { unimplemented!() }
fn __aenter__(&'p self, py: Python<'p>)
fn __aenter__(&'p mut self, py: Python<'p>)
-> Self::Result where Self: PyAsyncAenterProtocol<'p> { unimplemented!() }
fn __aexit__(&'p self, py: Python<'p>,
fn __aexit__(&'p mut self, py: Python<'p>,
exc_type: Option<Self::ExcType>,
exc_value: Option<Self::ExcValue>,
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)
-> Self::Result where Self: PyObjectGetAttrProtocol<'p> {unimplemented!()}
fn __setattr__(&'p self, py: Python<'p>, name: Self::Name, value: Self::Value)
fn __setattr__(&'p mut self, py: Python<'p>, name: Self::Name, value: Self::Value)
-> Self::Result where Self: PyObjectSetAttrProtocol<'p> {unimplemented!()}
fn __delattr__(&'p self, py: Python<'p>, name: Self::Name)
fn __delattr__(&'p mut self, py: Python<'p>, name: Self::Name)
-> Self::Result where Self: PyObjectDelAttrProtocol<'p> {unimplemented!()}
fn __str__(&'p self, py: Python<'p>)

View file

@ -16,10 +16,10 @@ use callback::PyObjectCallbackConverter;
/// Iterator protocol
#[allow(unused_variables)]
pub trait PyIterProtocol<'p> : PyTypeInfo {
fn __iter__(&'p self, py: Python<'p>)
fn __iter__(&'p mut self, py: Python<'p>)
-> Self::Result where Self: PyIterIterProtocol<'p> { unimplemented!() }
fn __next__(&'p self, py: Python<'p>)
fn __next__(&'p mut self, py: Python<'p>)
-> Self::Result where Self: PyIterNextProtocol<'p> { unimplemented!() }
}

View file

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

View file

@ -23,10 +23,10 @@ pub trait PyMappingProtocol<'p>: PyTypeInfo + Sized + 'static {
fn __getitem__(&'p self, py: Python<'p>, key: Self::Key)
-> Self::Result where Self: PyMappingGetItemProtocol<'p> {unimplemented!()}
fn __setitem__(&'p self, py: Python<'p>, key: Self::Key, value: Self::Value)
fn __setitem__(&'p mut self, py: Python<'p>, key: Self::Key, value: Self::Value)
-> Self::Result where Self: PyMappingSetItemProtocol<'p> {unimplemented!()}
fn __delitem__(&'p self, py: Python<'p>, key: Self::Key)
fn __delitem__(&'p mut self, py: Python<'p>, key: Self::Key)
-> Self::Result where Self: PyMappingDelItemProtocol<'p> {unimplemented!()}
fn __iter__(&'p self, py: Python<'p>)

View file

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

View file

@ -23,10 +23,10 @@ pub trait PySequenceProtocol<'p>: PyTypeInfo + Sized + 'static {
fn __getitem__(&'p self, py: Python<'p>, key: isize) -> Self::Result
where Self: PySequenceGetItemProtocol<'p> { unimplemented!() }
fn __setitem__(&'p self, py: Python<'p>, key: isize, value: Self::Value) -> Self::Result
fn __setitem__(&'p mut self, py: Python<'p>, key: isize, value: Self::Value) -> Self::Result
where Self: PySequenceSetItemProtocol<'p> { unimplemented!() }
fn __delitem__(&'p self, py: Python<'p>, key: isize) -> Self::Result
fn __delitem__(&'p mut self, py: Python<'p>, key: isize) -> Self::Result
where Self: PySequenceDelItemProtocol<'p> { unimplemented!() }
fn __contains__(&'p self, py: Python<'p>, item: Self::Item) -> Self::Result
@ -38,10 +38,10 @@ pub trait PySequenceProtocol<'p>: PyTypeInfo + Sized + 'static {
fn __repeat__(&'p self, py: Python<'p>, count: isize) -> Self::Result
where Self: PySequenceRepeatProtocol<'p> { unimplemented!() }
fn __inplace_concat__(&'p self, py: Python<'p>, other: Self::Other) -> Self::Result
fn __inplace_concat__(&'p mut self, py: Python<'p>, other: Self::Other) -> Self::Result
where Self: PySequenceInplaceConcatProtocol<'p> { unimplemented!() }
fn __inplace_repeat__(&'p self, py: Python<'p>, count: isize) -> Self::Result
fn __inplace_repeat__(&'p mut self, py: Python<'p>, count: isize) -> Self::Result
where Self: PySequenceInplaceRepeatProtocol<'p> { unimplemented!() }
}

View file

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

View file

@ -69,9 +69,9 @@ pub use pyptr::{Py, PyPtr};
pub use err::{PyErr, PyResult, PyDowncastError};
pub use objects::*;
pub use python::{AsPy, Python};
pub use python::{AsPy, Python, PythonToken};
pub use pythonrun::{GILGuard, GILProtected, prepare_freethreaded_python};
pub use conversion::{FromPyObject, /*RefFromPyObject,*/ ToPyObject, IntoPyObject, ToPyTuple};
pub use conversion::{FromPyObject, RefFromPyObject, ToPyObject, IntoPyObject, ToPyTuple};
pub use class::{CompareOp};
pub mod class;
pub use class::*;

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

View file

@ -22,22 +22,22 @@ macro_rules! pyobject_newtype(
impl<'p> $crate::python::AsPy<'p> for &'p $name {
#[inline]
fn py<'a>(&'a self) -> Python<'p> {
fn py<'a>(&'a self) -> $crate::Python<'p> {
unsafe { $crate::python::Python::assume_gil_acquired() }
}
}
impl $crate::python::ToPythonPointer for $name {
#[inline]
fn as_ptr(&self) -> *mut ffi::PyObject {
self as *const _ as *mut ffi::PyObject
fn as_ptr(&self) -> *mut $crate::ffi::PyObject {
self as *const _ as *mut $crate::ffi::PyObject
}
}
impl<'a> $crate::python::ToPythonPointer for &'a $name {
#[inline]
fn as_ptr(&self) -> *mut ffi::PyObject {
self as *const _ as *mut ffi::PyObject
fn as_ptr(&self) -> *mut $crate::ffi::PyObject {
self as *const _ as *mut $crate::ffi::PyObject
}
}
@ -63,6 +63,32 @@ macro_rules! pyobject_newtype(
unsafe { &mut $crate::ffi::$typeobject }
}
}
impl $crate::std::fmt::Debug for $name {
default fn fmt(&self, f: &mut $crate::std::fmt::Formatter)
-> Result<(), $crate::std::fmt::Error>
{
let py = unsafe { $crate::python::Python::assume_gil_acquired() };
let s = unsafe { $crate::Py::<$crate::PyString>::cast_from_owned_nullptr(
py, $crate::ffi::PyObject_Repr(
$crate::python::ToPythonPointer::as_ptr(self))) };
let repr_obj = try!(s.map_err(|_| $crate::std::fmt::Error));
f.write_str(&repr_obj.to_string_lossy())
}
}
impl $crate::std::fmt::Display for $name {
fn fmt(&self, f: &mut $crate::std::fmt::Formatter)
-> Result<(), $crate::std::fmt::Error>
{
let py = unsafe { $crate::python::Python::assume_gil_acquired() };
let s = unsafe { $crate::Py::<$crate::PyString>::cast_from_owned_nullptr(
py, $crate::ffi::PyObject_Str(
$crate::python::ToPythonPointer::as_ptr(self))) };
let str_obj = try!(s.map_err(|_| $crate::std::fmt::Error));
f.write_str(&str_obj.to_string_lossy())
}
}
);
);

View file

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

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

View file

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

View file

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