Merge pull request #42 from PyO3/py-ptr

Use reference for native objects
This commit is contained in:
Nikolay Kim 2017-06-23 10:48:26 -07:00 committed by GitHub
commit 736ad15aee
58 changed files with 2351 additions and 2352 deletions

View File

@ -62,7 +62,6 @@ pub fn impl_method_proto(cls: &Box<syn::Ty>,
-> <#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! {
@ -80,13 +79,13 @@ 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() <= 1 {
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 arg_ty = get_arg_ty(sig, 1);
let (ty, succ) = get_res_success(ty);
let tmp = extract_decl(syn::parse_item(
@ -99,9 +98,8 @@ pub fn impl_method_proto(cls: &Box<syn::Ty>,
&self,
arg: Option<<#cls as #p<'p>>::#arg_name>)
-> <#cls as #p<'p>>::Result {}}.as_str()).unwrap());
modify_arg_ty(sig, 2, &tmp, &tmp2);
modify_arg_ty(sig, 1, &tmp, &tmp2);
modify_self_ty(sig);
modify_py_ty(sig);
if pyres {
quote! {
@ -121,15 +119,15 @@ 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() <= 2 {
print_err(format!("Not enough arguments {}", n), quote!(sig));
return Tokens::new();
}
let p = syn::Ident::from(proto);
let arg1_name = syn::Ident::from(arg1);
let arg1_ty = get_arg_ty(sig, 2);
let arg1_ty = get_arg_ty(sig, 1);
let arg2_name = syn::Ident::from(arg2);
let arg2_ty = get_arg_ty(sig, 3);
let arg2_ty = get_arg_ty(sig, 2);
let (ty, succ) = get_res_success(ty);
// rewrite ty
@ -145,10 +143,9 @@ pub fn impl_method_proto(cls: &Box<syn::Ty>,
arg1: Option<<#cls as #p<'p>>::#arg1_name>,
arg2: Option<<#cls as #p<'p>>::#arg2_name>)
-> <#cls as #p<'p>>::Result {}}.as_str()).unwrap());
modify_arg_ty(sig, 1, &tmp, &tmp2);
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! {
@ -170,17 +167,17 @@ 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() <= 3 {
print_err(format!("Not enough arguments {}", n), quote!(sig));
return Tokens::new();
}
let p = syn::Ident::from(proto);
let arg1_name = syn::Ident::from(arg1);
let arg1_ty = get_arg_ty(sig, 2);
let arg1_ty = get_arg_ty(sig, 1);
let arg2_name = syn::Ident::from(arg2);
let arg2_ty = get_arg_ty(sig, 3);
let arg2_ty = get_arg_ty(sig, 2);
let arg3_name = syn::Ident::from(arg3);
let arg3_ty = get_arg_ty(sig, 4);
let arg3_ty = get_arg_ty(sig, 3);
let (ty, succ) = get_res_success(ty);
// rewrite ty
@ -198,11 +195,10 @@ pub fn impl_method_proto(cls: &Box<syn::Ty>,
arg2: Option<<#cls as #p<'p>>::#arg2_name>,
arg3: Option<<#cls as #p<'p>>::#arg3_name>)
-> <#cls as #p<'p>>::Result {}}.as_str()).unwrap());
modify_arg_ty(sig, 1, &tmp, &tmp2);
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 {
@ -338,13 +334,13 @@ fn modify_arg_ty(sig: &mut syn::MethodSig, idx: usize,
&syn::Ty::Path(_, ref path) => {
let seg = path.segments.last().unwrap().clone();
if seg.ident.as_ref() == "Option" {
sig.decl.inputs[idx] = fix_name(pat, &decl2.inputs[idx-1]);
sig.decl.inputs[idx] = fix_name(pat, &decl2.inputs[idx]);
} else {
sig.decl.inputs[idx] = fix_name(pat, &decl1.inputs[idx-1]);
sig.decl.inputs[idx] = fix_name(pat, &decl1.inputs[idx]);
}
},
_ => {
sig.decl.inputs[idx] = fix_name(pat, &decl1.inputs[idx-1]);
sig.decl.inputs[idx] = fix_name(pat, &decl1.inputs[idx]);
}
}
},
@ -364,41 +360,6 @@ fn modify_self_ty(sig: &mut syn::MethodSig)
}
}
// modify Python signature
fn modify_py_ty(sig: &mut syn::MethodSig)
{
if sig.decl.inputs.len() <= 1 {
return
}
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

@ -13,6 +13,7 @@ pub struct FnArg<'a> {
pub mode: &'a syn::BindingMode,
pub ty: &'a syn::Ty,
pub optional: Option<&'a syn::Ty>,
pub py: bool,
}
#[derive(Clone, PartialEq, Debug)]
@ -42,7 +43,6 @@ impl<'a> FnSpec<'a> {
let (fn_type, fn_attrs) = parse_attributes(meth_attrs);
let mut has_self = false;
let mut py = false;
let mut arguments = Vec::new();
for input in sig.decl.inputs.iter() {
@ -67,21 +67,26 @@ impl<'a> FnSpec<'a> {
panic!("unsupported argument: {:?}", pat),
};
if !py {
match ty {
&syn::Ty::Path(_, ref path) =>
if let Some(segment) = path.segments.last() {
if segment.ident.as_ref() == "Python" {
py = true;
continue;
}
},
_ => (),
}
}
let py = match ty {
&syn::Ty::Path(_, ref path) =>
if let Some(segment) = path.segments.last() {
segment.ident.as_ref() == "Python"
} else {
false
},
_ => false
};
let opt = check_arg_ty_and_optional(name, ty);
arguments.push(FnArg{name: ident, mode: mode, ty: ty, optional: opt});
arguments.push(
FnArg {
name: ident,
mode: mode,
ty: ty,
optional: opt,
py: py,
}
);
}
&syn::FnArg::Ignored(_) =>
panic!("ignored argument: {:?}", name),

View File

@ -45,42 +45,37 @@ pub fn py3_init(fnname: &syn::Ident, name: &String, doc: syn::Lit) -> Tokens {
pub unsafe extern "C" fn #cb_name() -> *mut ::pyo3::ffi::PyObject {
use std;
extern crate pyo3 as _pyo3;
use pyo3::IntoPyPointer;
use pyo3::{IntoPyPointer, ObjectProtocol};
static mut MODULE_DEF: _pyo3::ffi::PyModuleDef = _pyo3::ffi::PyModuleDef_INIT;
// We can't convert &'static str to *const c_char within a static initializer,
// so we'll do it here in the module initialization:
MODULE_DEF.m_name = concat!(stringify!(#cb_name), "\0").as_ptr() as *const _;
let guard = _pyo3::callback::AbortOnDrop("py_module_init");
let py = _pyo3::Python::assume_gil_acquired();
_pyo3::ffi::PyEval_InitThreads();
let module = _pyo3::ffi::PyModule_Create(&mut MODULE_DEF);
if module.is_null() {
std::mem::forget(guard);
return module;
}
_pyo3::callback::cb_meth("py_module_init", |py| {
_pyo3::ffi::PyEval_InitThreads();
let module = match _pyo3::PyObject::from_owned_ptr(
py, module).cast_into::<PyModule>(py)
{
Ok(m) => m,
Err(e) => {
_pyo3::PyErr::from(e).restore(py);
std::mem::forget(guard);
return std::ptr::null_mut();
let module = _pyo3::ffi::PyModule_Create(&mut MODULE_DEF);
if module.is_null() {
return module;
}
};
module.add(py, "__doc__", #doc).expect("Failed to add doc for module");
let ret = match #fnname(py, &module) {
Ok(_) => module.into_ptr(),
Err(e) => {
e.restore(py);
std::ptr::null_mut()
let module = match py.cast_from_ptr_or_err::<_pyo3::PyModule>(module) {
Ok(m) => m,
Err(e) => {
_pyo3::PyErr::from(e).restore(py);
return std::ptr::null_mut();
}
};
module.add("__doc__", #doc).expect("Failed to add doc for module");
match #fnname(py, module) {
Ok(_) => module.into_ptr(),
Err(e) => {
e.restore(py);
std::ptr::null_mut()
}
}
};
std::mem::forget(guard);
ret
})
}
}
}
@ -133,9 +128,7 @@ pub fn py2_init(fnname: &syn::Ident, name: &String, doc: syn::Lit) -> Tokens {
return
}
let module = match pyo3::PyObject::from_borrowed_ptr(
py, module).cast_into::<pyo3::PyModule>(py)
{
let module = match py.cast_from_ptr_or_err::<_pyo3::PyModule>(module) {
Ok(m) => m,
Err(e) => {
_pyo3::PyErr::from(e).restore(py);
@ -143,8 +136,8 @@ pub fn py2_init(fnname: &syn::Ident, name: &String, doc: syn::Lit) -> Tokens {
return
}
};
module.add(py, "__doc__", #doc).expect("Failed to add doc for module");
let ret = match #fnname(py, &module) {
module.add("__doc__", #doc).expect("Failed to add doc for module");
let ret = match #fnname(py, module) {
Ok(()) => (),
Err(e) => e.restore(py)
};
@ -207,7 +200,6 @@ fn wrap_fn(item: &mut syn::Item) -> Option<Box<syn::Block>> {
match item.node {
syn::ItemKind::Fn(ref decl, _, _, _, _, _) => {
let mut py = false;
let mut arguments = Vec::new();
for input in decl.inputs.iter() {
@ -221,24 +213,22 @@ fn wrap_fn(item: &mut syn::Item) -> Option<Box<syn::Block>> {
panic!("unsupported argument: {:?}", pat),
};
if !py {
match ty {
&syn::Ty::Path(_, ref path) =>
if let Some(segment) = path.segments.last() {
if segment.ident.as_ref() == "Python" {
py = true;
continue;
}
},
_ => (),
}
}
let py = match ty {
&syn::Ty::Path(_, ref path) =>
if let Some(segment) = path.segments.last() {
segment.ident.as_ref() == "Python"
} else {
false
},
_ => false
};
let opt = method::check_arg_ty_and_optional(&name, ty);
arguments.push(method::FnArg {name: ident,
mode: mode,
ty: ty,
optional: opt});
optional: opt,
py: py});
}
&syn::FnArg::Ignored(_) =>
panic!("ignored argument: {:?}", name),
@ -286,7 +276,7 @@ fn wrap_fn(item: &mut syn::Item) -> Option<Box<syn::Block>> {
Box::into_raw(Box::new(def.as_method_def())),
std::ptr::null_mut()));
#m.add(py, stringify!(#fnname), func)?
#m.add(stringify!(#fnname), func)?
}
}
}
@ -309,16 +299,17 @@ fn wrap_fn(item: &mut syn::Item) -> Option<Box<syn::Block>> {
/// Generate static method wrapper (PyCFunction, PyCFunctionWithKeywords)
pub fn impl_wrap(name: &syn::Ident, spec: &method::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| if item.py {syn::Ident::from("py")} else {item.name.clone()}).collect();
let cb = quote! {{
#name(py, #(#names),*)
#name(#(#names),*)
}};
let body = py_method::impl_arg_params(spec, cb);
let output = &spec.output;
quote! {
#[allow(unused_mut)]
#[allow(unused_variables)]
unsafe extern "C" fn wrap(_slf: *mut _pyo3::ffi::PyObject,
args: *mut _pyo3::ffi::PyObject,
kwargs: *mut _pyo3::ffi::PyObject) -> *mut _pyo3::ffi::PyObject
@ -326,14 +317,12 @@ pub fn impl_wrap(name: &syn::Ident, spec: &method::FnSpec) -> Tokens {
const LOCATION: &'static str = concat!(stringify!(#name), "()");
_pyo3::callback::cb_meth(LOCATION, |py| {
let args = _pyo3::PyTuple::from_borrowed_ptr(py, args);
let args = py.cast_from_borrowed_ptr::<_pyo3::PyTuple>(args);
let kwargs = _pyo3::argparse::get_kwargs(py, kwargs);
let result: #output = {
#body
};
py.release(kwargs);
py.release(args);
_pyo3::callback::cb_convert(
_pyo3::callback::PyObjectCallbackConverter, py, result)
})

View File

@ -13,7 +13,7 @@ pub fn build_py_class(ast: &mut syn::DeriveInput, attr: String) -> Tokens {
let params = parse_attribute(attr);
let doc = utils::get_doc(&ast.attrs, true);
let base = syn::Ident::from("_pyo3::PyObject");
let base = syn::Ident::from("_pyo3::PyInstance");
let mut token: Option<syn::Ident> = None;
match ast.body {
@ -55,16 +55,16 @@ fn impl_class(cls: &syn::Ident, base: &syn::Ident,
let extra = if let Some(token) = token {
Some(quote! {
impl _pyo3::PyObjectWithToken for #cls {
#[inline]
fn token<'p>(&'p self) -> _pyo3::Python<'p> {
self.#token.token()
self.#token.py()
}
}
impl _pyo3::ToPyObject for #cls
{
#[inline]
fn to_object<'p>(&self, py: _pyo3::Python<'p>) -> _pyo3::PyObject {
_pyo3::PyObject::from_borrowed_ptr(py, self.as_ptr())
unsafe { _pyo3::PyObject::from_borrowed_ptr(py, self.as_ptr()) }
}
#[inline]
@ -78,11 +78,11 @@ fn impl_class(cls: &syn::Ident, base: &syn::Ident,
{
#[inline]
fn into_object<'p>(self, py: _pyo3::Python) -> _pyo3::PyObject {
_pyo3::PyObject::from_borrowed_ptr(py, self.as_ptr())
unsafe { _pyo3::PyObject::from_borrowed_ptr(py, self.as_ptr()) }
}
}
impl std::convert::AsRef<PyObject> for #cls {
fn as_ref(&self) -> &_pyo3::PyObject {
impl std::convert::AsRef<PyInstance> for #cls {
fn as_ref(&self) -> &_pyo3::PyInstance {
unsafe{std::mem::transmute(self.as_ptr())}
}
}
@ -98,29 +98,16 @@ fn impl_class(cls: &syn::Ident, base: &syn::Ident,
impl std::fmt::Debug for #cls {
fn fmt(&self, f : &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
let py = _pyo3::PyObjectWithToken::token(self);
let ptr = <#cls as _pyo3::ToPyPointer>::as_ptr(self);
let repr = unsafe {
_pyo3::PyString::downcast_from_ptr(
py, _pyo3::ffi::PyObject_Repr(ptr)).map_err(|_| std::fmt::Error)?
};
let result = f.write_str(&repr.to_string_lossy(py));
py.release(repr);
result
use pyo3::ObjectProtocol;
let s = try!(self.repr().map_err(|_| std::fmt::Error));
f.write_str(&s.to_string_lossy())
}
}
impl std::fmt::Display for #cls {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
let py = _pyo3::PyObjectWithToken::token(self);
let ptr = <#cls as _pyo3::ToPyPointer>::as_ptr(self);
let str_obj = unsafe {
_pyo3::PyString::downcast_from_ptr(
py, _pyo3::ffi::PyObject_Str(ptr)).map_err(|_| std::fmt::Error)?
};
let result = f.write_str(&str_obj.to_string_lossy(py));
py.release(str_obj);
result
use pyo3::ObjectProtocol;
let s = try!(self.str().map_err(|_| std::fmt::Error));
f.write_str(&s.to_string_lossy())
}
}
})
@ -184,6 +171,12 @@ fn impl_class(cls: &syn::Ident, base: &syn::Ident,
static mut TYPE_OBJECT: _pyo3::ffi::PyTypeObject = _pyo3::ffi::PyTypeObject_INIT;
unsafe { &mut TYPE_OBJECT }
}
#[inline]
fn is_instance(ptr: *mut ffi::PyObject) -> bool {
unsafe {ffi::PyObject_TypeCheck(
ptr, <#cls as _pyo3::typeob::PyTypeInfo>::type_object()) != 0}
}
}
impl _pyo3::typeob::PyTypeObject for #cls {
@ -195,13 +188,12 @@ fn impl_class(cls: &syn::Ident, base: &syn::Ident,
if (ty.tp_flags & _pyo3::ffi::Py_TPFLAGS_READY) == 0 {
// automatically initialize the class on-demand
let to = _pyo3::typeob::initialize_type::<#cls>(
_pyo3::typeob::initialize_type::<#cls>(
py, None, <#cls as _pyo3::typeob::PyTypeInfo>::type_name(),
<#cls as _pyo3::typeob::PyTypeInfo>::type_description(), ty).expect(
format!("An error occurred while initializing class {}",
<#cls as _pyo3::typeob::PyTypeInfo>::type_name())
.as_ref());
py.release(to);
}
});
}
@ -209,8 +201,7 @@ fn impl_class(cls: &syn::Ident, base: &syn::Ident,
impl _pyo3::PyDowncastFrom for #cls
{
fn downcast_from<'a, 'p>(py: Python<'p>, ob: &'a _pyo3::PyObject)
-> Result<&'a #cls, _pyo3::PyDowncastError<'p>>
fn downcast_from(ob: &_pyo3::PyInstance) -> Result<&#cls, _pyo3::PyDowncastError>
{
unsafe {
let checked = ffi::PyObject_TypeCheck(
@ -221,15 +212,28 @@ fn impl_class(cls: &syn::Ident, base: &syn::Ident,
let ptr = (ob.as_ptr() as *mut u8).offset(offset) as *mut #cls;
Ok(ptr.as_ref().unwrap())
} else {
Err(_pyo3::PyDowncastError(py, None))
Err(_pyo3::PyDowncastError(ob.token(), None))
}
}
}
unsafe fn unchecked_downcast_from(ob: &_pyo3::PyInstance) -> &Self
{
let offset = <#cls as _pyo3::typeob::PyTypeInfo>::offset();
let ptr = (ob.as_ptr() as *mut u8).offset(offset) as *mut #cls;
std::mem::transmute(ptr)
}
unsafe fn unchecked_mut_downcast_from(ob: &_pyo3::PyInstance) -> &mut Self
{
let offset = <#cls as _pyo3::typeob::PyTypeInfo>::offset();
let ptr = (ob.as_ptr() as *mut u8).offset(offset) as *mut #cls;
std::mem::transmute(ptr)
}
}
impl _pyo3::PyMutDowncastFrom for #cls
{
fn downcast_mut_from<'a, 'p>(py: Python<'p>, ob: &'a mut _pyo3::PyObject)
-> Result<&'a mut #cls, _pyo3::PyDowncastError<'p>>
fn downcast_mut_from(ob: &mut _pyo3::PyInstance)
-> Result<&mut #cls, _pyo3::PyDowncastError>
{
unsafe {
let checked = ffi::PyObject_TypeCheck(
@ -240,7 +244,7 @@ fn impl_class(cls: &syn::Ident, base: &syn::Ident,
let ptr = (ob.as_ptr() as *mut u8).offset(offset) as *mut #cls;
Ok(ptr.as_mut().unwrap())
} else {
Err(_pyo3::PyDowncastError(py, None))
Err(_pyo3::PyDowncastError(ob.token(), None))
}
}
}

View File

@ -55,7 +55,7 @@ fn impl_methods(ty: &Box<syn::Ty>, impls: &mut Vec<syn::ImplItem>) -> Tokens {
quote! {
#[feature(specialization)]
#[allow(non_upper_case_globals, unused_attributes,
unused_qualifications, unused_variables)]
unused_qualifications, unused_variables, unused_imports)]
const #dummy_const: () = {
extern crate pyo3 as _pyo3;

View File

@ -53,17 +53,13 @@ pub fn impl_wrap(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec, noargs: b
const LOCATION: &'static str = concat!(
stringify!(#cls), ".", stringify!(#name), "()");
_pyo3::callback::cb_meth(LOCATION, |py| {
let slf = _pyo3::Py::<#cls>::from_borrowed_ptr(slf);
let slf = py.mut_cast_from_borrowed_ptr::<#cls>(slf);
let result = {
let result: #output = {
#cb
};
_pyo3::callback::cb_convert(
_pyo3::callback::PyObjectCallbackConverter, py, result)
let result: #output = {
#cb
};
py.release(slf);
result
_pyo3::callback::cb_convert(
_pyo3::callback::PyObjectCallbackConverter, py, result)
})
}
}
@ -79,21 +75,16 @@ pub fn impl_wrap(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec, noargs: b
const LOCATION: &'static str = concat!(
stringify!(#cls), ".", stringify!(#name), "()");
_pyo3::callback::cb_meth(LOCATION, |py| {
let slf = _pyo3::Py::<#cls>::from_borrowed_ptr(slf);
let args = _pyo3::PyTuple::from_borrowed_ptr(py, args);
use pyo3::ToPyPointer;
let slf = py.mut_cast_from_borrowed_ptr::<#cls>(slf);
let args = py.cast_from_borrowed_ptr::<_pyo3::PyTuple>(args);
let kwargs = _pyo3::argparse::get_kwargs(py, kwargs);
let result = {
let result: #output = {
#body
};
_pyo3::callback::cb_convert(
_pyo3::callback::PyObjectCallbackConverter, py, result)
let result: #output = {
#body
};
py.release(kwargs);
py.release(args);
py.release(slf);
result
_pyo3::callback::cb_convert(
_pyo3::callback::PyObjectCallbackConverter, py, result)
})
}
}
@ -113,14 +104,13 @@ pub fn impl_proto_wrap(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec) ->
{
const LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#name),"()");
_pyo3::callback::cb_meth(LOCATION, |py| {
let slf = _pyo3::Py::<#cls>::from_borrowed_ptr(slf);
let args = _pyo3::PyTuple::from_borrowed_ptr(py, args);
let slf = py.mut_cast_from_borrowed_ptr::<#cls>(slf);
let args = py.cast_from_borrowed_ptr::<_pyo3::PyTuple>(args);
let kwargs = _pyo3::argparse::get_kwargs(py, kwargs);
let result = {
#body
};
py.release(slf);
_pyo3::callback::cb_convert(
_pyo3::callback::PyObjectCallbackConverter, py, result)
})
@ -130,9 +120,10 @@ pub fn impl_proto_wrap(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec) ->
/// Generate class method wrapper (PyCFunction, PyCFunctionWithKeywords)
pub fn impl_wrap_type(cls: &Box<syn::Ty>, name: &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| if item.py {syn::Ident::from("py")} else {item.name.clone()}).collect();
let cb = quote! {{
#cls::#name(&cls, py, #(#names),*)
#cls::#name(&cls, #(#names),*)
}};
let body = impl_arg_params(spec, cb);
@ -148,7 +139,7 @@ pub fn impl_wrap_type(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec) -> T
_pyo3::callback::cb_meth(LOCATION, |py| {
let cls = _pyo3::PyType::from_type_ptr(py, cls);
let args = _pyo3::PyTuple::from_borrowed_ptr(py, args);
let args = py.cast_from_borrowed_ptr::<_pyo3::PyTuple>(args);
let kwargs = _pyo3::argparse::get_kwargs(py, kwargs);
let result: #output = {
@ -163,9 +154,10 @@ pub fn impl_wrap_type(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec) -> T
/// Generate class method wrapper (PyCFunction, PyCFunctionWithKeywords)
pub fn impl_wrap_class(cls: &Box<syn::Ty>, name: &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| if item.py {syn::Ident::from("py")} else {item.name.clone()}).collect();
let cb = quote! {{
#cls::#name(&cls, py, #(#names),*)
#cls::#name(&cls, #(#names),*)
}};
let body = impl_arg_params(spec, cb);
let output = &spec.output;
@ -180,7 +172,7 @@ pub fn impl_wrap_class(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec) ->
_pyo3::callback::cb_meth(LOCATION, |py| {
let cls = _pyo3::PyType::from_type_ptr(py, cls as *mut _pyo3::ffi::PyTypeObject);
let args = _pyo3::PyTuple::from_borrowed_ptr(py, args);
let args = py.cast_from_borrowed_ptr::<_pyo3::PyTuple>(args);
let kwargs = _pyo3::argparse::get_kwargs(py, kwargs);
let result: #output = {
@ -195,9 +187,10 @@ pub fn impl_wrap_class(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec) ->
/// Generate static method wrapper (PyCFunction, PyCFunctionWithKeywords)
pub fn impl_wrap_static(cls: &Box<syn::Ty>, name: &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| if item.py {syn::Ident::from("py")} else {item.name.clone()}).collect();
let cb = quote! {{
#cls::#name(py, #(#names),*)
#cls::#name(#(#names),*)
}};
let body = impl_arg_params(spec, cb);
@ -212,7 +205,7 @@ pub fn impl_wrap_static(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec) ->
const LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#name), "()");
_pyo3::callback::cb_meth(LOCATION, |py| {
let args = _pyo3::PyTuple::from_borrowed_ptr(py, args);
let args = py.cast_from_borrowed_ptr::<_pyo3::PyTuple>(args);
let kwargs = _pyo3::argparse::get_kwargs(py, kwargs);
let result: #output = {
@ -236,8 +229,8 @@ fn impl_wrap_getter(cls: &Box<syn::Ty>, name: &syn::Ident, _spec: &FnSpec) -> To
stringify!(#cls), ".getter_", stringify!(#name), "()");
_pyo3::callback::cb_unary::<#cls, _, _, _>(
LOCATION, slf, _pyo3::callback::PyObjectCallbackConverter, |py, slf| {
slf.#name(py)
})
slf.#name()
})
}
}
}
@ -258,14 +251,13 @@ fn impl_wrap_setter(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec) -> Tok
const LOCATION: &'static str = concat!(
stringify!(#cls), ".setter", stringify!(#name), "()");
_pyo3::callback::cb_setter(LOCATION, |py| {
let slf = _pyo3::Py::<#cls>::from_borrowed_ptr(slf);
let value = _pyo3::PyObject::from_borrowed_ptr(py, value);
let slf = py.mut_cast_from_borrowed_ptr::<#cls>(slf);
let value = py.cast_from_borrowed_ptr(value);
let result = match <#val_ty as _pyo3::FromPyObject>::extract(py, &value) {
Ok(val) => slf.as_mut(py).#name(py, val),
let result = match <#val_ty as _pyo3::FromPyObject>::extract(value) {
Ok(val) => slf.#name(val),
Err(e) => Err(e)
};
py.release(slf);
match result {
Ok(_) => 0,
Err(e) => {
@ -280,20 +272,26 @@ 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 {
let names: Vec<&syn::Ident> = spec.args.iter().map(|item| item.name).collect();
let names: Vec<syn::Ident> = spec.args.iter().map(
|item| if item.py {syn::Ident::from("py")} else {item.name.clone()}).collect();
quote! {{
slf.as_mut(py).#fname(py, #(#names),*)
slf.#fname(#(#names),*)
}}
}
pub fn impl_arg_params(spec: &FnSpec, body: Tokens) -> Tokens {
if spec.args.is_empty() {
let args: Vec<FnArg> = spec.args.iter()
.filter(|item| !item.py).map(|item| item.clone()).collect();
if args.is_empty() {
return body
}
let mut params = Vec::new();
for arg in spec.args.iter() {
if arg.py {
continue
}
if ! (spec.is_args(&arg.name) || spec.is_kwargs(&arg.name)) {
let name = arg.name.as_ref();
let kwonly = if spec.is_kw_only(&arg.name) {
@ -341,9 +339,9 @@ pub fn impl_arg_params(spec: &FnSpec, body: Tokens) -> Tokens {
];
let mut output = [#(#placeholders),*];
let result = match _pyo3::argparse::parse_args(
match _pyo3::argparse::parse_args(
py, Some(LOCATION), PARAMS, &args,
kwargs.as_ref(), #accept_args, #accept_kwargs, &mut output)
kwargs, #accept_args, #accept_kwargs, &mut output)
{
Ok(_) => {
let mut _iter = output.iter();
@ -351,18 +349,14 @@ pub fn impl_arg_params(spec: &FnSpec, body: Tokens) -> Tokens {
#body
},
Err(err) => Err(err)
};
for p in output.iter_mut() {
if let Some(ob) = p.take() {
py.release(ob);
}
}
result
}
}
fn impl_arg_param(arg: &FnArg, spec: &FnSpec, body: &Tokens) -> Tokens {
if arg.py {
return body.clone()
}
let ty = arg.ty;
let name = arg.name;
@ -372,7 +366,7 @@ fn impl_arg_param(arg: &FnArg, spec: &FnSpec, body: &Tokens) -> Tokens {
if spec.is_args(&name) {
quote! {
match <#ty as _pyo3::FromPyObject>::extract(py, args.as_ref())
match <#ty as _pyo3::FromPyObject>::extract(args.as_ref())
{
Ok(#name) => {
#body
@ -383,7 +377,7 @@ fn impl_arg_param(arg: &FnArg, spec: &FnSpec, body: &Tokens) -> Tokens {
}
else if spec.is_kwargs(&name) {
quote! {
let #name = kwargs.as_ref();
let #name = kwargs;
#body
}
}
@ -402,10 +396,10 @@ fn impl_arg_param(arg: &FnArg, spec: &FnSpec, body: &Tokens) -> Tokens {
match
match _iter.next().unwrap().as_ref() {
Some(obj) => {
if obj.is_none(py) {
if obj.is_none() {
Ok(#default)
} else {
match obj.extract(py) {
match obj.extract() {
Ok(obj) => Ok(Some(obj)),
Err(e) => Err(e)
}
@ -422,10 +416,10 @@ fn impl_arg_param(arg: &FnArg, spec: &FnSpec, body: &Tokens) -> Tokens {
quote! {
match match _iter.next().unwrap().as_ref() {
Some(obj) => {
if obj.is_none(py) {
if obj.is_none() {
Ok(#default)
} else {
match obj.extract(py) {
match obj.extract() {
Ok(obj) => Ok(obj),
Err(e) => Err(e),
}
@ -440,7 +434,7 @@ fn impl_arg_param(arg: &FnArg, spec: &FnSpec, body: &Tokens) -> Tokens {
}
else {
quote! {
match _iter.next().unwrap().as_ref().unwrap().extract(py)
match _iter.next().unwrap().as_ref().unwrap().extract()
{
Ok(#name) => {
#body

View File

@ -5,8 +5,8 @@
use ffi;
use python::Python;
use objects::{PyObject, PyTuple, PyDict, PyString, exc};
use conversion::RefFromPyObject;
use objects::{PyInstance, PyTuple, PyDict, PyString, exc};
//use conversion::RefFromPyObject;
use err::{self, PyResult};
/// Description of a python parameter; used for `parse_args()`.
@ -16,7 +16,7 @@ pub struct ParamDescription<'a> {
/// Whether the parameter is optional.
pub is_optional: bool,
/// Whether the parameter is optional.
pub kw_only: bool
pub kw_only: bool,
}
/// Parse argument list
@ -31,12 +31,12 @@ pub fn parse_args<'p>(py: Python<'p>,
fname: Option<&str>, params: &[ParamDescription],
args: &'p PyTuple, kwargs: Option<&'p PyDict>,
accept_args: bool, accept_kwargs: bool,
output: &mut[Option<PyObject>]) -> PyResult<()>
output: &mut[Option<&'p PyInstance>]) -> PyResult<()>
{
assert!(params.len() == output.len());
let nargs = args.len(py);
let nkeywords = kwargs.map_or(0, |d| d.len(py));
let nargs = args.len();
let nkeywords = kwargs.map_or(0, |d| d.len());
if !accept_args && (nargs + nkeywords > params.len()) {
return Err(err::PyErr::new::<exc::TypeError, _>(
py,
@ -51,7 +51,7 @@ pub fn parse_args<'p>(py: Python<'p>,
let mut used_keywords = 0;
// Iterate through the parameters and assign values to output:
for (i, (p, out)) in params.iter().zip(output).enumerate() {
match kwargs.and_then(|d| d.get_item(py, p.name)) {
match kwargs.and_then(|d| d.get_item(p.name)) {
Some(kwarg) => {
*out = Some(kwarg);
used_keywords += 1;
@ -66,7 +66,7 @@ pub fn parse_args<'p>(py: Python<'p>,
*out = None;
}
else if i < nargs {
*out = Some(args.get_item(py, i));
*out = Some(args.get_item(i));
} else {
*out = None;
if !p.is_optional {
@ -81,8 +81,8 @@ pub fn parse_args<'p>(py: Python<'p>,
}
if !accept_kwargs && used_keywords != nkeywords {
// check for extraneous keyword arguments
for (key, _value) in kwargs.unwrap().items(py) {
let key = try!(try!(key.cast_as::<PyString>(py)).to_string(py));
for (key, _value) in kwargs.unwrap().items() {
let key = try!(try!(key.cast_as::<PyString>(py)).to_string());
if !params.iter().any(|p| p.name == key) {
return Err(err::PyErr::new::<exc::TypeError, _>(
py,
@ -96,25 +96,25 @@ pub fn parse_args<'p>(py: Python<'p>,
#[inline]
#[doc(hidden)]
pub unsafe fn get_kwargs(py: Python, ptr: *mut ffi::PyObject) -> Option<PyDict> {
pub unsafe fn get_kwargs<'p>(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<&PyDict> {
if ptr.is_null() {
None
} else {
Some(PyDict::from_borrowed_ptr(py, ptr))
Some(py.cast_from_ptr::<PyDict>(ptr))
}
}
#[doc(hidden)] // used in py_argparse_extract!() macro
pub fn with_extracted_or_default<'p, P: ?Sized, R, F>(
py: Python, obj: Option<&'p PyObject>, f: F, default: &'static P) -> PyResult<R>
/*#[doc(hidden)] // used in py_argparse_extract!() macro
pub fn with_extracted_or_default<P: ?Sized, R, F>(
py: Python, obj: Option<&PyInstance>, f: F, default: &'static P) -> PyResult<R>
where F: FnOnce(&P) -> PyResult<R>,
P: RefFromPyObject<'p>
P: RefFromPyObject
{
match obj {
Some(obj) => match P::with_extracted(py, obj, f) {
Some(obj) => match P::with_extracted(obj, f) {
Ok(result) => result,
Err(e) => Err(e)
},
None => f(default)
}
}
}*/

View File

@ -25,7 +25,7 @@ use ffi;
use exc;
use err::{self, PyResult};
use python::{Python, ToPyPointer};
use objects::PyObject;
use objects::PyInstance;
/// Allows access to the underlying buffer used by a python object such as `bytes`, `bytearray` or `array.array`.
pub struct PyBuffer(Box<ffi::Py_buffer>); // use Box<> because Python expects that the Py_buffer struct has a stable memory address
@ -138,7 +138,7 @@ fn validate(b: &ffi::Py_buffer) {
impl PyBuffer {
/// Get the underlying buffer from the specified python object.
pub fn get(py: Python, obj: &PyObject) -> PyResult<PyBuffer> {
pub fn get(py: Python, obj: &PyInstance) -> PyResult<PyBuffer> {
unsafe {
let mut buf = Box::new(mem::zeroed::<ffi::Py_buffer>());
err::error_on_minusone(
@ -621,8 +621,8 @@ mod test {
let gil = Python::acquire_gil();
let py = gil.python();
let array = py.import("array").unwrap().call_method(
py, "array", ("f", (1.0, 1.5, 2.0, 2.5)), None).unwrap();
let buffer = PyBuffer::get(py, &array).unwrap();
"array", ("f", (1.0, 1.5, 2.0, 2.5)), None).unwrap();
let buffer = PyBuffer::get(py, array.into()).unwrap();
assert_eq!(buffer.dimensions(), 1);
assert_eq!(buffer.item_count(), 4);
assert_eq!(buffer.format().to_str().unwrap(), "f");

View File

@ -4,12 +4,13 @@ use std::os::raw::c_int;
use std::{any, mem, ptr, isize, io, panic};
use libc;
use pythonrun;
use python::{Python, IntoPyPointer};
use objects::exc;
use conversion::IntoPyObject;
use ffi::{self, Py_hash_t};
use err::{PyErr, PyResult};
use token::{Py, AsPyRef};
use instance::{Py, AsPyRef};
use typeob::PyTypeInfo;
@ -170,6 +171,7 @@ pub unsafe fn handle<'p, F, T, C>(location: &str, _c: C, f: F) -> C::R
C: CallbackConverter<T>
{
let guard = AbortOnDrop(location);
let pool = pythonrun::Pool::new();
let ret = panic::catch_unwind(|| {
let py = Python::assume_gil_acquired();
match f(py) {
@ -189,6 +191,7 @@ pub unsafe fn handle<'p, F, T, C>(location: &str, _c: C, f: F) -> C::R
C::error_value()
}
};
drop(pool);
mem::forget(guard);
ret
}
@ -202,6 +205,7 @@ pub unsafe fn cb_unary<Slf, F, T, C>(location: &str,
C: CallbackConverter<T>
{
let guard = AbortOnDrop(location);
let pool = pythonrun::Pool::new();
let ret = panic::catch_unwind(|| {
let py = Python::assume_gil_acquired();
let slf = Py::<Slf>::from_borrowed_ptr(slf);
@ -225,6 +229,7 @@ pub unsafe fn cb_unary<Slf, F, T, C>(location: &str,
C::error_value()
}
};
drop(pool);
mem::forget(guard);
ret
}
@ -236,6 +241,7 @@ pub unsafe fn cb_unary_unit<Slf, F>(location: &str, slf: *mut ffi::PyObject, f:
Slf: PyTypeInfo,
{
let guard = AbortOnDrop(location);
let pool = pythonrun::Pool::new();
let ret = panic::catch_unwind(|| {
let py = Python::assume_gil_acquired();
let slf = Py::<Slf>::from_borrowed_ptr(slf);
@ -251,6 +257,7 @@ pub unsafe fn cb_unary_unit<Slf, F>(location: &str, slf: *mut ffi::PyObject, f:
-1
}
};
drop(pool);
mem::forget(guard);
ret
}
@ -260,6 +267,7 @@ pub unsafe fn cb_meth<F>(location: &str, f: F) -> *mut ffi::PyObject
F: panic::UnwindSafe
{
let guard = AbortOnDrop(location);
let pool = pythonrun::Pool::new();
let ret = panic::catch_unwind(|| {
let py = Python::assume_gil_acquired();
f(py)
@ -271,6 +279,7 @@ pub unsafe fn cb_meth<F>(location: &str, f: F) -> *mut ffi::PyObject
ptr::null_mut()
}
};
drop(pool);
mem::forget(guard);
ret
}
@ -281,6 +290,7 @@ pub unsafe fn cb_pyfunc<F, C, T>(location: &str, _c: C, f: F) -> C::R
C: CallbackConverter<T>
{
let guard = AbortOnDrop(location);
let pool = pythonrun::Pool::new();
let ret = panic::catch_unwind(|| {
let py = Python::assume_gil_acquired();
f(py)
@ -292,6 +302,7 @@ pub unsafe fn cb_pyfunc<F, C, T>(location: &str, _c: C, f: F) -> C::R
C::error_value()
}
};
drop(pool);
mem::forget(guard);
ret
}
@ -301,6 +312,7 @@ pub unsafe fn cb_setter<F>(location: &str, f: F) -> c_int
F: panic::UnwindSafe
{
let guard = AbortOnDrop(location);
let pool = pythonrun::Pool::new();
let ret = panic::catch_unwind(|| {
let py = Python::assume_gil_acquired();
f(py)
@ -312,6 +324,7 @@ pub unsafe fn cb_setter<F>(location: &str, f: F) -> c_int
-1
}
};
drop(pool);
mem::forget(guard);
ret
}

View File

@ -10,7 +10,7 @@
use ffi;
use err::PyResult;
use python::Python;
use python::PyDowncastFrom;
use callback::PyObjectCallbackConverter;
use typeob::PyTypeInfo;
use class::methods::PyMethodDef;
@ -20,21 +20,21 @@ use class::methods::PyMethodDef;
///
/// Each method in this trait corresponds to Python async/await implementation.
#[allow(unused_variables)]
pub trait PyAsyncProtocol<'p>: PyTypeInfo + Sized + 'static {
pub trait PyAsyncProtocol<'p>: PyTypeInfo + PyDowncastFrom {
fn __await__(&'p self, py: Python<'p>)
fn __await__(&'p self)
-> Self::Result where Self: PyAsyncAwaitProtocol<'p> { unimplemented!() }
fn __aiter__(&'p self, py: Python<'p>)
fn __aiter__(&'p self)
-> Self::Result where Self: PyAsyncAiterProtocol<'p> { unimplemented!() }
fn __anext__(&'p mut self, py: Python<'p>)
fn __anext__(&'p mut self)
-> Self::Result where Self: PyAsyncAnextProtocol<'p> { unimplemented!() }
fn __aenter__(&'p mut self, py: Python<'p>)
fn __aenter__(&'p mut self)
-> Self::Result where Self: PyAsyncAenterProtocol<'p> { unimplemented!() }
fn __aexit__(&'p mut self, py: Python<'p>,
fn __aexit__(&'p mut self,
exc_type: Option<Self::ExcType>,
exc_value: Option<Self::ExcValue>,
traceback: Option<Self::Traceback>)

View File

@ -11,13 +11,13 @@ use std::os::raw::c_int;
use ::CompareOp;
use ffi;
use callback;
use err::{PyErr, PyResult};
use python::{Python, IntoPyPointer};
use objects::PyObject;
use objects::exc;
use token::{Py, AsPyRef};
use python::{Python, IntoPyPointer, PyDowncastFrom};
use objects::{exc, PyInstance};
use typeob::PyTypeInfo;
use conversion::{FromPyObject, IntoPyObject};
use objectprotocol::ObjectProtocol;
use callback::{PyObjectCallbackConverter, HashConverter, BoolCallbackConverter};
use class::methods::PyMethodDef;
@ -27,40 +27,40 @@ use class::methods::PyMethodDef;
/// Basic python class customization
#[allow(unused_variables)]
pub trait PyObjectProtocol<'p>: PyTypeInfo + Sized + 'static {
pub trait PyObjectProtocol<'p>: PyTypeInfo + PyDowncastFrom + Sized + 'static {
fn __getattr__(&'p self, py: Python<'p>, name: Self::Name)
fn __getattr__(&'p self, name: Self::Name)
-> Self::Result where Self: PyObjectGetAttrProtocol<'p> {unimplemented!()}
fn __setattr__(&'p mut self, py: Python<'p>, name: Self::Name, value: Self::Value)
fn __setattr__(&'p mut self, name: Self::Name, value: Self::Value)
-> Self::Result where Self: PyObjectSetAttrProtocol<'p> {unimplemented!()}
fn __delattr__(&'p mut self, py: Python<'p>, name: Self::Name)
fn __delattr__(&'p mut self, name: Self::Name)
-> Self::Result where Self: PyObjectDelAttrProtocol<'p> {unimplemented!()}
fn __str__(&'p self, py: Python<'p>)
fn __str__(&'p self)
-> Self::Result where Self: PyObjectStrProtocol<'p> {unimplemented!()}
fn __repr__(&'p self, py: Python<'p>)
fn __repr__(&'p self)
-> Self::Result where Self: PyObjectReprProtocol<'p> {unimplemented!()}
fn __format__(&'p self, py: Python<'p>, format_spec: Self::Format)
fn __format__(&'p self, format_spec: Self::Format)
-> Self::Result where Self: PyObjectFormatProtocol<'p> {unimplemented!()}
fn __hash__(&'p self, py: Python<'p>)
fn __hash__(&'p self)
-> Self::Result where Self: PyObjectHashProtocol<'p> {unimplemented!()}
fn __bool__(&'p self, py: Python<'p>)
fn __bool__(&'p self)
-> Self::Result where Self: PyObjectBoolProtocol<'p> {unimplemented!()}
fn __bytes__(&'p self, py: Python<'p>)
fn __bytes__(&'p self)
-> Self::Result where Self: PyObjectBytesProtocol<'p> {unimplemented!()}
/// This method is used by Python2 only.
fn __unicode__(&'p self, py: Python<'p>)
fn __unicode__(&'p self)
-> Self::Result where Self: PyObjectUnicodeProtocol<'p> {unimplemented!()}
fn __richcmp__(&'p self, py: Python<'p>, other: Self::Other, op: CompareOp)
fn __richcmp__(&'p self, other: Self::Other, op: CompareOp)
-> Self::Result where Self: PyObjectRichcmpProtocol<'p> {unimplemented!()}
}
@ -355,59 +355,39 @@ impl<'p, T> PyObjectRichcmpProtocolImpl for T where T: PyObjectProtocol<'p>
}
}
impl<T> PyObjectRichcmpProtocolImpl for T
where T: for<'p> PyObjectRichcmpProtocol<'p>
where T: for<'p> PyObjectRichcmpProtocol<'p> + PyDowncastFrom
{
#[inline]
fn tp_richcompare() -> Option<ffi::richcmpfunc> {
unsafe extern "C" fn wrap<T>(slf: *mut ffi::PyObject,
arg: *mut ffi::PyObject,
op: c_int) -> *mut ffi::PyObject
where T: for<'p> PyObjectRichcmpProtocol<'p>
where T: for<'p> PyObjectRichcmpProtocol<'p> + PyDowncastFrom
{
const LOCATION: &'static str = concat!(stringify!(T), ".__richcmp__()");
let guard = ::callback::AbortOnDrop(LOCATION);
let ret = std::panic::catch_unwind(|| {
let py = Python::assume_gil_acquired();
let slf = Py::<T>::from_borrowed_ptr(slf);
let arg = PyObject::from_borrowed_ptr(py, arg);
callback::cb_meth(LOCATION, |py| {
let slf = py.cast_from_borrowed_ptr::<T>(slf);
let arg = py.cast_from_borrowed_ptr::<PyInstance>(arg);
let result = {
let res = match extract_op(py, op) {
Ok(op) => {
match arg.extract(py) {
Ok(arg) => {
slf.as_ref(py).__richcmp__(py, arg, op).into()
}
Err(e) => Err(e.into()),
}
},
Err(e) => Err(e)
};
match res {
Ok(val) => {
val.into_object(py).into_ptr()
}
Err(e) => {
e.restore(py);
std::ptr::null_mut()
}
}
let res = match extract_op(py, op) {
Ok(op) => match arg.extract() {
Ok(arg) =>
slf.__richcmp__(arg, op).into(),
Err(e) => Err(e.into()),
},
Err(e) => Err(e)
};
py.release(arg);
py.release(slf);
result
});
let ret = match ret {
Ok(r) => r,
Err(ref err) => {
::callback::handle_panic(Python::assume_gil_acquired(), err);
std::ptr::null_mut()
match res {
Ok(val) => {
val.into_object(py).into_ptr()
}
Err(e) => {
e.restore(py);
std::ptr::null_mut()
}
}
};
std::mem::forget(guard);
ret
})
}
Some(wrap::<T>)
}

View File

@ -9,7 +9,6 @@ use std::os::raw::c_int;
use ffi;
use err::PyResult;
use python::Python;
use typeob::PyTypeInfo;
use callback::UnitCallbackConverter;
@ -18,11 +17,11 @@ use callback::UnitCallbackConverter;
#[allow(unused_variables)]
pub trait PyBufferProtocol<'p> : PyTypeInfo + Sized + 'static
{
fn bf_getbuffer(&'p self, py: Python<'p>,
fn bf_getbuffer(&'p self,
view: *mut ffi::Py_buffer, flags: c_int) -> Self::Result
where Self: PyBufferGetBufferProtocol<'p> { unimplemented!() }
fn bf_releasebuffer(&'p self, py: Python<'p>, view: *mut ffi::Py_buffer) -> Self::Result
fn bf_releasebuffer(&'p self, view: *mut ffi::Py_buffer) -> Self::Result
where Self: PyBufferReleaseBufferProtocol<'p> { unimplemented!() }
}
@ -79,8 +78,8 @@ impl<T> PyBufferGetBufferProtocolImpl for T
where T: for<'p> PyBufferGetBufferProtocol<'p>
{
const LOCATION: &'static str = concat!(stringify!(T), ".buffer_get::<PyBufferProtocol>()");
::callback::cb_unary::<T, _, _, _>(LOCATION, slf, UnitCallbackConverter, |py, slf| {
slf.bf_getbuffer(py, arg1, arg2).into()
::callback::cb_unary::<T, _, _, _>(LOCATION, slf, UnitCallbackConverter, |_, slf| {
slf.bf_getbuffer(arg1, arg2).into()
})
}
Some(wrap::<T>)

View File

@ -5,7 +5,6 @@
//!
use err::PyResult;
use python::Python;
use typeob::PyTypeInfo;
use class::methods::PyMethodDef;
@ -14,10 +13,10 @@ use class::methods::PyMethodDef;
#[allow(unused_variables)]
pub trait PyContextProtocol<'p>: PyTypeInfo {
fn __enter__(&'p mut self, py: Python<'p>)
fn __enter__(&'p mut self)
-> Self::Result where Self: PyContextEnterProtocol<'p> {unimplemented!()}
fn __exit__(&'p mut self, py: Python<'p>,
fn __exit__(&'p mut self,
exc_type: Option<Self::ExcType>,
exc_value: Option<Self::ExcValue>,
traceback: Option<Self::Traceback>)

View File

@ -9,8 +9,8 @@ use std::os::raw::c_int;
use ffi;
use err::PyResult;
use python::Python;
use objects::{PyType, PyObject};
use python::PyDowncastFrom;
use objects::{PyType, PyInstance};
use callback::{PyObjectCallbackConverter, UnitCallbackConverter};
use typeob::PyTypeInfo;
use class::methods::PyMethodDef;
@ -19,18 +19,18 @@ use conversion::{IntoPyObject, FromPyObject};
/// Descriptor interface
#[allow(unused_variables)]
pub trait PyDescrProtocol<'p>: PyTypeInfo {
pub trait PyDescrProtocol<'p>: PyTypeInfo + PyDowncastFrom {
fn __get__(&'p self, py: Python<'p>, instance: &'p PyObject, owner: Option<&'p PyType>)
fn __get__(&'p self, instance: &'p PyInstance, owner: Option<&'p PyType>)
-> Self::Result where Self: PyDescrGetProtocol<'p> { unimplemented!() }
fn __set__(&'p self, py: Python<'p>, instance: &'p PyObject, value: &'p PyObject)
fn __set__(&'p self, instance: &'p PyInstance, value: &'p PyInstance)
-> Self::Result where Self: PyDescrSetProtocol<'p> { unimplemented!() }
fn __delete__(&'p self, py: Python<'p>, instance: &'p PyObject)
fn __delete__(&'p self, instance: &'p PyInstance)
-> Self::Result where Self: PyDescrDeleteProtocol<'p> { unimplemented!() }
fn __set_name__(&'p self, py: Python<'p>, instance: &'p PyObject)
fn __set_name__(&'p self, instance: &'p PyInstance)
-> Self::Result where Self: PyDescrSetNameProtocol<'p> { unimplemented!() }
}

View File

@ -3,13 +3,11 @@
//! Python GC support
//!
use std::mem;
use std::os::raw::{c_int, c_void};
use ffi;
use callback;
use python::{Python, ToPyPointer};
use callback::AbortOnDrop;
use token::{Py, AsPyRef};
use typeob::PyTypeInfo;
pub struct PyTraverseError(c_int);
@ -18,10 +16,10 @@ pub struct PyTraverseError(c_int);
#[allow(unused_variables)]
pub trait PyGCProtocol<'p> : PyTypeInfo {
fn __traverse__(&'p self, py: Python<'p>, visit: PyVisit)
fn __traverse__(&'p self, visit: PyVisit)
-> Result<(), PyTraverseError> { unimplemented!() }
fn __clear__(&'p mut self, py: Python<'p>) { unimplemented!() }
fn __clear__(&'p mut self) { unimplemented!() }
}
@ -30,11 +28,10 @@ pub trait PyGCClearProtocol<'p>: PyGCProtocol<'p> {}
impl<'p, T> PyGCProtocol<'p> for T where T: PyTypeInfo {
default fn __traverse__(&'p self, _py: Python<'p>, _: PyVisit)
-> Result<(), PyTraverseError> {
default fn __traverse__(&'p self, _: PyVisit) -> Result<(), PyTraverseError> {
Ok(())
}
default fn __clear__(&'p mut self, _py: Python<'p>) {}
default fn __clear__(&'p mut self) {}
}
#[doc(hidden)]
@ -97,17 +94,13 @@ impl<T> PyGCTraverseProtocolImpl for T where T: for<'p> PyGCTraverseProtocol<'p>
{
const LOCATION: &'static str = concat!(stringify!(T), ".__traverse__()");
let guard = AbortOnDrop(LOCATION);
let py = Python::assume_gil_acquired();
let visit = PyVisit { visit: visit, arg: arg, _py: py };
let slf = Py::<T>::from_borrowed_ptr(slf);
let ret = match slf.as_ref(py).__traverse__(py, visit) {
Ok(()) => 0,
Err(PyTraverseError(code)) => code
};
mem::forget(guard);
ret
callback::cb_unary_unit::<T, _>(LOCATION, slf, |py, slf| {
let visit = PyVisit { visit: visit, arg: arg, _py: py };
match slf.__traverse__(visit) {
Ok(()) => 0,
Err(PyTraverseError(code)) => code
}
})
}
Some(tp_traverse::<T>)
@ -136,12 +129,10 @@ impl<T> PyGCClearProtocolImpl for T where T: for<'p> PyGCClearProtocol<'p>
{
const LOCATION: &'static str = concat!(stringify!(T), ".__clear__()");
let guard = AbortOnDrop(LOCATION);
let py = Python::assume_gil_acquired();
let slf = Py::<T>::from_borrowed_ptr(slf);
T::__clear__(&mut slf.as_mut(py), py);
mem::forget(guard);
0
callback::cb_unary_unit::<T, _>(LOCATION, slf, |_, slf| {
slf.__clear__();
0
})
}
Some(tp_clear::<T>)
}

View File

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

View File

@ -8,19 +8,14 @@ macro_rules! py_unary_func {
};
($trait:ident, $class:ident :: $f:ident, $res_type:ty, $conv:expr, $ret_type:ty) => {{
unsafe extern "C" fn wrap<T>(slf: *mut $crate::ffi::PyObject) -> $ret_type
where T: for<'p> $trait<'p>
where T: for<'p> $trait<'p> + $crate::PyDowncastFrom
{
use token::AsPyRef;
const LOCATION: &'static str = concat!(stringify!($class), ".", stringify!($f), "()");
$crate::callback::cb_pyfunc::<_, _, $res_type>(LOCATION, $conv, |py| {
let slf = $crate::Py::<T>::from_borrowed_ptr(slf);
let result = {
let res = slf.as_mut(py).$f(py).into();
$crate::callback::cb_convert($conv, py, res)
};
py.release(slf);
result
let slf = py.mut_cast_from_borrowed_ptr::<T>(slf);
let res = slf.$f().into();
$crate::callback::cb_convert($conv, py, res)
})
}
Some(wrap::<$class>)
@ -33,19 +28,15 @@ macro_rules! py_unary_func {
($trait:ident, $class:ident :: $f:ident, $res_type:ty, $conv:ty) => {{
unsafe extern "C" fn wrap<T>(slf: *mut $crate::ffi::PyObject)
-> *mut $crate::ffi::PyObject
where T: for<'p> $trait<'p>
where T: for<'p> $trait<'p> + $crate::PyDowncastFrom
{
use token::AsPyRef;
use $crate::ObjectProtocol;
const LOCATION: &'static str = concat!(stringify!($class), ".", stringify!($f), "()");
$crate::callback::cb_pyfunc::<_, _, $res_type>(LOCATION, $conv, |py| {
let slf = $crate::Py::<T>::from_borrowed_ptr(slf);
let result = {
let res = slf.as_mut(py).$f(py).into();
$crate::callback::cb_convert($conv, py, res)
};
py.release(slf);
result
let slf = py.mut_cast_from_borrowed_ptr::<T>(slf);
let res = slf.$f().into();
$crate::callback::cb_convert($conv, py, res)
})
}
Some(wrap::<$class>)
@ -59,11 +50,11 @@ macro_rules! py_len_func {
($trait:ident, $class:ident :: $f:ident, $conv:expr) => {{
unsafe extern "C" fn wrap<T>(slf: *mut $crate::ffi::PyObject)
-> $crate::ffi::Py_ssize_t
where T: for<'p> $trait<'p>
where T: for<'p> $trait<'p> + $crate::PyDowncastFrom
{
const LOCATION: &'static str = concat!(stringify!($class), ".", stringify!($f), "()");
$crate::callback::cb_unary::<T, _, _, _>(LOCATION, slf, $conv, |py, slf| {
slf.$f(py).into()
$crate::callback::cb_unary::<T, _, _, _>(LOCATION, slf, $conv, |_, slf| {
slf.$f().into()
})
}
Some(wrap::<$class>)
@ -80,27 +71,20 @@ macro_rules! py_binary_func{
#[allow(unused_mut)]
unsafe extern "C" fn wrap<T>(slf: *mut ffi::PyObject,
arg: *mut ffi::PyObject) -> $return
where T: for<'p> $trait<'p>
where T: for<'p> $trait<'p> + $crate::PyDowncastFrom
{
use token::AsPyRef;
use $crate::ObjectProtocol;
const LOCATION: &'static str = concat!(stringify!($class), ".", stringify!($f), "()");
$crate::callback::cb_pyfunc::<_, _, $res_type>(LOCATION, $conv, |py| {
let slf = $crate::Py::<T>::from_borrowed_ptr(slf);
let arg = $crate::PyObject::from_borrowed_ptr(py, arg);
let slf = py.mut_cast_from_borrowed_ptr::<T>(slf);
let arg = py.cast_from_borrowed_ptr::<$crate::PyInstance>(arg);
let result = {
let result = match arg.extract(py) {
Ok(arg) => {
slf.as_mut(py).$f(py, arg).into()
}
Err(e) => Err(e.into()),
};
$crate::callback::cb_convert($conv, py, result)
let result = match arg.extract() {
Ok(arg) => slf.$f(arg).into(),
Err(e) => Err(e.into()),
};
py.release(arg);
py.release(slf);
result
$crate::callback::cb_convert($conv, py, result)
})
}
Some(wrap::<$class>)
@ -114,37 +98,29 @@ macro_rules! py_binary_self_func{
#[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>
where T: for<'p> $trait<'p> + $crate::PyDowncastFrom
{
use token::AsPyRef;
use $crate::ObjectProtocol;
const LOCATION: &'static str = concat!(stringify!($class), ".", stringify!($f), "()");
$crate::callback::cb_meth(LOCATION, |py| {
let slf1 = $crate::Py::<T>::from_borrowed_ptr(slf);
let arg = $crate::PyObject::from_borrowed_ptr(py, arg);
let slf1 = py.mut_cast_from_borrowed_ptr::<T>(slf);
let arg = py.cast_from_borrowed_ptr::<$crate::PyInstance>(arg);
let result = {
let result = match arg.extract(py) {
Ok(arg) => {
slf1.as_mut(py).$f(py, arg).into()
}
Err(e) => Err(e.into()),
};
match result {
Ok(_) => {
ffi::Py_INCREF(slf);
slf
}
Err(e) => {
e.restore(py);
$crate::std::ptr::null_mut()
}
}
let result = match arg.extract() {
Ok(arg) => slf1.$f(arg).into(),
Err(e) => Err(e.into()),
};
py.release(arg);
py.release(slf1);
result
match result {
Ok(_) => {
ffi::Py_INCREF(slf);
slf
}
Err(e) => {
e.restore(py);
$crate::std::ptr::null_mut()
}
}
})
}
Some(wrap::<$class>)
@ -159,19 +135,14 @@ macro_rules! py_ssizearg_func {
#[allow(unused_mut)]
unsafe extern "C" fn wrap<T>(slf: *mut ffi::PyObject,
arg: $crate::Py_ssize_t) -> *mut $crate::ffi::PyObject
where T: for<'p> $trait<'p>
where T: for<'p> $trait<'p> + $crate::PyDowncastFrom
{
use token::AsPyRef;
const LOCATION: &'static str = concat!(stringify!($class), ".", stringify!($f), "()");
$crate::callback::cb_meth(LOCATION, |py| {
let slf = $crate::Py::<T>::from_borrowed_ptr(slf);
let result = {
let result = slf.as_mut(py).$f(py, arg as isize).into();
$crate::callback::cb_convert($conv, py, result)
};
py.release(slf);
result
let slf = py.mut_cast_from_borrowed_ptr::<T>(slf);
let result = slf.$f(arg as isize).into();
$crate::callback::cb_convert($conv, py, result)
})
}
Some(wrap::<$class>)
@ -188,30 +159,24 @@ macro_rules! py_ternary_func{
unsafe extern "C" fn wrap<T>(slf: *mut $crate::ffi::PyObject,
arg1: *mut $crate::ffi::PyObject,
arg2: *mut $crate::ffi::PyObject) -> $return_type
where T: for<'p> $trait<'p>
where T: for<'p> $trait<'p> + $crate::PyDowncastFrom
{
use token::AsPyRef;
use $crate::ObjectProtocol;
const LOCATION: &'static str = concat!(stringify!($class), ".", stringify!($f), "()");
$crate::callback::cb_pyfunc::<_, _, $res_type>(LOCATION, $conv, |py| {
let slf = $crate::Py::<T>::from_borrowed_ptr(slf);
let arg1 = $crate::PyObject::from_borrowed_ptr(py, arg1);
let arg2 = $crate::PyObject::from_borrowed_ptr(py, arg2);
let slf = py.mut_cast_from_borrowed_ptr::<T>(slf);
let arg1 = py.cast_from_borrowed_ptr::<$crate::PyInstance>(arg1);
let arg2 = py.cast_from_borrowed_ptr::<$crate::PyInstance>(arg2);
let result = {
let result = match arg1.extract(py) {
Ok(arg1) => match arg2.extract(py) {
Ok(arg2) => slf.as_mut(py).$f(py, arg1, arg2).into(),
Err(e) => Err(e.into())
},
Err(e) => Err(e.into()),
};
$crate::callback::cb_convert($conv, py, result)
let result = match arg1.extract() {
Ok(arg1) => match arg2.extract() {
Ok(arg2) => slf.$f(arg1, arg2).into(),
Err(e) => Err(e.into())
},
Err(e) => Err(e.into()),
};
py.release(arg2);
py.release(arg1);
py.release(slf);
result
$crate::callback::cb_convert($conv, py, result)
})
}
@ -229,35 +194,29 @@ macro_rules! py_ternary_self_func{
-> *mut $crate::ffi::PyObject
where T: for<'p> $trait<'p>
{
use token::AsPyRef;
use $crate::ObjectProtocol;
const LOCATION: &'static str = concat!(stringify!($class), ".", stringify!($f), "()");
$crate::callback::cb_meth(LOCATION, |py| {
let slf1 = $crate::Py::<T>::from_borrowed_ptr(slf);
let arg1 = $crate::PyObject::from_borrowed_ptr(py, arg1);
let arg2 = $crate::PyObject::from_borrowed_ptr(py, arg2);
let slf1 = py.mut_cast_from_borrowed_ptr::<T>(slf);
let arg1 = py.cast_from_borrowed_ptr::<$crate::PyInstance>(arg1);
let arg2 = py.cast_from_borrowed_ptr::<$crate::PyInstance>(arg2);
let result = {
let result = match arg1.extract(py) {
Ok(arg1) => match arg2.extract(py) {
Ok(arg2) => slf1.as_mut(py).$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 result = match arg1.extract() {
Ok(arg1) => match arg2.extract() {
Ok(arg2) => slf1.$f(arg1, arg2).into(),
Err(e) => Err(e.into())
},
Err(e) => Err(e.into()),
};
py.release(arg2);
py.release(arg1);
py.release(slf1);
result
match result {
Ok(_) => slf,
Err(e) => {
e.restore(py);
$crate::std::ptr::null_mut()
}
}
})
}
Some(wrap::<T>)
@ -274,6 +233,7 @@ macro_rules! py_func_set{
value: *mut $crate::ffi::PyObject) -> $crate::c_int
where T: for<'p> $trait<'p>
{
use $crate::ObjectProtocol;
const LOCATION: &'static str = concat!(stringify!($class), ".", stringify!($f), "()");
$crate::callback::cb_unary_unit::<T, _>(LOCATION, slf, |py, slf| {
if value.is_null() {
@ -282,20 +242,16 @@ macro_rules! py_func_set{
e.restore(py);
-1
} else {
let name = $crate::PyObject::from_borrowed_ptr(py, name);
let value = $crate::PyObject::from_borrowed_ptr(py, value);
let result = match name.extract(py) {
Ok(name) => match value.extract(py) {
Ok(value) => {
slf.$f(py, name, value).into()
},
let name = py.mut_cast_from_borrowed_ptr::<$crate::PyInstance>(name);
let value = py.cast_from_borrowed_ptr::<$crate::PyInstance>(value);
let result = match name.extract() {
Ok(name) => match value.extract() {
Ok(value) =>
slf.$f(name, value).into(),
Err(e) => Err(e.into()),
},
Err(e) => Err(e.into()),
};
py.release(value);
py.release(name);
match result {
Ok(_) =>
0,
@ -323,40 +279,33 @@ macro_rules! py_func_del{
value: *mut $crate::ffi::PyObject) -> $crate::c_int
where T: for<'p> $trait<'p>
{
use token::AsPyRef;
use $crate::ObjectProtocol;
const LOCATION: &'static str = concat!(stringify!($class), ".", stringify!($f), "()");
$crate::callback::cb_pyfunc::<_, _, ()>(
LOCATION, $crate::callback::UnitCallbackConverter, |py|
{
if value.is_null() {
let slf = $crate::Py::<T>::from_borrowed_ptr(slf);
let name = PyObject::from_borrowed_ptr(py, name);
let slf = py.mut_cast_from_borrowed_ptr::<T>(slf);
let name = py.cast_from_borrowed_ptr::<$crate::PyInstance>(name);
let result = {
let result = match name.extract(py) {
Ok(name) =>
slf.as_mut(py).$f(py, name).into(),
Err(e) => Err(e.into()),
};
match result {
Ok(_) => 0,
Err(e) => {
e.restore(py);
-1
}
}
let result = match name.extract() {
Ok(name) => slf.$f(name).into(),
Err(e) => Err(e.into()),
};
py.release(name);
py.release(slf);
result
match result {
Ok(_) => 0,
Err(e) => {
e.restore(py);
-1
}
}
} else {
let e = PyErr::new::<exc::NotImplementedError, _>(
py, format!("Subscript assignment not supported by {:?}",
stringify!(T)));
e.restore(py);
-1
}
})
}
@ -373,59 +322,48 @@ macro_rules! py_func_set_del{
unsafe extern "C" fn wrap<T>(slf: *mut $crate::ffi::PyObject,
name: *mut $crate::ffi::PyObject,
value: *mut $crate::ffi::PyObject) -> $crate::c_int
where T: for<'p> $trait<'p> + for<'p> $trait2<'p>
where T: for<'p> $trait<'p> + for<'p> $trait2<'p> + $crate::PyDowncastFrom
{
use token::AsPyRef;
use $crate::ObjectProtocol;
const LOCATION: &'static str = concat!(stringify!($class), ".", stringify!($f), "()");
$crate::callback::cb_pyfunc::<_, _, ()>(
LOCATION, $crate::callback::UnitCallbackConverter, |py|
{
let slf = $crate::Py::<T>::from_borrowed_ptr(slf);
let name = PyObject::from_borrowed_ptr(py, name);
let slf = py.mut_cast_from_borrowed_ptr::<T>(slf);
let name = py.cast_from_borrowed_ptr::<$crate::PyInstance>(name);
let result = {
if value.is_null() {
let result = match name.extract(py) {
Ok(name) =>
slf.as_mut(py).$f2(py, name).into(),
Err(e) => Err(e.into()),
};
match result {
Ok(_) => 0,
Err(e) => {
e.restore(py);
-1
}
if value.is_null() {
let result = match name.extract() {
Ok(name) => slf.$f2(name).into(),
Err(e) => Err(e.into()),
};
match result {
Ok(_) => 0,
Err(e) => {
e.restore(py);
-1
}
} else {
let value = ::PyObject::from_borrowed_ptr(py, value);
let result = {
let result = match name.extract(py) {
Ok(name) => match value.extract(py) {
Ok(value) => {
slf.as_mut(py).$f(py, name, value).into()
},
Err(e) => Err(e.into()),
},
Err(e) => Err(e.into()),
};
match result {
Ok(_) => 0,
Err(e) => {
e.restore(py);
-1
}
}
};
py.release(value);
result
}
};
py.release(name);
py.release(slf);
result
} else {
let value = py.cast_from_borrowed_ptr::<$crate::PyInstance>(value);
let result = match name.extract() {
Ok(name) => match value.extract() {
Ok(value) => {
slf.$f(name, value).into()
},
Err(e) => Err(e.into()),
},
Err(e) => Err(e.into()),
};
match result {
Ok(_) => 0,
Err(e) => {
e.restore(py);
-1
}
}
}
})
}
Some(wrap::<T>)

View File

@ -5,8 +5,8 @@
use ffi;
use err::{PyErr, PyResult};
use python::Python;
use objects::{exc, PyObject};
use python::{Python, PyDowncastFrom};
use objects::exc;
use callback::{PyObjectCallbackConverter, LenResultConverter};
use conversion::{IntoPyObject, FromPyObject};
use typeob::PyTypeInfo;
@ -15,27 +15,27 @@ use class::methods::PyMethodDef;
/// Mapping interface
#[allow(unused_variables)]
pub trait PyMappingProtocol<'p>: PyTypeInfo + Sized + 'static {
pub trait PyMappingProtocol<'p>: PyTypeInfo + PyDowncastFrom + Sized + 'static {
fn __len__(&'p self, py: Python<'p>)
fn __len__(&'p self)
-> Self::Result where Self: PyMappingLenProtocol<'p> {unimplemented!()}
fn __getitem__(&'p self, py: Python<'p>, key: Self::Key)
fn __getitem__(&'p self, key: Self::Key)
-> Self::Result where Self: PyMappingGetItemProtocol<'p> {unimplemented!()}
fn __setitem__(&'p mut self, py: Python<'p>, key: Self::Key, value: Self::Value)
fn __setitem__(&'p mut self, key: Self::Key, value: Self::Value)
-> Self::Result where Self: PyMappingSetItemProtocol<'p> {unimplemented!()}
fn __delitem__(&'p mut self, py: Python<'p>, key: Self::Key)
fn __delitem__(&'p mut self, key: Self::Key)
-> Self::Result where Self: PyMappingDelItemProtocol<'p> {unimplemented!()}
fn __iter__(&'p self, py: Python<'p>)
-> Self::Result where Self: PyMappingIterProtocol<'p> {unimplemented!()}
fn __contains__(&'p self, py: Python<'p>, value: Self::Value)
fn __contains__(&'p self, value: Self::Value)
-> Self::Result where Self: PyMappingContainsProtocol<'p> {unimplemented!()}
fn __reversed__(&'p self, py: Python<'p>)
fn __reversed__(&'p self)
-> Self::Result where Self: PyMappingReversedProtocol<'p> {unimplemented!()}
}

View File

@ -5,120 +5,119 @@
use ffi;
use err::PyResult;
use python::Python;
use callback::PyObjectCallbackConverter;
use typeob::PyTypeInfo;
use class::methods::PyMethodDef;
use class::basic::PyObjectProtocolImpl;
use ::{IntoPyObject, FromPyObject};
use {IntoPyObject, FromPyObject, PyDowncastFrom};
/// Number interface
#[allow(unused_variables)]
pub trait PyNumberProtocol<'p>: PyTypeInfo {
pub trait PyNumberProtocol<'p>: PyTypeInfo + PyDowncastFrom {
fn __add__(&'p self, py: Python<'p>, other: Self::Other)
fn __add__(&'p self, other: Self::Other)
-> Self::Result where Self: PyNumberAddProtocol<'p> { unimplemented!() }
fn __sub__(&'p self, py: Python<'p>, other: Self::Other)
fn __sub__(&'p self, other: Self::Other)
-> Self::Result where Self: PyNumberSubProtocol<'p> { unimplemented!() }
fn __mul__(&'p self, py: Python<'p>, other: Self::Other)
fn __mul__(&'p self, other: Self::Other)
-> Self::Result where Self: PyNumberMulProtocol<'p> { unimplemented!() }
fn __matmul__(&'p self, py: Python<'p>, other: Self::Other)
fn __matmul__(&'p self, other: Self::Other)
-> Self::Result where Self: PyNumberMatmulProtocol<'p> { unimplemented!() }
fn __truediv__(&'p self, py: Python<'p>, other: Self::Other)
fn __truediv__(&'p self, other: Self::Other)
-> Self::Result where Self: PyNumberTruedivProtocol<'p> { unimplemented!() }
fn __floordiv__(&'p self, py: Python<'p>, other: Self::Other)
fn __floordiv__(&'p self, other: Self::Other)
-> Self::Result where Self: PyNumberFloordivProtocol<'p> { unimplemented!() }
fn __mod__(&'p self, py: Python<'p>, other: Self::Other)
fn __mod__(&'p self, other: Self::Other)
-> Self::Result where Self: PyNumberModProtocol<'p> { unimplemented!() }
fn __divmod__(&'p self, py: Python<'p>, other: Self::Other)
fn __divmod__(&'p self, other: Self::Other)
-> Self::Result where Self: PyNumberDivmodProtocol<'p> { unimplemented!() }
fn __pow__(&'p self, py: Python<'p>, other: Self::Other, modulo: Self::Modulo)
fn __pow__(&'p self, other: Self::Other, modulo: Self::Modulo)
-> Self::Result where Self: PyNumberPowProtocol<'p> { unimplemented!() }
fn __lshift__(&'p self, py: Python<'p>, other: Self::Other)
fn __lshift__(&'p self, other: Self::Other)
-> Self::Result where Self: PyNumberLShiftProtocol<'p> { unimplemented!() }
fn __rshift__(&'p self, py: Python<'p>, other: Self::Other)
fn __rshift__(&'p self, other: Self::Other)
-> Self::Result where Self: PyNumberRShiftProtocol<'p> { unimplemented!() }
fn __and__(&'p self, py: Python<'p>, other: Self::Other)
fn __and__(&'p self, other: Self::Other)
-> Self::Result where Self: PyNumberAndProtocol<'p> { unimplemented!() }
fn __xor__(&'p self, py: Python<'p>, other: Self::Other)
fn __xor__(&'p self, other: Self::Other)
-> Self::Result where Self: PyNumberXorProtocol<'p> { unimplemented!() }
fn __or__(&'p self, py: Python<'p>, other: Self::Other)
fn __or__(&'p self, other: Self::Other)
-> Self::Result where Self: PyNumberOrProtocol<'p> { unimplemented!() }
fn __radd__(&'p self, py: Python<'p>, other: Self::Other)
fn __radd__(&'p self, other: Self::Other)
-> Self::Result where Self: PyNumberRAddProtocol<'p> { unimplemented!() }
fn __rsub__(&'p self, py: Python<'p>, other: Self::Other)
fn __rsub__(&'p self, other: Self::Other)
-> Self::Result where Self: PyNumberRSubProtocol<'p> { unimplemented!() }
fn __rmul__(&'p self, py: Python<'p>, other: Self::Other)
fn __rmul__(&'p self, other: Self::Other)
-> Self::Result where Self: PyNumberRMulProtocol<'p> { unimplemented!() }
fn __rmatmul__(&'p self, py: Python<'p>, other: Self::Other)
fn __rmatmul__(&'p self, other: Self::Other)
-> Self::Result where Self: PyNumberRMatmulProtocol<'p> { unimplemented!() }
fn __rtruediv__(&'p self, py: Python<'p>, other: Self::Other)
fn __rtruediv__(&'p self, other: Self::Other)
-> Self::Result where Self: PyNumberRTruedivProtocol<'p> { unimplemented!() }
fn __rfloordiv__(&'p self, py: Python<'p>, other: Self::Other)
fn __rfloordiv__(&'p self, other: Self::Other)
-> Self::Result where Self: PyNumberRFloordivProtocol<'p> { unimplemented!() }
fn __rmod__(&'p self, py: Python<'p>, other: Self::Other)
fn __rmod__(&'p self, other: Self::Other)
-> Self::Result where Self: PyNumberRModProtocol<'p> { unimplemented!() }
fn __rdivmod__(&'p self, py: Python<'p>, other: Self::Other)
fn __rdivmod__(&'p self, other: Self::Other)
-> Self::Result where Self: PyNumberRDivmodProtocol<'p> { unimplemented!() }
fn __rpow__(&'p self, py: Python<'p>, other: Self::Other)
fn __rpow__(&'p self, other: Self::Other)
-> Self::Result where Self: PyNumberRPowProtocol<'p> { unimplemented!() }
fn __rlshift__(&'p self, py: Python<'p>, other: Self::Other)
fn __rlshift__(&'p self, other: Self::Other)
-> Self::Result where Self: PyNumberRLShiftProtocol<'p> { unimplemented!() }
fn __rrshift__(&'p self, py: Python<'p>, other: Self::Other)
fn __rrshift__(&'p self, other: Self::Other)
-> Self::Result where Self: PyNumberRRShiftProtocol<'p> { unimplemented!() }
fn __rand__(&'p self, py: Python<'p>, other: Self::Other)
fn __rand__(&'p self, other: Self::Other)
-> Self::Result where Self: PyNumberRAndProtocol<'p> { unimplemented!() }
fn __rxor__(&'p self, py: Python<'p>, other: Self::Other)
fn __rxor__(&'p self, other: Self::Other)
-> Self::Result where Self: PyNumberRXorProtocol<'p> { unimplemented!() }
fn __ror__(&'p self, py: Python<'p>, other: Self::Other)
fn __ror__(&'p self, other: Self::Other)
-> Self::Result where Self: PyNumberROrProtocol<'p> { unimplemented!() }
fn __iadd__(&'p mut self, py: Python<'p>, other: Self::Other)
fn __iadd__(&'p mut self, other: Self::Other)
-> Self::Result where Self: PyNumberIAddProtocol<'p> { unimplemented!() }
fn __isub__(&'p mut self, py: Python<'p>, other: Self::Other)
fn __isub__(&'p mut self, other: Self::Other)
-> Self::Result where Self: PyNumberISubProtocol<'p> { unimplemented!() }
fn __imul__(&'p mut self, py: Python<'p>, other: Self::Other)
fn __imul__(&'p mut self, other: Self::Other)
-> Self::Result where Self: PyNumberIMulProtocol<'p> { unimplemented!() }
fn __imatmul__(&'p mut self, py: Python<'p>, other: Self::Other)
fn __imatmul__(&'p mut self, other: Self::Other)
-> Self::Result where Self: PyNumberIMatmulProtocol<'p> { unimplemented!() }
fn __itruediv__(&'p mut self, py: Python<'p>, other: Self::Other)
fn __itruediv__(&'p mut self, other: Self::Other)
-> Self::Result where Self: PyNumberITruedivProtocol<'p> {unimplemented!()}
fn __ifloordiv__(&'p mut self, py: Python<'p>, other: Self::Other)
fn __ifloordiv__(&'p mut self, other: Self::Other)
-> Self::Result where Self: PyNumberIFloordivProtocol<'p> {unimplemented!() }
fn __imod__(&'p mut self, py: Python<'p>, other: Self::Other)
fn __imod__(&'p mut self, other: Self::Other)
-> Self::Result where Self: PyNumberIModProtocol<'p> { unimplemented!() }
fn __ipow__(&'p mut self, py: Python<'p>, other: Self::Other, modulo: Self::Modulo)
fn __ipow__(&'p mut self, other: Self::Other, modulo: Self::Modulo)
-> Self::Result where Self: PyNumberIPowProtocol<'p> { unimplemented!() }
fn __ilshift__(&'p mut self, py: Python<'p>, other: Self::Other)
fn __ilshift__(&'p mut self, other: Self::Other)
-> Self::Result where Self: PyNumberILShiftProtocol<'p> { unimplemented!() }
fn __irshift__(&'p mut self, py: Python<'p>, other: Self::Other)
fn __irshift__(&'p mut self, other: Self::Other)
-> Self::Result where Self: PyNumberIRShiftProtocol<'p> { unimplemented!() }
fn __iand__(&'p mut self, py: Python<'p>, other: Self::Other)
fn __iand__(&'p mut self, other: Self::Other)
-> Self::Result where Self: PyNumberIAndProtocol<'p> { unimplemented!() }
fn __ixor__(&'p mut self, py: Python<'p>, other: Self::Other)
fn __ixor__(&'p mut self, other: Self::Other)
-> Self::Result where Self: PyNumberIXorProtocol<'p> { unimplemented!() }
fn __ior__(&'p mut self, py: Python<'p>, other: Self::Other)
fn __ior__(&'p mut self, other: Self::Other)
-> Self::Result where Self: PyNumberIOrProtocol<'p> { unimplemented!() }
// Unary arithmetic
fn __neg__(&'p self, py: Python<'p>)
fn __neg__(&'p self)
-> Self::Result where Self: PyNumberNegProtocol<'p> { unimplemented!() }
fn __pos__(&'p self, py: Python<'p>)
fn __pos__(&'p self)
-> Self::Result where Self: PyNumberPosProtocol<'p> { unimplemented!() }
fn __abs__(&'p self, py: Python<'p>)
fn __abs__(&'p self)
-> Self::Result where Self: PyNumberAbsProtocol<'p> { unimplemented!() }
fn __invert__(&'p self, py: Python<'p>)
fn __invert__(&'p self)
-> Self::Result where Self: PyNumberInvertProtocol<'p> { unimplemented!() }
fn __complex__(&'p self, py: Python<'p>)
fn __complex__(&'p self)
-> Self::Result where Self: PyNumberComplexProtocol<'p> { unimplemented!() }
fn __int__(&'p self, py: Python<'p>)
fn __int__(&'p self)
-> Self::Result where Self: PyNumberIntProtocol<'p> { unimplemented!() }
fn __float__(&'p self, py: Python<'p>)
fn __float__(&'p self)
-> Self::Result where Self: PyNumberFloatProtocol<'p> { unimplemented!() }
fn __round__(&'p self, py: Python<'p>)
fn __round__(&'p self)
-> Self::Result where Self: PyNumberRoundProtocol<'p> { unimplemented!() }
fn __index__(&'p self, py: Python<'p>)
fn __index__(&'p self)
-> Self::Result where Self: PyNumberIndexProtocol<'p> { unimplemented!() }
}

View File

@ -6,10 +6,10 @@
use std::os::raw::c_int;
use ffi;
use python::Python;
use python::PyDowncastFrom;
use err::{PyErr, PyResult};
use objects::exc;
use objects::PyObject;
use objects::{exc, PyInstance};
use objectprotocol::ObjectProtocol;
use callback::{PyObjectCallbackConverter, LenResultConverter, BoolCallbackConverter};
use typeob::PyTypeInfo;
use conversion::{IntoPyObject, FromPyObject};
@ -17,32 +17,33 @@ use conversion::{IntoPyObject, FromPyObject};
/// Sequece interface
#[allow(unused_variables)]
pub trait PySequenceProtocol<'p>: PyTypeInfo + Sized + 'static {
fn __len__(&'p self, py: Python<'p>) -> Self::Result
pub trait PySequenceProtocol<'p>: PyTypeInfo + PyDowncastFrom
{
fn __len__(&'p self) -> Self::Result
where Self: PySequenceLenProtocol<'p> { unimplemented!() }
fn __getitem__(&'p self, py: Python<'p>, key: isize) -> Self::Result
fn __getitem__(&'p self, key: isize) -> Self::Result
where Self: PySequenceGetItemProtocol<'p> { unimplemented!() }
fn __setitem__(&'p mut self, py: Python<'p>, key: isize, value: Self::Value) -> Self::Result
fn __setitem__(&'p mut self, key: isize, value: Self::Value) -> Self::Result
where Self: PySequenceSetItemProtocol<'p> { unimplemented!() }
fn __delitem__(&'p mut self, py: Python<'p>, key: isize) -> Self::Result
fn __delitem__(&'p mut self, key: isize) -> Self::Result
where Self: PySequenceDelItemProtocol<'p> { unimplemented!() }
fn __contains__(&'p self, py: Python<'p>, item: Self::Item) -> Self::Result
fn __contains__(&'p self, item: Self::Item) -> Self::Result
where Self: PySequenceContainsProtocol<'p> { unimplemented!() }
fn __concat__(&'p self, py: Python<'p>, other: Self::Other) -> Self::Result
fn __concat__(&'p self, other: Self::Other) -> Self::Result
where Self: PySequenceConcatProtocol<'p> { unimplemented!() }
fn __repeat__(&'p self, py: Python<'p>, count: isize) -> Self::Result
fn __repeat__(&'p self, count: isize) -> Self::Result
where Self: PySequenceRepeatProtocol<'p> { unimplemented!() }
fn __inplace_concat__(&'p mut self, py: Python<'p>, other: Self::Other) -> Self::Result
fn __inplace_concat__(&'p mut self, other: Self::Other) -> Self::Result
where Self: PySequenceInplaceConcatProtocol<'p> { unimplemented!() }
fn __inplace_repeat__(&'p mut self, py: Python<'p>, count: isize) -> Self::Result
fn __inplace_repeat__(&'p mut self, count: isize) -> Self::Result
where Self: PySequenceInplaceRepeatProtocol<'p> { unimplemented!() }
}
@ -224,10 +225,10 @@ impl<T> PySequenceSetItemProtocolImpl for T
e.restore(py);
-1
} else {
let value = PyObject::from_borrowed_ptr(py, value);
let result = match value.extract(py) {
let value = py.cast_from_borrowed_ptr::<PyInstance>(value);
let result = match value.extract() {
Ok(value) => {
slf.__setitem__(py, key as isize, value).into()
slf.__setitem__(key as isize, value).into()
},
Err(e) => Err(e.into()),
};
@ -269,7 +270,7 @@ impl<T> PySequenceDelItemProtocolImpl for T
const LOCATION: &'static str = "T.__detitem__()";
::callback::cb_unary_unit::<T, _>(LOCATION, slf, |py, slf| {
if value.is_null() {
let result = slf.__delitem__(py, key as isize).into();
let result = slf.__delitem__(key as isize).into();
match result {
Ok(_) => 0,
Err(e) => {
@ -304,7 +305,7 @@ impl<T> PySequenceDelItemProtocolImpl for T
const LOCATION: &'static str = "T.__set/del_item__()";
::callback::cb_unary_unit::<T, _>(LOCATION, slf, |py, slf| {
if value.is_null() {
let result = slf.__delitem__(py, key as isize).into();
let result = slf.__delitem__(key as isize).into();
match result {
Ok(_) => 0,
Err(e) => {
@ -313,10 +314,10 @@ impl<T> PySequenceDelItemProtocolImpl for T
}
}
} else {
let value = ::PyObject::from_borrowed_ptr(py, value);
let result = match value.extract(py) {
let value = py.cast_from_borrowed_ptr::<PyInstance>(value);
let result = match value.extract() {
Ok(value) => {
slf.__setitem__(py, key as isize, value).into()
slf.__setitem__(key as isize, value).into()
},
Err(e) => Err(e.into()),
};

View File

@ -1,8 +1,11 @@
use ffi;
use err::PyResult;
use python::{Python, ToPyPointer, PyDowncastFrom};
use objects::{PyObject, PyTuple};
use pointer::PyObject;
use objects::{PyInstance, PyTuple};
use objectprotocol::ObjectProtocol;
use typeob::PyTypeInfo;
use instance::Py;
/// Conversion trait that allows various objects to be converted into `PyObject`
@ -31,7 +34,7 @@ pub trait IntoPyObject {
/// Converts self into a Python object. (Consumes self)
#[inline]
fn into_object(self, py: Python) -> ::objects::PyObject
fn into_object(self, py: Python) -> PyObject
where Self: Sized;
}
@ -40,7 +43,7 @@ pub trait IntoPyObject {
pub trait IntoPyTuple {
/// Converts self into a PyTuple object.
fn into_tuple(self, py: Python) -> PyTuple;
fn into_tuple(self, py: Python) -> Py<PyTuple>;
}
@ -67,41 +70,30 @@ pub trait IntoPyTuple {
/// the inherent method `PyObject::extract()` can be used.
pub trait FromPyObject<'source> : Sized {
/// Extracts `Self` from the source `PyObject`.
fn extract(py: Python, ob: &'source PyObject) -> PyResult<Self>;
fn extract(ob: &'source PyInstance) -> PyResult<Self>;
}
pub trait RefFromPyObject<'p> {
fn with_extracted<F, R>(py: Python, obj: &'p PyObject, f: F) -> PyResult<R>
pub trait RefFromPyObject {
fn with_extracted<F, R>(ob: &PyInstance, f: F) -> PyResult<R>
where F: FnOnce(&Self) -> R;
}
impl <'p, T: ?Sized> RefFromPyObject<'p> for T
where for<'a> &'a T: FromPyObject<'p> + Sized
impl <T: ?Sized> RefFromPyObject for T
where for<'a> &'a T: FromPyObject<'a> + Sized
{
#[inline]
fn with_extracted<F, R>(py: Python, obj: &'p PyObject, f: F) -> PyResult<R>
fn with_extracted<F, R>(obj: &PyInstance, f: F) -> PyResult<R>
where F: FnOnce(&Self) -> R
{
match FromPyObject::extract(py, obj) {
match FromPyObject::extract(obj) {
Ok(val) => Ok(f(val)),
Err(e) => Err(e)
}
}
}
// Default IntoPyObject implementation
/*impl<T> IntoPyObject for T where T: ToPyObject
{
#[inline]
fn into_object(self, py: Python) -> ::PyObject
{
self.to_object(py)
}
}*/
/// Identity conversion: allows using existing `PyObject` instances where
/// `T: ToPyObject` is expected.
// `ToPyObject` for references
impl <'a, T: ?Sized> ToPyObject for &'a T where T: ToPyObject {
#[inline]
@ -130,7 +122,7 @@ impl <T> ToPyObject for Option<T> where T: ToPyObject {
}
impl<T> IntoPyObject for Option<T> where T: IntoPyObject {
fn into_object(self, py: Python) -> ::PyObject {
fn into_object(self, py: Python) -> PyObject {
match self {
Some(val) => val.into_object(py),
None => py.None(),
@ -151,24 +143,24 @@ impl IntoPyObject for () {
}
/// Extract reference to instance from `PyObject`
impl<'source, T> FromPyObject<'source> for &'source T
impl<'a, T> FromPyObject<'a> for &'a T
where T: PyTypeInfo + PyDowncastFrom
{
#[inline]
default fn extract(py: Python, ob: &'source PyObject) -> PyResult<&'source T>
default fn extract(ob: &'a PyInstance) -> PyResult<&'a T>
{
Ok(ob.cast_as(py)?)
Ok(ob.cast_as()?)
}
}
impl <'source, T> FromPyObject<'source> for Option<T> where T: FromPyObject<'source>
impl<'source, T> FromPyObject<'source> for Option<T> where T: FromPyObject<'source>
{
fn extract(py: Python, obj: &'source PyObject) -> PyResult<Self>
fn extract(obj: &'source PyInstance) -> PyResult<Self>
{
if obj.as_ptr() == unsafe { ffi::Py_None() } {
Ok(None)
} else {
match T::extract(py, obj) {
match T::extract(obj) {
Ok(v) => Ok(Some(v)),
Err(e) => Err(e)
}

View File

@ -6,9 +6,11 @@ use std::error::Error;
use libc;
use ffi;
use python::{ToPyPointer, IntoPyPointer, Python, PyDowncastInto, PyClone};
use objects::{PyObject, PyType, exc};
use typeob::{PyTypeObject};
use python::{ToPyPointer, IntoPyPointer, Python, PyClone};
use PyObject;
use objects::{PyInstance, PyType, exc};
use instance::Py;
use typeob::PyTypeObject;
use conversion::{ToPyObject, IntoPyTuple, IntoPyObject};
/**
@ -34,10 +36,10 @@ let gil = Python::acquire_gil();
let py = gil.python();
let ctx = PyDict::new(py);
ctx.set_item(py, "CustomError", py.get_type::<CustomError>()).unwrap();
ctx.set_item("CustomError", py.get_type::<CustomError>()).unwrap();
py.run("assert str(CustomError) == \"<class 'mymodule.CustomError'>\"", None, Some(&ctx)).unwrap();
py.run("assert CustomError('oops').args == ('oops',)", None, Some(&ctx)).unwrap();
py.run("assert CustomError('oops').args == ('oops',)", None, Some(ctx)).unwrap();
}
```
*/
@ -76,7 +78,7 @@ macro_rules! py_exception {
}
#[inline]
fn type_object(py: $crate::Python) -> $crate::PyType {
fn type_object<'p>(py: $crate::Python<'p>) -> &'p $crate::PyType {
unsafe { $crate::PyType::from_type_ptr(py, $name::type_object(py)) }
}
}
@ -90,7 +92,7 @@ macro_rules! py_exception {
#[derive(Debug)]
pub struct PyErr {
/// The type of the exception. This should be either a `PyClass` or a `PyType`.
pub ptype: PyType,
pub ptype: Py<PyType>,
/// The value of the exception.
///
/// This can be either an instance of `ptype`,
@ -140,24 +142,25 @@ impl PyErr {
///
/// `base` can be an existing exception type to subclass, or a tuple of classes
/// `dict` specifies an optional dictionary of class variables and methods
pub fn new_type(py: Python, name: &str, base: Option<PyType>, dict: Option<PyObject>)
-> PyType
pub fn new_type<'p>(py: Python<'p>,
name: &str, base: Option<&PyType>, dict: Option<PyObject>)
-> &'p PyType
{
let base: *mut ffi::PyObject = match base {
None => std::ptr::null_mut(),
Some(obj) => obj.into_ptr()
Some(obj) => obj.as_ptr()
};
let dict: *mut ffi::PyObject = match dict {
None => std::ptr::null_mut(),
Some(obj) => obj.into_ptr(),
Some(obj) => obj.as_ptr(),
};
unsafe {
let null_terminated_name = CString::new(name).expect("Failed to initialize nul terminated exception name");
let ptr = ffi::PyErr_NewException(
null_terminated_name.as_ptr() as *mut c_char,
base, dict) as *mut ffi::PyTypeObject;
null_terminated_name.as_ptr() as *mut c_char, base, dict)
as *mut ffi::PyTypeObject;
PyType::from_type_ptr(py, ptr)
}
}
@ -183,19 +186,19 @@ impl PyErr {
// and because we mustn't panic in normalize().
PyErr {
ptype: if ptype.is_null() {
py.get_type::<exc::SystemError>()
py.get_type::<exc::SystemError>().into()
} else {
PyObject::from_owned_ptr(py, ptype).unchecked_cast_into::<PyType>()
PyType::from_type_ptr(py, ptype as *mut ffi::PyTypeObject).into()
},
pvalue: PyObject::from_owned_ptr_or_opt(py, pvalue),
ptraceback: PyObject::from_owned_ptr_or_opt(py, ptraceback)
}
}
fn new_helper(_py: Python, ty: PyType, value: PyObject) -> PyErr {
fn new_helper(_py: Python, ty: &PyType, value: PyObject) -> PyErr {
assert!(unsafe { ffi::PyExceptionClass_Check(ty.as_ptr()) } != 0);
PyErr {
ptype: ty,
ptype: ty.into(),
pvalue: Some(value),
ptraceback: None
}
@ -211,23 +214,23 @@ impl PyErr {
}
fn from_instance_helper<'p>(py: Python, obj: PyObject) -> PyErr {
if unsafe { ffi::PyExceptionInstance_Check(obj.as_ptr()) } != 0 {
let ptr = obj.as_ptr();
if unsafe { ffi::PyExceptionInstance_Check(ptr) } != 0 {
PyErr {
ptype: unsafe { PyObject::from_borrowed_ptr(
py, ffi::PyExceptionInstance_Class(obj.as_ptr()))
.unchecked_cast_into::<PyType>() },
ptype: unsafe { PyType::from_type_ptr(py, ptr as *mut ffi::PyTypeObject).into() },
pvalue: Some(obj),
ptraceback: None
}
} else if unsafe { ffi::PyExceptionClass_Check(obj.as_ptr()) } != 0 {
PyErr {
ptype: PyType::downcast_into(py, obj).expect("Failed to downcast into PyType"),
ptype: unsafe { Py::from_borrowed_ptr(ptr) },
pvalue: None,
ptraceback: None
}
} else {
PyErr {
ptype: py.get_type::<exc::TypeError>(),
ptype: py.get_type::<exc::TypeError>().into(),
pvalue: Some("exceptions must derive from BaseException".into_object(py)),
ptraceback: None
}
@ -238,9 +241,9 @@ impl PyErr {
/// `exc` is the exception type; usually one of the standard exceptions like `py.get_type::<exc::RuntimeError>()`.
/// `value` is the exception instance, or a tuple of arguments to pass to the exception constructor.
#[inline]
pub fn new_lazy_init(exc: PyType, value: Option<PyObject>) -> PyErr {
pub fn new_lazy_init(exc: &PyType, value: Option<PyObject>) -> PyErr {
PyErr {
ptype: exc,
ptype: exc.into(),
pvalue: value,
ptraceback: None
}
@ -254,7 +257,7 @@ impl PyErr {
where A: IntoPyTuple
{
PyErr {
ptype: exc.clone_ref(py),
ptype: exc.into(),
pvalue: Some(args.into_tuple(py).into()),
ptraceback: None
}
@ -307,7 +310,7 @@ impl PyErr {
}
/// Retrieves the exception type.
pub fn get_type(&self, py: Python) -> PyType {
pub fn get_type(&self, py: Python) -> Py<PyType> {
self.ptype.clone_ref(py)
}
@ -317,7 +320,7 @@ impl PyErr {
pub fn instance(&mut self, py: Python) -> PyObject {
self.normalize(py);
match self.pvalue {
Some(ref instance) => instance.to_object(py),
Some(ref instance) => instance.clone_ref(py),
None => py.None(),
}
}
@ -334,7 +337,7 @@ impl PyErr {
/// Issue a warning message.
/// May return a PyErr if warnings-as-errors is enabled.
pub fn warn(py: Python, category: &PyObject, message: &str, stacklevel: i32) -> PyResult<()> {
pub fn warn(py: Python, category: &PyInstance, message: &str, stacklevel: i32) -> PyResult<()> {
let message = CString::new(message).map_err(|e| e.to_pyerr(py))?;
unsafe {
error_on_minusone(py, ffi::PyErr_WarnEx(

View File

@ -27,6 +27,12 @@ pub unsafe fn PyString_Check(op : *mut PyObject) -> c_int {
PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_STRING_SUBCLASS)
}
#[inline(always)]
pub unsafe fn PyBaseString_Check(op : *mut PyObject) -> c_int {
PyType_FastSubclass(
Py_TYPE(op), Py_TPFLAGS_STRING_SUBCLASS | Py_TPFLAGS_UNICODE_SUBCLASS)
}
#[inline(always)]
pub unsafe fn PyString_CheckExact(op : *mut PyObject) -> c_int {
let u : *mut PyTypeObject = &mut PyString_Type;

View File

@ -3,7 +3,7 @@ use std::os::raw::{c_void, c_int, c_uint, c_ulong, c_char};
use ffi3::pyport::{Py_ssize_t, Py_hash_t};
#[repr(C)]
#[derive(Copy, Clone)]
#[derive(Copy, Clone, Debug)]
pub struct PyObject {
#[cfg(py_sys_config="Py_TRACE_REFS")]
_ob_next: *mut PyObject,
@ -36,6 +36,9 @@ pub struct PyVarObject {
#[inline(always)]
pub unsafe fn Py_REFCNT(ob : *mut PyObject) -> Py_ssize_t {
if ob.is_null() {
panic!();
}
(*ob).ob_refcnt
}

View File

@ -32,7 +32,7 @@ pub enum PyThreadState { }
}
#[repr(C)]
#[derive(Copy, Clone)]
#[derive(Copy, Clone, Debug)]
pub enum PyGILState_STATE {
PyGILState_LOCKED,
PyGILState_UNLOCKED

View File

@ -1,35 +0,0 @@
// Copyright (c) 2017-present PyO3 Project and Contributors
use std::fmt;
use pointers::PyPtr;
use python::Python;
use objectprotocol::ObjectProtocol;
impl fmt::Debug for PyPtr {
fn fmt(&self, f : &mut fmt::Formatter) -> Result<(), fmt::Error> {
let gil = Python::acquire_gil();
let py = gil.python();
// TODO: we shouldn't use fmt::Error when repr() fails
let r = self.as_object(py);
let repr_obj = try!(r.repr(py).map_err(|_| fmt::Error));
let result = f.write_str(&repr_obj.to_string_lossy(py));
py.release(repr_obj);
result
}
}
impl fmt::Display for PyPtr {
default fn fmt(&self, f : &mut fmt::Formatter) -> Result<(), fmt::Error> {
let gil = Python::acquire_gil();
let py = gil.python();
// TODO: we shouldn't use fmt::Error when repr() fails
let r = self.as_object(py);
let str_obj = try!(r.str(py).map_err(|_| fmt::Error));
let result = f.write_str(&str_obj.to_string_lossy(py));
py.release(str_obj);
result
}
}

View File

@ -6,8 +6,10 @@ use std::marker::PhantomData;
use ffi;
use err::{PyResult, PyErr, PyDowncastError};
use objects::PyObject;
use conversion::{ToPyObject, IntoPyObject};
use pointer::PyObject;
use objects::PyInstance;
use objectprotocol::ObjectProtocol;
use conversion::{ToPyObject, IntoPyObject, FromPyObject};
use python::{Python, IntoPyPointer, ToPyPointer, PyDowncastInto};
use typeob::{PyTypeInfo, PyObjectAlloc};
@ -15,16 +17,19 @@ use typeob::{PyTypeInfo, PyObjectAlloc};
pub struct PyToken(PhantomData<Rc<()>>);
impl PyToken {
pub fn token(&self) -> Python {
pub fn py<'p>(&'p self) -> Python<'p> {
unsafe { Python::assume_gil_acquired() }
}
}
pub trait PyObjectWithToken : Sized {
pub trait PyObjectWithToken: Sized {
fn token(&self) -> Python;
}
pub trait AsPyRef<T> : Sized {
pub trait PyNativeType: PyObjectWithToken {}
pub trait AsPyRef<T>: Sized {
fn as_ref(&self, py: Python) -> &T;
@ -70,9 +75,10 @@ pub trait AsPyRef<T> : Sized {
}
/// Wrapper around unsafe `*mut ffi::PyObject` pointer. Decrement ref counter on `Drop`
pub struct Py<T>(*mut ffi::PyObject, std::marker::PhantomData<T>);
#[derive(Debug)]
pub struct Py<T>(pub *mut ffi::PyObject, std::marker::PhantomData<T>);
// `PyPtr` is thread-safe, because any python related operations require a Python<'p> token.
// `Py<T>` is thread-safe, because any python related operations require a Python<'p> token.
unsafe impl<T> Send for Py<T> {}
unsafe impl<T> Sync for Py<T> {}
@ -129,12 +135,6 @@ impl<T> Py<T> {
unsafe { ffi::Py_REFCNT(self.0) }
}
/// Get reference to &PyObject.
#[inline]
pub fn as_object<'p>(&self, _py: Python<'p>) -> &PyObject {
unsafe { std::mem::transmute(self) }
}
/// Clone self, Calls Py_INCREF() on the ptr.
#[inline]
pub fn clone_ref(&self, _py: Python) -> Py<T> {
@ -179,7 +179,7 @@ impl<T> Py<T> where T: PyTypeInfo,
impl<T> AsPyRef<T> for Py<T> where T: PyTypeInfo {
#[inline]
fn as_ref(&self, _py: Python) -> &T {
default fn as_ref(&self, _py: Python) -> &T {
let offset = <T as PyTypeInfo>::offset();
unsafe {
let ptr = (self.as_ptr() as *mut u8).offset(offset) as *mut T;
@ -187,7 +187,7 @@ impl<T> AsPyRef<T> for Py<T> where T: PyTypeInfo {
}
}
#[inline]
fn as_mut(&self, _py: Python) -> &mut T {
default fn as_mut(&self, _py: Python) -> &mut T {
let offset = <T as PyTypeInfo>::offset();
unsafe {
let ptr = (self.as_ptr() as *mut u8).offset(offset) as *mut T;
@ -196,9 +196,23 @@ impl<T> AsPyRef<T> for Py<T> where T: PyTypeInfo {
}
}
impl<T> AsPyRef<T> for Py<T> where T: PyTypeInfo + PyNativeType {
#[inline]
fn as_ref(&self, _py: Python) -> &T {
unsafe {std::mem::transmute(self)}
}
#[inline]
fn as_mut(&self, _py: Python) -> &mut T {
unsafe {std::mem::transmute(self as *const _ as *mut T)}
}
}
impl<T> ToPyObject for Py<T> {
fn to_object(&self, py: Python) -> PyObject {
PyObject::from_borrowed_ptr(py, self.as_ptr())
unsafe {
PyObject::from_borrowed_ptr(py, self.as_ptr())
}
}
}
@ -250,8 +264,9 @@ impl<T> Drop for Py<T> {
impl<T> std::convert::From<Py<T>> for PyObject {
#[inline]
fn from(ob: Py<T>) -> Self {
unsafe{std::mem::transmute(ob)}
unsafe {std::mem::transmute(ob)}
}
}
@ -295,10 +310,7 @@ impl<T> PyDowncastInto for Py<T> where T: PyTypeInfo
{
unsafe{
let ptr = ob.into_ptr();
let checked = ffi::PyObject_TypeCheck(
ptr, <T as PyTypeInfo>::type_object()) != 0;
if checked {
if T::is_instance(ptr) {
Ok(Py::from_owned_ptr(ptr))
} else {
ffi::Py_DECREF(ptr);
@ -307,12 +319,11 @@ impl<T> PyDowncastInto for Py<T> where T: PyTypeInfo
}
}
fn downcast_from_ptr<'p>(py: Python<'p>, ptr: *mut ffi::PyObject)
-> Result<Self, PyDowncastError<'p>>
fn downcast_into_from_ptr<'p>(py: Python<'p>, ptr: *mut ffi::PyObject)
-> Result<Self, PyDowncastError<'p>>
{
unsafe{
let checked = ffi::PyObject_TypeCheck(ptr, <T as PyTypeInfo>::type_object()) != 0;
if checked {
if T::is_instance(ptr) {
Ok(Py::from_owned_ptr(ptr))
} else {
ffi::Py_DECREF(ptr);
@ -331,20 +342,13 @@ impl<T> PyDowncastInto for Py<T> where T: PyTypeInfo
}
impl<'a, T> ::FromPyObject<'a> for Py<T> where T: PyTypeInfo
impl<'a, T> FromPyObject<'a> for Py<T> where T: ToPyPointer + FromPyObject<'a>
{
/// Extracts `Self` from the source `PyObject`.
fn extract(py: Python, ob: &'a PyObject) -> PyResult<Self>
fn extract(ob: &'a PyInstance) -> PyResult<Self>
{
unsafe {
let checked = ffi::PyObject_TypeCheck(
ob.as_ptr(), <T as PyTypeInfo>::type_object()) != 0;
if checked {
Ok( Py::from_borrowed_ptr(ob.as_ptr()) )
} else {
Err(::PyDowncastError(py, None).into())
}
ob.extract::<T>().map(|val| Py::from_borrowed_ptr(val.as_ptr()))
}
}
}

View File

@ -34,7 +34,7 @@
//! ```rust
//! extern crate pyo3;
//!
//! use pyo3::{Python, PyDict, PyResult};
//! use pyo3::{Python, PyDict, PyResult, ObjectProtocol};
//!
//! fn main() {
//! let gil = Python::acquire_gil();
@ -43,11 +43,11 @@
//!
//! fn hello(py: Python) -> PyResult<()> {
//! let sys = py.import("sys")?;
//! let version: String = sys.get(py, "version")?.extract(py)?;
//! let version: String = sys.get("version")?.extract()?;
//!
//! let locals = PyDict::new(py);
//! locals.set_item(py, "os", py.import("os")?)?;
//! let user: String = py.eval("os.getenv('USER') or os.getenv('USERNAME')", None, Some(&locals))?.extract(py)?;
//! locals.set_item("os", py.import("os")?)?;
//! let user: String = py.eval("os.getenv('USER') or os.getenv('USERNAME')", None, Some(locals))?.extract()?;
//!
//! println!("Hello {}, I'm Python {}", user, version);
//! Ok(())
@ -72,7 +72,7 @@
//!
//! 1. `m`: The module name.
//! 2. name of function visible to Python code.
//! 3. arguments description string, i.e. "param1, param2=None, *, param3=55"
//! 3. comma separated arguments, i.e. param="None", "*", param3="55"
//!
//!
//! # Example
@ -81,7 +81,7 @@
//! #![feature(proc_macro, specialization)]
//!
//! extern crate pyo3;
//! use pyo3::{py, Python, PyResult, PyObject, PyModule, PyString};
//! use pyo3::{py, Python, PyResult, PyModule, PyString, ObjectProtocol};
//!
//! // add bindings to the generated python module
//! // N.B: names: "libhello" must be the name of the `.so` or `.pyd` file
@ -95,9 +95,9 @@
//! // Note that the `#[pyfn()]` annotation automatically converts the arguments from
//! // Python objects to Rust values; and the Rust return value back into a Python object.
//! #[pyfn(m, "run_rust_func")]
//! fn run(py: Python, name: PyString) -> PyResult<PyObject> {
//! fn run(py: Python, name: &PyString) -> PyResult<()> {
//! println!("Rust says: Hello {} of Python!", name);
//! Ok(py.None())
//! Ok(())
//! }
//!
//! Ok(())
@ -152,20 +152,15 @@ pub mod ffi {
}
pub use ffi::{Py_ssize_t, Py_hash_t};
mod pointers;
pub use pointers::PyPtr;
pub mod token;
pub use token::{PyToken, PyObjectWithToken, Py, AsPyRef};
pub use err::{PyErr, PyResult, PyDowncastError, ToPyErr};
pub use objects::*;
pub use objectprotocol::ObjectProtocol;
pub use pointer::PyObject;
pub use python::{Python, ToPyPointer, IntoPyPointer, PyClone,
PyMutDowncastFrom, PyDowncastFrom, PyDowncastInto};
pub use pythonrun::{GILGuard, prepare_freethreaded_python};
pub use conversion::{FromPyObject, RefFromPyObject, ToPyObject, IntoPyObject, IntoPyTuple};
pub use instance::{PyToken, PyObjectWithToken, AsPyRef, Py, PyNativeType};
pub use conversion::{FromPyObject, ToPyObject, IntoPyObject, IntoPyTuple};
pub mod class;
pub use class::*;
@ -190,11 +185,12 @@ macro_rules! cstr(
);
mod python;
mod fmt;
mod err;
mod conversion;
mod instance;
mod objects;
mod objectprotocol;
mod pointer;
mod pythonrun;
pub mod callback;
pub mod typeob;

View File

@ -1,35 +1,36 @@
// Copyright (c) 2017-present PyO3 Project and Contributors
//
// based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython
use libc;
use std;
use std::cmp::Ordering;
use std::os::raw::c_int;
use ffi;
use err::{PyErr, PyResult, self};
use python::{Python, PyDowncastInto, ToPyPointer};
use objects::{PyObject, PyDict, PyString, PyIterator, PyType};
use conversion::{ToPyObject, IntoPyTuple};
use err::{PyErr, PyResult, PyDowncastError, self};
use python::{Python, ToPyPointer, PyDowncastFrom, PyClone};
use pointer::PyObject;
use objects::{PyInstance, PyDict, PyString, PyIterator, PyType};
use conversion::{ToPyObject, IntoPyTuple, FromPyObject};
use instance::PyObjectWithToken;
pub trait ObjectProtocol {
/// Determines whether this object has the given attribute.
/// This is equivalent to the Python expression 'hasattr(self, attr_name)'.
fn hasattr<N>(&self, py: Python, attr_name: N) -> PyResult<bool> where N: ToPyObject;
fn hasattr<N>(&self, attr_name: N) -> PyResult<bool> where N: ToPyObject;
/// Retrieves an attribute value.
/// This is equivalent to the Python expression 'self.attr_name'.
fn getattr<N>(&self, py: Python, attr_name: N) -> PyResult<PyObject> where N: ToPyObject;
fn getattr<N>(&self, attr_name: N) -> PyResult<&PyInstance> where N: ToPyObject;
/// Sets an attribute value.
/// This is equivalent to the Python expression 'self.attr_name = value'.
fn setattr<N, V>(&self, py: Python, attr_name: N, value: V) -> PyResult<()>
fn setattr<N, V>(&self, attr_name: N, value: V) -> PyResult<()>
where N: ToPyObject, V: ToPyObject;
/// Deletes an attribute.
/// This is equivalent to the Python expression 'del self.attr_name'.
fn delattr<N>(&self, py: Python, attr_name: N) -> PyResult<()> where N: ToPyObject;
fn delattr<N>(&self, attr_name: N) -> PyResult<()> where N: ToPyObject;
/// Compares two Python objects.
///
@ -46,7 +47,7 @@ pub trait ObjectProtocol {
/// else:
/// raise TypeError("ObjectProtocol::compare(): All comparisons returned false")
/// ```
fn compare<O>(&self, py: Python, other: O) -> PyResult<Ordering> where O: ToPyObject;
fn compare<O>(&self, other: O) -> PyResult<Ordering> where O: ToPyObject;
/// Compares two Python objects.
///
@ -57,136 +58,133 @@ pub trait ObjectProtocol {
/// * CompareOp::Le: `self <= other`
/// * CompareOp::Gt: `self > other`
/// * CompareOp::Ge: `self >= other`
fn rich_compare<O>(&self, py: Python, other: O, compare_op: ::CompareOp)
-> PyResult<PyObject> where O: ToPyObject;
fn rich_compare<O>(&self, other: O, compare_op: ::CompareOp) -> PyResult<PyObject>
where O: ToPyObject;
/// Compute the string representation of self.
/// This is equivalent to the Python expression 'repr(self)'.
fn repr(&self, py: Python) -> PyResult<PyString>;
fn repr(&self) -> PyResult<&PyString>;
/// Compute the string representation of self.
/// This is equivalent to the Python expression 'str(self)'.
fn str(&self, py: Python) -> PyResult<PyString>;
fn str(&self) -> PyResult<&PyString>;
/// Determines whether this object is callable.
fn is_callable(&self, py: Python) -> bool;
fn is_callable(&self) -> bool;
/// Calls the object.
/// This is equivalent to the Python expression: 'self(*args, **kwargs)'
fn call<A>(&self, py: Python, args: A, kwargs: Option<&PyDict>) -> PyResult<PyObject>
fn call<A>(&self, args: A, kwargs: Option<&PyDict>) -> PyResult<&PyInstance>
where A: IntoPyTuple;
/// Calls a method on the object.
/// This is equivalent to the Python expression: 'self.name(*args, **kwargs)'
fn call_method<A>(&self, py: Python,
name: &str, args: A,
kwargs: Option<&PyDict>) -> PyResult<PyObject>
fn call_method<A>(&self, name: &str, args: A, kwargs: Option<&PyDict>)
-> PyResult<&PyInstance>
where A: IntoPyTuple;
/// Retrieves the hash code of the object.
/// This is equivalent to the Python expression: 'hash(self)'
fn hash(&self, py: Python) -> PyResult<::Py_hash_t>;
fn hash(&self) -> PyResult<::Py_hash_t>;
/// Returns whether the object is considered to be true.
/// This is equivalent to the Python expression: 'not not self'
fn is_true(&self, py: Python) -> PyResult<bool>;
fn is_true(&self) -> PyResult<bool>;
/// Returns whether the object is considered to be None.
/// This is equivalent to the Python expression: 'is None'
#[inline]
fn is_none(&self, py: Python) -> bool;
fn is_none(&self) -> bool;
/// Returns the length of the sequence or mapping.
/// This is equivalent to the Python expression: 'len(self)'
fn len(&self, py: Python) -> PyResult<usize>;
fn len(&self) -> PyResult<usize>;
/// This is equivalent to the Python expression: 'self[key]'
fn get_item<K>(&self, py: Python, key: K) -> PyResult<PyObject> where K: ToPyObject;
fn get_item<K>(&self, key: K) -> PyResult<&PyInstance> where K: ToPyObject;
/// Sets an item value.
/// This is equivalent to the Python expression 'self[key] = value'.
fn set_item<K, V>(&self, py: Python, key: K, value: V) -> PyResult<()>
fn set_item<K, V>(&self, key: K, value: V) -> PyResult<()>
where K: ToPyObject, V: ToPyObject;
/// Deletes an item.
/// This is equivalent to the Python expression 'del self[key]'.
fn del_item<K>(&self, py: Python, key: K) -> PyResult<()> where K: ToPyObject;
fn del_item<K>(&self, key: K) -> PyResult<()> where K: ToPyObject;
/// Takes an object and returns an iterator for it.
/// This is typically a new iterator but if the argument
/// is an iterator, this returns itself.
fn iter<'p>(&self, py: Python<'p>) -> PyResult<PyIterator<'p>>;
fn iter<'p>(&'p self) -> PyResult<PyIterator<'p>>;
/// Gets the Python type object for this object's type.
#[inline]
fn get_type(&self, py: Python) -> PyType;
fn get_type(&self) -> &PyType;
/// Casts the PyObject to a concrete Python object type.
/// Fails with `PyDowncastError` if the object is not of the expected type.
fn cast_as<'a, D>(&'a self) -> Result<&'a D, PyDowncastError<'a>>
where D: PyDowncastFrom,
&'a PyInstance: std::convert::From<&'a Self>;
/// Extracts some type from the Python object.
/// This is a wrapper function around `FromPyObject::extract()`.
#[inline]
fn extract<'a, D>(&'a self) -> PyResult<D>
where D: FromPyObject<'a>,
&'a PyInstance: std::convert::From<&'a Self>;
/// Returns reference count for python object.
fn get_refcnt(&self) -> isize;
/// Clones PyObject. (utility function)
fn clone_ref(&self, ptr: &PyObject) -> PyObject;
/// Gets the Python builtin value `None`.
#[allow(non_snake_case)] // the Python keyword starts with uppercase
fn None(&self) -> PyObject;
}
impl<T> ObjectProtocol for T where T: ToPyPointer {
impl<T> ObjectProtocol for T where T: PyObjectWithToken + ToPyPointer {
/// Determines whether this object has the given attribute.
/// This is equivalent to the Python expression 'hasattr(self, attr_name)'.
#[inline]
fn hasattr<N>(&self, py: Python, attr_name: N) -> PyResult<bool> where N: ToPyObject {
attr_name.with_borrowed_ptr(py, |attr_name| unsafe {
fn hasattr<N>(&self, attr_name: N) -> PyResult<bool> where N: ToPyObject {
attr_name.with_borrowed_ptr(self.token(), |attr_name| unsafe {
Ok(ffi::PyObject_HasAttr(self.as_ptr(), attr_name) != 0)
})
}
/// Retrieves an attribute value.
/// This is equivalent to the Python expression 'self.attr_name'.
#[inline]
fn getattr<N>(&self, py: Python, attr_name: N) -> PyResult<PyObject> where N: ToPyObject
fn getattr<N>(&self, attr_name: N) -> PyResult<&PyInstance> where N: ToPyObject
{
attr_name.with_borrowed_ptr(py, |attr_name| unsafe {
PyObject::from_owned_ptr_or_err(
py, ffi::PyObject_GetAttr(self.as_ptr(), attr_name))
attr_name.with_borrowed_ptr(self.token(), |attr_name| unsafe {
self.token().cast_from_ptr_or_err(
ffi::PyObject_GetAttr(self.as_ptr(), attr_name))
})
}
/// Sets an attribute value.
/// This is equivalent to the Python expression 'self.attr_name = value'.
#[inline]
fn setattr<N, V>(&self, py: Python, attr_name: N, value: V) -> PyResult<()>
fn setattr<N, V>(&self, attr_name: N, value: V) -> PyResult<()>
where N: ToPyObject, V: ToPyObject
{
attr_name.with_borrowed_ptr(
py, move |attr_name|
value.with_borrowed_ptr(py, |value| unsafe {
self.token(), move |attr_name|
value.with_borrowed_ptr(self.token(), |value| unsafe {
err::error_on_minusone(
py, ffi::PyObject_SetAttr(self.as_ptr(), attr_name, value))
self.token(), ffi::PyObject_SetAttr(self.as_ptr(), attr_name, value))
}))
}
/// Deletes an attribute.
/// This is equivalent to the Python expression 'del self.attr_name'.
#[inline]
fn delattr<N>(&self, py: Python, attr_name: N) -> PyResult<()> where N: ToPyObject {
attr_name.with_borrowed_ptr(py, |attr_name| unsafe {
err::error_on_minusone(py,
fn delattr<N>(&self, attr_name: N) -> PyResult<()> where N: ToPyObject {
attr_name.with_borrowed_ptr(self.token(), |attr_name| unsafe {
err::error_on_minusone(self.token(),
ffi::PyObject_DelAttr(self.as_ptr(), attr_name))
})
}
/// Compares two Python objects.
///
/// On Python 2, this is equivalent to the Python expression 'cmp(self, other)'.
///
/// On Python 3, this is equivalent to:
/// ```
/// if self == other:
/// return Equal
/// elif a < b:
/// return Less
/// elif a > b:
/// return Greater
/// else:
/// raise TypeError("ObjectProtocol::compare(): All comparisons returned false")
/// ```
fn compare<O>(&self, py: Python, other: O) -> PyResult<Ordering> where O: ToPyObject {
fn compare<O>(&self, other: O) -> PyResult<Ordering> where O: ToPyObject {
unsafe fn do_compare(py: Python,
a: *mut ffi::PyObject,
b: *mut ffi::PyObject) -> PyResult<Ordering> {
@ -211,183 +209,176 @@ impl<T> ObjectProtocol for T where T: ToPyPointer {
Err(PyErr::new::<::exc::TypeError, _>(py, "ObjectProtocol::compare(): All comparisons returned false"))
}
other.with_borrowed_ptr(py, |other| unsafe {
do_compare(py, self.as_ptr(), other)
other.with_borrowed_ptr(self.token(), |other| unsafe {
do_compare(self.token(), self.as_ptr(), other)
})
}
/// Compares two Python objects.
///
/// Depending on the value of `compare_op`, equivalent to one of the following Python expressions:
/// * CompareOp::Eq: `self == other`
/// * CompareOp::Ne: `self != other`
/// * CompareOp::Lt: `self < other`
/// * CompareOp::Le: `self <= other`
/// * CompareOp::Gt: `self > other`
/// * CompareOp::Ge: `self >= other`
fn rich_compare<O>(&self, py: Python, other: O, compare_op: ::CompareOp)
fn rich_compare<O>(&self, other: O, compare_op: ::CompareOp)
-> PyResult<PyObject> where O: ToPyObject {
unsafe {
other.with_borrowed_ptr(py, |other| {
other.with_borrowed_ptr(self.token(), |other| {
PyObject::from_owned_ptr_or_err(
py, ffi::PyObject_RichCompare(
self.as_ptr(), other, compare_op as libc::c_int))
self.token(), ffi::PyObject_RichCompare(
self.as_ptr(), other, compare_op as c_int))
})
}
}
/// Compute the string representation of self.
/// This is equivalent to the Python expression 'repr(self)'.
#[inline]
fn repr(&self, py: Python) -> PyResult<PyString> {
Ok(PyString::downcast_from_ptr(
py, unsafe{ffi::PyObject_Repr(self.as_ptr())})?)
fn repr(&self) -> PyResult<&PyString> {
unsafe {
self.token().cast_from_ptr_or_err(ffi::PyObject_Repr(self.as_ptr()))
}
}
/// Compute the string representation of self.
/// This is equivalent to the Python expression 'str(self)'.
#[inline]
fn str(&self, py: Python) -> PyResult<PyString> {
Ok(PyString::downcast_from_ptr(
py, unsafe{ffi::PyObject_Str(self.as_ptr())})?)
fn str(&self) -> PyResult<&PyString> {
unsafe {
self.token().cast_from_ptr_or_err(ffi::PyObject_Str(self.as_ptr()))
}
}
/// Determines whether this object is callable.
#[inline]
fn is_callable(&self, _py: Python) -> bool {
fn is_callable(&self) -> bool {
unsafe {
ffi::PyCallable_Check(self.as_ptr()) != 0
}
}
/// Calls the object.
/// This is equivalent to the Python expression: 'self(*args, **kwargs)'
#[inline]
fn call<A>(&self, py: Python, args: A, kwargs: Option<&PyDict>) -> PyResult<PyObject>
fn call<A>(&self, args: A, kwargs: Option<&PyDict>) -> PyResult<&PyInstance>
where A: IntoPyTuple
{
let t = args.into_tuple(py);
let t = args.into_tuple(self.token());
let result = unsafe {
PyObject::from_borrowed_ptr_or_err(
py, ffi::PyObject_Call(self.as_ptr(), t.as_ptr(), kwargs.as_ptr()))
self.token().cast_from_borrowed_ptr_or_err(
ffi::PyObject_Call(self.as_ptr(), t.as_ptr(), kwargs.as_ptr()))
};
py.release(t);
self.token().release(t);
result
}
/// Calls a method on the object.
/// This is equivalent to the Python expression: 'self.name(*args, **kwargs)'
#[inline]
fn call_method<A>(&self, py: Python,
name: &str, args: A,
kwargs: Option<&PyDict>) -> PyResult<PyObject>
fn call_method<A>(&self, name: &str, args: A, kwargs: Option<&PyDict>)
-> PyResult<&PyInstance>
where A: IntoPyTuple
{
name.with_borrowed_ptr(py, |name| unsafe {
let t = args.into_tuple(py);
name.with_borrowed_ptr(self.token(), |name| unsafe {
let t = args.into_tuple(self.token());
let ptr = ffi::PyObject_GetAttr(self.as_ptr(), name);
let result = PyObject::from_borrowed_ptr_or_err(
py, ffi::PyObject_Call(ptr, t.as_ptr(), kwargs.as_ptr()));
py.release(t);
let result = self.token().cast_from_borrowed_ptr_or_err(
ffi::PyObject_Call(ptr, t.as_ptr(), kwargs.as_ptr()));
self.token().release(t);
result
})
}
/// Retrieves the hash code of the object.
/// This is equivalent to the Python expression: 'hash(self)'
#[inline]
fn hash(&self, py: Python) -> PyResult<ffi::Py_hash_t> {
fn hash(&self) -> PyResult<ffi::Py_hash_t> {
let v = unsafe { ffi::PyObject_Hash(self.as_ptr()) };
if v == -1 {
Err(PyErr::fetch(py))
Err(PyErr::fetch(self.token()))
} else {
Ok(v)
}
}
/// Returns whether the object is considered to be true.
/// This is equivalent to the Python expression: 'not not self'
#[inline]
fn is_true(&self, py: Python) -> PyResult<bool> {
fn is_true(&self) -> PyResult<bool> {
let v = unsafe { ffi::PyObject_IsTrue(self.as_ptr()) };
if v == -1 {
Err(PyErr::fetch(py))
Err(PyErr::fetch(self.token()))
} else {
Ok(v != 0)
}
}
/// Returns whether the object is considered to be None.
/// This is equivalent to the Python expression: 'is None'
#[inline]
fn is_none(&self, _py: Python) -> bool {
fn is_none(&self) -> bool {
unsafe { ffi::Py_None() == self.as_ptr() }
}
/// Returns the length of the sequence or mapping.
/// This is equivalent to the Python expression: 'len(self)'
#[inline]
fn len(&self, py: Python) -> PyResult<usize> {
fn len(&self) -> PyResult<usize> {
let v = unsafe { ffi::PyObject_Size(self.as_ptr()) };
if v == -1 {
Err(PyErr::fetch(py))
Err(PyErr::fetch(self.token()))
} else {
Ok(v as usize)
}
}
/// This is equivalent to the Python expression: 'self[key]'
#[inline]
fn get_item<K>(&self, py: Python, key: K) -> PyResult<PyObject> where K: ToPyObject {
key.with_borrowed_ptr(py, |key| unsafe {
PyObject::from_owned_ptr_or_err(
py, ffi::PyObject_GetItem(self.as_ptr(), key))
fn get_item<K>(&self, key: K) -> PyResult<&PyInstance> where K: ToPyObject {
key.with_borrowed_ptr(self.token(), |key| unsafe {
self.token().cast_from_ptr_or_err(
ffi::PyObject_GetItem(self.as_ptr(), key))
})
}
/// Sets an item value.
/// This is equivalent to the Python expression 'self[key] = value'.
#[inline]
fn set_item<K, V>(&self, py: Python, key: K, value: V) -> PyResult<()>
fn set_item<K, V>(&self, key: K, value: V) -> PyResult<()>
where K: ToPyObject, V: ToPyObject
{
key.with_borrowed_ptr(py, move |key|
value.with_borrowed_ptr(py, |value| unsafe {
err::error_on_minusone(py,
ffi::PyObject_SetItem(self.as_ptr(), key, value))
key.with_borrowed_ptr(
self.token(), move |key|
value.with_borrowed_ptr(self.token(), |value| unsafe {
err::error_on_minusone(
self.token(), ffi::PyObject_SetItem(self.as_ptr(), key, value))
}))
}
/// Deletes an item.
/// This is equivalent to the Python expression 'del self[key]'.
#[inline]
fn del_item<K>(&self, py: Python, key: K) -> PyResult<()> where K: ToPyObject {
key.with_borrowed_ptr(py, |key| unsafe {
err::error_on_minusone(py,
ffi::PyObject_DelItem(self.as_ptr(), key))
fn del_item<K>(&self, key: K) -> PyResult<()> where K: ToPyObject {
key.with_borrowed_ptr(self.token(), |key| unsafe {
err::error_on_minusone(
self.token(), ffi::PyObject_DelItem(self.as_ptr(), key))
})
}
/// Takes an object and returns an iterator for it.
/// This is typically a new iterator but if the argument
/// is an iterator, this returns itself.
#[inline]
fn iter<'p>(&self, py: Python<'p>) -> PyResult<PyIterator<'p>> {
fn iter<'p>(&'p self) -> PyResult<PyIterator<'p>> {
unsafe {
let ptr = PyObject::from_owned_ptr_or_err(
py, ffi::PyObject_GetIter(self.as_ptr()))?;
PyIterator::from_object(py, ptr).map_err(|e| e.into())
self.token(), ffi::PyObject_GetIter(self.as_ptr()))?;
PyIterator::from_object(self.token(), ptr).map_err(|e| e.into())
}
}
/// Gets the Python type object for this object's type.
#[inline]
fn get_type(&self, py: Python) -> PyType {
fn get_type(&self) -> &PyType {
unsafe {
PyType::from_type_ptr(py, (*self.as_ptr()).ob_type)
PyType::from_type_ptr(self.token(), (*self.as_ptr()).ob_type)
}
}
#[inline]
fn cast_as<'a, D>(&'a self) -> Result<&'a D, PyDowncastError<'a>>
where D: PyDowncastFrom,
&'a PyInstance: std::convert::From<&'a Self>
{
<D as PyDowncastFrom>::downcast_from(self.into())
}
#[inline]
fn extract<'a, D>(&'a self) -> PyResult<D>
where D: FromPyObject<'a>,
&'a PyInstance: std::convert::From<&'a T>
{
FromPyObject::extract(self.into())
}
fn clone_ref(&self, ptr: &PyObject) -> PyObject {
ptr.clone_ref(self.token())
}
#[allow(non_snake_case)] // the Python keyword starts with uppercase
#[inline]
fn None(&self) -> PyObject {
unsafe { PyObject::from_borrowed_ptr(self.token(), ffi::Py_None()) }
}
fn get_refcnt(&self) -> isize {
unsafe { ffi::Py_REFCNT(self.as_ptr()) }
}
@ -395,17 +386,18 @@ impl<T> ObjectProtocol for T where T: ToPyPointer {
#[cfg(test)]
mod test {
use python::{Python};
use instance::AsPyRef;
use python::{Python, PyDowncastFrom};
use conversion::ToPyObject;
//use objects::{PyTuple}; //PyList,
use super::ObjectProtocol;
use objects::PyString;
#[test]
fn test_debug_string() {
let gil = Python::acquire_gil();
let py = gil.python();
let v = "Hello\n".to_object(py);
assert_eq!(format!("{:?}", v), "'Hello\\n'");
let s = PyString::downcast_from(v.as_ref(py)).unwrap();
assert_eq!(format!("{:?}", s), "'Hello\\n'");
}
#[test]
@ -413,17 +405,7 @@ mod test {
let gil = Python::acquire_gil();
let py = gil.python();
let v = "Hello\n".to_object(py);
assert_eq!(format!("{}", v), "Hello\n");
}
#[test]
fn test_compare() {
use std::cmp::Ordering;
let gil = Python::acquire_gil();
let py = gil.python();
let one = 1i32.to_object(py);
assert_eq!(one.compare(py, 1).unwrap(), Ordering::Equal);
assert_eq!(one.compare(py, 2).unwrap(), Ordering::Less);
assert_eq!(one.compare(py, 0).unwrap(), Ordering::Greater);
let s = PyString::downcast_from(v.as_ref(py)).unwrap();
assert_eq!(format!("{}", s), "Hello\n");
}
}

View File

@ -1,11 +1,10 @@
use ffi;
use pointers::PyPtr;
use pointer::PyObject;
use python::{ToPyPointer, Python};
use objects::PyObject;
use conversion::{ToPyObject, IntoPyObject};
/// Represents a Python `bool`.
pub struct PyBool(PyPtr);
pub struct PyBool(PyObject);
pyobject_convert!(PyBool);
pyobject_nativetype!(PyBool, PyBool_Type, PyBool_Check);
@ -14,15 +13,15 @@ pyobject_nativetype!(PyBool, PyBool_Type, PyBool_Check);
impl PyBool {
/// Depending on `val`, returns `py.True()` or `py.False()`.
#[inline]
pub fn new(_py: Python, val: bool) -> PyBool {
unsafe { PyBool(
PyPtr::from_borrowed_ptr(if val { ffi::Py_True() } else { ffi::Py_False() })
)}
pub fn new<'p>(py: Python<'p>, val: bool) -> &'p PyBool {
unsafe {
py.cast_from_ptr(if val { ffi::Py_True() } else { ffi::Py_False() })
}
}
/// Gets whether this boolean is `true`.
#[inline]
pub fn is_true(&self, _py: Python) -> bool {
pub fn is_true(&self) -> bool {
self.as_ptr() == unsafe { ::ffi::Py_True() }
}
}
@ -31,7 +30,11 @@ impl PyBool {
impl ToPyObject for bool {
#[inline]
fn to_object(&self, py: Python) -> PyObject {
PyBool::new(py, *self).into()
unsafe {
PyObject::from_borrowed_ptr(
py,
if *self { ffi::Py_True() } else { ffi::Py_False() })
}
}
#[inline]
@ -54,23 +57,24 @@ impl IntoPyObject for bool {
///
/// Fails with `TypeError` if the input is not a Python `bool`.
pyobject_extract!(py, obj to bool => {
Ok(try!(obj.cast_as::<PyBool>(py)).is_true(py))
Ok(try!(obj.cast_as::<PyBool>()).is_true())
});
#[cfg(test)]
mod test {
use python::{Python};
use objects::PyObject;
use python::Python;
use objects::PyInstance;
use conversion::ToPyObject;
use objectprotocol::ObjectProtocol;
#[test]
fn test_true() {
let gil = Python::acquire_gil();
let py = gil.python();
assert!(py.True().is_true(py));
let t: PyObject = py.True().into();
assert_eq!(true, t.extract(py).unwrap());
assert!(py.True().is_true());
let t: &PyInstance = py.True().into();
assert_eq!(true, t.extract().unwrap());
assert!(true.to_object(py) == py.True().into());
}
@ -78,9 +82,9 @@ mod test {
fn test_false() {
let gil = Python::acquire_gil();
let py = gil.python();
assert!(!py.False().is_true(py));
let t: PyObject = py.False().into();
assert_eq!(false, t.extract(py).unwrap());
assert!(!py.False().is_true());
let t: &PyInstance = py.False().into();
assert_eq!(false, t.extract().unwrap());
assert!(false.to_object(py) == py.False().into());
}
}

View File

@ -1,17 +1,15 @@
// Copyright (c) 2017-present PyO3 Project and Contributors
use std;
use std::ptr;
use std::os::raw::c_char;
use ffi;
use pointer::PyObject;
use instance::PyObjectWithToken;
use python::{Python, ToPyPointer};
use objects::PyObject;
use err::{PyResult, PyErr};
use pointers::PyPtr;
/// Represents a Python bytearray.
pub struct PyByteArray(PyPtr);
pub struct PyByteArray(PyObject);
pyobject_convert!(PyByteArray);
pyobject_nativetype!(PyByteArray, PyByteArray_Type, PyByteArray_Check);
@ -21,29 +19,29 @@ impl PyByteArray {
/// The byte string is initialized by copying the data from the `&[u8]`.
///
/// Panics if out of memory.
pub fn new(_py: Python, src: &[u8]) -> PyByteArray {
pub fn new<'p>(py: Python<'p>, src: &[u8]) -> &'p PyByteArray {
let ptr = src.as_ptr() as *const c_char;
let len = src.len() as ffi::Py_ssize_t;
let ptr = unsafe {ffi::PyByteArray_FromStringAndSize(ptr, len)};
PyByteArray(PyPtr::from_owned_ptr_or_panic(ptr))
unsafe {
py.cast_from_ptr::<PyByteArray>(
ffi::PyByteArray_FromStringAndSize(ptr, len))
}
}
/// Creates a new Python bytearray object
/// from other PyObject, that implements the buffer protocol.
pub fn from<I>(py: Python, src: I) -> PyResult<PyByteArray>
pub fn from<'p, I>(py: Python<'p>, src: I) -> PyResult<&'p PyByteArray>
where I: ToPyPointer
{
let res = unsafe {ffi::PyByteArray_FromObject(src.as_ptr())};
if res != ptr::null_mut() {
Ok(PyByteArray(PyPtr::from_owned_ptr_or_panic(res)))
} else {
Err(PyErr::fetch(py))
unsafe {
py.cast_from_ptr_or_err(
ffi::PyByteArray_FromObject(src.as_ptr()))
}
}
/// Gets the length of the bytearray.
#[inline]
pub fn len(&self, _py: Python) -> usize {
pub fn len(&self) -> usize {
// non-negative Py_ssize_t should always fit into Rust usize
unsafe {
ffi::PyByteArray_Size(self.0.as_ptr()) as usize
@ -51,7 +49,7 @@ impl PyByteArray {
}
/// Gets the Python bytearray data as byte slice.
pub fn data(&self, _py: Python) -> &mut [u8] {
pub fn data(&self) -> &mut [u8] {
unsafe {
let buffer = ffi::PyByteArray_AsString(self.0.as_ptr()) as *mut u8;
let length = ffi::PyByteArray_Size(self.0.as_ptr()) as usize;
@ -60,13 +58,13 @@ impl PyByteArray {
}
/// Resize bytearray object.
pub fn resize(&self, py: Python, len: usize) -> PyResult<()> {
pub fn resize(&self, len: usize) -> PyResult<()> {
unsafe {
let result = ffi::PyByteArray_Resize(self.0.as_ptr(), len as ffi::Py_ssize_t);
if result == 0 {
Ok(())
} else {
Err(PyErr::fetch(py))
Err(PyErr::fetch(self.token()))
}
}
}
@ -77,7 +75,8 @@ impl PyByteArray {
mod test {
use exc;
use python::Python;
use objects::{PyObject, PyByteArray};
use pointer::PyObject;
use objects::PyByteArray;
#[test]
fn test_bytearray() {
@ -86,20 +85,21 @@ mod test {
let src = b"Hello Python";
let bytearray = PyByteArray::new(py, src);
assert_eq!(src.len(), bytearray.len(py));
assert_eq!(src, bytearray.data(py));
assert_eq!(src.len(), bytearray.len());
assert_eq!(src, bytearray.data());
let ba: PyObject = bytearray.into();
let bytearray = PyByteArray::from(py, &ba).unwrap();
assert_eq!(src.len(), bytearray.len(py));
assert_eq!(src, bytearray.data(py));
let bytearray = PyByteArray::from(py, ba).unwrap();
bytearray.resize(py, 20).unwrap();
assert_eq!(20, bytearray.len(py));
assert_eq!(src.len(), bytearray.len());
assert_eq!(src, bytearray.data());
bytearray.resize(20).unwrap();
assert_eq!(20, bytearray.len());
let none = py.None();
if let Err(mut err) = PyByteArray::from(py, &none) {
assert!(py.is_instance::<exc::TypeError>(&err.instance(py)).unwrap())
assert!(py.is_instance::<exc::TypeError, _>(&err.instance(py)).unwrap())
} else {
panic!("error");
}

View File

@ -5,14 +5,15 @@
use std::{mem, collections, hash, cmp};
use ffi;
use pointers::PyPtr;
use pointer::PyObject;
use instance::PyObjectWithToken;
use python::{Python, ToPyPointer};
use conversion::{ToPyObject};
use objects::{PyObject, PyList};
use conversion::ToPyObject;
use objects::{PyInstance, PyList};
use err::{self, PyResult, PyErr};
/// Represents a Python `dict`.
pub struct PyDict(PyPtr);
pub struct PyDict(PyObject);
pyobject_convert!(PyDict);
pyobject_nativetype!(PyDict, PyDict_Type, PyDict_Check);
@ -22,103 +23,99 @@ impl PyDict {
/// Creates a new empty dictionary.
///
/// May panic when running out of memory.
pub fn new(_py: Python) -> PyDict {
unsafe { PyDict(PyPtr::from_owned_ptr_or_panic(ffi::PyDict_New())) }
}
/// Construct a new dict with the given raw pointer
/// Undefined behavior if the pointer is NULL or invalid.
pub unsafe fn from_borrowed_ptr(_py: Python, ptr: *mut ffi::PyObject) -> PyDict {
PyDict(PyPtr::from_borrowed_ptr(ptr))
pub fn new<'p>(py: Python<'p>) -> &'p PyDict {
unsafe {
py.cast_from_ptr::<PyDict>(ffi::PyDict_New())
}
}
/// Return a new dictionary that contains the same key-value pairs as self.
/// Corresponds to `dict(self)` in Python.
pub fn copy(&self, py: Python) -> PyResult<PyDict> {
pub fn copy(&self) -> PyResult<&PyDict> {
unsafe {
Ok(PyDict(
PyPtr::from_owned_ptr_or_err(py, ffi::PyDict_Copy(self.0.as_ptr()))?
))
self.token().cast_from_ptr_or_err::<PyDict>(ffi::PyDict_Copy(self.as_ptr()))
}
}
/// Empty an existing dictionary of all key-value pairs.
#[inline]
pub fn clear(&self, _py: Python) {
pub fn clear(&self) {
unsafe { ffi::PyDict_Clear(self.as_ptr()) }
}
/// Return the number of items in the dictionary.
/// This is equivalent to len(p) on a dictionary.
#[inline]
pub fn len(&self, _py: Python) -> usize {
pub fn len(&self) -> usize {
unsafe { ffi::PyDict_Size(self.as_ptr()) as usize }
}
/// Determine if the dictionary contains the specified key.
/// This is equivalent to the Python expression `key in self`.
pub fn contains<K>(&self, py: Python, key: K) -> PyResult<bool> where K: ToPyObject {
key.with_borrowed_ptr(py, |key| unsafe {
pub fn contains<K>(&self, key: K) -> PyResult<bool> where K: ToPyObject {
key.with_borrowed_ptr(self.token(), |key| unsafe {
match ffi::PyDict_Contains(self.as_ptr(), key) {
1 => Ok(true),
0 => Ok(false),
_ => Err(PyErr::fetch(py))
_ => Err(PyErr::fetch(self.token()))
}
})
}
/// Gets an item from the dictionary.
/// Returns None if the item is not present, or if an error occurs.
pub fn get_item<K>(&self, py: Python, key: K) -> Option<PyObject> where K: ToPyObject {
key.with_borrowed_ptr(py, |key| unsafe {
PyObject::from_borrowed_ptr_or_opt(
py, ffi::PyDict_GetItem(self.as_ptr(), key))
pub fn get_item<K>(&self, key: K) -> Option<&PyInstance> where K: ToPyObject {
key.with_borrowed_ptr(self.token(), |key| unsafe {
self.token().cast_from_borrowed_ptr_or_opt(
ffi::PyDict_GetItem(self.as_ptr(), key))
})
}
/// Sets an item value.
/// This is equivalent to the Python expression `self[key] = value`.
pub fn set_item<K, V>(&self, py: Python, key: K, value: V)
-> PyResult<()> where K: ToPyObject, V: ToPyObject {
pub fn set_item<K, V>(&self, key: K, value: V) -> PyResult<()>
where K: ToPyObject, V: ToPyObject
{
key.with_borrowed_ptr(
py, move |key|
value.with_borrowed_ptr(py, |value| unsafe {
self.token(), move |key|
value.with_borrowed_ptr(self.token(), |value| unsafe {
err::error_on_minusone(
py, ffi::PyDict_SetItem(self.as_ptr(), key, value))
self.token(), ffi::PyDict_SetItem(self.as_ptr(), key, value))
}))
}
/// Deletes an item.
/// This is equivalent to the Python expression `del self[key]`.
pub fn del_item<K>(&self, py: Python, key: K) -> PyResult<()> where K: ToPyObject {
key.with_borrowed_ptr(py, |key| unsafe {
pub fn del_item<K>(&self, key: K) -> PyResult<()> where K: ToPyObject
{
key.with_borrowed_ptr(self.token(), |key| unsafe {
err::error_on_minusone(
py, ffi::PyDict_DelItem(self.as_ptr(), key))
self.token(), ffi::PyDict_DelItem(self.as_ptr(), key))
})
}
/// List of dict items.
/// This is equivalent to the python expression `list(dict.items())`.
pub fn items_list(&self, py: Python) -> PyList {
pub fn items_list(&self) -> &PyList {
unsafe {
PyObject::from_owned_ptr(
py, ffi::PyDict_Items(self.as_ptr())).unchecked_cast_into::<PyList>()
self.token().cast_from_ptr::<PyList>(
ffi::PyDict_Items(self.as_ptr()))
}
}
/// Returns the list of (key, value) pairs in this dictionary.
pub fn items(&self, py: Python) -> Vec<(PyObject, PyObject)> {
pub fn items(&self) -> Vec<(PyObject, PyObject)> {
// Note that we don't provide an iterator because
// PyDict_Next() is unsafe to use when the dictionary might be changed
// by other python code.
let mut vec = Vec::with_capacity(self.len(py));
let mut vec = Vec::with_capacity(self.len());
unsafe {
let mut pos = 0;
let mut key: *mut ffi::PyObject = mem::uninitialized();
let mut value: *mut ffi::PyObject = mem::uninitialized();
while ffi::PyDict_Next(self.as_ptr(), &mut pos, &mut key, &mut value) != 0 {
vec.push((PyObject::from_borrowed_ptr(py, key),
PyObject::from_borrowed_ptr(py, value)));
vec.push((PyObject::from_borrowed_ptr(self.token(), key),
PyObject::from_borrowed_ptr(self.token(), value)));
}
}
vec
@ -132,7 +129,7 @@ impl <K, V> ToPyObject for collections::HashMap<K, V>
fn to_object(&self, py: Python) -> PyObject {
let dict = PyDict::new(py);
for (key, value) in self {
dict.set_item(py, key, value).expect("Failed to set_item on dict");
dict.set_item(key, value).expect("Failed to set_item on dict");
};
dict.into()
}
@ -145,7 +142,7 @@ impl <K, V> ToPyObject for collections::BTreeMap<K, V>
fn to_object(&self, py: Python) -> PyObject {
let dict = PyDict::new(py);
for (key, value) in self {
dict.set_item(py, key, value).expect("Failed to set_item on dict");
dict.set_item(key, value).expect("Failed to set_item on dict");
};
dict.into()
}
@ -155,10 +152,32 @@ impl <K, V> ToPyObject for collections::BTreeMap<K, V>
mod test {
use std::collections::{BTreeMap, HashMap};
use python::Python;
use instance::AsPyRef;
use conversion::ToPyObject;
use objects::{PyDict, PyTuple};
use ::PyDowncastFrom;
use {PyDowncastFrom, ObjectProtocol};
#[test]
fn test_new() {
let gil = Python::acquire_gil();
let py = gil.python();
let dict = PyDict::new(py);
dict.set_item(7, 32).unwrap();
assert_eq!(32, dict.get_item(7i32).unwrap().extract::<i32>().unwrap());
assert_eq!(None, dict.get_item(8i32));
}
#[test]
fn test_copy() {
let gil = Python::acquire_gil();
let py = gil.python();
let dict = PyDict::new(py);
dict.set_item(7, 32).unwrap();
let ndict = dict.copy().unwrap();
assert_eq!(32, ndict.get_item(7i32).unwrap().extract::<i32>().unwrap());
assert_eq!(None, ndict.get_item(8i32));
}
#[test]
fn test_len() {
@ -166,12 +185,12 @@ mod test {
let py = gil.python();
let mut v = HashMap::new();
let ob = v.to_object(py);
let dict = PyDict::downcast_from(py, &ob).unwrap();
assert_eq!(0, dict.len(py));
let dict = PyDict::downcast_from(ob.as_ref(py)).unwrap();
assert_eq!(0, dict.len());
v.insert(7, 32);
let ob = v.to_object(py);
let dict2 = PyDict::downcast_from(py, &ob).unwrap();
assert_eq!(1, dict2.len(py));
let dict2 = PyDict::downcast_from(ob.as_ref(py)).unwrap();
assert_eq!(1, dict2.len());
}
#[test]
@ -181,9 +200,9 @@ mod test {
let mut v = HashMap::new();
v.insert(7, 32);
let ob = v.to_object(py);
let dict = PyDict::downcast_from(py, &ob).unwrap();
assert_eq!(true, dict.contains(py, 7i32).unwrap());
assert_eq!(false, dict.contains(py, 8i32).unwrap());
let dict = PyDict::downcast_from(ob.as_ref(py)).unwrap();
assert_eq!(true, dict.contains(7i32).unwrap());
assert_eq!(false, dict.contains(8i32).unwrap());
}
#[test]
@ -193,9 +212,9 @@ mod test {
let mut v = HashMap::new();
v.insert(7, 32);
let ob = v.to_object(py);
let dict = PyDict::downcast_from(py, &ob).unwrap();
assert_eq!(32, dict.get_item(py, 7i32).unwrap().extract::<i32>(py).unwrap());
assert_eq!(None, dict.get_item(py, 8i32));
let dict = PyDict::downcast_from(ob.as_ref(py)).unwrap();
assert_eq!(32, dict.get_item(7i32).unwrap().extract::<i32>().unwrap());
assert_eq!(None, dict.get_item(8i32));
}
#[test]
@ -205,11 +224,11 @@ mod test {
let mut v = HashMap::new();
v.insert(7, 32);
let ob = v.to_object(py);
let dict = PyDict::downcast_from(py, &ob).unwrap();
assert!(dict.set_item(py, 7i32, 42i32).is_ok()); // change
assert!(dict.set_item(py, 8i32, 123i32).is_ok()); // insert
assert_eq!(42i32, dict.get_item(py, 7i32).unwrap().extract::<i32>(py).unwrap());
assert_eq!(123i32, dict.get_item(py, 8i32).unwrap().extract::<i32>(py).unwrap());
let dict = PyDict::downcast_from(ob.as_ref(py)).unwrap();
assert!(dict.set_item(7i32, 42i32).is_ok()); // change
assert!(dict.set_item(8i32, 123i32).is_ok()); // insert
assert_eq!(42i32, dict.get_item(7i32).unwrap().extract::<i32>().unwrap());
assert_eq!(123i32, dict.get_item(8i32).unwrap().extract::<i32>().unwrap());
}
#[test]
@ -219,14 +238,13 @@ mod test {
let mut v = HashMap::new();
v.insert(7, 32);
let ob = v.to_object(py);
let dict = PyDict::downcast_from(py, &ob).unwrap();
assert!(dict.set_item(py, 7i32, 42i32).is_ok()); // change
assert!(dict.set_item(py, 8i32, 123i32).is_ok()); // insert
let dict = PyDict::downcast_from(ob.as_ref(py)).unwrap();
assert!(dict.set_item(7i32, 42i32).is_ok()); // change
assert!(dict.set_item(8i32, 123i32).is_ok()); // insert
assert_eq!(32i32, *v.get(&7i32).unwrap()); // not updated!
assert_eq!(None, v.get(&8i32));
}
#[test]
fn test_del_item() {
let gil = Python::acquire_gil();
@ -234,10 +252,10 @@ mod test {
let mut v = HashMap::new();
v.insert(7, 32);
let ob = v.to_object(py);
let dict = PyDict::downcast_from(py, &ob).unwrap();
assert!(dict.del_item(py, 7i32).is_ok());
assert_eq!(0, dict.len(py));
assert_eq!(None, dict.get_item(py, 7i32));
let dict = PyDict::downcast_from(ob.as_ref(py)).unwrap();
assert!(dict.del_item(7i32).is_ok());
assert_eq!(0, dict.len());
assert_eq!(None, dict.get_item(7i32));
}
#[test]
@ -247,8 +265,8 @@ mod test {
let mut v = HashMap::new();
v.insert(7, 32);
let ob = v.to_object(py);
let dict = PyDict::downcast_from(py, &ob).unwrap();
assert!(dict.del_item(py, 7i32).is_ok()); // change
let dict = PyDict::downcast_from(ob.as_ref(py)).unwrap();
assert!(dict.del_item(7i32).is_ok()); // change
assert_eq!(32i32, *v.get(&7i32).unwrap()); // not updated!
}
@ -261,14 +279,14 @@ mod test {
v.insert(8, 42);
v.insert(9, 123);
let ob = v.to_object(py);
let dict = PyDict::downcast_from(py, &ob).unwrap();
let dict = PyDict::downcast_from(ob.as_ref(py)).unwrap();
// Can't just compare against a vector of tuples since we don't have a guaranteed ordering.
let mut key_sum = 0;
let mut value_sum = 0;
for el in dict.items_list(py).iter(py) {
let tuple = el.cast_into::<PyTuple>(py).unwrap();
key_sum += tuple.get_item(py, 0).extract::<i32>(py).unwrap();
value_sum += tuple.get_item(py, 1).extract::<i32>(py).unwrap();
for el in dict.items_list().iter() {
let tuple = el.cast_as::<PyTuple>().unwrap();
key_sum += tuple.get_item(0).extract::<i32>().unwrap();
value_sum += tuple.get_item(1).extract::<i32>().unwrap();
}
assert_eq!(7 + 8 + 9, key_sum);
assert_eq!(32 + 42 + 123, value_sum);
@ -283,11 +301,11 @@ mod test {
v.insert(8, 42);
v.insert(9, 123);
let ob = v.to_object(py);
let dict = PyDict::downcast_from(py, &ob).unwrap();
let dict = PyDict::downcast_from(ob.as_ref(py)).unwrap();
// Can't just compare against a vector of tuples since we don't have a guaranteed ordering.
let mut key_sum = 0;
let mut value_sum = 0;
for (key, value) in dict.items(py) {
for (key, value) in dict.items() {
key_sum += key.extract::<i32>(py).unwrap();
value_sum += value.extract::<i32>(py).unwrap();
}
@ -304,10 +322,10 @@ mod test {
map.insert(1, 1);
let m = map.to_object(py);
let py_map = PyDict::downcast_from(py, &m).unwrap();
let py_map = PyDict::downcast_from(m.as_ref(py)).unwrap();
assert!(py_map.len(py) == 1);
assert!( py_map.get_item(py, 1).unwrap().extract::<i32>(py).unwrap() == 1);
assert!(py_map.len() == 1);
assert!( py_map.get_item(1).unwrap().extract::<i32>().unwrap() == 1);
}
#[test]
@ -319,9 +337,9 @@ mod test {
map.insert(1, 1);
let m = map.to_object(py);
let py_map = PyDict::downcast_from(py, &m).unwrap();
let py_map = PyDict::downcast_from(m.as_ref(py)).unwrap();
assert!(py_map.len(py) == 1);
assert!( py_map.get_item(py, 1).unwrap().extract::<i32>(py).unwrap() == 1);
assert!(py_map.len() == 1);
assert!( py_map.get_item(1).unwrap().extract::<i32>().unwrap() == 1);
}
}

View File

@ -9,9 +9,10 @@ use std::{self, mem, ops};
use std::ffi::CStr;
use ffi;
use python::{Python, IntoPyPointer};
use pointer::PyObject;
use python::{Python, ToPyPointer};
use err::PyResult;
use super::{PyObject, PyTuple, PyType};
use super::{PyTuple, PyType};
macro_rules! exc_type(
($name:ident, $exc_name:ident) => (
@ -24,7 +25,7 @@ macro_rules! exc_type(
fn init_type(_py: Python) {}
#[inline]
fn type_object(py: $crate::python::Python) -> $crate::PyType {
fn type_object<'p>(py: $crate::python::Python<'p>) -> &'p $crate::PyType {
unsafe { PyType::from_type_ptr(py, ffi::$exc_name as *mut ffi::PyTypeObject) }
}
}
@ -126,10 +127,10 @@ impl UnicodeDecodeError {
impl StopIteration {
pub fn stop_iteration(_py: Python, args: PyTuple) {
pub fn stop_iteration(_py: Python, args: &PyTuple) {
unsafe {
ffi::PyErr_SetObject(
ffi::PyExc_StopIteration as *mut ffi::PyObject, args.into_ptr());
ffi::PyExc_StopIteration as *mut ffi::PyObject, args.as_ptr());
}
}
}

View File

@ -5,10 +5,10 @@
use std::os::raw::c_double;
use ffi;
use objects::PyObject;
use pointers::PyPtr;
use pointer::PyObject;
use python::{ToPyPointer, Python};
use err::PyErr;
use instance::{Py, PyObjectWithToken};
use conversion::{ToPyObject, IntoPyObject};
/// Represents a Python `float` object.
@ -17,7 +17,7 @@ use conversion::{ToPyObject, IntoPyObject};
/// by using [`ToPyObject`](trait.ToPyObject.html)
/// and [extract](struct.PyObject.html#method.extract)
/// with `f32`/`f64`.
pub struct PyFloat(PyPtr);
pub struct PyFloat(PyObject);
pyobject_convert!(PyFloat);
pyobject_nativetype!(PyFloat, PyFloat_Type, PyFloat_Check);
@ -25,14 +25,14 @@ pyobject_nativetype!(PyFloat, PyFloat_Type, PyFloat_Check);
impl PyFloat {
/// Creates a new Python `float` object.
pub fn new(_py: Python, val: c_double) -> PyFloat {
pub fn new(_py: Python, val: c_double) -> Py<PyFloat> {
unsafe {
PyFloat(PyPtr::from_owned_ptr_or_panic(ffi::PyFloat_FromDouble(val)))
Py::from_owned_ptr_or_panic(ffi::PyFloat_FromDouble(val))
}
}
/// Gets the value of this float.
pub fn value(&self, _py: Python) -> c_double {
pub fn value(&self) -> c_double {
unsafe { ffi::PyFloat_AsDouble(self.0.as_ptr()) }
}
}
@ -50,8 +50,8 @@ impl IntoPyObject for f64 {
pyobject_extract!(py, obj to f64 => {
let v = unsafe { ffi::PyFloat_AsDouble(obj.as_ptr()) };
if v == -1.0 && PyErr::occurred(py) {
Err(PyErr::fetch(py))
if v == -1.0 && PyErr::occurred(obj.token()) {
Err(PyErr::fetch(obj.token()))
} else {
Ok(v)
}
@ -69,7 +69,7 @@ impl IntoPyObject for f32 {
}
pyobject_extract!(py, obj to f32 => {
Ok(try!(obj.extract::<f64>(py)) as f32)
Ok(try!(obj.extract::<f64>()) as f32)
});

View File

@ -3,16 +3,16 @@
// based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython
use ffi;
use pointers::PyPtr;
use objects::PyInstance;
use python::{Python, ToPyPointer, IntoPyPointer};
use objects::PyObject;
use instance::PyObjectWithToken;
use err::{PyErr, PyResult, PyDowncastError};
/// A python iterator object.
///
/// Unlike other python objects, this class includes a `Python<'p>` token
/// so that `PyIterator` can implement the rust `Iterator` trait.
pub struct PyIterator<'p>(PyPtr, Python<'p>);
pub struct PyIterator<'p>(&'p PyInstance);
impl <'p> PyIterator<'p> {
@ -24,7 +24,7 @@ impl <'p> PyIterator<'p> {
unsafe {
let ptr = obj.into_ptr();
if ffi::PyIter_Check(ptr) != 0 {
Ok(PyIterator(PyPtr::from_borrowed_ptr(ptr), py))
Ok(PyIterator(py.cast_from_ptr(ptr)))
} else {
ffi::Py_DECREF(ptr);
Err(PyDowncastError(py, None))
@ -34,20 +34,23 @@ impl <'p> PyIterator<'p> {
}
impl <'p> Iterator for PyIterator<'p> {
type Item = PyResult<PyObject>;
type Item = PyResult<&'p PyInstance>;
/// Retrieves the next item from an iterator.
/// Returns `None` when the iterator is exhausted.
/// If an exception occurs, returns `Some(Err(..))`.
/// Further `next()` calls after an exception occurs are likely
/// to repeatedly result in the same exception.
fn next(&mut self) -> Option<PyResult<PyObject>> {
match unsafe { PyObject::from_owned_ptr_or_opt(
self.1, ffi::PyIter_Next(self.0.as_ptr())) } {
fn next(&mut self) -> Option<Self::Item> {
let py = self.0.token();
match unsafe {
py.cast_from_ptr_or_opt(ffi::PyIter_Next(self.0.as_ptr())) }
{
Some(obj) => Some(Ok(obj)),
None => {
if PyErr::occurred(self.1) {
Some(Err(PyErr::fetch(self.1)))
if PyErr::occurred(py) {
Some(Err(PyErr::fetch(py)))
} else {
None
}
@ -58,8 +61,10 @@ impl <'p> Iterator for PyIterator<'p> {
#[cfg(test)]
mod tests {
use python::{Python};
use instance::AsPyRef;
use python::{Python, PyDowncastFrom};
use conversion::ToPyObject;
use objects::PyInstance;
use objectprotocol::ObjectProtocol;
#[test]
@ -67,9 +72,10 @@ mod tests {
let gil_guard = Python::acquire_gil();
let py = gil_guard.python();
let obj = vec![10, 20].to_object(py);
let mut it = obj.iter(py).unwrap();
assert_eq!(10, it.next().unwrap().unwrap().extract(py).unwrap());
assert_eq!(20, it.next().unwrap().unwrap().extract(py).unwrap());
let inst = PyInstance::downcast_from(obj.as_ref(py)).unwrap();
let mut it = inst.iter().unwrap();
assert_eq!(10, it.next().unwrap().unwrap().extract().unwrap());
assert_eq!(20, it.next().unwrap().unwrap().extract().unwrap());
assert!(it.next().is_none());
}
}

View File

@ -4,39 +4,41 @@
use err::{self, PyResult};
use ffi::{self, Py_ssize_t};
use pointers::PyPtr;
use instance::PyObjectWithToken;
use pointer::PyObject;
use objects::PyInstance;
use python::{Python, ToPyPointer, IntoPyPointer};
use objects::PyObject;
use conversion::{ToPyObject, IntoPyObject};
/// Represents a Python `list`.
pub struct PyList(PyPtr);
pub struct PyList(PyObject);
pyobject_convert!(PyList);
pyobject_nativetype!(PyList, PyList_Type, PyList_Check);
impl PyList {
/// Construct a new list with the given elements.
pub fn new<T: ToPyObject>(py: Python, elements: &[T]) -> PyList {
pub fn new<'p, T: ToPyObject>(py: Python<'p>, elements: &[T]) -> &'p PyList {
unsafe {
let ptr = ffi::PyList_New(elements.len() as Py_ssize_t);
for (i, e) in elements.iter().enumerate() {
ffi::PyList_SetItem(ptr, i as Py_ssize_t, e.to_object(py).into_ptr());
let obj = e.to_object(py).into_ptr();
ffi::PyList_SetItem(ptr, i as Py_ssize_t, obj);
}
PyList(PyPtr::from_owned_ptr_or_panic(ptr))
py.cast_from_ptr::<PyList>(ptr)
}
}
/// Construct a new empty list.
pub fn empty(_py: Python) -> PyList {
pub fn empty<'p>(py: Python<'p>) -> &'p PyList {
unsafe {
PyList(PyPtr::from_owned_ptr_or_panic(ffi::PyList_New(0)))
py.cast_from_ptr::<PyList>(ffi::PyList_New(0))
}
}
/// Gets the length of the list.
#[inline]
pub fn len(&self, _py: Python) -> usize {
pub fn len(&self) -> usize {
// non-negative Py_ssize_t should always fit into Rust usize
unsafe {
ffi::PyList_Size(self.as_ptr()) as usize
@ -46,57 +48,67 @@ impl PyList {
/// Gets the item at the specified index.
///
/// Panics if the index is out of range.
pub fn get_item(&self, py: Python, index: isize) -> PyObject {
pub fn get_item(&self, index: isize) -> &PyInstance {
unsafe {
PyObject::from_borrowed_ptr(
py, ffi::PyList_GetItem(self.as_ptr(), index as Py_ssize_t))
let ptr = ffi::PyList_GetItem(self.as_ptr(), index as Py_ssize_t);
let ob = PyObject::from_borrowed_ptr(self.token(), ptr);
self.token().track_object(ob)
}
}
/// Gets the item at the specified index.
///
/// Panics if the index is out of range.
pub fn get_parked_item(&self, index: isize) -> PyObject {
unsafe {
let ptr = ffi::PyList_GetItem(self.as_ptr(), index as Py_ssize_t);
PyObject::from_borrowed_ptr(self.token(), ptr)
}
}
/// Sets the item at the specified index.
///
/// Panics if the index is out of range.
pub fn set_item<I>(&self, py: Python, index: isize, item: I) -> PyResult<()>
pub fn set_item<I>(&self, index: isize, item: I) -> PyResult<()>
where I: ToPyObject
{
item.with_borrowed_ptr(py, |item| unsafe {
item.with_borrowed_ptr(self.token(), |item| unsafe {
err::error_on_minusone(
py, ffi::PyList_SetItem(self.as_ptr(), index, item))
self.token(), ffi::PyList_SetItem(self.as_ptr(), index, item))
})
}
/// Inserts an item at the specified index.
///
/// Panics if the index is out of range.
pub fn insert_item<I>(&self, py: Python, index: isize, item: I) -> PyResult<()>
pub fn insert_item<I>(&self, index: isize, item: I) -> PyResult<()>
where I: ToPyObject
{
item.with_borrowed_ptr(py, |item| unsafe {
item.with_borrowed_ptr(self.token(), |item| unsafe {
err::error_on_minusone(
py, ffi::PyList_Insert(self.as_ptr(), index, item))
self.token(), ffi::PyList_Insert(self.as_ptr(), index, item))
})
}
#[inline]
pub fn iter<'a, 'p>(&'a self, py: Python<'p>) -> PyListIterator<'a, 'p> {
PyListIterator { py: py, list: self, index: 0 }
pub fn iter(&self) -> PyListIterator {
PyListIterator { list: self, index: 0 }
}
}
/// Used by `PyList::iter()`.
pub struct PyListIterator<'a, 'p> {
py: Python<'p>,
pub struct PyListIterator<'a> {
list: &'a PyList,
index: isize,
}
impl<'a, 'p> Iterator for PyListIterator<'a, 'p> {
type Item = PyObject;
impl<'a> Iterator for PyListIterator<'a> {
type Item = &'a PyInstance;
#[inline]
fn next(&mut self) -> Option<PyObject> {
if self.index < self.list.len(self.py) as isize {
let item = self.list.get_item(self.py, self.index);
fn next(&mut self) -> Option<&'a PyInstance> {
if self.index < self.list.len() as isize {
let item = self.list.get_item(self.index);
self.index += 1;
Some(item)
} else {
@ -139,24 +151,39 @@ impl <T> IntoPyObject for Vec<T> where T: IntoPyObject {
let obj = e.into_object(py).into_ptr();
ffi::PyList_SetItem(ptr, i as Py_ssize_t, obj);
}
::PyObject::from_owned_ptr_or_panic(py, ptr)
PyObject::from_owned_ptr_or_panic(py, ptr)
}
}
}
#[cfg(test)]
mod test {
use python::{Python, PyDowncastInto};
use instance::AsPyRef;
use python::{Python, PyDowncastFrom};
use conversion::ToPyObject;
use objects::PyList;
use objectprotocol::ObjectProtocol;
#[test]
fn test_new() {
let gil = Python::acquire_gil();
let py = gil.python();
let v = vec![2, 3, 5, 7];
let list = PyList::new(py, &v);
assert_eq!(2, list.get_item(0).extract::<i32>().unwrap());
assert_eq!(3, list.get_item(1).extract::<i32>().unwrap());
assert_eq!(5, list.get_item(2).extract::<i32>().unwrap());
assert_eq!(7, list.get_item(3).extract::<i32>().unwrap());
}
#[test]
fn test_len() {
let gil = Python::acquire_gil();
let py = gil.python();
let v = vec![1,2,3,4];
let list = PyList::downcast_into(py, v.to_object(py)).unwrap();
assert_eq!(4, list.len(py));
let ob = v.to_object(py);
let list = PyList::downcast_from(ob.as_ref(py)).unwrap();
assert_eq!(4, list.len());
}
#[test]
@ -164,11 +191,25 @@ mod test {
let gil = Python::acquire_gil();
let py = gil.python();
let v = vec![2, 3, 5, 7];
let list = PyList::downcast_into(py, v.to_object(py)).unwrap();
assert_eq!(2, list.get_item(py, 0).extract::<i32>(py).unwrap());
assert_eq!(3, list.get_item(py, 1).extract::<i32>(py).unwrap());
assert_eq!(5, list.get_item(py, 2).extract::<i32>(py).unwrap());
assert_eq!(7, list.get_item(py, 3).extract::<i32>(py).unwrap());
let ob = v.to_object(py);
let list = PyList::downcast_from(ob.as_ref(py)).unwrap();
assert_eq!(2, list.get_item(0).extract::<i32>().unwrap());
assert_eq!(3, list.get_item(1).extract::<i32>().unwrap());
assert_eq!(5, list.get_item(2).extract::<i32>().unwrap());
assert_eq!(7, list.get_item(3).extract::<i32>().unwrap());
}
#[test]
fn test_get_parked_item() {
let gil = Python::acquire_gil();
let py = gil.python();
let v = vec![2, 3, 5, 7];
let ob = v.to_object(py);
let list = PyList::downcast_from(ob.as_ref(py)).unwrap();
assert_eq!(2, list.get_parked_item(0).extract::<i32>(py).unwrap());
assert_eq!(3, list.get_parked_item(1).extract::<i32>(py).unwrap());
assert_eq!(5, list.get_parked_item(2).extract::<i32>(py).unwrap());
assert_eq!(7, list.get_parked_item(3).extract::<i32>(py).unwrap());
}
#[test]
@ -176,11 +217,12 @@ mod test {
let gil = Python::acquire_gil();
let py = gil.python();
let v = vec![2, 3, 5, 7];
let list = PyList::downcast_into(py, v.to_object(py)).unwrap();
let ob = v.to_object(py);
let list = PyList::downcast_from(ob.as_ref(py)).unwrap();
let val = 42i32.to_object(py);
assert_eq!(2, list.get_item(py, 0).extract::<i32>(py).unwrap());
list.set_item(py, 0, val).unwrap();
assert_eq!(42, list.get_item(py, 0).extract::<i32>(py).unwrap());
assert_eq!(2, list.get_item(0).extract::<i32>().unwrap());
list.set_item(0, val).unwrap();
assert_eq!(42, list.get_item(0).extract::<i32>().unwrap());
}
#[test]
@ -188,14 +230,15 @@ mod test {
let gil = Python::acquire_gil();
let py = gil.python();
let v = vec![2, 3, 5, 7];
let list = PyList::downcast_into(py, v.to_object(py)).unwrap();
let ob = v.to_object(py);
let list = PyList::downcast_from(ob.as_ref(py)).unwrap();
let val = 42i32.to_object(py);
assert_eq!(4, list.len(py));
assert_eq!(2, list.get_item(py, 0).extract::<i32>(py).unwrap());
list.insert_item(py, 0, val).unwrap();
assert_eq!(5, list.len(py));
assert_eq!(42, list.get_item(py, 0).extract::<i32>(py).unwrap());
assert_eq!(2, list.get_item(py, 1).extract::<i32>(py).unwrap());
assert_eq!(4, list.len());
assert_eq!(2, list.get_item(0).extract::<i32>().unwrap());
list.insert_item(0, val).unwrap();
assert_eq!(5, list.len());
assert_eq!(42, list.get_item(0).extract::<i32>().unwrap());
assert_eq!(2, list.get_item(1).extract::<i32>().unwrap());
}
#[test]
@ -203,10 +246,11 @@ mod test {
let gil = Python::acquire_gil();
let py = gil.python();
let v = vec![2, 3, 5, 7];
let list = PyList::downcast_into(py, v.to_object(py)).unwrap();
let ob = v.to_object(py);
let list = PyList::downcast_from(ob.as_ref(py)).unwrap();
let mut idx = 0;
for el in list.iter(py) {
assert_eq!(v[idx], el.extract::<i32>(py).unwrap());
for el in list.iter() {
assert_eq!(v[idx], el.extract::<i32>().unwrap());
idx += 1;
}
assert_eq!(idx, v.len());
@ -217,8 +261,9 @@ mod test {
let gil = Python::acquire_gil();
let py = gil.python();
let v = vec![2, 3, 5, 7];
let list = PyList::downcast_into(py, v.to_object(py)).unwrap();
let v2 = list.as_ref().extract::<Vec<i32>>(py).unwrap();
let ob = v.to_object(py);
let list = PyList::downcast_from(ob.as_ref(py)).unwrap();
let v2 = list.as_ref().extract::<Vec<i32>>().unwrap();
assert_eq!(v, v2);
}
}

View File

@ -1,6 +1,5 @@
// Copyright (c) 2017-present PyO3 Project and Contributors
pub use self::object::PyObject;
pub use self::typeobject::PyType;
pub use self::module::PyModule;
pub use self::iterator::PyIterator;
@ -29,17 +28,77 @@ pub use self::num3::PyLong as PyInt;
#[cfg(not(Py_3))]
pub use self::num2::{PyInt, PyLong};
//#[macro_export]
macro_rules! pyobject_nativetype(
macro_rules! pyobject_downcast(
($name: ident, $checkfunction: ident) => (
impl $crate::python::PyDowncastFrom for $name
{
fn downcast_from(ob: &$crate::PyInstance)
-> Result<&$name, $crate::PyDowncastError>
{
use $crate::{ToPyPointer, PyObjectWithToken};
unsafe {
if $crate::ffi::$checkfunction(ob.as_ptr()) > 0 {
Ok($crate::std::mem::transmute(ob))
} else {
Err($crate::PyDowncastError(ob.token(), None))
}
}
}
unsafe fn unchecked_downcast_from(ob: &$crate::PyInstance) -> &Self
{
$crate::std::mem::transmute(ob)
}
unsafe fn unchecked_mut_downcast_from(ob: &$crate::PyInstance) -> &mut Self
{
#[allow(mutable_transmutes)]
$crate::std::mem::transmute(ob)
}
}
impl<'a> $crate::FromPyObject<'a> for &'a $name
{
/// Extracts `Self` from the source `PyObject`.
fn extract(ob: &'a $crate::PyInstance) -> $crate::PyResult<Self>
{
use instance::PyObjectWithToken;
unsafe {
if $crate::ffi::$checkfunction(ob.as_ptr()) != 0 {
Ok($crate::std::mem::transmute(ob))
} else {
Err($crate::PyDowncastError(ob.token(), None).into())
}
}
}
}
);
);
macro_rules! pyobject_convert(
($name: ident) => (
impl $crate::std::convert::AsRef<PyObject> for $name {
fn as_ref(&self) -> &$crate::PyObject {
impl<'a> $crate::std::convert::From<&'a $name> for &'a $crate::PyInstance {
fn from(ob: &'a $name) -> Self {
unsafe{$crate::std::mem::transmute(ob)}
}
}
)
);
macro_rules! pyobject_nativetype(
($name: ident) => {
impl $crate::PyNativeType for $name {}
impl $crate::std::convert::AsRef<$crate::PyInstance> for $name {
fn as_ref(&self) -> &$crate::PyInstance {
unsafe{$crate::std::mem::transmute(self)}
}
}
impl $crate::PyClone for $name {
fn clone_ref(&self, _py: $crate::Python) -> Self {
$name(unsafe{$crate::PyPtr::from_borrowed_ptr(self.as_ptr())})
impl $crate::PyObjectWithToken for $name {
#[inline]
fn token<'p>(&'p self) -> $crate::Python<'p> {
unsafe { $crate::Python::assume_gil_acquired() }
}
}
impl $crate::python::ToPyPointer for $name {
@ -49,32 +108,33 @@ macro_rules! pyobject_nativetype(
self.0.as_ptr()
}
}
impl<'a> $crate::python::ToPyPointer for &'a $name {
impl $crate::python::IntoPyPointer for $name {
/// Gets the underlying FFI pointer, returns a borrowed pointer.
#[inline]
fn as_ptr(&self) -> *mut $crate::ffi::PyObject {
self.0.as_ptr()
}
}
impl $crate::python::IntoPyPointer for $name {
/// Gets the underlying FFI pointer, returns a owned pointer.
#[inline]
#[must_use]
fn into_ptr(self) -> *mut $crate::ffi::PyObject {
let ptr = self.0.as_ptr();
$crate::std::mem::forget(self);
unsafe { $crate::ffi::Py_INCREF(ptr); }
ptr
}
}
);
($name: ident, $typeobject: ident, $checkfunction: ident) => {
pyobject_downcast!($name, $checkfunction);
pyobject_nativetype!($name, $typeobject);
impl<'a> $crate::python::IntoPyPointer for &'a $name {
/// Gets the underlying FFI pointer, returns a borrowed pointer.
#[inline]
fn into_ptr(self) -> *mut $crate::ffi::PyObject {
let ptr = self.0.as_ptr();
unsafe { $crate::ffi::Py_INCREF(ptr); }
ptr
}
}
impl PartialEq for $name {
#[inline]
fn eq(&self, o: &$name) -> bool {
self.as_ptr() == o.as_ptr()
}
}
};
($name: ident, $typeobject: ident) => (
($name: ident, $typeobject: ident, $checkfunction: ident) => {
pyobject_nativetype!($name);
impl $crate::typeob::PyTypeInfo for $name {
@ -82,7 +142,7 @@ macro_rules! pyobject_nativetype(
#[inline]
fn size() -> usize {
$crate::std::mem::size_of::<ffi::PyObject>()
$crate::std::mem::size_of::<$crate::ffi::PyObject>()
}
#[inline]
fn offset() -> isize {
@ -96,14 +156,19 @@ macro_rules! pyobject_nativetype(
fn type_object() -> &'static mut $crate::ffi::PyTypeObject {
unsafe { &mut $crate::ffi::$typeobject }
}
#[inline]
fn is_instance(ptr: *mut $crate::ffi::PyObject) -> bool {
#[allow(unused_unsafe)]
unsafe { $crate::ffi::$checkfunction(ptr) > 0 }
}
}
impl $crate::typeob::PyTypeObject for $name {
#[inline(always)]
fn init_type(_py: Python) {}
fn init_type(_py: $crate::Python) {}
#[inline]
fn type_object(py: $crate::Python) -> $crate::PyType {
fn type_object<'p>(py: $crate::Python<'p>) -> &'p $crate::PyType {
unsafe { $crate::PyType::from_type_ptr(py, &mut $crate::ffi::$typeobject) }
}
}
@ -112,23 +177,22 @@ macro_rules! pyobject_nativetype(
{
#[inline]
fn to_object<'p>(&self, py: $crate::Python<'p>) -> $crate::PyObject {
$crate::PyObject::from_borrowed_ptr(py, self.0.as_ptr())
unsafe {$crate::PyObject::from_borrowed_ptr(py, self.0.as_ptr())}
}
#[inline]
fn with_borrowed_ptr<F, R>(&self, _py: $crate::Python, f: F) -> R
where F: FnOnce(*mut ffi::PyObject) -> R
where F: FnOnce(*mut $crate::ffi::PyObject) -> R
{
f(self.0.as_ptr())
}
}
impl $crate::IntoPyObject for $name
impl<'a> $crate::IntoPyObject for &'a $name
{
#[inline]
fn into_object(self, _py: $crate::Python) -> $crate::PyObject
{
unsafe { $crate::std::mem::transmute(self) }
fn into_object<'p>(self, py: $crate::Python) -> $crate::PyObject {
unsafe { $crate::PyObject::from_borrowed_ptr(py, self.as_ptr()) }
}
}
@ -136,18 +200,9 @@ macro_rules! pyobject_nativetype(
fn fmt(&self, f: &mut $crate::std::fmt::Formatter)
-> Result<(), $crate::std::fmt::Error>
{
use $crate::python::PyDowncastInto;
let gil = $crate::Python::acquire_gil();
let py = gil.python();
let s = unsafe { $crate::PyString::downcast_from_ptr(
py, $crate::ffi::PyObject_Repr(
$crate::python::ToPyPointer::as_ptr(self))) };
let repr_obj = try!(s.map_err(|_| $crate::std::fmt::Error));
let result = f.write_str(&repr_obj.to_string_lossy(py));
py.release(repr_obj);
result
use $crate::ObjectProtocol;
let s = try!(self.repr().map_err(|_| $crate::std::fmt::Error));
f.write_str(&s.to_string_lossy())
}
}
@ -155,129 +210,25 @@ macro_rules! pyobject_nativetype(
fn fmt(&self, f: &mut $crate::std::fmt::Formatter)
-> Result<(), $crate::std::fmt::Error>
{
let gil = $crate::Python::acquire_gil();
let py = gil.python();
use $crate::python::PyDowncastInto;
let s = unsafe { $crate::PyString::downcast_from_ptr(
py, $crate::ffi::PyObject_Str(
$crate::python::ToPyPointer::as_ptr(self))) };
let str_obj = try!(s.map_err(|_| $crate::std::fmt::Error));
let result = f.write_str(&str_obj.to_string_lossy(py));
py.release(str_obj);
result
}
}
);
);
macro_rules! pyobject_downcast(
($name: ident, $checkfunction: ident) => (
impl $crate::python::PyDowncastFrom for $name
{
fn downcast_from<'a, 'p>(py: $crate::Python<'p>, ob: &'a $crate::PyObject)
-> Result<&'a $name, $crate::PyDowncastError<'p>>
{
use $crate::ToPyPointer;
unsafe {
if $crate::ffi::$checkfunction(ob.as_ptr()) > 0 {
let ptr = ob as *const _ as *mut u8 as *mut $name;
Ok(ptr.as_ref().expect("Failed to call as_ref"))
} else {
Err($crate::PyDowncastError(py, None))
}
}
}
}
impl $crate::python::PyDowncastInto for $name
{
fn downcast_into<'p, I>(py: $crate::Python<'p>, ob: I)
-> Result<Self, $crate::PyDowncastError<'p>>
where I: $crate::IntoPyPointer
{
unsafe{
let ptr = ob.into_ptr();
if ffi::$checkfunction(ptr) != 0 {
Ok($name(PyPtr::from_owned_ptr(ptr)))
} else {
$crate::ffi::Py_DECREF(ptr);
Err($crate::PyDowncastError(py, None))
}
}
}
fn downcast_from_ptr<'p>(py: $crate::Python<'p>, ptr: *mut $crate::ffi::PyObject)
-> Result<$name, $crate::PyDowncastError<'p>>
{
unsafe{
if ffi::$checkfunction(ptr) != 0 {
Ok($name(PyPtr::from_owned_ptr(ptr)))
} else {
$crate::ffi::Py_DECREF(ptr);
Err($crate::PyDowncastError(py, None))
}
}
}
fn unchecked_downcast_into<'p, I>(ob: I) -> Self
where I: $crate::IntoPyPointer
{
unsafe{
$name(PyPtr::from_owned_ptr(ob.into_ptr()))
}
use $crate::ObjectProtocol;
let s = try!(self.str().map_err(|_| $crate::std::fmt::Error));
f.write_str(&s.to_string_lossy())
}
}
impl<'a> $crate::FromPyObject<'a> for $name
{
/// Extracts `Self` from the source `PyObject`.
fn extract(py: Python, ob: &'a $crate::PyObject) -> $crate::PyResult<Self>
{
unsafe {
if ffi::$checkfunction(ob.as_ptr()) != 0 {
Ok( $name($crate::pointers::PyPtr::from_borrowed_ptr(ob.as_ptr())) )
} else {
Err(::PyDowncastError(py, None).into())
}
}
}
}
impl<'a> $crate::FromPyObject<'a> for &'a $name
{
/// Extracts `Self` from the source `PyObject`.
fn extract(py: Python, ob: &'a $crate::PyObject) -> $crate::PyResult<Self>
{
unsafe {
if ffi::$checkfunction(ob.as_ptr()) != 0 {
Ok($crate::std::mem::transmute(ob))
} else {
Err($crate::PyDowncastError(py, None).into())
}
}
}
}
);
);
macro_rules! pyobject_convert(
($name: ident) => (
impl $crate::std::convert::From<$name> for $crate::PyObject {
fn from(ob: $name) -> Self {
unsafe{$crate::std::mem::transmute(ob)}
}
}
)
pyobject_downcast!($name, $checkfunction);
};
);
macro_rules! pyobject_extract(
($py:ident, $obj:ident to $t:ty => $body: block) => {
impl<'source> ::conversion::FromPyObject<'source>
for $t
impl<'source> $crate::FromPyObject<'source> for $t
{
fn extract($py: Python, $obj: &'source ::PyObject) -> $crate::PyResult<Self>
fn extract($obj: &'source $crate::PyInstance) -> $crate::PyResult<Self>
{
#[allow(unused_imports)]
use objectprotocol::ObjectProtocol;
$body
}
}
@ -285,6 +236,12 @@ macro_rules! pyobject_extract(
);
use python::ToPyPointer;
/// Represents general python instance.
pub struct PyInstance(::PyObject);
pyobject_nativetype!(PyInstance, PyBaseObject_Type, PyObject_Check);
mod typeobject;
mod module;
mod dict;
@ -299,7 +256,6 @@ mod slice;
mod stringdata;
mod stringutils;
mod set;
mod object;
pub mod exc;
#[cfg(Py_3)]

View File

@ -8,53 +8,59 @@ use std::os::raw::c_char;
use std::ffi::{CStr, CString};
use conversion::{ToPyObject, IntoPyTuple};
use pointers::PyPtr;
use pointer::PyObject;
use python::{Python, ToPyPointer};
use objects::{PyObject, PyDict, PyType, exc};
use objects::{PyInstance, PyDict, PyType, exc};
use objectprotocol::ObjectProtocol;
use instance::PyObjectWithToken;
use err::{PyResult, PyErr, ToPyErr};
/// Represents a Python module object.
pub struct PyModule(PyPtr);
pub struct PyModule(PyObject);
pyobject_convert!(PyModule);
pyobject_nativetype!(PyModule, PyModule_Type, PyModule_Check);
impl<'p> PyModule {
impl PyModule {
/// Create a new module object with the `__name__` attribute set to name.
pub fn new(py: Python, name: &str) -> PyResult<PyModule> {
pub fn new<'p>(py: Python<'p>, name: &str) -> PyResult<&'p PyModule> {
let name = CString::new(name).map_err(|e| e.to_pyerr(py))?;
Ok(PyModule(PyPtr::from_owned_ptr_or_err(
py, unsafe{ffi::PyModule_New(name.as_ptr())} )?))
unsafe {
py.cast_from_ptr_or_err(
ffi::PyModule_New(name.as_ptr()))
}
}
/// Import the Python module with the specified name.
pub fn import(py: Python, name: &str) -> PyResult<PyModule> {
pub fn import<'p>(py: Python<'p>, name: &str) -> PyResult<&'p PyModule> {
let name = CString::new(name).map_err(|e| e.to_pyerr(py))?;
Ok(PyModule(PyPtr::from_owned_ptr_or_err(
py, unsafe{ffi::PyImport_ImportModule(name.as_ptr())} )?))
unsafe {
py.cast_from_ptr_or_err(
ffi::PyImport_ImportModule(name.as_ptr()))
}
}
/// Return the dictionary object that implements module's namespace;
/// this object is the same as the `__dict__` attribute of the module object.
pub fn dict(&self, py: Python) -> PyDict {
pub fn dict(&self) -> &PyDict {
unsafe {
PyDict::from_borrowed_ptr(py, ffi::PyModule_GetDict(self.as_ptr()))
self.token().cast_from_ptr::<PyDict>(
ffi::PyModule_GetDict(self.as_ptr()))
}
}
unsafe fn str_from_ptr<'a>(&'a self, py: Python, ptr: *const c_char) -> PyResult<&'a str> {
unsafe fn str_from_ptr<'a>(&'a self, ptr: *const c_char) -> PyResult<&'a str> {
if ptr.is_null() {
Err(PyErr::fetch(py))
Err(PyErr::fetch(self.token()))
} else {
let slice = CStr::from_ptr(ptr).to_bytes();
match std::str::from_utf8(slice) {
Ok(s) => Ok(s),
Err(e) => Err(PyErr::from_instance(
py,
try!(exc::UnicodeDecodeError::new_utf8(py, slice, e))))
self.token(),
try!(exc::UnicodeDecodeError::new_utf8(self.token(), slice, e))))
}
}
}
@ -62,38 +68,37 @@ impl<'p> PyModule {
/// Gets the module name.
///
/// May fail if the module does not have a `__name__` attribute.
pub fn name<'a>(&'a self, py: Python) -> PyResult<&'a str> {
unsafe { self.str_from_ptr(py, ffi::PyModule_GetName(self.as_ptr())) }
pub fn name<'a>(&'a self) -> PyResult<&'a str> {
unsafe { self.str_from_ptr(ffi::PyModule_GetName(self.as_ptr())) }
}
/// Gets the module filename.
///
/// May fail if the module does not have a `__file__` attribute.
pub fn filename<'a>(&'a self, py: Python) -> PyResult<&'a str> {
unsafe { self.str_from_ptr(py, ffi::PyModule_GetFilename(self.as_ptr())) }
pub fn filename<'a>(&'a self) -> PyResult<&'a str> {
unsafe { self.str_from_ptr(ffi::PyModule_GetFilename(self.as_ptr())) }
}
/// Calls a function in the module.
/// This is equivalent to the Python expression: `getattr(module, name)(*args, **kwargs)`
pub fn call<A>(&self, py: Python, name: &str,
args: A, kwargs: Option<&PyDict>) -> PyResult<PyObject>
pub fn call<A>(&self, name: &str, args: A, kwargs: Option<&PyDict>) -> PyResult<&PyInstance>
where A: IntoPyTuple
{
self.getattr(py, name)?.call(py, args, kwargs)
self.getattr(name)?.call(args, kwargs)
}
/// Gets a member from the module.
/// This is equivalent to the Python expression: `getattr(module, name)`
pub fn get(&self, py: Python, name: &str) -> PyResult<PyObject>
pub fn get(&self, name: &str) -> PyResult<&PyInstance>
{
self.getattr(py, name)
self.getattr(name)
}
/// Adds a member to the module.
///
/// This is a convenience function which can be used from the module's initialization function.
pub fn add<V>(&self, py: Python, name: &str, value: V) -> PyResult<()> where V: ToPyObject {
self.setattr(py, name, value)
pub fn add<V>(&self, name: &str, value: V) -> PyResult<()> where V: ToPyObject {
self.setattr(name, value)
}
/// Adds a new extension type to the module.
@ -101,30 +106,26 @@ impl<'p> PyModule {
/// This is a convenience function that initializes the `class`,
/// sets `new_type.__module__` to this module's name,
/// and adds the type to this module.
pub fn add_class<T>(&self, py: Python) -> PyResult<()>
pub fn add_class<T>(&self) -> PyResult<()>
where T: ::typeob::PyTypeInfo
{
let mut ty = <T as ::typeob::PyTypeInfo>::type_object();
let type_name = <T as ::typeob::PyTypeInfo>::type_name();
let ty = if (ty.tp_flags & ffi::Py_TPFLAGS_READY) != 0 {
unsafe { PyType::from_type_ptr(py, ty) }
unsafe { PyType::from_type_ptr(self.token(), ty) }
} else {
// automatically initialize the class
let name = self.name(py)?;
let name = self.name()?;
let type_description = <T as ::typeob::PyTypeInfo>::type_description();
let to = ::typeob::initialize_type::<T>(
py, Some(name), type_name, type_description, ty)
::typeob::initialize_type::<T>(
self.token(), Some(name), type_name, type_description, ty)
.expect(format!("An error occurred while initializing class {}",
<T as ::typeob::PyTypeInfo>::type_name()).as_ref());
py.release(to);
unsafe { PyType::from_type_ptr(py, ty) }
unsafe { PyType::from_type_ptr(self.token(), ty) }
};
self.setattr(py, type_name, &ty)?;
py.release(ty);
Ok(())
self.setattr(type_name, ty)
}
}

View File

@ -8,11 +8,11 @@ extern crate num_traits;
use self::num_traits::cast::cast;
use ffi;
use objects::exc;
use objects::PyObject;
use pointers::PyPtr;
use pointer::PyObject;
use python::{ToPyPointer, IntoPyPointer, Python};
use err::{PyResult, PyErr};
use instance::{Py, PyObjectWithToken};
use objects::{exc, PyInstance};
use conversion::{ToPyObject, IntoPyObject, FromPyObject};
/// Represents a Python `int` object.
@ -23,7 +23,7 @@ use conversion::{ToPyObject, IntoPyObject, FromPyObject};
/// by using [ToPyObject](trait.ToPyObject.html)
/// and [extract](struct.PyObject.html#method.extract)
/// with the primitive Rust integer types.
pub struct PyInt(PyPtr);
pub struct PyInt(PyObject);
pyobject_convert!(PyInt);
pyobject_nativetype!(PyInt, PyInt_Type, PyInt_Check);
@ -35,7 +35,7 @@ pyobject_nativetype!(PyInt, PyInt_Type, PyInt_Check);
/// by using [ToPyObject](trait.ToPyObject.html)
/// and [extract](struct.PyObject.html#method.extract)
/// with the primitive Rust integer types.
pub struct PyLong(PyPtr);
pub struct PyLong(PyObject);
pyobject_convert!(PyLong);
pyobject_nativetype!(PyLong, PyLong_Type, PyLong_Check);
@ -46,9 +46,9 @@ impl PyInt {
/// Note: you might want to call `val.to_py_object(py)` instead
/// to avoid truncation if the value does not fit into a `c_long`,
/// and to make your code compatible with Python 3.x.
pub fn new(_py: Python, val: c_long) -> PyInt {
pub fn new(_py: Python, val: c_long) -> Py<PyInt> {
unsafe {
PyInt(PyPtr::from_owned_ptr_or_panic(ffi::PyLong_FromLong(val)))
Py::from_owned_ptr_or_panic(ffi::PyLong_FromLong(val))
}
}
@ -58,7 +58,7 @@ impl PyInt {
/// but not for `long` objects.
/// In almost all cases, you can avoid the distinction between these types
/// by simply calling `obj.extract::<i32>(py)`.
pub fn value(&self, _py: Python) -> c_long {
pub fn value(&self) -> c_long {
unsafe { ffi::PyInt_AS_LONG(self.0.as_ptr()) }
}
}
@ -81,12 +81,12 @@ macro_rules! int_fits_c_long(
}
pyobject_extract!(py, obj to $rust_type => {
let val = unsafe { ffi::PyLong_AsLong(obj.as_ptr()) };
if val == -1 && PyErr::occurred(py) {
return Err(PyErr::fetch(py));
if val == -1 && PyErr::occurred(obj.token()) {
return Err(PyErr::fetch(obj.token()));
}
match cast::<c_long, $rust_type>(val) {
Some(v) => Ok(v),
None => Err(overflow_error(py))
None => Err(overflow_error(obj.token()))
}
});
)
@ -107,10 +107,10 @@ macro_rules! int_fits_larger_int(
}
}
pyobject_extract!(py, obj to $rust_type => {
let val = try!(obj.extract::<$larger_type>(py));
let val = try!(obj.extract::<$larger_type>());
match cast::<$larger_type, $rust_type>(val) {
Some(v) => Ok(v),
None => Err(overflow_error(py))
None => Err(overflow_error(obj.token()))
}
});
)
@ -153,20 +153,22 @@ macro_rules! int_convert_u64_or_i64 (
}
impl <'source> FromPyObject<'source> for $rust_type {
fn extract(py: Python, obj: &'source PyObject) -> PyResult<$rust_type>
fn extract(obj: &'source PyInstance) -> PyResult<$rust_type>
{
let ptr = obj.as_ptr();
unsafe {
if ffi::PyLong_Check(ptr) != 0 {
err_if_invalid_value(py, !0, $pylong_as_ull_or_ull(ptr))
err_if_invalid_value(obj.token(), !0, $pylong_as_ull_or_ull(ptr))
} else if ffi::PyInt_Check(ptr) != 0 {
match cast::<c_long, $rust_type>(ffi::PyInt_AS_LONG(ptr)) {
Some(v) => Ok(v),
None => Err(overflow_error(py))
None => Err(overflow_error(obj.token()))
}
} else {
let num = PyPtr::from_owned_ptr_or_err(py, ffi::PyNumber_Long(ptr))?;
err_if_invalid_value(py, !0, $pylong_as_ull_or_ull(num.into_ptr()))
let num = PyObject::from_owned_ptr_or_err(
obj.token(), ffi::PyNumber_Long(ptr))?;
err_if_invalid_value(
obj.token(), !0, $pylong_as_ull_or_ull(num.into_ptr()))
}
}
}

View File

@ -8,11 +8,11 @@ extern crate num_traits;
use self::num_traits::cast::cast;
use ffi;
use objects::exc;
use objects::PyObject;
use pointers::PyPtr;
use pointer::PyObject;
use python::{ToPyPointer, Python};
use err::{PyResult, PyErr};
use objects::{exc, PyInstance};
use instance::PyObjectWithToken;
use conversion::{ToPyObject, IntoPyObject, FromPyObject};
/// Represents a Python `int` object.
@ -21,11 +21,12 @@ use conversion::{ToPyObject, IntoPyObject, FromPyObject};
/// by using [`ToPyObject`](trait.ToPyObject.html)
/// and [extract](struct.PyObject.html#method.extract)
/// with the primitive Rust integer types.
pub struct PyLong(PyPtr);
pub struct PyLong(PyObject);
pyobject_convert!(PyLong);
pyobject_nativetype!(PyLong, PyLong_Type, PyLong_Check);
macro_rules! int_fits_c_long(
($rust_type:ty) => (
impl ToPyObject for $rust_type {
@ -44,12 +45,12 @@ macro_rules! int_fits_c_long(
}
pyobject_extract!(py, obj to $rust_type => {
let val = unsafe { ffi::PyLong_AsLong(obj.as_ptr()) };
if val == -1 && PyErr::occurred(py) {
return Err(PyErr::fetch(py));
if val == -1 && PyErr::occurred(obj.token()) {
return Err(PyErr::fetch(obj.token()));
}
match cast::<c_long, $rust_type>(val) {
Some(v) => Ok(v),
None => Err(overflow_error(py))
None => Err(overflow_error(obj.token()))
}
});
)
@ -70,10 +71,10 @@ macro_rules! int_fits_larger_int(
}
}
pyobject_extract!(py, obj to $rust_type => {
let val = try!(obj.extract::<$larger_type>(py));
let val = try!(obj.extract::<$larger_type>());
match cast::<$larger_type, $rust_type>(val) {
Some(v) => Ok(v),
None => Err(overflow_error(py))
None => Err(overflow_error(obj.token()))
}
});
)
@ -109,18 +110,18 @@ macro_rules! int_convert_u64_or_i64 (
}
}
impl<'source> FromPyObject<'source> for $rust_type {
fn extract(py: Python, ob: &'source PyObject) -> PyResult<$rust_type>
fn extract(ob: &'source PyInstance) -> PyResult<$rust_type>
{
let ptr = ob.as_ptr();
unsafe {
if ffi::PyLong_Check(ptr) != 0 {
err_if_invalid_value(py, !0, $pylong_as_ull_or_ull(ptr))
err_if_invalid_value(ob.token(), !0, $pylong_as_ull_or_ull(ptr))
} else {
let num = ffi::PyNumber_Long(ptr);
if num.is_null() {
Err(PyErr::fetch(py))
Err(PyErr::fetch(ob.token()))
} else {
err_if_invalid_value(py, !0, $pylong_as_ull_or_ull(num))
err_if_invalid_value(ob.token(), !0, $pylong_as_ull_or_ull(num))
}
}
}

View File

@ -1,127 +0,0 @@
// Copyright (c) 2017-present PyO3 Project and Contributors
use std;
use ffi;
use pointers::PyPtr;
use err::{PyErr, PyResult, PyDowncastError};
use python::{Python, ToPyPointer};
use conversion::FromPyObject;
pub struct PyObject(PyPtr);
pyobject_nativetype!(PyObject, PyBaseObject_Type, PyObject_Check);
impl PyObject {
#[inline]
pub fn from_owned_ptr(_py: Python, ptr: *mut ffi::PyObject) -> PyObject {
unsafe { PyObject(PyPtr::from_owned_ptr(ptr)) }
}
#[inline]
pub fn from_owned_ptr_or_err(py: Python, ptr: *mut ffi::PyObject)
-> PyResult<PyObject> {
Ok(PyObject(PyPtr::from_owned_ptr_or_err(py, ptr)?))
}
#[inline]
pub fn from_owned_ptr_or_panic(_py: Python, ptr: *mut ffi::PyObject)
-> PyObject {
PyObject(PyPtr::from_owned_ptr_or_panic(ptr))
}
#[inline]
pub fn from_owned_ptr_or_opt(_py: Python, ptr: *mut ffi::PyObject) -> Option<PyObject>
{
if ptr.is_null() {
None
} else {
Some(PyObject(unsafe{PyPtr::from_owned_ptr(ptr)}))
}
}
#[inline]
pub fn from_borrowed_ptr(_py: Python, ptr: *mut ffi::PyObject) -> PyObject {
unsafe { PyObject(PyPtr::from_borrowed_ptr(ptr)) }
}
#[inline]
pub fn from_borrowed_ptr_or_opt(_py: Python, ptr: *mut ffi::PyObject) -> Option<PyObject>
{
if ptr.is_null() {
None
} else {
Some(PyObject(unsafe{PyPtr::from_borrowed_ptr(ptr)}))
}
}
#[inline]
pub fn from_borrowed_ptr_or_err(py: Python, ptr: *mut ffi::PyObject) -> PyResult<PyObject>
{
if ptr.is_null() {
Err(PyErr::fetch(py))
} else {
Ok(PyObject(unsafe{PyPtr::from_borrowed_ptr(ptr)}))
}
}
/// Transmutes a slice of owned FFI pointers to `&[Py<'p, PyObject>]`.
/// Undefined behavior if any pointer in the slice is NULL or invalid.
#[inline]
pub unsafe fn borrow_from_owned_ptr_slice<'a>(ptr: &'a [*mut ffi::PyObject])
-> &'a [PyObject] {
std::mem::transmute(ptr)
}
/// Casts the PyObject to a concrete Python object type.
/// Fails with `PyDowncastError` if the object is not of the expected type.
#[inline]
pub fn cast_as<'a, 'p, D>(&'a self, py: Python<'p>) -> Result<&'a D, PyDowncastError<'p>>
where D: ::PyDowncastFrom
{
<D as ::PyDowncastFrom>::downcast_from(py, &self)
}
/// Casts the PyObject to a concrete Python object type.
/// Fails with `PyDowncastError` if the object is not of the expected type.
#[inline]
pub fn cast_into<'p, D>(self, py: Python<'p>) -> Result<D, PyDowncastError<'p>>
where D: ::PyDowncastInto
{
<D as ::PyDowncastInto>::downcast_into(py, self)
}
/// Casts the PyObject to a concrete Python object type.
/// Fails with `PyDowncastError` if the object is not of the expected type.
#[inline]
pub fn unchecked_cast_into<'p, D>(self) -> D where D: ::PyDowncastInto
{
<D as ::PyDowncastInto>::unchecked_downcast_into(self)
}
/// Extracts some type from the Python object.
/// This is a wrapper function around `FromPyObject::extract()`.
#[inline]
pub fn extract<'a, D>(&'a self, py: Python) -> PyResult<D> where D: FromPyObject<'a>
{
FromPyObject::extract(py, &self)
}
pub fn get_refcnt(&self) -> isize {
unsafe { ffi::Py_REFCNT(self.0.as_ptr()) }
}
#[inline]
pub unsafe fn drop_ref(&mut self) {
self.0.drop_ref();
}
}
impl<'p> PartialEq for PyObject {
#[inline]
fn eq(&self, other: &PyObject) -> bool {
self.as_ptr() == other.as_ptr()
}
}

View File

@ -3,10 +3,11 @@
// based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython
use ffi;
use pointers::PyPtr;
use python::{Python, ToPyPointer, PyDowncastFrom, PyDowncastInto};
use pointer::PyObject;
use instance::PyObjectWithToken;
use python::{Python, ToPyPointer, PyDowncastFrom};
use conversion::{FromPyObject, ToPyObject};
use objects::{PyObject, PyList, PyTuple};
use objects::{PyInstance, PyList, PyTuple};
use ffi::Py_ssize_t;
use err;
use err::{PyErr, PyResult};
@ -15,18 +16,19 @@ use objectprotocol::ObjectProtocol;
/// Represents a reference to a python object supporting the sequence protocol.
pub struct PySequence(PyPtr);
pub struct PySequence(PyObject);
pyobject_nativetype!(PySequence);
pyobject_downcast!(PySequence, PySequence_Check);
impl PySequence {
/// Returns the number of objects in sequence. This is equivalent to Python `len()`.
#[inline]
pub fn len(&self, py: Python) -> PyResult<isize> {
let v = unsafe { ffi::PySequence_Size(self.0.as_ptr()) };
pub fn len(&self) -> PyResult<isize> {
let v = unsafe { ffi::PySequence_Size(self.as_ptr()) };
if v == -1 {
Err(PyErr::fetch(py))
Err(PyErr::fetch(self.token()))
} else {
Ok(v as isize)
}
@ -34,10 +36,10 @@ impl PySequence {
/// Return the concatenation of o1 and o2. Equivalent to python `o1 + o2`
#[inline]
pub fn concat(&self, py: Python, other: &PySequence) -> PyResult<PySequence> {
pub fn concat(&self, other: &PySequence) -> PyResult<&PySequence> {
unsafe {
Ok(PySequence(PyPtr::from_owned_ptr_or_err(
py, ffi::PySequence_Concat(self.as_ptr(), other.as_ptr()))?))
self.token().cast_from_ptr_or_err::<PySequence>(
ffi::PySequence_Concat(self.as_ptr(), other.as_ptr()))
}
}
@ -45,49 +47,57 @@ impl PySequence {
/// Equivalent to python `o * count`
/// NB: Python accepts negative counts; it returns an empty Sequence.
#[inline]
pub fn repeat(&self, py: Python, count: isize) -> PyResult<PySequence> {
pub fn repeat(&self, count: isize) -> PyResult<&PySequence> {
unsafe {
Ok(PySequence(PyPtr::from_owned_ptr_or_err(
py, ffi::PySequence_Repeat(self.as_ptr(), count as Py_ssize_t))?))
self.token().cast_from_ptr_or_err::<PySequence>(
ffi::PySequence_Repeat(self.as_ptr(), count as Py_ssize_t))
}
}
/// Return the concatenation of o1 and o2 on success. Equivalent to python `o1 += o2`
/// Concatenate of o1 and o2 on success. Equivalent to python `o1 += o2`
#[inline]
pub fn in_place_concat(&self, py: Python, other: &PySequence) -> PyResult<PySequence> {
pub fn in_place_concat(&self, other: &PySequence) -> PyResult<()> {
unsafe {
Ok(PySequence(PyPtr::from_owned_ptr_or_err(
py, ffi::PySequence_InPlaceConcat(self.0.as_ptr(), other.as_ptr()))?))
let ptr = ffi::PySequence_InPlaceConcat(self.as_ptr(), other.as_ptr());
if ptr.is_null() {
Err(PyErr::fetch(self.token()))
} else {
Ok(())
}
}
}
/// Return the result of repeating sequence object o count times.
/// Repeate sequence object o count times and store in self.
/// Equivalent to python `o *= count`
/// NB: Python accepts negative counts; it empties the Sequence.
#[inline]
pub fn in_place_repeat(&self, py: Python, count: isize) -> PyResult<PySequence> {
pub fn in_place_repeat(&self, count: isize) -> PyResult<()> {
unsafe {
Ok(PySequence(PyPtr::from_owned_ptr_or_err(
py, ffi::PySequence_InPlaceRepeat(self.as_ptr(), count as Py_ssize_t))?))
let ptr = ffi::PySequence_InPlaceRepeat(self.as_ptr(), count as Py_ssize_t);
if ptr.is_null() {
Err(PyErr::fetch(self.token()))
} else {
Ok(())
}
}
}
/// Return the ith element of the Sequence. Equivalent to python `o[index]`
#[inline]
pub fn get_item(&self, py: Python, index: isize) -> PyResult<PyObject> {
pub fn get_item(&self, index: isize) -> PyResult<&PyInstance> {
unsafe {
PyObject::from_owned_ptr_or_err(
py, ffi::PySequence_GetItem(self.as_ptr(), index as Py_ssize_t))
self.token().cast_from_ptr_or_err(
ffi::PySequence_GetItem(self.as_ptr(), index as Py_ssize_t))
}
}
/// Return the slice of sequence object o between begin and end.
/// This is the equivalent of the Python expression `o[begin:end]`
#[inline]
pub fn get_slice(&self, py: Python, begin: isize, end: isize) -> PyResult<PyObject> {
pub fn get_slice(&self, begin: isize, end: isize) -> PyResult<&PyInstance> {
unsafe {
PyObject::from_owned_ptr_or_err(
py, ffi::PySequence_GetSlice(
self.token().cast_from_ptr_or_err(
ffi::PySequence_GetSlice(
self.as_ptr(), begin as Py_ssize_t, end as Py_ssize_t))
}
}
@ -95,9 +105,10 @@ impl PySequence {
/// Assign object v to the ith element of o.
/// Equivalent to Python statement `o[i] = v`
#[inline]
pub fn set_item(&self, py: Python, i: isize, v: &PyObject) -> PyResult<()> {
pub fn set_item(&self, i: isize, v: &PyInstance) -> PyResult<()> {
unsafe {
err::error_on_minusone(py,
err::error_on_minusone(
self.token(),
ffi::PySequence_SetItem(self.as_ptr(), i as Py_ssize_t, v.as_ptr()))
}
}
@ -105,9 +116,10 @@ impl PySequence {
/// Delete the ith element of object o.
/// Python statement `del o[i]`
#[inline]
pub fn del_item(&self, py: Python, i: isize) -> PyResult<()> {
pub fn del_item(&self, i: isize) -> PyResult<()> {
unsafe {
err::error_on_minusone(py,
err::error_on_minusone(
self.token(),
ffi::PySequence_DelItem(self.as_ptr(), i as Py_ssize_t))
}
}
@ -115,10 +127,10 @@ impl PySequence {
/// Assign the sequence object v to the slice in sequence object o from i1 to i2.
/// This is the equivalent of the Python statement `o[i1:i2] = v`
#[inline]
pub fn set_slice(&self, py: Python, i1: isize, i2: isize, v: &PyObject) -> PyResult<()> {
pub fn set_slice(&self, i1: isize, i2: isize, v: &PyInstance) -> PyResult<()> {
unsafe {
err::error_on_minusone(
py, ffi::PySequence_SetSlice(
self.token(), ffi::PySequence_SetSlice(
self.as_ptr(), i1 as Py_ssize_t, i2 as Py_ssize_t, v.as_ptr()))
}
}
@ -126,24 +138,24 @@ impl PySequence {
/// Delete the slice in sequence object o from i1 to i2.
/// equivalent of the Python statement `del o[i1:i2]`
#[inline]
pub fn del_slice(&self, py: Python, i1: isize, i2: isize) -> PyResult<()> {
pub fn del_slice(&self, i1: isize, i2: isize) -> PyResult<()> {
unsafe {
err::error_on_minusone(
py, ffi::PySequence_DelSlice(self.as_ptr(), i1 as Py_ssize_t, i2 as Py_ssize_t))
self.token(),
ffi::PySequence_DelSlice(self.as_ptr(), i1 as Py_ssize_t, i2 as Py_ssize_t))
}
}
/// Return the number of occurrences of value in o, that is, return the number of keys for
/// which `o[key] == value`
#[inline]
pub fn count<V>(&self, py: Python, value: V) -> PyResult<usize>
where V: ToPyObject
pub fn count<V>(&self, value: V) -> PyResult<usize> where V: ToPyObject
{
let r = value.with_borrowed_ptr(py, |ptr| unsafe {
let r = value.with_borrowed_ptr(self.token(), |ptr| unsafe {
ffi::PySequence_Count(self.as_ptr(), ptr)
});
if r == -1 {
Err(PyErr::fetch(py))
Err(PyErr::fetch(self.token()))
} else {
Ok(r as usize)
}
@ -151,30 +163,28 @@ impl PySequence {
/// Determine if o contains value. this is equivalent to the Python expression `value in o`
#[inline]
pub fn contains<V>(&self, py: Python, value: V) -> PyResult<bool>
where V: ToPyObject
pub fn contains<V>(&self, value: V) -> PyResult<bool> where V: ToPyObject
{
let r = value.with_borrowed_ptr(py, |ptr| unsafe {
let r = value.with_borrowed_ptr(self.token(), |ptr| unsafe {
ffi::PySequence_Contains(self.as_ptr(), ptr)
});
match r {
0 => Ok(false),
1 => Ok(true),
_ => Err(PyErr::fetch(py))
_ => Err(PyErr::fetch(self.token()))
}
}
/// Return the first index i for which o[i] == value.
/// This is equivalent to the Python expression `o.index(value)`
#[inline]
pub fn index<V>(&self, py: Python, value: V) -> PyResult<usize>
where V: ToPyObject
pub fn index<V>(&self, value: V) -> PyResult<usize> where V: ToPyObject
{
let r = value.with_borrowed_ptr(py, |ptr| unsafe {
let r = value.with_borrowed_ptr(self.token(), |ptr| unsafe {
ffi::PySequence_Index(self.as_ptr(), ptr)
});
if r == -1 {
Err(PyErr::fetch(py))
Err(PyErr::fetch(self.token()))
} else {
Ok(r as usize)
}
@ -182,29 +192,26 @@ impl PySequence {
/// Return a fresh list based on the Sequence.
#[inline]
pub fn list(&self, py: Python) -> PyResult<PyList> {
pub fn list<'p>(&self, py: Python<'p>) -> PyResult<&'p PyList> {
unsafe {
Ok(PyList::downcast_from_ptr(
py, ffi::PySequence_List(self.as_ptr()))?)
py.cast_from_ptr_or_err(ffi::PySequence_List(self.as_ptr()))
}
}
/// Return a fresh tuple based on the Sequence.
#[inline]
pub fn tuple(&self, py: Python) -> PyResult<PyTuple> {
pub fn tuple<'p>(&self, py: Python<'p>) -> PyResult<&'p PyTuple> {
unsafe {
Ok(PyTuple::downcast_from_ptr(
py, ffi::PySequence_Tuple(self.as_ptr()))?)
py.cast_from_ptr_or_err(ffi::PySequence_Tuple(self.as_ptr()))
}
}
}
impl<'source, T> FromPyObject<'source> for Vec<T>
where for<'a> T: FromPyObject<'a>
impl<'a, T> FromPyObject<'a> for Vec<T> where T: FromPyObject<'a>
{
default fn extract(py: Python, obj: &'source PyObject) -> PyResult<Self> {
extract_sequence(py, obj)
default fn extract(obj: &'a PyInstance) -> PyResult<Self> {
extract_sequence(obj)
}
}
@ -212,7 +219,7 @@ impl<'source, T> FromPyObject<'source> for Vec<T>
impl <'source, T> FromPyObject<'source> for Vec<T>
where for<'a> T: FromPyObject<'a> + buffer::Element + Copy
{
fn extract(py: Python, obj: &'source PyObject) -> PyResult<Self> {
fn extract(py: Python, obj: &'source PyInstance) -> PyResult<Self> {
// first try buffer protocol
if let Ok(buf) = buffer::PyBuffer::get(py, obj) {
if buf.dimensions() == 1 {
@ -228,21 +235,21 @@ impl <'source, T> FromPyObject<'source> for Vec<T>
}
}*/
fn extract_sequence<T>(py: Python, obj: &PyObject) -> PyResult<Vec<T>>
where for<'a> T: FromPyObject<'a>
fn extract_sequence<'s, T>(obj: &'s PyInstance) -> PyResult<Vec<T>> where T: FromPyObject<'s>
{
let seq = PySequence::downcast_from(py, obj)?;
let seq = PySequence::downcast_from(obj)?;
let mut v = Vec::new();
for item in try!(seq.iter(py)) {
for item in try!(seq.iter()) {
let item = try!(item);
v.push(try!(T::extract(py, &item)));
v.push(try!(item.extract::<T>()));
}
Ok(v)
}
#[cfg(test)]
mod test {
use python::{Python, PyDowncastInto};
use instance::AsPyRef;
use python::{Python, PyDowncastFrom};
use conversion::ToPyObject;
use objects::{PySequence};
use objectprotocol::ObjectProtocol;
@ -252,7 +259,7 @@ mod test {
let gil = Python::acquire_gil();
let py = gil.python();
let v = 42i32;
assert!(v.to_object(py).cast_into::<PySequence>(py).is_err());
assert!(v.to_object(py).cast_as::<PySequence>(py).is_err());
}
#[test]
@ -260,36 +267,38 @@ mod test {
let gil = Python::acquire_gil();
let py = gil.python();
let v = "London Calling";
assert!(v.to_object(py).cast_into::<PySequence>(py).is_ok());
assert!(v.to_object(py).cast_as::<PySequence>(py).is_ok());
}
#[test]
fn test_seq_empty() {
let gil = Python::acquire_gil();
let py = gil.python();
let v : Vec<i32> = vec![];
let seq = v.to_object(py).cast_into::<PySequence>(py).unwrap();
assert_eq!(0, seq.len(py).unwrap());
let ob = v.to_object(py);
let seq = ob.cast_as::<PySequence>(py).unwrap();
assert_eq!(0, seq.len().unwrap());
let needle = 7i32.to_object(py);
assert_eq!(false, seq.contains(py, &needle).unwrap());
assert_eq!(false, seq.contains(&needle).unwrap());
}
#[test]
fn test_seq_contains() {
let gil = Python::acquire_gil();
let py = gil.python();
let v : Vec<i32> = vec![1, 1, 2, 3, 5, 8];
let seq = v.to_object(py).cast_into::<PySequence>(py).unwrap();
assert_eq!(6, seq.len(py).unwrap());
let v: Vec<i32> = vec![1, 1, 2, 3, 5, 8];
let ob = v.to_object(py);
let seq = ob.cast_as::<PySequence>(py).unwrap();
assert_eq!(6, seq.len().unwrap());
let bad_needle = 7i32.to_object(py);
assert_eq!(false, seq.contains(py, &bad_needle).unwrap());
assert_eq!(false, seq.contains(&bad_needle).unwrap());
let good_needle = 8i32.to_object(py);
assert_eq!(true, seq.contains(py, &good_needle).unwrap());
assert_eq!(true, seq.contains(&good_needle).unwrap());
let type_coerced_needle = 8f32.to_object(py);
assert_eq!(true, seq.contains(py, &type_coerced_needle).unwrap());
assert_eq!(true, seq.contains(&type_coerced_needle).unwrap());
}
#[test]
@ -297,19 +306,20 @@ mod test {
let gil = Python::acquire_gil();
let py = gil.python();
let v : Vec<i32> = vec![1, 1, 2, 3, 5, 8];
let seq = v.to_object(py).cast_into::<PySequence>(py).unwrap();
assert_eq!(1, seq.get_item(py, 0).unwrap().extract::<i32>(py).unwrap());
assert_eq!(1, seq.get_item(py, 1).unwrap().extract::<i32>(py).unwrap());
assert_eq!(2, seq.get_item(py, 2).unwrap().extract::<i32>(py).unwrap());
assert_eq!(3, seq.get_item(py, 3).unwrap().extract::<i32>(py).unwrap());
assert_eq!(5, seq.get_item(py, 4).unwrap().extract::<i32>(py).unwrap());
assert_eq!(8, seq.get_item(py, 5).unwrap().extract::<i32>(py).unwrap());
assert_eq!(8, seq.get_item(py, -1).unwrap().extract::<i32>(py).unwrap());
assert_eq!(5, seq.get_item(py, -2).unwrap().extract::<i32>(py).unwrap());
assert_eq!(3, seq.get_item(py, -3).unwrap().extract::<i32>(py).unwrap());
assert_eq!(2, seq.get_item(py, -4).unwrap().extract::<i32>(py).unwrap());
assert_eq!(1, seq.get_item(py, -5).unwrap().extract::<i32>(py).unwrap());
assert!(seq.get_item(py, 10).is_err());
let ob = v.to_object(py);
let seq = ob.cast_as::<PySequence>(py).unwrap();
assert_eq!(1, seq.get_item(0).unwrap().extract::<i32>().unwrap());
assert_eq!(1, seq.get_item(1).unwrap().extract::<i32>().unwrap());
assert_eq!(2, seq.get_item(2).unwrap().extract::<i32>().unwrap());
assert_eq!(3, seq.get_item(3).unwrap().extract::<i32>().unwrap());
assert_eq!(5, seq.get_item(4).unwrap().extract::<i32>().unwrap());
assert_eq!(8, seq.get_item(5).unwrap().extract::<i32>().unwrap());
assert_eq!(8, seq.get_item(-1).unwrap().extract::<i32>().unwrap());
assert_eq!(5, seq.get_item(-2).unwrap().extract::<i32>().unwrap());
assert_eq!(3, seq.get_item(-3).unwrap().extract::<i32>().unwrap());
assert_eq!(2, seq.get_item(-4).unwrap().extract::<i32>().unwrap());
assert_eq!(1, seq.get_item(-5).unwrap().extract::<i32>().unwrap());
assert!(seq.get_item(10).is_err());
}
// fn test_get_slice() {}
@ -320,62 +330,66 @@ mod test {
fn test_seq_del_item() {
let gil = Python::acquire_gil();
let py = gil.python();
let v : Vec<i32> = vec![1, 1, 2, 3, 5, 8];
let seq = v.to_object(py).cast_into::<PySequence>(py).unwrap();
assert!(seq.del_item(py, 10).is_err());
assert_eq!(1, seq.get_item(py, 0).unwrap().extract::<i32>(py).unwrap());
assert!(seq.del_item(py, 0).is_ok());
assert_eq!(1, seq.get_item(py, 0).unwrap().extract::<i32>(py).unwrap());
assert!(seq.del_item(py, 0).is_ok());
assert_eq!(2, seq.get_item(py, 0).unwrap().extract::<i32>(py).unwrap());
assert!(seq.del_item(py, 0).is_ok());
assert_eq!(3, seq.get_item(py, 0).unwrap().extract::<i32>(py).unwrap());
assert!(seq.del_item(py, 0).is_ok());
assert_eq!(5, seq.get_item(py, 0).unwrap().extract::<i32>(py).unwrap());
assert!(seq.del_item(py, 0).is_ok());
assert_eq!(8, seq.get_item(py, 0).unwrap().extract::<i32>(py).unwrap());
assert!(seq.del_item(py, 0).is_ok());
assert_eq!(0, seq.len(py).unwrap());
assert!(seq.del_item(py, 0).is_err());
let v: Vec<i32> = vec![1, 1, 2, 3, 5, 8];
let ob = v.to_object(py);
let seq = ob.cast_as::<PySequence>(py).unwrap();
assert!(seq.del_item(10).is_err());
assert_eq!(1, seq.get_item(0).unwrap().extract::<i32>().unwrap());
assert!(seq.del_item(0).is_ok());
assert_eq!(1, seq.get_item(0).unwrap().extract::<i32>().unwrap());
assert!(seq.del_item(0).is_ok());
assert_eq!(2, seq.get_item(0).unwrap().extract::<i32>().unwrap());
assert!(seq.del_item(0).is_ok());
assert_eq!(3, seq.get_item(0).unwrap().extract::<i32>().unwrap());
assert!(seq.del_item(0).is_ok());
assert_eq!(5, seq.get_item(0).unwrap().extract::<i32>().unwrap());
assert!(seq.del_item(0).is_ok());
assert_eq!(8, seq.get_item(0).unwrap().extract::<i32>().unwrap());
assert!(seq.del_item(0).is_ok());
assert_eq!(0, seq.len().unwrap());
assert!(seq.del_item(0).is_err());
}
#[test]
fn test_seq_index() {
let gil = Python::acquire_gil();
let py = gil.python();
let v : Vec<i32> = vec![1, 1, 2, 3, 5, 8];
let seq = v.to_object(py).cast_into::<PySequence>(py).unwrap();
assert_eq!(0, seq.index(py, 1i32).unwrap());
assert_eq!(2, seq.index(py, 2i32).unwrap());
assert_eq!(3, seq.index(py, 3i32).unwrap());
assert_eq!(4, seq.index(py, 5i32).unwrap());
assert_eq!(5, seq.index(py, 8i32).unwrap());
assert!(seq.index(py, 42i32).is_err());
let v: Vec<i32> = vec![1, 1, 2, 3, 5, 8];
let ob = v.to_object(py);
let seq = ob.cast_as::<PySequence>(py).unwrap();
assert_eq!(0, seq.index(1i32).unwrap());
assert_eq!(2, seq.index(2i32).unwrap());
assert_eq!(3, seq.index(3i32).unwrap());
assert_eq!(4, seq.index(5i32).unwrap());
assert_eq!(5, seq.index(8i32).unwrap());
assert!(seq.index(42i32).is_err());
}
#[test]
fn test_seq_count() {
let gil = Python::acquire_gil();
let py = gil.python();
let v : Vec<i32> = vec![1, 1, 2, 3, 5, 8];
let seq = v.to_object(py).cast_into::<PySequence>(py).unwrap();
assert_eq!(2, seq.count(py, 1i32).unwrap());
assert_eq!(1, seq.count(py, 2i32).unwrap());
assert_eq!(1, seq.count(py, 3i32).unwrap());
assert_eq!(1, seq.count(py, 5i32).unwrap());
assert_eq!(1, seq.count(py, 8i32).unwrap());
assert_eq!(0, seq.count(py, 42i32).unwrap());
let v: Vec<i32> = vec![1, 1, 2, 3, 5, 8];
let ob = v.to_object(py);
let seq = ob.cast_as::<PySequence>(py).unwrap();
assert_eq!(2, seq.count(1i32).unwrap());
assert_eq!(1, seq.count(2i32).unwrap());
assert_eq!(1, seq.count(3i32).unwrap());
assert_eq!(1, seq.count(5i32).unwrap());
assert_eq!(1, seq.count(8i32).unwrap());
assert_eq!(0, seq.count(42i32).unwrap());
}
#[test]
fn test_seq_iter() {
let gil = Python::acquire_gil();
let py = gil.python();
let v : Vec<i32> = vec![1, 1, 2, 3, 5, 8];
let seq = v.to_object(py).cast_into::<PySequence>(py).unwrap();
let v: Vec<i32> = vec![1, 1, 2, 3, 5, 8];
let ob = v.to_object(py);
let seq = ob.cast_as::<PySequence>(py).unwrap();
let mut idx = 0;
for el in seq.iter(py).unwrap() {
assert_eq!(v[idx], el.unwrap().extract::<i32>(py).unwrap());
for el in seq.iter().unwrap() {
assert_eq!(v[idx], el.unwrap().extract::<i32>().unwrap());
idx += 1;
}
assert_eq!(idx, v.len());
@ -386,13 +400,14 @@ mod test {
let gil = Python::acquire_gil();
let py = gil.python();
let v = vec!["It", "was", "the", "worst", "of", "times"];
let seq = v.to_object(py).cast_into::<PySequence>(py).unwrap();
let ob = v.to_object(py);
let seq = ob.cast_as::<PySequence>(py).unwrap();
let bad_needle = "blurst".to_object(py);
assert_eq!(false, seq.contains(py, bad_needle).unwrap());
assert_eq!(false, seq.contains(bad_needle).unwrap());
let good_needle = "worst".to_object(py);
assert_eq!(true, seq.contains(py, good_needle).unwrap());
assert_eq!(true, seq.contains(good_needle).unwrap());
}
#[test]
@ -400,12 +415,13 @@ mod test {
let gil = Python::acquire_gil();
let py = gil.python();
let v : Vec<i32> = vec![1, 2, 3];
let seq = v.to_object(py).cast_into::<PySequence>(py).unwrap();
let concat_seq = seq.concat(py, &seq).unwrap();
assert_eq!(6, concat_seq.len(py).unwrap());
let ob = v.to_object(py);
let seq = ob.cast_as::<PySequence>(py).unwrap();
let concat_seq = seq.concat(&seq).unwrap();
assert_eq!(6, concat_seq.len().unwrap());
let concat_v : Vec<i32> = vec![1, 2, 3, 1, 2, 3];
for (el, cc) in seq.iter(py).unwrap().zip(concat_v) {
assert_eq!(cc, el.unwrap().extract::<i32>(py).unwrap());
for (el, cc) in concat_seq.iter().unwrap().zip(concat_v) {
assert_eq!(cc, el.unwrap().extract::<i32>().unwrap());
}
}
@ -414,9 +430,10 @@ mod test {
let gil = Python::acquire_gil();
let py = gil.python();
let v = "string";
let seq = v.to_object(py).cast_into::<PySequence>(py).unwrap();
let concat_seq = seq.concat(py, &seq).unwrap();
assert_eq!(12, concat_seq.len(py).unwrap());
let ob = v.to_object(py);
let seq = ob.cast_as::<PySequence>(py).unwrap();
let concat_seq = seq.concat(&seq).unwrap();
assert_eq!(12, concat_seq.len().unwrap());
/*let concat_v = "stringstring".to_owned();
for (el, cc) in seq.iter(py).unwrap().zip(concat_v.chars()) {
assert_eq!(cc, el.unwrap().extract::<char>(py).unwrap()); //TODO: extract::<char>() is not implemented
@ -428,12 +445,13 @@ mod test {
let gil = Python::acquire_gil();
let py = gil.python();
let v = vec!["foo", "bar"];
let seq = v.to_object(py).cast_into::<PySequence>(py).unwrap();
let repeat_seq = seq.repeat(py, 3).unwrap();
assert_eq!(6, repeat_seq.len(py).unwrap());
let ob = v.to_object(py);
let seq = ob.cast_as::<PySequence>(py).unwrap();
let repeat_seq = seq.repeat(3).unwrap();
assert_eq!(6, repeat_seq.len().unwrap());
let repeated = vec!["foo", "bar", "foo", "bar", "foo", "bar"];
for (el, rpt) in seq.iter(py).unwrap().zip(repeated.iter()) {
assert_eq!(*rpt, el.unwrap().extract::<String>(py).unwrap());
for (el, rpt) in repeat_seq.iter().unwrap().zip(repeated.iter()) {
assert_eq!(*rpt, el.unwrap().extract::<String>().unwrap());
}
}
@ -442,7 +460,8 @@ mod test {
let gil = Python::acquire_gil();
let py = gil.python();
let v = vec!["foo", "bar"];
let seq = v.to_object(py).cast_into::<PySequence>(py).unwrap();
let ob = v.to_object(py);
let seq = ob.cast_as::<PySequence>(py).unwrap();
assert!(seq.list(py).is_ok());
}
@ -451,7 +470,8 @@ mod test {
let gil = Python::acquire_gil();
let py = gil.python();
let v = "foo";
let seq = PySequence::downcast_into(py, v.to_object(py)).unwrap();
let ob = v.to_object(py);
let seq = PySequence::downcast_from(ob.as_ref(py)).unwrap();
assert!(seq.list(py).is_ok());
}
@ -460,7 +480,8 @@ mod test {
let gil = Python::acquire_gil();
let py = gil.python();
let v = ("foo", "bar");
let seq = v.to_object(py).cast_into::<PySequence>(py).unwrap();
let ob = v.to_object(py);
let seq = ob.cast_as::<PySequence>(py).unwrap();
assert!(seq.tuple(py).is_ok());
}
@ -469,7 +490,8 @@ mod test {
let gil = Python::acquire_gil();
let py = gil.python();
let v = vec!["foo", "bar"];
let seq = v.to_object(py).cast_into::<PySequence>(py).unwrap();
let ob = v.to_object(py);
let seq = ob.cast_as::<PySequence>(py).unwrap();
assert!(seq.tuple(py).is_ok());
}
@ -477,7 +499,7 @@ mod test {
fn test_extract_tuple_to_vec() {
let gil = Python::acquire_gil();
let py = gil.python();
let v: Vec<i32> = py.eval("(1, 2)", None, None).unwrap().extract(py).unwrap();
let v: Vec<i32> = py.eval("(1, 2)", None, None).unwrap().extract().unwrap();
assert!(v == [1, 2]);
}
@ -485,7 +507,7 @@ mod test {
fn test_extract_range_to_vec() {
let gil = Python::acquire_gil();
let py = gil.python();
let v: Vec<i32> = py.eval("range(1, 5)", None, None).unwrap().extract(py).unwrap();
let v: Vec<i32> = py.eval("range(1, 5)", None, None).unwrap().extract().unwrap();
assert!(v == [1, 2, 3, 4]);
}
@ -493,7 +515,7 @@ mod test {
fn test_extract_bytearray_to_vec() {
let gil = Python::acquire_gil();
let py = gil.python();
let v: Vec<u8> = py.eval("bytearray(b'abc')", None, None).unwrap().extract(py).unwrap();
let v: Vec<u8> = py.eval("bytearray(b'abc')", None, None).unwrap().extract().unwrap();
assert!(v == b"abc");
}
}

View File

@ -4,78 +4,77 @@
use std::{hash, collections};
use ffi;
use python::{Python, ToPyPointer};
use pointers::PyPtr;
use pointer::PyObject;
use conversion::ToPyObject;
use objects::PyObject;
use instance::{AsPyRef, Py, PyObjectWithToken};
use err::{self, PyResult, PyErr};
/// Represents a Python `set`
pub struct PySet(PyPtr);
pub struct PySet(PyObject);
/// Represents a Python `frozenset`
pub struct PyFrozenSet(PyPtr);
pub struct PyFrozenSet(PyObject);
pyobject_convert!(PySet);
pyobject_nativetype!(PySet, PySet_Type, PySet_Check);
pyobject_convert!(PyFrozenSet);
pyobject_nativetype!(PySet, PySet_Type, PySet_Check);
pyobject_nativetype!(PyFrozenSet, PyFrozenSet_Type, PyFrozenSet_Check);
impl PySet {
/// Creates a new set.
///
/// May panic when running out of memory.
pub fn new<T: ToPyObject>(py: Python, elements: &[T]) -> PySet {
pub fn new<T: ToPyObject>(py: Python, elements: &[T]) -> Py<PySet> {
let list = elements.to_object(py);
unsafe {
let ptr = ffi::PySet_New(list.as_ptr());
PySet(PyPtr::from_owned_ptr_or_panic(ptr))
Py::from_owned_ptr_or_panic(ffi::PySet_New(list.as_ptr()))
}
}
/// Remove all elements from the set.
#[inline]
pub fn clear(&self, _py: Python) {
pub fn clear(&self) {
unsafe { ffi::PySet_Clear(self.as_ptr()); }
}
/// Return the number of items in the set.
/// This is equivalent to len(p) on a set.
#[inline]
pub fn len(&self, _py: Python) -> usize {
pub fn len(&self) -> usize {
unsafe { ffi::PySet_Size(self.as_ptr()) as usize }
}
/// Determine if the set contains the specified key.
/// This is equivalent to the Python expression `key in self`.
pub fn contains<K>(&self, py: Python, key: K) -> PyResult<bool> where K: ToPyObject {
key.with_borrowed_ptr(py, |key| unsafe {
pub fn contains<K>(&self, key: K) -> PyResult<bool> where K: ToPyObject {
key.with_borrowed_ptr(self.token(), |key| unsafe {
match ffi::PySet_Contains(self.as_ptr(), key) {
1 => Ok(true),
0 => Ok(false),
_ => Err(PyErr::fetch(py))
_ => Err(PyErr::fetch(self.token()))
}
})
}
/// Remove element from the set if it is present.
pub fn discard<K>(&self, py: Python, key: K) where K: ToPyObject {
key.with_borrowed_ptr(py, |key| unsafe {
pub fn discard<K>(&self, key: K) where K: ToPyObject {
key.with_borrowed_ptr(self.token(), |key| unsafe {
ffi::PySet_Discard(self.as_ptr(), key);
})
}
/// Add element to the set.
pub fn add<K>(&self, py: Python, key: K) -> PyResult<()> where K: ToPyObject {
key.with_borrowed_ptr(py, move |key| unsafe {
err::error_on_minusone(py, ffi::PySet_Add(self.as_ptr(), key))
pub fn add<K>(&self, key: K) -> PyResult<()> where K: ToPyObject {
key.with_borrowed_ptr(self.token(), move |key| unsafe {
err::error_on_minusone(self.token(), ffi::PySet_Add(self.as_ptr(), key))
})
}
/// Remove and return an arbitrary element from the set
pub fn pop(&self, py: Python) -> Option<PyObject> {
pub fn pop(&self) -> Option<PyObject> {
unsafe {
PyObject::from_borrowed_ptr_or_opt(py, ffi::PySet_Pop(self.as_ptr()))
PyObject::from_owned_ptr_or_opt(self.token(), ffi::PySet_Pop(self.as_ptr()))
}
}
}
@ -85,8 +84,11 @@ impl<T> ToPyObject for collections::HashSet<T>
{
fn to_object(&self, py: Python) -> PyObject {
let set = PySet::new::<T>(py, &[]);
for val in self {
set.add(py, val).expect("Failed to add to set");
{
let s = set.as_ref(py);
for val in self {
s.add(val).expect("Failed to add to set");
}
}
set.into()
}
@ -97,8 +99,11 @@ impl<T> ToPyObject for collections::BTreeSet<T>
{
fn to_object(&self, py: Python) -> PyObject {
let set = PySet::new::<T>(py, &[]);
for val in self {
set.add(py, val).expect("Failed to add to set");
{
let s = set.as_ref(py);
for val in self {
s.add(val).expect("Failed to add to set");
}
}
set.into()
}
@ -108,29 +113,28 @@ impl PyFrozenSet {
/// Creates a new frozenset.
///
/// May panic when running out of memory.
pub fn new<T: ToPyObject>(py: Python, elements: &[T]) -> PyFrozenSet {
pub fn new<T: ToPyObject>(py: Python, elements: &[T]) -> Py<PyFrozenSet> {
let list = elements.to_object(py);
unsafe {
let ptr = ffi::PyFrozenSet_New(list.as_ptr());
PyFrozenSet(PyPtr::from_owned_ptr_or_panic(ptr))
Py::from_owned_ptr_or_panic(ffi::PyFrozenSet_New(list.as_ptr()))
}
}
/// Return the number of items in the set.
/// This is equivalent to len(p) on a set.
#[inline]
pub fn len(&self, _py: Python) -> usize {
pub fn len(&self) -> usize {
unsafe { ffi::PySet_Size(self.as_ptr()) as usize }
}
/// Determine if the set contains the specified key.
/// This is equivalent to the Python expression `key in self`.
pub fn contains<K>(&self, py: Python, key: K) -> PyResult<bool> where K: ToPyObject {
key.with_borrowed_ptr(py, |key| unsafe {
pub fn contains<K>(&self, key: K) -> PyResult<bool> where K: ToPyObject {
key.with_borrowed_ptr(self.token(), |key| unsafe {
match ffi::PySet_Contains(self.as_ptr(), key) {
1 => Ok(true),
0 => Ok(false),
_ => Err(PyErr::fetch(py))
_ => Err(PyErr::fetch(self.token()))
}
})
}
@ -139,10 +143,11 @@ impl PyFrozenSet {
#[cfg(test)]
mod test {
use std::collections::{HashSet};
use python::{Python, PyDowncastInto};
use super::{PySet, PyFrozenSet};
use python::{Python, PyDowncastFrom};
use conversion::ToPyObject;
use objectprotocol::ObjectProtocol;
use super::{PySet, PyFrozenSet};
use instance::AsPyRef;
#[test]
fn test_set_new() {
@ -150,7 +155,7 @@ mod test {
let py = gil.python();
let set = PySet::new(py, &[1]);
assert_eq!(1, set.len(py));
assert_eq!(1, set.as_ref(py).len());
}
#[test]
@ -160,22 +165,23 @@ mod test {
let mut v = HashSet::new();
let ob = v.to_object(py);
let set = PySet::downcast_into(py, ob).unwrap();
assert_eq!(0, set.len(py));
let set = PySet::downcast_from(ob.as_ref(py)).unwrap();
assert_eq!(0, set.len());
v.insert(7);
let ob = v.to_object(py);
let set2 = PySet::downcast_into(py, ob).unwrap();
assert_eq!(1, set2.len(py));
let set2 = PySet::downcast_from(ob.as_ref(py)).unwrap();
assert_eq!(1, set2.len());
}
#[test]
fn test_set_clear() {
let gil = Python::acquire_gil();
let py = gil.python();
let set = PySet::new(py, &[1]);
assert_eq!(1, set.len(py));
set.clear(py);
assert_eq!(0, set.len(py));
let ob = PySet::new(py, &[1]);
let set = ob.as_ref(py);
assert_eq!(1, set.len());
set.clear();
assert_eq!(0, set.len());
}
#[test]
@ -183,37 +189,40 @@ mod test {
let gil = Python::acquire_gil();
let py = gil.python();
let set = PySet::new(py, &[1]);
assert!(set.contains(py, 1).unwrap());
assert!(set.as_ref(py).contains(1).unwrap());
}
#[test]
fn test_set_discard() {
let gil = Python::acquire_gil();
let py = gil.python();
let set = PySet::new(py, &[1]);
set.discard(py, 2);
assert_eq!(1, set.len(py));
set.discard(py, 1);
assert_eq!(0, set.len(py));
let ob = PySet::new(py, &[1]);
let set = ob.as_ref(py);
set.discard(2);
assert_eq!(1, set.len());
set.discard(1);
assert_eq!(0, set.len());
}
#[test]
fn test_set_add() {
let gil = Python::acquire_gil();
let py = gil.python();
let set = PySet::new(py, &[1, 2]);
set.add(py, 1).unwrap(); // Add a dupliated element
assert!(set.contains(py, 1).unwrap());
let ob = PySet::new(py, &[1, 2]);
let set = ob.as_ref(py);
set.add(1).unwrap(); // Add a dupliated element
assert!(set.contains(1).unwrap());
}
#[test]
fn test_set_pop() {
let gil = Python::acquire_gil();
let py = gil.python();
let set = PySet::new(py, &[1]);
let val = set.pop(py);
let ob = PySet::new(py, &[1]);
let set = ob.as_ref(py);
let val = set.pop();
assert!(val.is_some());
let val2 = set.pop(py);
let val2 = set.pop();
assert!(val2.is_none());
}
@ -222,9 +231,10 @@ mod test {
let gil = Python::acquire_gil();
let py = gil.python();
let set = PySet::new(py, &[1]);
for el in set.iter(py).unwrap() {
assert_eq!(1i32, el.unwrap().extract::<i32>(py).unwrap());
let ob = PySet::new(py, &[1]);
let set = ob.as_ref(py);
for el in set.iter().unwrap() {
assert_eq!(1i32, el.unwrap().extract::<i32>().unwrap());
}
}
@ -233,16 +243,18 @@ mod test {
let gil = Python::acquire_gil();
let py = gil.python();
let set = PyFrozenSet::new(py, &[1]);
assert_eq!(1, set.len(py));
let ob = PyFrozenSet::new(py, &[1]);
let set = ob.as_ref(py);
assert_eq!(1, set.len());
}
#[test]
fn test_frozenset_contains() {
let gil = Python::acquire_gil();
let py = gil.python();
let set = PyFrozenSet::new(py, &[1]);
assert!(set.contains(py, 1).unwrap());
let ob = PyFrozenSet::new(py, &[1]);
let set = ob.as_ref(py);
assert!(set.contains(1).unwrap());
}
#[test]
@ -250,9 +262,10 @@ mod test {
let gil = Python::acquire_gil();
let py = gil.python();
let set = PyFrozenSet::new(py, &[1]);
for el in set.iter(py).unwrap() {
assert_eq!(1i32, el.unwrap().extract::<i32>(py).unwrap());
let ob = PyFrozenSet::new(py, &[1]);
let set = ob.as_ref(py);
for el in set.iter().unwrap() {
assert_eq!(1i32, el.unwrap().extract::<i32>().unwrap());
}
}
}

View File

@ -2,16 +2,16 @@
use std::os::raw::c_long;
use pointers::PyPtr;
use pointer::PyObject;
use python::{ToPyPointer, Python};
use err::{PyErr, PyResult};
use ffi::{self, Py_ssize_t};
use objects::PyObject;
use instance::{Py, PyObjectWithToken};
use conversion::ToPyObject;
/// Represents a Python `slice`. Only `c_long` indeces supprted
/// at the moment by `PySlice` object.
pub struct PySlice(PyPtr);
pub struct PySlice(PyObject);
pyobject_convert!(PySlice);
pyobject_nativetype!(PySlice, PySlice_Type, PySlice_Check);
@ -40,18 +40,18 @@ impl PySliceIndices {
impl PySlice {
/// Construct a new slice with the given elements.
pub fn new(_py: Python, start: isize, stop: isize, step: isize) -> PySlice {
pub fn new(_py: Python, start: isize, stop: isize, step: isize) -> Py<PySlice> {
unsafe {
let ptr = ffi::PySlice_New(ffi::PyLong_FromLong(start as i64),
ffi::PyLong_FromLong(stop as i64),
ffi::PyLong_FromLong(step as i64));
PySlice(PyPtr::from_owned_ptr_or_panic(ptr))
Py::from_owned_ptr_or_panic(ptr)
}
}
/// Retrieve the start, stop, and step indices from the slice object slice assuming a sequence of length length, and store the length of the slice in slicelength.
#[inline]
pub fn indices(&self, py: Python, length: c_long) -> PyResult<PySliceIndices> {
pub fn indices(&self, length: c_long) -> PyResult<PySliceIndices> {
// non-negative Py_ssize_t should always fit into Rust usize
unsafe {
let slicelen: isize = 0;
@ -72,7 +72,7 @@ impl PySlice {
slicelength: slicelen,
})
} else {
Err(PyErr::fetch(py))
Err(PyErr::fetch(self.token()))
}
}
}

View File

@ -8,13 +8,15 @@ use std::borrow::Cow;
use std::os::raw::c_char;
use ffi;
use pointers::PyPtr;
use instance::{Py, PyObjectWithToken};
use pointer::PyObject;
use objects::PyInstance;
use python::{ToPyPointer, Python};
use err::{PyResult, PyErr};
use super::{PyObject, PyStringData};
use super::PyStringData;
/// Represents a Python string.
pub struct PyString(PyPtr);
pub struct PyString(PyObject);
pyobject_convert!(PyString);
pyobject_nativetype!(PyString, PyUnicode_Type, PyUnicode_Check);
@ -24,46 +26,45 @@ pyobject_nativetype!(PyString, PyUnicode_Type, PyUnicode_Check);
pub use PyString as PyUnicode;
/// Represents a Python byte string.
pub struct PyBytes(PyPtr);
pub struct PyBytes(PyObject);
pyobject_convert!(PyBytes);
pyobject_nativetype!(PyBytes, PyBytes_Type, PyBytes_Check);
impl PyString {
/// Creates a new Python string object.
///
/// Panics if out of memory.
pub fn new(_py: Python, s: &str) -> PyString {
pub fn new(_py: Python, s: &str) -> Py<PyString> {
let ptr = s.as_ptr() as *const c_char;
let len = s.len() as ffi::Py_ssize_t;
unsafe {
PyString(PyPtr::from_owned_ptr_or_panic(
ffi::PyUnicode_FromStringAndSize(ptr, len)))
Py::from_owned_ptr_or_panic(ffi::PyUnicode_FromStringAndSize(ptr, len))
}
}
pub fn from_object(py: Python, src: &PyObject, encoding: &str, errors: &str)
-> PyResult<PyString> {
pub fn from_object(py: Python, src: &PyInstance, encoding: &str, errors: &str)
-> PyResult<Py<PyString>> {
unsafe {
Ok(PyString(
PyPtr::from_owned_ptr_or_err(
py, ffi::PyUnicode_FromEncodedObject(
src.as_ptr(),
encoding.as_ptr() as *const i8,
errors.as_ptr() as *const i8))?))
Ok(Py::from_owned_ptr_or_err(
py, ffi::PyUnicode_FromEncodedObject(
src.as_ptr(),
encoding.as_ptr() as *const i8,
errors.as_ptr() as *const i8))?)
}
}
/// Gets the python string data in its underlying representation.
pub fn data(&self, py: Python) -> PyStringData {
pub fn data(&self) -> PyStringData {
// TODO: return the original representation instead
// of forcing the UTF-8 representation to be created.
unsafe {
let mut size : ffi::Py_ssize_t = mem::uninitialized();
let data = ffi::PyUnicode_AsUTF8AndSize(self.0.as_ptr(), &mut size) as *const u8;
if data.is_null() {
PyErr::fetch(py).print(py);
PyErr::fetch(self.token()).print(self.token());
panic!("PyUnicode_AsUTF8AndSize failed");
}
PyStringData::Utf8(std::slice::from_raw_parts(data, size as usize))
@ -74,30 +75,30 @@ impl PyString {
///
/// Returns a `UnicodeDecodeError` if the input is not valid unicode
/// (containing unpaired surrogates).
pub fn to_string(&self, py: Python) -> PyResult<Cow<str>> {
self.data(py).to_string(py)
pub fn to_string(&self) -> PyResult<Cow<str>> {
self.data().to_string(self.token())
}
/// Convert the `PyString` into a Rust string.
///
/// Unpaired surrogates invalid UTF-8 sequences are
/// replaced with U+FFFD REPLACEMENT CHARACTER.
pub fn to_string_lossy(&self, py: Python) -> Cow<str> {
self.data(py).to_string_lossy()
pub fn to_string_lossy(&self) -> Cow<str> {
self.data().to_string_lossy()
}
}
impl PyBytes {
/// Creates a new Python byte string object.
/// The byte string is initialized by copying the data from the `&[u8]`.
///
/// Panics if out of memory.
pub fn new(_py: Python, s: &[u8]) -> PyBytes {
pub fn new(_py: Python, s: &[u8]) -> Py<PyBytes> {
let ptr = s.as_ptr() as *const c_char;
let len = s.len() as ffi::Py_ssize_t;
unsafe {
PyBytes(PyPtr::from_owned_ptr_or_panic(
ffi::PyBytes_FromStringAndSize(ptr, len)))
Py::from_owned_ptr_or_panic(ffi::PyBytes_FromStringAndSize(ptr, len))
}
}
@ -115,6 +116,7 @@ impl PyBytes {
#[cfg(test)]
mod test {
use python::Python;
use instance::AsPyRef;
use conversion::{ToPyObject, RefFromPyObject};
#[test]
@ -133,7 +135,7 @@ mod test {
let s = "Hello Python";
let py_string = s.to_object(py);
let mut called = false;
RefFromPyObject::with_extracted(py, &py_string.into(),
RefFromPyObject::with_extracted(py_string.as_ref(py),
|s2: &str| {
assert_eq!(s, s2);
called = true;

View File

@ -9,30 +9,32 @@ use std::ascii::AsciiExt;
use std::os::raw::c_char;
use ffi;
use conversion::FromPyObject;
use err::{PyResult, PyDowncastError};
use pointers::PyPtr;
use python::{Python, ToPyPointer, IntoPyPointer, PyDowncastInto, PyDowncastFrom};
use super::{PyObject, PyStringData};
use err::PyResult;
use pointer::PyObject;
use instance::{Py, PyObjectWithToken};
use python::{Python, ToPyPointer};
use objectprotocol::ObjectProtocol;
use super::{PyInstance, PyStringData};
/// Represents a Python string.
pub struct PyString(PyPtr);
pub struct PyString(PyObject);
pyobject_convert!(PyString);
pyobject_nativetype!(PyString, PyBaseString_Type);
pyobject_nativetype!(PyString, PyBaseString_Type, PyBaseString_Check);
/// Represents a Python unicode string.
pub struct PyUnicode(PyPtr);
pub struct PyUnicode(PyObject);
pyobject_convert!(PyUnicode);
pyobject_nativetype!(PyUnicode, PyUnicode_Type, PyUnicode_Check);
/// Represents a Python byte string. Corresponds to `str` in Python 2
pub struct PyBytes(PyPtr);
pub struct PyBytes(PyObject);
pyobject_convert!(PyBytes);
pyobject_nativetype!(PyBytes, PyBaseString_Type, PyString_Check);
impl PyString {
/// Creates a new Python string object.
///
@ -41,21 +43,20 @@ impl PyString {
/// Use `PyUnicode::new()` to always create a unicode string.
///
/// Panics if out of memory.
pub fn new(py: Python, s: &str) -> PyString {
pub fn new(py: Python, s: &str) -> Py<PyString> {
if s.is_ascii() {
PyBytes::new(py, s.as_bytes()).into_basestring()
PyBytes::new(py, s.as_bytes()).into()
} else {
PyUnicode::new(py, s).into_basestring()
PyUnicode::new(py, s).into()
}
}
pub fn from_object(py: Python, src: &PyObject,
encoding: &str, errors: &str) -> PyResult<PyString> {
pub fn from_object(src: &PyInstance, encoding: &str, errors: &str) -> PyResult<Py<PyString>> {
unsafe {
Ok(PyString(PyPtr::from_owned_ptr_or_err(
py, ffi::PyUnicode_FromEncodedObject(
Ok(Py::from_owned_ptr_or_err(
src.token(), ffi::PyUnicode_FromEncodedObject(
src.as_ptr(), encoding.as_ptr() as *const i8, errors.as_ptr() as *const i8))?
))
)
}
}
@ -64,12 +65,11 @@ impl PyString {
/// For Python 2 byte strings, this function always returns `PyStringData::Utf8`,
/// even if the bytes are not valid UTF-8.
/// For unicode strings, returns the underlying representation used by Python.
pub fn data(&self, py: Python) -> PyStringData {
let ob: &PyObject = self.as_ref();
if let Ok(bytes) = ob.cast_as::<PyBytes>(py) {
PyStringData::Utf8(bytes.data(py))
} else if let Ok(unicode) = ob.cast_as::<PyUnicode>(py) {
unicode.data(py)
pub fn data(&self) -> PyStringData {
if let Ok(bytes) = self.cast_as::<PyBytes>() {
PyStringData::Utf8(bytes.data())
} else if let Ok(unicode) = self.cast_as::<PyUnicode>() {
unicode.data()
} else {
panic!("PyString is neither `str` nor `unicode`")
}
@ -83,8 +83,8 @@ impl PyString {
/// Returns a `UnicodeDecodeError` if the input is not valid unicode
/// (containing unpaired surrogates, or a Python 2.7 byte string that is
/// not valid UTF-8).
pub fn to_string(&self, py: Python) -> PyResult<Cow<str>> {
self.data(py).to_string(py)
pub fn to_string(&self) -> PyResult<Cow<str>> {
self.data().to_string(self.token())
}
/// Convert the `PyString` into a Rust string.
@ -94,100 +94,8 @@ impl PyString {
///
/// Unpaired surrogates and (on Python 2.7) invalid UTF-8 sequences are
/// replaced with U+FFFD REPLACEMENT CHARACTER.
pub fn to_string_lossy(&self, py: Python) -> Cow<str> {
self.data(py).to_string_lossy()
}
#[inline]
pub fn is_base_string(ptr: *mut ffi::PyObject) -> bool {
unsafe {
ffi::PyType_FastSubclass(
ffi::Py_TYPE(ptr),
ffi::Py_TPFLAGS_STRING_SUBCLASS | ffi::Py_TPFLAGS_UNICODE_SUBCLASS) != 0
}
}
}
impl PyDowncastFrom for PyString
{
fn downcast_from<'a, 'p>(py: Python<'p>, ob: &'a PyObject)
-> Result<&'a PyString, PyDowncastError<'p>>
{
unsafe {
if PyString::is_base_string(ob.as_ptr()) {
let ptr = ob as *const _ as *mut u8 as *mut PyString;
Ok(ptr.as_ref().expect("Failed to call as_ref"))
} else {
Err(PyDowncastError(py, None))
}
}
}
}
impl PyDowncastInto for PyString
{
fn downcast_into<'p, I>(py: Python<'p>, ob: I) -> Result<Self, PyDowncastError<'p>>
where I: IntoPyPointer
{
unsafe{
let ptr = ob.into_ptr();
if PyString::is_base_string(ptr) {
Ok(PyString(PyPtr::from_owned_ptr(ptr)))
} else {
ffi::Py_DECREF(ptr);
Err(PyDowncastError(py, None))
}
}
}
fn downcast_from_ptr<'p>(py: Python<'p>, ptr: *mut ffi::PyObject)
-> Result<PyString, PyDowncastError<'p>>
{
unsafe{
if PyString::is_base_string(ptr) {
Ok(PyString(PyPtr::from_owned_ptr(ptr)))
} else {
ffi::Py_DECREF(ptr);
Err(PyDowncastError(py, None))
}
}
}
fn unchecked_downcast_into<'p, I>(ob: I) -> Self where I: IntoPyPointer
{
unsafe{
PyString(PyPtr::from_owned_ptr(ob.into_ptr()))
}
}
}
impl<'a> FromPyObject<'a> for PyString
{
/// Extracts `Self` from the source `PyObject`.
fn extract(py: Python, ob: &'a PyObject) -> PyResult<Self>
{
unsafe {
if PyString::is_base_string(ob.as_ptr()) {
Ok( PyString(PyPtr::from_borrowed_ptr(ob.as_ptr())) )
} else {
Err(PyDowncastError(py, None).into())
}
}
}
}
impl<'a> FromPyObject<'a> for &'a PyString
{
/// Extracts `Self` from the source `PyObject`.
fn extract(py: Python, ob: &'a PyObject) -> PyResult<Self>
{
unsafe {
if PyString::is_base_string(ob.as_ptr()) {
Ok(std::mem::transmute(ob))
} else {
Err(PyDowncastError(py, None).into())
}
}
pub fn to_string_lossy(&self) -> Cow<str> {
self.data().to_string_lossy()
}
}
@ -196,23 +104,16 @@ impl PyBytes {
/// The byte string is initialized by copying the data from the `&[u8]`.
///
/// Panics if out of memory.
pub fn new(_py: Python, s: &[u8]) -> PyBytes {
pub fn new(_py: Python, s: &[u8]) -> Py<PyBytes> {
let ptr = s.as_ptr() as *const c_char;
let len = s.len() as ffi::Py_ssize_t;
unsafe {
PyBytes(PyPtr::from_owned_ptr_or_panic(
ffi::PyBytes_FromStringAndSize(ptr, len)))
Py::from_owned_ptr_or_panic(ffi::PyBytes_FromStringAndSize(ptr, len))
}
}
/// Converts from `PyBytes` to `PyString`.
#[inline]
pub fn into_basestring(self) -> PyString {
<PyString as ::PyDowncastInto>::unchecked_downcast_into(self)
}
/// Gets the Python string data as byte slice.
pub fn data(&self, _py: Python) -> &[u8] {
pub fn data(&self) -> &[u8] {
unsafe {
let buffer = ffi::PyBytes_AsString(self.as_ptr()) as *const u8;
let length = ffi::PyBytes_Size(self.as_ptr()) as usize;
@ -226,36 +127,27 @@ impl PyUnicode {
/// Creates a new Python unicode string object.
///
/// Panics if out of memory.
pub fn new(_py: Python, s: &str) -> PyUnicode {
pub fn new(_py: Python, s: &str) -> Py<PyUnicode> {
let ptr = s.as_ptr() as *const c_char;
let len = s.len() as ffi::Py_ssize_t;
unsafe {
PyUnicode(PyPtr::from_owned_ptr_or_panic(
ffi::PyUnicode_FromStringAndSize(ptr, len)))
Py::from_owned_ptr_or_panic(ffi::PyUnicode_FromStringAndSize(ptr, len))
}
}
pub fn from_object(py: Python, src: &PyObject, encoding: &str, errors: &str)
-> PyResult<PyUnicode>
pub fn from_object(src: &PyInstance, encoding: &str, errors: &str) -> PyResult<Py<PyUnicode>>
{
unsafe {
Ok(PyUnicode(
PyPtr::from_owned_ptr_or_err(
py, ffi::PyUnicode_FromEncodedObject(
src.as_ptr(),
encoding.as_ptr() as *const i8,
errors.as_ptr() as *const i8))?))
Ok(Py::from_owned_ptr_or_err(
src.token(), ffi::PyUnicode_FromEncodedObject(
src.as_ptr(),
encoding.as_ptr() as *const i8,
errors.as_ptr() as *const i8))?)
}
}
/// Converts from `PyUnicode` to `PyString`.
#[inline]
pub fn into_basestring(self) -> PyString {
<PyString as ::PyDowncastInto>::unchecked_downcast_into(self)
}
/// Gets the python string data in its underlying representation.
pub fn data(&self, _py: Python) -> PyStringData {
pub fn data(&self) -> PyStringData {
unsafe {
let buffer = ffi::PyUnicode_AS_UNICODE(self.as_ptr());
let length = ffi::PyUnicode_GET_SIZE(self.as_ptr()) as usize;
@ -267,21 +159,39 @@ impl PyUnicode {
///
/// Returns a `UnicodeDecodeError` if the input is not valid unicode
/// (containing unpaired surrogates).
pub fn to_string(&self, py: Python) -> PyResult<Cow<str>> {
self.data(py).to_string(py)
pub fn to_string(&self) -> PyResult<Cow<str>> {
self.data().to_string(self.token())
}
/// Convert the `PyString` into a Rust string.
///
/// Unpaired surrogates are replaced with U+FFFD REPLACEMENT CHARACTER.
pub fn to_string_lossy(&self, py: Python) -> Cow<str> {
self.data(py).to_string_lossy()
pub fn to_string_lossy(&self) -> Cow<str> {
self.data().to_string_lossy()
}
}
/// Converts from `PyBytes` to `PyString`.
impl std::convert::From<Py<PyBytes>> for Py<PyString> {
#[inline]
fn from(ob: Py<PyBytes>) -> Py<PyString> {
<Py<PyString> as ::PyDowncastInto>::unchecked_downcast_into(ob)
}
}
/// Converts from `PyUnicode` to `PyString`.
impl std::convert::From<Py<PyUnicode>> for Py<PyString> {
#[inline]
fn from(ob: Py<PyUnicode>) -> Py<PyString> {
<Py<PyString> as ::PyDowncastInto>::unchecked_downcast_into(ob)
}
}
#[cfg(test)]
mod test {
use python::Python;
use instance::AsPyRef;
use conversion::{ToPyObject, RefFromPyObject};
#[test]
@ -300,7 +210,7 @@ mod test {
let s = "Hello Python";
let py_string = s.to_object(py);
let mut called = false;
RefFromPyObject::with_extracted(py, &py_string,
RefFromPyObject::with_extracted(py_string.as_ref(py),
|s2: &str| {
assert_eq!(s, s2);
called = true;

View File

@ -1,8 +1,10 @@
use std::borrow::Cow;
use err::PyResult;
use objects::{PyObject, PyString};
use python::{ToPyPointer, Python};
use pointer::PyObject;
use objects::{PyInstance, PyString};
use objectprotocol::ObjectProtocol;
use python::Python;
use conversion::{ToPyObject, IntoPyObject, RefFromPyObject};
/// Converts Rust `str` to Python object.
@ -52,25 +54,26 @@ impl<'a> IntoPyObject for &'a String {
/// Allows extracting strings from Python objects.
/// Accepts Python `str` and `unicode` objects.
pyobject_extract!(py, obj to Cow<'source, str> => {
try!(obj.cast_as::<PyString>(py)).to_string(py)
});
impl<'source> ::FromPyObject<'source> for Cow<'source, str>
{
fn extract(ob: &'source PyInstance) -> PyResult<Self>
{
try!(ob.cast_as::<PyString>()).to_string()
}
}
/// Allows extracting strings from Python objects.
/// Accepts Python `str` and `unicode` objects.
pyobject_extract!(py, obj to String => {
let s = try!(obj.cast_as::<PyString>(py));
s.to_string(py).map(Cow::into_owned)
let s = try!(obj.cast_as::<PyString>());
s.to_string().map(Cow::into_owned)
});
impl<'p> RefFromPyObject<'p> for str {
fn with_extracted<F, R>(py: Python, obj: &'p PyObject, f: F) -> PyResult<R>
impl RefFromPyObject for str {
fn with_extracted<F, R>(obj: &PyInstance, f: F) -> PyResult<R>
where F: FnOnce(&str) -> R
{
let p = PyObject::from_borrowed_ptr(py, obj.as_ptr());
let s = try!(p.extract::<Cow<str>>(py));
let s = try!(obj.extract::<Cow<str>>());
Ok(f(&s))
}
}

View File

@ -6,14 +6,16 @@ use std::slice;
use ffi::{self, Py_ssize_t};
use err::{PyErr, PyResult};
use pointers::PyPtr;
use instance::{Py, PyObjectWithToken};
use pointer::PyObject;
use objects::PyInstance;
use objectprotocol::ObjectProtocol;
use python::{Python, ToPyPointer, IntoPyPointer};
use conversion::{FromPyObject, ToPyObject, IntoPyTuple, IntoPyObject};
use objects::PyObject;
use super::exc;
/// Represents a Python tuple object.
pub struct PyTuple(PyPtr);
pub struct PyTuple(PyObject);
pyobject_convert!(PyTuple);
pyobject_nativetype!(PyTuple, PyTuple_Type, PyTuple_Check);
@ -22,32 +24,27 @@ pyobject_nativetype!(PyTuple, PyTuple_Type, PyTuple_Check);
impl PyTuple {
/// Construct a new tuple with the given elements.
pub fn new<T: ToPyObject>(py: Python, elements: &[T]) -> PyTuple {
pub fn new<T: ToPyObject>(py: Python, elements: &[T]) -> Py<PyTuple> {
unsafe {
let len = elements.len();
let ptr = ffi::PyTuple_New(len as Py_ssize_t);
for (i, e) in elements.iter().enumerate() {
ffi::PyTuple_SetItem(ptr, i as Py_ssize_t, e.to_object(py).into_ptr());
}
PyTuple(PyPtr::from_owned_ptr_or_panic(ptr))
Py::from_owned_ptr_or_panic(ptr)
}
}
/// Construct a new tuple with the given raw pointer
pub unsafe fn from_borrowed_ptr(_py: Python, ptr: *mut ffi::PyObject) -> PyTuple {
PyTuple(PyPtr::from_borrowed_ptr(ptr))
}
/// Retrieves the empty tuple.
pub fn empty(_py: Python) -> PyTuple {
pub fn empty(_py: Python) -> Py<PyTuple> {
unsafe {
PyTuple(PyPtr::from_owned_ptr_or_panic(ffi::PyTuple_New(0)))
Py::from_owned_ptr_or_panic(ffi::PyTuple_New(0))
}
}
/// Gets the length of the tuple.
#[inline]
pub fn len(&self, _py: Python) -> usize {
pub fn len(&self) -> usize {
unsafe {
// non-negative Py_ssize_t should always fit into Rust uint
ffi::PyTuple_GET_SIZE(self.as_ptr()) as usize
@ -57,30 +54,18 @@ impl PyTuple {
/// Gets the item at the specified index.
///
/// Panics if the index is out of range.
pub fn get_item(&self, py: Python, index: usize) -> PyObject {
pub fn get_item(&self, index: usize) -> &PyInstance {
// TODO: reconsider whether we should panic
// It's quite inconsistent that this method takes `Python` when `len()` does not.
assert!(index < self.len(py));
assert!(index < self.len());
unsafe {
PyObject::from_borrowed_ptr(
py, ffi::PyTuple_GET_ITEM(self.as_ptr(), index as Py_ssize_t))
self.token().cast_from_borrowed_ptr(
ffi::PyTuple_GET_ITEM(self.as_ptr(), index as Py_ssize_t))
}
}
/// Gets the item at the specified index.
/// Panics if the index is out of range.
pub fn into_item(self, py: Python, index: usize) -> PyObject {
assert!(index < self.len(py));
let result = unsafe {
PyObject::from_borrowed_ptr(
py, ffi::PyTuple_GET_ITEM(self.as_ptr(), index as Py_ssize_t))
};
py.release(self);
result
}
#[inline]
pub fn as_slice<'a>(&'a self, py: Python) -> &'a [PyObject] {
pub fn as_slice<'a>(&'a self) -> &'a [PyObject] {
// This is safe because PyObject has the same memory layout as *mut ffi::PyObject,
// and because tuples are immutable.
// (We don't even need a Python token, thanks to immutability)
@ -88,41 +73,42 @@ impl PyTuple {
let ptr = self.as_ptr() as *mut ffi::PyTupleObject;
PyObject::borrow_from_owned_ptr_slice(
slice::from_raw_parts(
(*ptr).ob_item.as_ptr(), self.len(py)
(*ptr).ob_item.as_ptr(), self.len()
))
}
}
#[inline]
pub fn iter(&self, py: Python) -> slice::Iter<PyObject> {
self.as_slice(py).iter()
}
#[inline]
pub unsafe fn drop_ref(&mut self) {
self.0.drop_ref();
pub fn iter(&self) -> slice::Iter<PyObject> {
self.as_slice().iter()
}
}
impl IntoPyTuple for PyTuple {
fn into_tuple(self, _py: Python) -> PyTuple {
impl<'a> IntoPyTuple for &'a PyTuple {
fn into_tuple(self, _py: Python) -> Py<PyTuple> {
self.into()
}
}
impl IntoPyTuple for Py<PyTuple> {
fn into_tuple(self, _py: Python) -> Py<PyTuple> {
self
}
}
impl<'a> IntoPyTuple for &'a str {
fn into_tuple(self, py: Python) -> PyTuple {
fn into_tuple(self, py: Python) -> Py<PyTuple> {
unsafe {
let ptr = ffi::PyTuple_New(1);
ffi::PyTuple_SetItem(ptr, 0, self.into_object(py).into_ptr());
PyTuple(PyPtr::from_owned_ptr_or_panic(ptr))
Py::from_owned_ptr_or_panic(ptr)
}
}
}
fn wrong_tuple_length(py: Python, t: &PyTuple, expected_length: usize) -> PyErr {
let msg = format!("Expected tuple of length {}, but got tuple of length {}.",
expected_length, t.len(py));
expected_length, t.len());
PyErr::new_lazy_init(
py.get_type::<exc::ValueError>(), Some(msg.into_object(py)))
}
@ -133,7 +119,7 @@ macro_rules! tuple_conversion ({$length:expr,$(($refN:ident, $n:tt, $T:ident)),+
unsafe {
let ptr = ffi::PyTuple_New($length);
$(ffi::PyTuple_SetItem(ptr, $n, self.$n.to_object(py).into_ptr());)+;
PyTuple(PyPtr::from_owned_ptr_or_panic(ptr)).into()
PyObject::from_owned_ptr_or_panic(py, ptr)
}
}
}
@ -142,32 +128,32 @@ macro_rules! tuple_conversion ({$length:expr,$(($refN:ident, $n:tt, $T:ident)),+
unsafe {
let ptr = ffi::PyTuple_New($length);
$(ffi::PyTuple_SetItem(ptr, $n, self.$n.into_object(py).into_ptr());)+;
PyTuple(PyPtr::from_owned_ptr_or_panic(ptr)).into()
PyObject::from_owned_ptr_or_panic(py, ptr)
}
}
}
impl <$($T: IntoPyObject),+> IntoPyTuple for ($($T,)+) {
fn into_tuple(self, py: Python) -> PyTuple {
fn into_tuple(self, py: Python) -> Py<PyTuple> {
unsafe {
let ptr = ffi::PyTuple_New($length);
$(ffi::PyTuple_SetItem(ptr, $n, self.$n.into_object(py).into_ptr());)+;
PyTuple(PyPtr::from_owned_ptr_or_panic(ptr))
Py::from_owned_ptr_or_panic(ptr)
}
}
}
impl<'s, $($T: FromPyObject<'s>),+> FromPyObject<'s> for ($($T,)+) {
fn extract(py: Python, obj: &'s PyObject) -> PyResult<Self>
fn extract(obj: &'s PyInstance) -> PyResult<Self>
{
let t = try!(obj.cast_as::<PyTuple>(py));
let slice = t.as_slice(py);
if t.len(py) == $length {
let t = try!(obj.cast_as::<PyTuple>());
let slice = t.as_slice();
if t.len() == $length {
Ok((
$( try!(slice[$n].extract::<$T>(py)), )+
$( try!(slice[$n].extract::<$T>(obj.token())), )+
))
} else {
Err(wrong_tuple_length(py, t, $length))
Err(wrong_tuple_length(obj.token(), t, $length))
}
}
}
@ -198,7 +184,7 @@ tuple_conversion!(9, (ref0, 0, A), (ref1, 1, B), (ref2, 2, C), (ref3, 3, D),
/// let gil = pyo3::Python::acquire_gil();
/// let py = gil.python();
/// let os = py.import("os").unwrap();
/// let pid = os.call(py, "get_pid", pyo3::NoArgs, None);
/// let pid = os.call("get_pid", pyo3::NoArgs, None);
/// ```
#[derive(Copy, Clone, Debug)]
pub struct NoArgs;
@ -221,7 +207,7 @@ impl IntoPyObject for NoArgs
/// Converts `NoArgs` to an empty Python tuple.
impl IntoPyTuple for NoArgs {
fn into_tuple(self, py: Python) -> PyTuple {
fn into_tuple(self, py: Python) -> Py<PyTuple> {
PyTuple::empty(py)
}
}
@ -229,7 +215,7 @@ impl IntoPyTuple for NoArgs {
/// Converts `()` to an empty Python tuple.
impl IntoPyTuple for () {
fn into_tuple(self, py: Python) -> PyTuple {
fn into_tuple(self, py: Python) -> Py<PyTuple> {
PyTuple::empty(py)
}
}
@ -238,11 +224,11 @@ impl IntoPyTuple for () {
/// Returns `Ok(NoArgs)` if the input is an empty Python tuple.
/// Otherwise, returns an error.
pyobject_extract!(py, obj to NoArgs => {
let t = try!(obj.cast_as::<PyTuple>(py));
if t.len(py) == 0 {
let t = try!(obj.cast_as::<PyTuple>());
if t.len() == 0 {
Ok(NoArgs)
} else {
Err(wrong_tuple_length(py, t, 0))
Err(wrong_tuple_length(obj.token(), t, 0))
}
});
@ -250,17 +236,31 @@ pyobject_extract!(py, obj to NoArgs => {
#[cfg(test)]
mod test {
use PyTuple;
use python::{Python, PyDowncastInto};
use conversion::IntoPyObject;
use instance::AsPyRef;
use python::{Python, PyDowncastFrom};
use conversion::ToPyObject;
use objects::PyInstance;
use objectprotocol::ObjectProtocol;
#[test]
fn test_new() {
let gil = Python::acquire_gil();
let py = gil.python();
let pyob = PyTuple::new(py, &[1, 2, 3]);
let ob = pyob.as_ref(py);
assert_eq!(3, ob.len());
let ob: &PyInstance = ob.into();
assert_eq!((1, 2, 3), ob.extract().unwrap());
}
#[test]
fn test_len() {
let gil = Python::acquire_gil();
let py = gil.python();
let tuple = PyTuple::downcast_into(py, (1, 2, 3).to_object(py)).unwrap();
assert_eq!(3, tuple.len(py));
assert_eq!((1, 2, 3), tuple.into_object(py).extract(py).unwrap());
let ob = (1, 2, 3).to_object(py);
let tuple = PyTuple::downcast_from(ob.as_ref(py)).unwrap();
assert_eq!(3, tuple.len());
let ob: &PyInstance = tuple.into();
assert_eq!((1, 2, 3), ob.extract().unwrap());
}
}

View File

@ -6,14 +6,14 @@ use std::ffi::CStr;
use std::borrow::Cow;
use ffi;
use pointers::PyPtr;
use pointer::PyObject;
use python::{Python, ToPyPointer};
use objects::PyObject;
use err::{PyErr, PyResult};
use instance::PyObjectWithToken;
use typeob::PyTypeObject;
/// Represents a reference to a Python type object.
pub struct PyType(PyPtr);
pub struct PyType(PyObject);
pyobject_convert!(PyType);
pyobject_nativetype!(PyType, PyType_Type, PyType_Check);
@ -30,26 +30,27 @@ impl PyType {
/// This increments the reference count on the type object.
/// Undefined behavior if the pointer is NULL or invalid.
#[inline]
pub unsafe fn from_type_ptr(_py: Python, p: *mut ffi::PyTypeObject) -> PyType {
PyType(PyPtr::from_borrowed_ptr(p as *mut ffi::PyObject))
pub unsafe fn from_type_ptr<'p>(py: Python<'p>, p: *mut ffi::PyTypeObject) -> &'p PyType
{
py.cast_from_borrowed_ptr::<PyType>(p as *mut ffi::PyObject)
}
/// Gets the name of the PyType.
pub fn name<'a>(&'a self, _py: Python) -> Cow<'a, str> {
pub fn name<'a>(&'a self) -> Cow<'a, str> {
unsafe {
CStr::from_ptr((*self.as_type_ptr()).tp_name).to_string_lossy()
}
}
/// Check whether `self` is subclass of type `T` like Python `issubclass` function
pub fn is_subclass<T>(&self, py: Python) -> PyResult<bool>
pub fn is_subclass<T>(&self) -> PyResult<bool>
where T: PyTypeObject
{
let result = unsafe {
ffi::PyObject_IsSubclass(self.as_ptr(), T::type_object(py).as_ptr())
ffi::PyObject_IsSubclass(self.as_ptr(), T::type_object(self.token()).as_ptr())
};
if result == -1 {
Err(PyErr::fetch(py))
Err(PyErr::fetch(self.token()))
} else if result == 1 {
Ok(true)
} else {
@ -58,12 +59,12 @@ impl PyType {
}
// Check whether `obj` is an instance of `self`
pub fn is_instance<T: ToPyPointer>(&self, py: Python, obj: &T) -> PyResult<bool> {
pub fn is_instance<T: ToPyPointer>(&self, obj: &T) -> PyResult<bool> {
let result = unsafe {
ffi::PyObject_IsInstance(obj.as_ptr(), self.as_ptr())
};
if result == -1 {
Err(PyErr::fetch(py))
Err(PyErr::fetch(self.token()))
} else if result == 1 {
Ok(true)
} else {
@ -71,11 +72,3 @@ impl PyType {
}
}
}
impl PartialEq for PyType {
#[inline]
fn eq(&self, other: &PyType) -> bool {
self.as_type_ptr() == other.as_type_ptr()
}
}
impl Eq for PyType { }

318
src/pointer.rs Normal file
View File

@ -0,0 +1,318 @@
// Copyright (c) 2017-present PyO3 Project and Contributors
use std;
use ffi;
use err::{PyErr, PyResult, PyDowncastError};
use instance::{AsPyRef, PyObjectWithToken};
use objects::{PyInstance, PyDict};
use conversion::{ToPyObject, IntoPyObject, IntoPyTuple, FromPyObject};
use python::{Python, PyClone, ToPyPointer, IntoPyPointer};
/// Wrapper around unsafe `*mut ffi::PyObject` pointer. Decrement ref counter on `Drop`
#[derive(Debug)]
pub struct PyObject(*mut ffi::PyObject);
// `PyPtr` is thread-safe, because any python related operations require a Python<'p> token.
unsafe impl Send for PyObject {}
unsafe impl Sync for PyObject {}
impl PyObject {
/// Creates a `PyPtr` instance for the given FFI pointer.
/// This moves ownership over the pointer into the `PyPtr`.
/// Undefined behavior if the pointer is NULL or invalid.
#[inline]
pub unsafe fn from_owned_ptr(_py: Python, ptr: *mut ffi::PyObject) -> PyObject {
debug_assert!(!ptr.is_null() && ffi::Py_REFCNT(ptr) > 0,
format!("REFCNT: {:?} - {:?}", ptr, ffi::Py_REFCNT(ptr)));
PyObject(ptr)
}
/// Cast from ffi::PyObject ptr to a concrete object.
#[inline]
pub fn from_owned_ptr_or_panic(py: Python, ptr: *mut ffi::PyObject) -> PyObject
{
if ptr.is_null() {
::err::panic_after_error();
} else {
unsafe{
PyObject::from_owned_ptr(py, ptr)
}
}
}
/// Construct `PyPtr` from the result of a Python FFI call that
/// returns a new reference (owned pointer).
/// Returns `Err(PyErr)` if the pointer is `null`.
/// Unsafe because the pointer might be invalid.
pub fn from_owned_ptr_or_err(py: Python, ptr: *mut ffi::PyObject) -> PyResult<PyObject>
{
if ptr.is_null() {
Err(PyErr::fetch(py))
} else {
Ok(unsafe{
PyObject::from_owned_ptr(py, ptr)
})
}
}
/// Construct `PyPtr` from the result of a Python FFI call that
/// returns a new reference (owned pointer).
/// Returns `None` if the pointer is `null`.
/// Unsafe because the pointer might be invalid.
pub fn from_owned_ptr_or_opt(py: Python, ptr: *mut ffi::PyObject) -> Option<PyObject>
{
if ptr.is_null() {
None
} else {
Some(unsafe{
PyObject::from_owned_ptr(py, ptr)
})
}
}
/// Creates a `PyPtr` instance for the given Python FFI pointer.
/// Calls Py_INCREF() on the ptr.
/// Undefined behavior if the pointer is NULL or invalid.
#[inline]
pub unsafe fn from_borrowed_ptr(_py: Python, ptr: *mut ffi::PyObject) -> PyObject {
debug_assert!(!ptr.is_null() && ffi::Py_REFCNT(ptr) > 0,
format!("REFCNT: {:?} - {:?}", ptr, ffi::Py_REFCNT(ptr)));
ffi::Py_INCREF(ptr);
PyObject(ptr)
}
/// Creates a `PyPtr` instance for the given Python FFI pointer.
/// Calls Py_INCREF() on the ptr.
/// Returns `Err(PyErr)` if the pointer is `null`.
/// Unsafe because the pointer might be invalid.
#[inline]
pub unsafe fn from_borrowed_ptr_or_err(py: Python, ptr: *mut ffi::PyObject)
-> PyResult<PyObject>
{
if ptr.is_null() {
Err(PyErr::fetch(py))
} else {
Ok(PyObject::from_owned_ptr(py, ptr))
}
}
/// Creates a `PyPtr` instance for the given Python FFI pointer.
/// Calls Py_INCREF() on the ptr.
/// Returns `None` if the pointer is `null`.
/// Unsafe because the pointer might be invalid.
#[inline]
pub unsafe fn from_borrowed_ptr_or_opt(py: Python, ptr: *mut ffi::PyObject)
-> Option<PyObject>
{
if ptr.is_null() {
None
} else {
Some(PyObject::from_owned_ptr(py, ptr))
}
}
/// Transmutes a slice of owned FFI pointers to `&[PyObject]`.
/// Undefined behavior if any pointer in the slice is NULL or invalid.
#[inline]
pub unsafe fn borrow_from_owned_ptr_slice<'a>(ptr: &'a [*mut ffi::PyObject])
-> &'a [PyObject] {
std::mem::transmute(ptr)
}
/// Gets the reference count of the ffi::PyObject pointer.
#[inline]
pub fn get_refcnt(&self) -> isize {
unsafe { ffi::Py_REFCNT(self.0) }
}
/// Returns whether the object is considered to be None.
/// This is equivalent to the Python expression: 'is None'
#[inline]
pub fn is_none(&self) -> bool {
unsafe { ffi::Py_None() == self.as_ptr() }
}
/// Casts the PyObject to a concrete Python object type.
/// Fails with `PyDowncastError` if the object is not of the expected type.
#[inline]
pub fn cast_as<D>(&self, py: Python) -> Result<&D, PyDowncastError>
where D: ::PyDowncastFrom
{
<D as ::PyDowncastFrom>::downcast_from(self.as_ref(py))
}
/// Extracts some type from the Python object.
/// This is a wrapper function around `FromPyObject::extract()`.
#[inline]
pub fn extract<'p, D>(&'p self, py: Python) -> PyResult<D> where D: FromPyObject<'p>
{
FromPyObject::extract(self.as_ref(py))
}
/// Calls the object.
/// This is equivalent to the Python expression: 'self(*args, **kwargs)'
#[inline]
pub fn call<A>(&self, py: Python, args: A, kwargs: Option<&PyDict>) -> PyResult<PyObject>
where A: IntoPyTuple
{
let t = args.into_tuple(py);
let result = unsafe {
PyObject::from_borrowed_ptr_or_err(
py, ffi::PyObject_Call(self.as_ptr(), t.as_ptr(), kwargs.as_ptr()))
};
py.release(t);
result
}
/// Retrieves an attribute value.
/// This is equivalent to the Python expression 'self.attr_name'.
#[inline]
pub fn getattr<N>(&self, py: Python, attr_name: N) -> PyResult<PyObject>
where N: ToPyObject
{
attr_name.with_borrowed_ptr(py, |attr_name| unsafe {
PyObject::from_owned_ptr_or_err(
py, ffi::PyObject_GetAttr(self.as_ptr(), attr_name))
})
}
/// Calls a method on the object.
/// This is equivalent to the Python expression: 'self.name(*args, **kwargs)'
#[inline]
pub fn call_method<A>(&self, py: Python,
name: &str, args: A,
kwargs: Option<&PyDict>) -> PyResult<PyObject>
where A: IntoPyTuple
{
name.with_borrowed_ptr(py, |name| unsafe {
let t = args.into_tuple(py);
let ptr = ffi::PyObject_GetAttr(self.as_ptr(), name);
let result = PyObject::from_borrowed_ptr_or_err(
py, ffi::PyObject_Call(ptr, t.as_ptr(), kwargs.as_ptr()));
py.release(t);
result
})
}
/// Calls `ffi::Py_DECREF` and sets ptr to null value.
#[inline]
pub unsafe fn drop_ref(&mut self) {
ffi::Py_DECREF(self.0);
self.0 = std::ptr::null_mut();
}
}
impl AsPyRef<PyInstance> for PyObject {
#[inline]
fn as_ref(&self, _py: Python) -> &PyInstance {
unsafe {std::mem::transmute(self)}
}
#[inline]
fn as_mut(&self, _py: Python) -> &mut PyInstance {
unsafe {std::mem::transmute(self as *const _ as *mut PyInstance)}
}
}
impl ToPyObject for PyObject
{
#[inline]
fn to_object<'p>(&self, py: Python<'p>) -> PyObject {
unsafe {PyObject::from_borrowed_ptr(py, self.as_ptr())}
}
#[inline]
fn with_borrowed_ptr<F, R>(&self, _py: Python, f: F) -> R
where F: FnOnce(*mut ffi::PyObject) -> R
{
f(self.as_ptr())
}
}
impl ToPyPointer for PyObject {
/// Gets the underlying FFI pointer, returns a borrowed pointer.
#[inline]
fn as_ptr(&self) -> *mut ffi::PyObject {
self.0
}
}
impl<'a> ToPyPointer for &'a PyObject {
/// Gets the underlying FFI pointer, returns a borrowed pointer.
#[inline]
fn as_ptr(&self) -> *mut ffi::PyObject {
self.0
}
}
impl IntoPyPointer for PyObject {
/// Gets the underlying FFI pointer, returns a owned pointer.
#[inline]
#[must_use]
fn into_ptr(self) -> *mut ffi::PyObject {
let ptr = self.0;
std::mem::forget(self);
ptr
}
}
impl PartialEq for PyObject {
#[inline]
fn eq(&self, o: &PyObject) -> bool {
self.0 == o.0
}
}
impl PyClone for PyObject {
fn clone_ref(&self, py: Python) -> Self {
unsafe {
PyObject::from_borrowed_ptr(py, self.as_ptr())
}
}
}
impl IntoPyObject for PyObject
{
#[inline]
fn into_object(self, _py: Python) -> PyObject
{
self
}
}
impl<'a> FromPyObject<'a> for PyObject
{
#[inline]
/// Extracts `Self` from the source `PyObject`.
fn extract(ob: &'a PyInstance) -> PyResult<Self>
{
unsafe {
Ok(PyObject::from_borrowed_ptr(ob.token(), ob.as_ptr()))
}
}
}
//use backtrace::Backtrace;
/// Dropping a `PyObject` instance decrements the reference count on the object by 1.
impl Drop for PyObject {
fn drop(&mut self) {
if !self.0.is_null() {
//unsafe {
//debug!("drop PyPtr: {:?} {} {:?} {:?} {:?}",
// self.0, ffi::Py_REFCNT(self.0), &self as *const _,
// std::ffi::CStr::from_ptr((*(*self.0).ob_type).tp_name).to_string_lossy(),
// &self);
//let bt = Backtrace::new();
//let bt = Backtrace::from(Vec::from(&bt.frames()[0..15]));
//println!("{:?}", bt);
//}
let _gil_guard = Python::acquire_gil();
unsafe { ffi::Py_DECREF(self.0); }
}
}
}

View File

@ -1,157 +0,0 @@
// Copyright (c) 2017-present PyO3 Project and Contributors
use std;
use ffi;
use err::{PyErr, PyResult, PyDowncastError};
use objects::PyObject;
use python::{Python, ToPyPointer, IntoPyPointer};
/// Wrapper around unsafe `*mut ffi::PyObject` pointer. Decrement ref counter on `Drop`
pub struct PyPtr(*mut ffi::PyObject);
// `PyPtr` is thread-safe, because any python related operations require a Python<'p> token.
unsafe impl Send for PyPtr {}
unsafe impl Sync for PyPtr {}
impl PyPtr {
/// Creates a `PyPtr` instance for the given FFI pointer.
/// This moves ownership over the pointer into the `PyPtr`.
/// Undefined behavior if the pointer is NULL or invalid.
#[inline]
pub unsafe fn from_owned_ptr(ptr: *mut ffi::PyObject) -> PyPtr {
debug_assert!(!ptr.is_null() && ffi::Py_REFCNT(ptr) > 0,
format!("REFCNT: {:?} - {:?}", ptr, ffi::Py_REFCNT(ptr)));
PyPtr(ptr)
}
/// Cast from ffi::PyObject ptr to a concrete object.
#[inline]
pub fn from_owned_ptr_or_panic(ptr: *mut ffi::PyObject) -> PyPtr
{
if ptr.is_null() {
::err::panic_after_error();
} else {
unsafe{
PyPtr::from_owned_ptr(ptr)
}
}
}
/// Construct `PyPtr` from the result of a Python FFI call that
/// returns a new reference (owned pointer).
/// Returns `Err(PyErr)` if the pointer is `null`.
/// Unsafe because the pointer might be invalid.
pub fn from_owned_ptr_or_err(py: Python, ptr: *mut ffi::PyObject) -> PyResult<PyPtr>
{
if ptr.is_null() {
Err(PyErr::fetch(py))
} else {
Ok(unsafe{
PyPtr::from_owned_ptr(ptr)
})
}
}
/// Creates a `PyPtr` instance for the given Python FFI pointer.
/// Calls Py_INCREF() on the ptr.
/// Undefined behavior if the pointer is NULL or invalid.
#[inline]
pub unsafe fn from_borrowed_ptr(ptr: *mut ffi::PyObject) -> PyPtr {
debug_assert!(!ptr.is_null() && ffi::Py_REFCNT(ptr) > 0,
format!("REFCNT: {:?} - {:?}", ptr, ffi::Py_REFCNT(ptr)));
ffi::Py_INCREF(ptr);
PyPtr::from_owned_ptr(ptr)
}
/// Gets the reference count of the ffi::PyObject pointer.
#[inline]
pub fn get_refcnt(&self) -> isize {
unsafe { ffi::Py_REFCNT(self.0) }
}
/// Get reference to &PyObject.
#[inline]
pub fn as_object<'p>(&self, _py: Python<'p>) -> &PyObject {
unsafe { std::mem::transmute(self) }
}
/// Converts `PyPtr` instance -> PyObject.
/// Consumes `self` without calling `Py_DECREF()`
#[inline]
pub fn into_object(self, _py: Python) -> PyObject {
unsafe { std::mem::transmute(self) }
}
/// Clone self, Calls Py_INCREF() on the ptr.
#[inline]
pub fn clone_ref(&self, _py: Python) -> PyPtr {
unsafe { PyPtr::from_borrowed_ptr(self.0) }
}
/// Casts the `PyPtr` imstance to a concrete Python object type.
/// Fails with `PyDowncastError` if the object is not of the expected type.
#[inline]
pub fn cast_into<D>(self, py: Python) -> Result<D, PyDowncastError>
where D: ::PyDowncastInto
{
<D as ::PyDowncastInto>::downcast_into(py, self)
}
/// Calls `ffi::Py_DECREF` and sets ptr to null value.
#[inline]
pub unsafe fn drop_ref(&mut self) {
ffi::Py_DECREF(self.0);
self.0 = std::ptr::null_mut();
}
}
impl ToPyPointer for PyPtr {
/// Gets the underlying FFI pointer, returns a borrowed pointer.
#[inline]
fn as_ptr(&self) -> *mut ffi::PyObject {
self.0
}
}
impl IntoPyPointer for PyPtr {
/// Gets the underlying FFI pointer, returns a owned pointer.
#[inline]
#[must_use]
fn into_ptr(self) -> *mut ffi::PyObject {
let ptr = self.0;
std::mem::forget(self);
ptr
}
}
impl PartialEq for PyPtr {
#[inline]
fn eq(&self, o: &PyPtr) -> bool {
self.0 == o.0
}
}
//use backtrace::Backtrace;
/// Dropping a `PyPtr` instance decrements the reference count on the object by 1.
impl Drop for PyPtr {
fn drop(&mut self) {
if !self.0.is_null() {
unsafe {
debug!("drop PyPtr: {:?} {} {:?} {:?} {:?}",
self.0, ffi::Py_REFCNT(self.0), &self as *const _,
std::ffi::CStr::from_ptr((*(*self.0).ob_type).tp_name).to_string_lossy(),
&self);
//let bt = Backtrace::new();
//let bt = Backtrace::from(Vec::from(&bt.frames()[0..15]));
//println!("{:?}", bt);
}
let _gil_guard = Python::acquire_gil();
unsafe { ffi::Py_DECREF(self.0); }
}
}
}

View File

@ -9,10 +9,11 @@ use std::os::raw::c_int;
use ffi;
use typeob::{PyTypeInfo, PyTypeObject, PyObjectAlloc};
use token::{Py, PyToken};
use objects::{PyObject, PyType, PyBool, PyDict, PyModule};
use instance::{Py, PyToken};
use pointer::PyObject;
use objects::{PyInstance, PyType, PyBool, PyDict, PyModule};
use err::{PyErr, PyResult, PyDowncastError, ToPyErr};
use pythonrun::GILGuard;
use pythonrun::{self, GILGuard};
/// Marker type that indicates that the GIL is currently held.
@ -33,15 +34,20 @@ pub struct Python<'p>(PhantomData<&'p GILGuard>);
pub trait PyDowncastFrom : Sized {
/// Cast from PyObject to a concrete Python object type.
fn downcast_from<'a, 'p>(Python<'p>, &'a PyObject) -> Result<&'a Self, PyDowncastError<'p>>;
fn downcast_from(&PyInstance) -> Result<&Self, PyDowncastError>;
/// Cast from PyObject to a concrete Python object type.
unsafe fn unchecked_downcast_from(&PyInstance) -> &Self;
/// Cast from PyObject to a concrete Python object type.
unsafe fn unchecked_mut_downcast_from(&PyInstance) -> &mut Self;
}
/// Trait implemented by Python object types that allow a checked downcast.
pub trait PyMutDowncastFrom : Sized {
/// Cast from PyObject to a concrete Python object type.
fn downcast_mut_from<'a, 'p>(Python<'p>, &'a mut PyObject) ->
Result<&'a mut Self, PyDowncastError<'p>>;
fn downcast_mut_from(&mut PyInstance) -> Result<&mut Self, PyDowncastError>;
}
/// Trait implemented by Python object types that allow a checked downcast.
@ -52,8 +58,8 @@ pub trait PyDowncastInto : Sized {
where I: ToPyPointer + IntoPyPointer;
/// Cast from ffi::PyObject to a concrete Python object type.
fn downcast_from_ptr<'p>(py: Python<'p>, ptr: *mut ffi::PyObject)
-> Result<Self, PyDowncastError<'p>>;
fn downcast_into_from_ptr<'p>(py: Python<'p>, ptr: *mut ffi::PyObject)
-> Result<Self, PyDowncastError<'p>>;
/// Cast from ffi::PyObject to a concrete Python object type.
fn unchecked_downcast_into<'p, I>(I) -> Self where I: IntoPyPointer;
@ -149,7 +155,7 @@ impl<'p> Python<'p> {
/// If `globals` is `None`, it defaults to Python module `__main__`.
/// If `locals` is `None`, it defaults to the value of `globals`.
pub fn eval(self, code: &str, globals: Option<&PyDict>,
locals: Option<&PyDict>) -> PyResult<PyObject> {
locals: Option<&PyDict>) -> PyResult<&'p PyInstance> {
self.run_code(code, ffi::Py_eval_input, globals, locals)
}
@ -159,8 +165,7 @@ impl<'p> Python<'p> {
/// If `locals` is `None`, it defaults to the value of `globals`.
pub fn run(self, code: &str, globals: Option<&PyDict>,
locals: Option<&PyDict>) -> PyResult<()> {
let result = self.run_code(code, ffi::Py_file_input, globals, locals)?;
self.release(result);
let _ = self.run_code(code, ffi::Py_file_input, globals, locals)?;
Ok(())
}
@ -171,7 +176,7 @@ impl<'p> Python<'p> {
/// If `globals` is `None`, it defaults to Python module `__main__`.
/// If `locals` is `None`, it defaults to the value of `globals`.
fn run_code(self, code: &str, start: c_int,
globals: Option<&PyDict>, locals: Option<&PyDict>) -> PyResult<PyObject> {
globals: Option<&PyDict>, locals: Option<&PyDict>) -> PyResult<&'p PyInstance> {
let code = CString::new(code).map_err(|e| e.to_pyerr(self))?;
unsafe {
@ -187,17 +192,17 @@ impl<'p> Python<'p> {
let res_ptr = ffi::PyRun_StringFlags(code.as_ptr(),
start, globals, locals, 0 as *mut _);
PyObject::from_owned_ptr_or_err(self, res_ptr)
self.cast_from_ptr_or_err(res_ptr)
}
}
/// Gets the Python type object for type T.
pub fn get_type<T>(self) -> PyType where T: PyTypeObject {
pub fn get_type<T>(self) -> &'p PyType where T: PyTypeObject {
T::type_object(self)
}
/// Import the Python module with the specified name.
pub fn import(self, name : &str) -> PyResult<PyModule> {
pub fn import(self, name : &str) -> PyResult<&'p PyModule> {
PyModule::import(self, name)
}
@ -211,14 +216,14 @@ impl<'p> Python<'p> {
/// Gets the Python builtin value `True`.
#[allow(non_snake_case)] // the Python keyword starts with uppercase
#[inline]
pub fn True(self) -> PyBool {
pub fn True(self) -> &'p PyBool {
PyBool::new(self, true)
}
/// Gets the Python builtin value `False`.
#[allow(non_snake_case)] // the Python keyword starts with uppercase
#[inline]
pub fn False(self) -> PyBool {
pub fn False(self) -> &'p PyBool {
PyBool::new(self, false)
}
@ -257,8 +262,8 @@ impl<'p> Python<'p> {
}
/// Check whether `obj` is an instance of type `T` like Python `isinstance` function
pub fn is_instance<T: PyTypeObject>(self, obj: &PyObject) -> PyResult<bool> {
T::type_object(self).is_instance(self, obj)
pub fn is_instance<T: PyTypeObject, V: ToPyPointer>(self, obj: &V) -> PyResult<bool> {
T::type_object(self).is_instance(obj)
}
/// Check whether type `T` is subclass of type `U` like Python `issubclass` function
@ -266,14 +271,109 @@ impl<'p> Python<'p> {
where T: PyTypeObject,
U: PyTypeObject
{
T::type_object(self).is_subclass::<U>(self)
T::type_object(self).is_subclass::<U>()
}
}
impl<'p> Python<'p> {
pub fn checked_cast_as<D>(self, obj: PyObject) -> Result<&'p D, PyDowncastError<'p>>
where D: PyDowncastFrom
{
unsafe {
let p = pythonrun::register(self, obj);
<D as PyDowncastFrom>::downcast_from(p)
}
}
pub unsafe fn cast_as<D>(self, obj: PyObject) -> &'p D
where D: PyDowncastFrom
{
let p = pythonrun::register(self, obj);
<D as PyDowncastFrom>::unchecked_downcast_from(p)
}
pub unsafe fn cast_from_ptr<D>(self, ptr: *mut ffi::PyObject) -> &'p D
where D: PyDowncastFrom
{
let obj = PyObject::from_owned_ptr_or_panic(self, ptr);
let p = pythonrun::register(self, obj);
<D as PyDowncastFrom>::unchecked_downcast_from(p)
}
pub fn cast_from_ptr_or_err<D>(self, ptr: *mut ffi::PyObject) -> PyResult<&'p D>
where D: PyDowncastFrom
{
let obj = PyObject::from_owned_ptr_or_err(self, ptr)?;
unsafe {
let p = pythonrun::register(self, obj);
Ok(<D as PyDowncastFrom>::unchecked_downcast_from(p))
}
}
pub fn cast_from_ptr_or_opt<D>(self, ptr: *mut ffi::PyObject) -> Option<&'p D>
where D: PyDowncastFrom
{
if ptr.is_null() {
None
} else {
unsafe {
let obj = PyObject::from_owned_ptr(self, ptr);
let p = pythonrun::register(self, obj);
Some(<D as PyDowncastFrom>::unchecked_downcast_from(p))
}
}
}
pub unsafe fn cast_from_borrowed_ptr<D>(self, ptr: *mut ffi::PyObject) -> &'p D
where D: PyDowncastFrom
{
let obj = PyObject::from_borrowed_ptr(self, ptr);
let p = pythonrun::register(self, obj);
<D as PyDowncastFrom>::unchecked_downcast_from(p)
}
pub unsafe fn cast_from_borrowed_ptr_or_err<D>(self, ptr: *mut ffi::PyObject)
-> PyResult<&'p D>
where D: PyDowncastFrom
{
let obj = PyObject::from_borrowed_ptr_or_err(self, ptr)?;
let p = pythonrun::register(self, obj);
Ok(<D as PyDowncastFrom>::unchecked_downcast_from(p))
}
pub unsafe fn cast_from_borrowed_ptr_or_opt<D>(self, ptr: *mut ffi::PyObject)
-> Option<&'p D>
where D: PyDowncastFrom
{
if ptr.is_null() {
None
} else {
let obj = PyObject::from_borrowed_ptr(self, ptr);
let p = pythonrun::register(self, obj);
Some(<D as PyDowncastFrom>::unchecked_downcast_from(p))
}
}
pub unsafe fn mut_cast_from_borrowed_ptr<D>(self, ptr: *mut ffi::PyObject) -> &'p mut D
where D: PyDowncastFrom
{
let obj = PyObject::from_borrowed_ptr(self, ptr);
let p = pythonrun::register(self, obj);
<D as PyDowncastFrom>::unchecked_mut_downcast_from(p)
}
pub fn track_object(self, obj: PyObject) -> &'p PyInstance
{
unsafe { pythonrun::register(self, obj) }
}
}
#[cfg(test)]
mod test {
use {Python, PyDict};
use objects::{PyBool, PyList, PyInt};
use Python;
use objectprotocol::ObjectProtocol;
use objects::{PyInstance, PyBool, PyList, PyInt, PyDict};
#[test]
fn test_eval() {
@ -281,22 +381,23 @@ mod test {
let py = gil.python();
// Make sure builtin names are accessible
let v: i32 = py.eval("min(1, 2)", None, None).unwrap().extract(py).unwrap();
let v: i32 = py.eval("min(1, 2)", None, None)
.map_err(|e| e.print(py)).unwrap().extract().unwrap();
assert_eq!(v, 1);
let d = PyDict::new(py);
d.set_item(py, "foo", 13).unwrap();
d.set_item("foo", 13).unwrap();
// Inject our own global namespace
let v: i32 = py.eval("foo + 29", Some(&d), None).unwrap().extract(py).unwrap();
let v: i32 = py.eval("foo + 29", Some(d), None).unwrap().extract().unwrap();
assert_eq!(v, 42);
// Inject our own local namespace
let v: i32 = py.eval("foo + 29", None, Some(&d)).unwrap().extract(py).unwrap();
let v: i32 = py.eval("foo + 29", None, Some(d)).unwrap().extract().unwrap();
assert_eq!(v, 42);
// Make sure builtin names are still accessible when using a local namespace
let v: i32 = py.eval("min(foo, 2)", None, Some(&d)).unwrap().extract(py).unwrap();
let v: i32 = py.eval("min(foo, 2)", None, Some(d)).unwrap().extract().unwrap();
assert_eq!(v, 2);
}
@ -304,10 +405,10 @@ mod test {
fn test_is_instance() {
let gil = Python::acquire_gil();
let py = gil.python();
assert!(py.is_instance::<PyBool>(py.True().as_ref()).unwrap());
assert!(py.is_instance::<PyBool, PyInstance>(py.True().into()).unwrap());
let list = PyList::new(py, &[1, 2, 3, 4]);
assert!(!py.is_instance::<PyBool>(list.as_ref()).unwrap());
assert!(py.is_instance::<PyList>(list.as_ref()).unwrap());
assert!(!py.is_instance::<PyBool, _>(list.as_ref()).unwrap());
assert!(py.is_instance::<PyList, _>(list.as_ref()).unwrap());
}
#[test]

View File

@ -1,24 +1,12 @@
// 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::{sync, rc, marker};
use std::{sync, rc, marker, mem};
use ffi;
use python::Python;
use python::{Python, ToPyPointer};
use pointer::PyObject;
use objects::PyInstance;
static START: sync::Once = sync::ONCE_INIT;
@ -71,6 +59,9 @@ pub fn prepare_freethreaded_python() {
// Note that the PyThreadState returned by PyEval_SaveThread is also held in TLS by the Python runtime,
// and will be restored by PyGILState_Ensure.
}
// initialize release pool
POOL = Box::into_raw(Box::new(Vec::with_capacity(250)));
});
}
@ -87,6 +78,7 @@ pub fn prepare_freethreaded_python() {
/// ```
#[must_use]
pub struct GILGuard {
pos: usize,
gstate: ffi::PyGILState_STATE,
// hack to opt out of Send on stable rust, which doesn't
// have negative impls
@ -96,11 +88,61 @@ pub struct GILGuard {
/// The Drop implementation for `GILGuard` will release the GIL.
impl Drop for GILGuard {
fn drop(&mut self) {
debug!("RELEASE");
unsafe { ffi::PyGILState_Release(self.gstate) }
unsafe {
drain(self.pos);
ffi::PyGILState_Release(self.gstate);
}
}
}
static mut POOL: *mut Vec<PyObject> = 0 as *mut _;
pub struct Pool {
pos: usize,
no_send: marker::PhantomData<rc::Rc<()>>,
}
impl Pool {
#[inline]
pub unsafe fn new() -> Pool {
let pool: &'static mut Vec<PyInstance> = mem::transmute(POOL);
Pool{ pos: pool.len(), no_send: marker::PhantomData }
}
// /// Retrieves the marker type that proves that the GIL was acquired.
// #[inline]
// pub fn python<'p>(&'p self) -> Python<'p> {
// unsafe { Python::assume_gil_acquired() }
//}
}
impl Drop for Pool {
fn drop(&mut self) {
unsafe {
drain(self.pos);
}
}
}
pub unsafe fn register<'p>(_py: Python<'p>, obj: PyObject) -> &'p PyInstance {
let pool: &'static mut Vec<PyObject> = mem::transmute(POOL);
pool.push(obj);
mem::transmute(&pool[pool.len()-1])
}
pub unsafe fn drain(pos: usize) {
let pool: &'static mut Vec<PyObject> = mem::transmute(POOL);
let len = pool.len();
if pos < len {
for ob in &mut pool[pos..len] {
ffi::Py_DECREF(ob.as_ptr());
}
pool.set_len(pos);
}
}
impl GILGuard {
/// Acquires the global interpreter lock, which allows access to the Python runtime.
///
@ -108,9 +150,13 @@ impl GILGuard {
/// See [prepare_freethreaded_python()](fn.prepare_freethreaded_python.html) for details.
pub fn acquire() -> GILGuard {
::pythonrun::prepare_freethreaded_python();
debug!("ACQUIRE");
let gstate = unsafe { ffi::PyGILState_Ensure() }; // acquire GIL
GILGuard { gstate: gstate, no_send: marker::PhantomData }
unsafe {
let gstate = ffi::PyGILState_Ensure(); // acquire GIL
let pool: &'static mut Vec<PyInstance> = mem::transmute(POOL);
GILGuard { pos: pool.len(), gstate: gstate, no_send: marker::PhantomData }
}
}
/// Retrieves the marker type that proves that the GIL was acquired.

View File

@ -5,7 +5,7 @@ use std::mem;
use std::ffi::{CStr, CString};
use std::collections::HashMap;
use {ffi, class};
use {ffi, class, pythonrun};
use err::{PyErr, PyResult};
use python::Python;
use objects::PyType;
@ -35,6 +35,9 @@ pub trait PyTypeInfo {
/// PyTypeObject instance for this type
fn type_object() -> &'static mut ffi::PyTypeObject;
/// Check `*mut ffi::PyObject` if it is the same type
fn is_instance(ptr: *mut ffi::PyObject) -> bool;
}
@ -60,6 +63,12 @@ impl<'a, T: ?Sized> PyTypeInfo for &'a T where T: PyTypeInfo {
default fn type_object() -> &'static mut ffi::PyTypeObject {
<T as PyTypeInfo>::type_object()
}
#[inline]
default fn is_instance(ptr: *mut ffi::PyObject) -> bool {
<T as PyTypeInfo>::is_instance(ptr)
}
}
pub trait PyObjectAlloc<T> {
@ -121,7 +130,7 @@ pub trait PyTypeObject {
fn init_type(py: Python);
/// Retrieves the type object for this Python object type.
fn type_object(py: Python) -> PyType;
fn type_object<'p>(py: Python<'p>) -> &'p PyType;
}
@ -133,17 +142,16 @@ impl<T> PyTypeObject for T where T: PyObjectAlloc<T> + PyTypeInfo {
if (ty.tp_flags & ffi::Py_TPFLAGS_READY) == 0 {
// automatically initialize the class on-demand
let to = initialize_type::<T>(
initialize_type::<T>(
py, None, <T as PyTypeInfo>::type_name(),
<T as PyTypeInfo>::type_description(), ty).expect(
format!("An error occurred while initializing class {}",
<T as PyTypeInfo>::type_name()).as_ref());
py.release(to);
}
}
#[inline]
default fn type_object(py: Python) -> PyType {
default fn type_object<'p>(py: Python<'p>) -> &'p PyType {
<T as PyTypeObject>::init_type(py);
unsafe { PyType::from_type_ptr(py, <T as PyTypeInfo>::type_object()) }
@ -151,9 +159,11 @@ impl<T> PyTypeObject for T where T: PyObjectAlloc<T> + PyTypeInfo {
}
pub fn initialize_type<T>(py: Python, module_name: Option<&str>, type_name: &str,
type_description: &'static str, type_object: &mut ffi::PyTypeObject)
-> PyResult<PyType>
pub fn initialize_type<'p, T>(py: Python<'p>,
module_name: Option<&str>,
type_name: &str,
type_description: &'static str,
type_object: &mut ffi::PyTypeObject) -> PyResult<&'p PyType>
where T: PyObjectAlloc<T> + PyTypeInfo
{
// type name
@ -267,6 +277,7 @@ unsafe extern "C" fn tp_dealloc_callback<T>(obj: *mut ffi::PyObject)
debug!("DEALLOC: {:?} - {:?}", obj,
CStr::from_ptr((*(*obj).ob_type).tp_name).to_string_lossy());
let guard = AbortOnDrop("Cannot unwind out of tp_dealloc");
let _pool = pythonrun::Pool::new();
let py = Python::assume_gil_acquired();
let r = <T as PyObjectAlloc<T>>::dealloc(py, obj);
mem::forget(guard);

View File

@ -1,8 +1,9 @@
extern crate compiletest_rs as compiletest;
use std::path::PathBuf;
use std::env::var;
//use std::path::PathBuf;
//use std::env::var;
/*
fn run_mode(mode: &'static str) {
let mut config = compiletest::default_config();
let cfg_mode = mode.parse().ok().expect("Invalid mode");
@ -22,4 +23,4 @@ fn run_mode(mode: &'static str) {
fn compile_tests() {
run_mode("compile-fail");
// run_mode("run-pass");
}
}*/

View File

@ -18,9 +18,9 @@ struct TestClass {
#[py::proto]
impl class::PyBufferProtocol for TestClass {
fn bf_getbuffer(&self, py: Python, view: *mut ffi::Py_buffer, flags: c_int) -> PyResult<()> {
fn bf_getbuffer(&self, view: *mut ffi::Py_buffer, flags: c_int) -> PyResult<()> {
if view == ptr::null_mut() {
return Err(PyErr::new::<exc::BufferError, _>(py, "View is null"))
return Err(PyErr::new::<exc::BufferError, _>(self.token(), "View is null"))
}
unsafe {
@ -28,7 +28,7 @@ impl class::PyBufferProtocol for TestClass {
}
if (flags & ffi::PyBUF_WRITABLE) == ffi::PyBUF_WRITABLE {
return Err(PyErr::new::<exc::BufferError, _>(py, "Object is not writable"))
return Err(PyErr::new::<exc::BufferError, _>(self.token(), "Object is not writable"))
}
let bytes = &self.vec;
@ -74,8 +74,8 @@ fn test_buffer() {
let t = py.init(|t| TestClass{vec: vec![b' ', b'2', b'3'], token: t}).unwrap();
let d = PyDict::new(py);
let _ = d.set_item(py, "ob", t);
py.run("assert bytes(ob) == b' 23'", None, Some(&d)).unwrap();
d.set_item("ob", t).unwrap();
py.run("assert bytes(ob) == b' 23'", None, Some(d)).unwrap();
}
#[cfg(not(Py_3))]
@ -87,6 +87,6 @@ fn test_buffer() {
let t = py.init(|t| TestClass{vec: vec![b' ', b'2', b'3'], token: t}).unwrap();
let d = PyDict::new(py);
let _ = d.set_item(py, "ob", t);
py.run("assert memoryview(ob).tobytes() == ' 23'", None, Some(&d)).unwrap();
d.set_item("ob", t).unwrap();
py.run("assert memoryview(ob).tobytes() == ' 23'", None, Some(d)).unwrap();
}

View File

@ -14,8 +14,8 @@ use pyo3::ffi;
macro_rules! py_run {
($py:expr, $val:ident, $code:expr) => {{
let d = PyDict::new($py);
d.set_item($py, stringify!($val), &$val).unwrap();
$py.run($code, None, Some(&d)).expect($code);
d.set_item(stringify!($val), &$val).unwrap();
$py.run($code, None, Some(d)).expect($code);
}}
}
@ -26,8 +26,8 @@ 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();
let res = $py.run($code, None, Some(&d));
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>()) {
panic!(format!("Expected {} but got {:?}", stringify!($err), err))
@ -45,7 +45,7 @@ fn empty_class() {
let py = gil.python();
let typeobj = py.get_type::<EmptyClass>();
// By default, don't allow creating instances from python.
assert!(typeobj.call(py, NoArgs, None).is_err());
assert!(typeobj.call(NoArgs, None).is_err());
py_assert!(py, typeobj, "typeobj.__name__ == 'EmptyClass'");
}
@ -59,10 +59,16 @@ struct ClassWithDocs { }
#[test]
fn class_with_docstr() {
let gil = Python::acquire_gil();
let py = gil.python();
let typeobj = py.get_type::<ClassWithDocs>();
py_run!(py, typeobj, "assert typeobj.__doc__ == 'Line1\\nLine2\\n Line3'");
{
let gil = Python::acquire_gil();
let py = gil.python();
println!("TEST1");
let typeobj = py.get_type::<ClassWithDocs>();
println!("TEST2");
py_run!(py, typeobj, "assert typeobj.__doc__ == 'Line1\\nLine2\\n Line3'");
println!("TEST3");
}
println!("TEST4");
}
#[py::class(name=CustomName)]
@ -84,11 +90,11 @@ fn empty_class_in_module() {
let gil = Python::acquire_gil();
let py = gil.python();
let module = PyModule::new(py, "test_module.nested").unwrap();
module.add_class::<EmptyClassInModule>(py).unwrap();
module.add_class::<EmptyClassInModule>().unwrap();
let ty = module.getattr(py, "EmptyClassInModule").unwrap();
assert_eq!(ty.getattr(py, "__name__").unwrap().extract::<String>(py).unwrap(), "EmptyClassInModule");
assert_eq!(ty.getattr(py, "__module__").unwrap().extract::<String>(py).unwrap(), "test_module.nested");
let ty = module.getattr("EmptyClassInModule").unwrap();
assert_eq!(ty.getattr("__name__").unwrap().extract::<String>().unwrap(), "EmptyClassInModule");
assert_eq!(ty.getattr("__module__").unwrap().extract::<String>().unwrap(), "test_module.nested");
}
#[py::class]
@ -99,8 +105,8 @@ struct EmptyClassWithNew {
#[py::methods]
impl EmptyClassWithNew {
#[__new__]
fn __new__(cls: &PyType, py: Python) -> PyResult<Py<EmptyClassWithNew>> {
Py::new(py, |t| EmptyClassWithNew{token: t})
fn __new__(cls: &PyType) -> PyResult<Py<EmptyClassWithNew>> {
Py::new(cls.token(), |t| EmptyClassWithNew{token: t})
}
}
@ -109,7 +115,7 @@ fn empty_class_with_new() {
let gil = Python::acquire_gil();
let py = gil.python();
let typeobj = py.get_type::<EmptyClassWithNew>();
assert!(typeobj.call(py, NoArgs, None).unwrap().cast_as::<EmptyClassWithNew>(py).is_ok());
assert!(typeobj.call(NoArgs, None).unwrap().cast_as::<EmptyClassWithNew>().is_ok());
}
#[py::class]
@ -121,8 +127,8 @@ struct NewWithOneArg {
#[py::methods]
impl NewWithOneArg {
#[new]
fn __new__(_cls: &PyType, py: Python, arg: i32) -> PyResult<Py<NewWithOneArg>> {
Py::new(py, |t| NewWithOneArg{_data: arg, token: t})
fn __new__(cls: &PyType, arg: i32) -> PyResult<Py<NewWithOneArg>> {
Py::new(cls.token(), |t| NewWithOneArg{_data: arg, token: t})
}
}
@ -131,8 +137,8 @@ fn new_with_one_arg() {
let gil = Python::acquire_gil();
let py = gil.python();
let typeobj = py.get_type::<NewWithOneArg>();
let wrp = typeobj.call(py, (42,), None).unwrap();
let obj = wrp.cast_as::<NewWithOneArg>(py).unwrap();
let wrp = typeobj.call((42,), None).unwrap();
let obj = wrp.cast_as::<NewWithOneArg>().unwrap();
assert_eq!(obj._data, 42);
}
@ -147,9 +153,9 @@ struct NewWithTwoArgs {
#[py::methods]
impl NewWithTwoArgs {
#[new]
fn __new__(_cls: &PyType, py: Python, arg1: i32, arg2: i32) -> PyResult<Py<NewWithTwoArgs>>
fn __new__(cls: &PyType, arg1: i32, arg2: i32) -> PyResult<Py<NewWithTwoArgs>>
{
Py::new(py, |t| NewWithTwoArgs{_data1: arg1, _data2: arg2, token: t})
Py::new(cls.token(), |t| NewWithTwoArgs{_data1: arg1, _data2: arg2, token: t})
}
}
@ -158,8 +164,8 @@ fn new_with_two_args() {
let gil = Python::acquire_gil();
let py = gil.python();
let typeobj = py.get_type::<NewWithTwoArgs>();
let wrp = typeobj.call(py, (10, 20), None).unwrap();
let obj = wrp.cast_as::<NewWithTwoArgs>(py).unwrap();
let wrp = typeobj.call((10, 20), None).unwrap();
let obj = wrp.cast_as::<NewWithTwoArgs>().unwrap();
assert_eq!(obj._data1, 10);
assert_eq!(obj._data2, 20);
}
@ -226,7 +232,7 @@ struct InstanceMethod {
#[py::methods]
impl InstanceMethod {
/// Test method
fn method(&self, py: Python) -> PyResult<i32> {
fn method(&self) -> PyResult<i32> {
Ok(self.member)
}
}
@ -237,11 +243,11 @@ fn instance_method() {
let py = gil.python();
let obj = Py::new(py, |t| InstanceMethod{member: 42, token: t}).unwrap();
assert!(obj.as_ref(py).method(py).unwrap() == 42);
assert!(obj.as_ref(py).method().unwrap() == 42);
let d = PyDict::new(py);
d.set_item(py, "obj", obj).unwrap();
py.run("assert obj.method() == 42", None, Some(&d)).unwrap();
py.run("assert obj.method.__doc__ == 'Test method'", None, Some(&d)).unwrap();
d.set_item("obj", obj).unwrap();
py.run("assert obj.method() == 42", None, Some(d)).unwrap();
py.run("assert obj.method.__doc__ == 'Test method'", None, Some(d)).unwrap();
}
#[py::class]
@ -252,22 +258,22 @@ struct InstanceMethodWithArgs {
#[py::methods]
impl InstanceMethodWithArgs {
fn method(&self, py: Python, multiplier: i32) -> PyResult<i32> {
fn method(&self, multiplier: i32) -> PyResult<i32> {
Ok(self.member * multiplier)
}
}
#[test]
//#[test]
fn instance_method_with_args() {
let gil = Python::acquire_gil();
let py = gil.python();
let obj = Py::new(py, |t| InstanceMethodWithArgs{member: 7, token: t}).unwrap();
assert!(obj.as_ref(py).method(py, 6).unwrap() == 42);
assert!(obj.as_ref(py).method(6).unwrap() == 42);
let d = PyDict::new(py);
d.set_item(py, "obj", obj).unwrap();
py.run("assert obj.method(3) == 21", None, Some(&d)).unwrap();
py.run("assert obj.method(multiplier=6) == 42", None, Some(&d)).unwrap();
d.set_item("obj", obj).unwrap();
py.run("assert obj.method(3) == 21", None, Some(d)).unwrap();
py.run("assert obj.method(multiplier=6) == 42", None, Some(d)).unwrap();
}
@ -277,13 +283,13 @@ struct ClassMethod {token: PyToken}
#[py::methods]
impl ClassMethod {
#[new]
fn __new__(cls: &PyType, py: Python) -> PyResult<Py<ClassMethod>> {
Py::new(py, |t| ClassMethod{token: t})
fn __new__(cls: &PyType) -> PyResult<Py<ClassMethod>> {
Py::new(cls.token(), |t| ClassMethod{token: t})
}
#[classmethod]
fn method(cls: &PyType, py: Python) -> PyResult<String> {
Ok(format!("{}.method()!", cls.name(py)))
fn method(cls: &PyType) -> PyResult<String> {
Ok(format!("{}.method()!", cls.name()))
}
}
@ -293,9 +299,9 @@ fn class_method() {
let py = gil.python();
let d = PyDict::new(py);
d.set_item(py, "C", py.get_type::<ClassMethod>()).unwrap();
py.run("assert C.method() == 'ClassMethod.method()!'", None, Some(&d)).unwrap();
py.run("assert C().method() == 'ClassMethod.method()!'", None, Some(&d)).unwrap();
d.set_item("C", py.get_type::<ClassMethod>()).unwrap();
py.run("assert C.method() == 'ClassMethod.method()!'", None, Some(d)).unwrap();
py.run("assert C().method() == 'ClassMethod.method()!'", None, Some(d)).unwrap();
}
@ -305,8 +311,8 @@ struct ClassMethodWithArgs{token: PyToken}
#[py::methods]
impl ClassMethodWithArgs {
#[classmethod]
fn method(cls: &PyType, py: Python, input: PyString) -> PyResult<String> {
Ok(format!("{}.method({})", cls.name(py), input))
fn method(cls: &PyType, input: &PyString) -> PyResult<String> {
Ok(format!("{}.method({})", cls.name(), input))
}
}
@ -316,8 +322,8 @@ fn class_method_with_args() {
let py = gil.python();
let d = PyDict::new(py);
d.set_item(py, "C", py.get_type::<ClassMethodWithArgs>()).unwrap();
py.run("assert C.method('abc') == 'ClassMethodWithArgs.method(abc)'", None, Some(&d)).unwrap();
d.set_item("C", py.get_type::<ClassMethodWithArgs>()).unwrap();
py.run("assert C.method('abc') == 'ClassMethodWithArgs.method(abc)'", None, Some(d)).unwrap();
}
#[py::class]
@ -328,8 +334,8 @@ struct StaticMethod {
#[py::methods]
impl StaticMethod {
#[new]
fn __new__(cls: &PyType, py: Python) -> PyResult<Py<StaticMethod>> {
Py::new(py, |t| StaticMethod{token: t})
fn __new__(cls: &PyType) -> PyResult<Py<StaticMethod>> {
Py::new(cls.token(), |t| StaticMethod{token: t})
}
#[staticmethod]
@ -345,9 +351,9 @@ fn static_method() {
assert_eq!(StaticMethod::method(py).unwrap(), "StaticMethod.method()!");
let d = PyDict::new(py);
d.set_item(py, "C", py.get_type::<StaticMethod>()).unwrap();
py.run("assert C.method() == 'StaticMethod.method()!'", None, Some(&d)).unwrap();
py.run("assert C().method() == 'StaticMethod.method()!'", None, Some(&d)).unwrap();
d.set_item("C", py.get_type::<StaticMethod>()).unwrap();
py.run("assert C.method() == 'StaticMethod.method()!'", None, Some(d)).unwrap();
py.run("assert C().method() == 'StaticMethod.method()!'", None, Some(d)).unwrap();
}
#[py::class]
@ -370,8 +376,8 @@ fn static_method_with_args() {
assert_eq!(StaticMethodWithArgs::method(py, 1234).unwrap(), "0x4d2");
let d = PyDict::new(py);
d.set_item(py, "C", py.get_type::<StaticMethodWithArgs>()).unwrap();
py.run("assert C.method(1337) == '0x539'", None, Some(&d)).unwrap();
d.set_item("C", py.get_type::<StaticMethodWithArgs>()).unwrap();
py.run("assert C.method(1337) == '0x539'", None, Some(d)).unwrap();
}
#[py::class]
@ -383,12 +389,12 @@ struct GCIntegration {
#[py::proto]
impl PyGCProtocol for GCIntegration {
fn __traverse__(&self, py: Python, visit: PyVisit) -> Result<(), PyTraverseError> {
fn __traverse__(&self, visit: PyVisit) -> Result<(), PyTraverseError> {
visit.call(&*self.self_ref.borrow())
}
fn __clear__(&mut self, py: Python) {
*self.self_ref.borrow_mut() = py.None();
fn __clear__(&mut self) {
*self.self_ref.borrow_mut() = self.token().None();
}
}
@ -399,7 +405,7 @@ fn gc_integration() {
let drop_called = Arc::new(AtomicBool::new(false));
let inst = Py::new(py, |t| GCIntegration{
self_ref: RefCell::new(py.None()),
self_ref: RefCell::new(py.None().into()),
dropped: TestDropCall { drop_called: drop_called.clone() },
token: t}).unwrap();
@ -418,7 +424,7 @@ pub struct Len {
#[py::proto]
impl PyMappingProtocol for Len {
fn __len__(&self, py: Python) -> PyResult<usize> {
fn __len__(&self) -> PyResult<usize> {
Ok(self.l)
}
}
@ -447,11 +453,11 @@ struct Iterator{
#[py::proto]
impl PyIterProtocol for Iterator {
fn __iter__(&mut self, py: Python) -> PyResult<Py<Iterator>> {
fn __iter__(&mut self) -> PyResult<Py<Iterator>> {
Ok(self.into())
}
fn __next__(&mut self, py: Python) -> PyResult<Option<i32>> {
fn __next__(&mut self) -> PyResult<Option<i32>> {
Ok(self.iter.next())
}
}
@ -471,24 +477,24 @@ struct StringMethods {token: PyToken}
#[py::proto]
impl<'p> PyObjectProtocol<'p> for StringMethods {
fn __str__(&self, py: Python) -> PyResult<&'static str> {
fn __str__(&self) -> PyResult<&'static str> {
Ok("str")
}
fn __repr__(&self, py: Python) -> PyResult<&'static str> {
fn __repr__(&self) -> PyResult<&'static str> {
Ok("repr")
}
fn __format__(&self, py: Python, format_spec: String) -> PyResult<String> {
fn __format__(&self, format_spec: String) -> PyResult<String> {
Ok(format!("format({})", format_spec))
}
fn __unicode__(&self, py: Python) -> PyResult<PyString> {
Ok(PyString::new(py, "unicode"))
fn __unicode__(&self) -> PyResult<PyObject> {
Ok(PyString::new(self.token(), "unicode").into())
}
fn __bytes__(&self, py: Python) -> PyResult<PyBytes> {
Ok(PyBytes::new(py, b"bytes"))
fn __bytes__(&self) -> PyResult<PyObject> {
Ok(PyBytes::new(self.token(), b"bytes").into())
}
}
@ -527,10 +533,10 @@ struct Comparisons {
#[py::proto]
impl PyObjectProtocol for Comparisons {
fn __hash__(&self, py: Python) -> PyResult<usize> {
fn __hash__(&self) -> PyResult<usize> {
Ok(self.val as usize)
}
fn __bool__(&self, py: Python) -> PyResult<bool> {
fn __bool__(&self) -> PyResult<bool> {
Ok(self.val != 0)
}
}
@ -561,13 +567,13 @@ struct Sequence {
#[py::proto]
impl PySequenceProtocol for Sequence {
fn __len__(&self, py: Python) -> PyResult<usize> {
fn __len__(&self) -> PyResult<usize> {
Ok(5)
}
fn __getitem__(&self, py: Python, key: isize) -> PyResult<isize> {
fn __getitem__(&self, key: isize) -> PyResult<isize> {
if key == 5 {
return Err(PyErr::new::<exc::IndexError, NoArgs>(py, NoArgs));
return Err(PyErr::new::<exc::IndexError, NoArgs>(self.token(), NoArgs));
}
Ok(key)
}
@ -591,7 +597,7 @@ struct Callable {token: PyToken}
impl Callable {
#[__call__]
fn __call__(&self, py: Python, arg: i32) -> PyResult<i32> {
fn __call__(&self, arg: i32) -> PyResult<i32> {
Ok(arg * 6)
}
}
@ -618,7 +624,7 @@ struct SetItem {
#[py::proto]
impl PyMappingProtocol<'a> for SetItem {
fn __setitem__(&mut self, py: Python, key: i32, val: i32) -> PyResult<()> {
fn __setitem__(&mut self, key: i32, val: i32) -> PyResult<()> {
self.key = key;
self.val = val;
Ok(())
@ -645,7 +651,7 @@ struct DelItem {
#[py::proto]
impl PyMappingProtocol<'a> for DelItem {
fn __delitem__(&mut self, py: Python, key: i32) -> PyResult<()> {
fn __delitem__(&mut self, key: i32) -> PyResult<()> {
self.key = key;
Ok(())
}
@ -670,12 +676,12 @@ struct SetDelItem {
#[py::proto]
impl PyMappingProtocol for SetDelItem {
fn __setitem__(&mut self, py: Python, key: i32, val: i32) -> PyResult<()> {
fn __setitem__(&mut self, key: i32, val: i32) -> PyResult<()> {
self.val = Some(val);
Ok(())
}
fn __delitem__(&mut self, py: Python, key: i32) -> PyResult<()> {
fn __delitem__(&mut self, key: i32) -> PyResult<()> {
self.val = None;
Ok(())
}
@ -698,7 +704,7 @@ struct Reversed {token: PyToken}
#[py::proto]
impl PyMappingProtocol for Reversed{
fn __reversed__(&self, py: Python) -> PyResult<&'static str> {
fn __reversed__(&self) -> PyResult<&'static str> {
Ok("I am reversed")
}
}
@ -717,7 +723,7 @@ struct Contains {token: PyToken}
#[py::proto]
impl PySequenceProtocol for Contains {
fn __contains__(&self, py: Python, item: i32) -> PyResult<bool> {
fn __contains__(&self, item: i32) -> PyResult<bool> {
Ok(item >= 0)
}
}
@ -741,19 +747,19 @@ struct UnaryArithmetic {token: PyToken}
#[py::proto]
impl PyNumberProtocol for UnaryArithmetic {
fn __neg__(&self, py: Python) -> PyResult<&'static str> {
fn __neg__(&self) -> PyResult<&'static str> {
Ok("neg")
}
fn __pos__(&self, py: Python) -> PyResult<&'static str> {
fn __pos__(&self) -> PyResult<&'static str> {
Ok("pos")
}
fn __abs__(&self, py: Python) -> PyResult<&'static str> {
fn __abs__(&self) -> PyResult<&'static str> {
Ok("abs")
}
fn __invert__(&self, py: Python) -> PyResult<&'static str> {
fn __invert__(&self) -> PyResult<&'static str> {
Ok("invert")
}
}
@ -778,42 +784,42 @@ struct BinaryArithmetic {
#[py::proto]
impl PyObjectProtocol for BinaryArithmetic {
fn __repr__(&self, py: Python) -> PyResult<&'static str> {
fn __repr__(&self) -> PyResult<&'static str> {
Ok("BA")
}
}
#[py::proto]
impl PyNumberProtocol for BinaryArithmetic {
fn __add__(&self, py: Python, rhs: &PyObject) -> PyResult<String> {
fn __add__(&self, rhs: &PyInstance) -> PyResult<String> {
Ok(format!("{:?} + {:?}", self, rhs))
}
fn __sub__(&self, py: Python, rhs: &PyObject) -> PyResult<String> {
fn __sub__(&self, rhs: &PyInstance) -> PyResult<String> {
Ok(format!("{:?} - {:?}", self, rhs))
}
fn __mul__(&self, py: Python, rhs: &PyObject) -> PyResult<String> {
fn __mul__(&self, rhs: &PyInstance) -> PyResult<String> {
Ok(format!("{:?} * {:?}", self, rhs))
}
fn __lshift__(&self, py: Python, rhs: &PyObject) -> PyResult<String> {
fn __lshift__(&self, rhs: &PyInstance) -> PyResult<String> {
Ok(format!("{:?} << {:?}", self, rhs))
}
fn __rshift__(&self, py: Python, rhs: &PyObject) -> PyResult<String> {
fn __rshift__(&self, rhs: &PyInstance) -> PyResult<String> {
Ok(format!("{:?} >> {:?}", self, rhs))
}
fn __and__(&self, py: Python, rhs: &PyObject) -> PyResult<String> {
fn __and__(&self, rhs: &PyInstance) -> PyResult<String> {
Ok(format!("{:?} & {:?}", self, rhs))
}
fn __xor__(&self, py: Python, rhs: &PyObject) -> PyResult<String> {
fn __xor__(&self, rhs: &PyInstance) -> PyResult<String> {
Ok(format!("{:?} ^ {:?}", self, rhs))
}
fn __or__(&self, py: Python, rhs: &PyObject) -> PyResult<String> {
fn __or__(&self, rhs: &PyInstance) -> PyResult<String> {
Ok(format!("{:?} | {:?}", self, rhs))
}
}
@ -852,18 +858,18 @@ struct RichComparisons {
#[py::proto]
impl PyObjectProtocol for RichComparisons {
fn __repr__(&self, py: Python) -> PyResult<&'static str> {
fn __repr__(&self) -> PyResult<&'static str> {
Ok("RC")
}
fn __richcmp__(&self, py: Python, other: &PyObject, op: CompareOp) -> PyResult<String> {
fn __richcmp__(&self, other: &PyInstance, op: CompareOp) -> PyResult<String> {
match op {
CompareOp::Lt => Ok(format!("{} < {:?}", self.__repr__(py).unwrap(), other)),
CompareOp::Le => Ok(format!("{} <= {:?}", self.__repr__(py).unwrap(), other)),
CompareOp::Eq => Ok(format!("{} == {:?}", self.__repr__(py).unwrap(), other)),
CompareOp::Ne => Ok(format!("{} != {:?}", self.__repr__(py).unwrap(), other)),
CompareOp::Gt => Ok(format!("{} > {:?}", self.__repr__(py).unwrap(), other)),
CompareOp::Ge => Ok(format!("{} >= {:?}", self.__repr__(py).unwrap(), other))
CompareOp::Lt => Ok(format!("{} < {:?}", self.__repr__().unwrap(), other)),
CompareOp::Le => Ok(format!("{} <= {:?}", self.__repr__().unwrap(), other)),
CompareOp::Eq => Ok(format!("{} == {:?}", self.__repr__().unwrap(), other)),
CompareOp::Ne => Ok(format!("{} != {:?}", self.__repr__().unwrap(), other)),
CompareOp::Gt => Ok(format!("{} > {:?}", self.__repr__().unwrap(), other)),
CompareOp::Ge => Ok(format!("{} >= {:?}", self.__repr__().unwrap(), other))
}
}
}
@ -875,16 +881,15 @@ struct RichComparisons2 {
#[py::proto]
impl PyObjectProtocol for RichComparisons2 {
fn __repr__(&self, py: Python) -> PyResult<&'static str> {
fn __repr__(&self) -> PyResult<&'static str> {
Ok("RC2")
}
fn __richcmp__(&self, py: Python,
other: &'p PyObject, op: CompareOp) -> PyResult<PyObject> {
fn __richcmp__(&self, other: &'p PyInstance, op: CompareOp) -> PyResult<PyObject> {
match op {
CompareOp::Eq => Ok(true.to_object(py)),
CompareOp::Ne => Ok(false.to_object(py)),
_ => Ok(py.NotImplemented())
CompareOp::Eq => Ok(true.to_object(self.token())),
CompareOp::Ne => Ok(false.to_object(self.token())),
_ => Ok(self.token().NotImplemented())
}
}
}
@ -950,49 +955,49 @@ struct InPlaceOperations {
#[py::proto]
impl PyObjectProtocol for InPlaceOperations {
fn __repr__(&self, py: Python) -> PyResult<String> {
fn __repr__(&self) -> PyResult<String> {
Ok(format!("IPO({:?})", self.value))
}
}
#[py::proto]
impl PyNumberProtocol for InPlaceOperations {
fn __iadd__(&mut self, py: Python, other: u32) -> PyResult<()> {
fn __iadd__(&mut self, other: u32) -> PyResult<()> {
self.value = self.value + other;
Ok(())
}
fn __isub__(&mut self, py: Python, other: u32) -> PyResult<()> {
fn __isub__(&mut self, other: u32) -> PyResult<()> {
self.value = self.value - other;
Ok(())
}
fn __imul__(&mut self, py: Python, other: u32) -> PyResult<()> {
fn __imul__(&mut self, other: u32) -> PyResult<()> {
self.value = self.value * other;
Ok(())
}
fn __ilshift__(&mut self, py: Python, other: u32) -> PyResult<()> {
fn __ilshift__(&mut self, other: u32) -> PyResult<()> {
self.value = self.value << other;
Ok(())
}
fn __irshift__(&mut self, py: Python, other: u32) -> PyResult<()> {
fn __irshift__(&mut self, other: u32) -> PyResult<()> {
self.value = self.value >> other;
Ok(())
}
fn __iand__(&mut self, py: Python, other: u32) -> PyResult<()> {
fn __iand__(&mut self, other: u32) -> PyResult<()> {
self.value = self.value & other;
Ok(())
}
fn __ixor__(&mut self, py: Python, other: u32) -> PyResult<()> {
fn __ixor__(&mut self, other: u32) -> PyResult<()> {
self.value = self.value ^ other;
Ok(())
}
fn __ior__(&mut self, py: Python, other: u32) -> PyResult<()> {
fn __ior__(&mut self, other: u32) -> PyResult<()> {
self.value = self.value | other;
Ok(())
}
@ -1037,16 +1042,16 @@ struct ContextManager {
#[py::proto]
impl<'p> PyContextProtocol<'p> for ContextManager {
fn __enter__(&mut self, py: Python) -> PyResult<i32> {
fn __enter__(&mut self) -> PyResult<i32> {
Ok(42)
}
fn __exit__(&mut self, py: Python,
ty: Option<PyType>,
value: Option<PyObject>,
traceback: Option<PyObject>) -> PyResult<bool> {
fn __exit__(&mut self,
ty: Option<&'p PyType>,
value: Option<&'p PyInstance>,
traceback: Option<&'p PyInstance>) -> PyResult<bool> {
self.exit_called = true;
if ty == Some(py.get_type::<exc::ValueError>()) {
if ty == Some(self.token().get_type::<exc::ValueError>()) {
Ok(true)
} else {
Ok(false)
@ -1083,16 +1088,16 @@ struct ClassWithProperties {
#[py::methods]
impl ClassWithProperties {
fn get_num(&self, py: Python) -> PyResult<i32> {
fn get_num(&self) -> PyResult<i32> {
Ok(self.num)
}
#[getter(DATA)]
fn get_data(&self, py: Python) -> PyResult<i32> {
fn get_data(&self) -> PyResult<i32> {
Ok(self.num)
}
#[setter(DATA)]
fn set_data(&mut self, py: Python, value: i32) -> PyResult<()> {
fn set_data(&mut self, value: i32) -> PyResult<()> {
self.num = value;
Ok(())
}

View File

@ -12,7 +12,7 @@ fn test_basics() {
let py = gil.python();
let v = PySlice::new(py, 1, 10, 2);
let indices = v.indices(py, 100).unwrap();
let indices = v.as_ref(py).indices(100).unwrap();
assert_eq!(1, indices.start);
assert_eq!(10, indices.stop);
assert_eq!(2, indices.step);
@ -28,19 +28,19 @@ struct Test {
#[py::proto]
impl<'p> PyMappingProtocol<'p> for Test
{
fn __getitem__(&self, py: Python, idx: PyObject) -> PyResult<PyObject> {
if let Ok(slice) = idx.cast_as::<PySlice>(py) {
let indices = slice.indices(py, 1000)?;
fn __getitem__(&self, idx: &PyInstance) -> PyResult<PyObject> {
if let Ok(slice) = idx.cast_as::<PySlice>() {
let indices = slice.indices(1000)?;
if indices.start == 100 && indices.stop == 200 && indices.step == 1 {
return Ok("slice".into_object(py))
return Ok("slice".into_object(self.token()))
}
}
else if let Ok(idx) = idx.extract::<isize>(py) {
else if let Ok(idx) = idx.extract::<isize>() {
if idx == 1 {
return Ok("int".into_object(py))
return Ok("int".into_object(self.token()))
}
}
Err(PyErr::new::<exc::ValueError, _>(py, "error"))
Err(PyErr::new::<exc::ValueError, _>(self.token(), "error"))
}
}
@ -51,8 +51,8 @@ fn test_cls_impl() {
let ob = py.init(|t| Test{token: t}).unwrap();
let d = PyDict::new(py);
d.set_item(py, "ob", ob).unwrap();
d.set_item("ob", ob).unwrap();
py.run("assert ob[1] == 'int'", None, Some(&d)).unwrap();
py.run("assert ob[100:200:1] == 'slice'", None, Some(&d)).unwrap();
py.run("assert ob[1] == 'int'", None, Some(d)).unwrap();
py.run("assert ob[100:200:1] == 'slice'", None, Some(d)).unwrap();
}