From 44611991c3d0607517601ba77f3ae737b94c562f Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Sun, 25 Oct 2015 17:55:29 +0100 Subject: [PATCH] Remove 'p lifetime from PyObject (#15) Since the `Python` token no longer is a part of `PyObject`, lots of methods now require the token as additional argument. This [breaking-change] breaks everything! --- README.md | 6 +- examples/hello.rs | 8 +- extensions/Makefile | 2 +- extensions/custom_type.rs | 14 +- extensions/hello.rs | 16 +- extensions/inheritance.rs | 8 +- src/argparse.rs | 43 ++--- src/conversion.rs | 53 +++--- src/err.rs | 110 ++++++----- src/function.rs | 15 +- src/lib.rs | 34 ++-- src/objectprotocol.rs | 108 ++++++----- src/objects/boolobject.rs | 22 +-- src/objects/dict.rs | 123 ++++++------- src/objects/exc.rs | 28 +-- src/objects/iterator.rs | 9 +- src/objects/list.rs | 116 ++++++------ src/objects/mod.rs | 80 ++++---- src/objects/module.rs | 49 +++-- src/objects/num.rs | 139 +++++++------- src/objects/object.rs | 151 +++++++-------- src/objects/oldstyle.rs | 23 +-- src/objects/sequence.rs | 336 +++++++++++++++++----------------- src/objects/string.rs | 153 ++++++++-------- src/objects/tests.rs | 9 +- src/objects/tuple.rs | 68 +++---- src/objects/typeobject.rs | 22 +-- src/python.rs | 168 +++++++++++------ src/rustobject/method.rs | 102 ++++++----- src/rustobject/mod.rs | 137 +++++++------- src/rustobject/tests.rs | 12 +- src/rustobject/typebuilder.rs | 89 ++++----- 32 files changed, 1139 insertions(+), 1114 deletions(-) diff --git a/README.md b/README.md index d4624403..ce81c62c 100644 --- a/README.md +++ b/README.md @@ -42,11 +42,11 @@ fn main() { let py = gil.python(); let sys = py.import("sys").unwrap(); - let version: String = sys.get("version").unwrap().extract().unwrap(); + let version: String = sys.get("version", py).unwrap().extract(py).unwrap(); let os = py.import("os").unwrap(); - let getenv = os.get("getenv").unwrap(); - let user: String = getenv.call(("USER",), None).unwrap().extract().unwrap(); + let getenv = os.get("getenv", py).unwrap(); + let user: String = getenv.call(("USER",), None, py).unwrap().extract(py).unwrap(); println!("Hello {}, I'm Python {}", user, version); } diff --git a/examples/hello.rs b/examples/hello.rs index 7ce2c07b..2973a0d0 100644 --- a/examples/hello.rs +++ b/examples/hello.rs @@ -1,6 +1,6 @@ extern crate cpython; -use cpython::{PythonObject, Python}; +use cpython::Python; use cpython::ObjectProtocol; //for call method fn main() { @@ -8,11 +8,11 @@ fn main() { let py = gil.python(); let sys = py.import("sys").unwrap(); - let version: String = sys.get("version").unwrap().extract().unwrap(); + let version: String = sys.get("version", py).unwrap().extract(py).unwrap(); let os = py.import("os").unwrap(); - let getenv = os.get("getenv").unwrap(); - let user: String = getenv.call(("USER",), None).unwrap().extract().unwrap(); + let getenv = os.get("getenv", py).unwrap(); + let user: String = getenv.call(("USER",), None, py).unwrap().extract(py).unwrap(); println!("Hello {}, I'm Python {}", user, version); } diff --git a/extensions/Makefile b/extensions/Makefile index 800537a8..28473f2c 100644 --- a/extensions/Makefile +++ b/extensions/Makefile @@ -4,7 +4,7 @@ rwildcard=$(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2) $(filter $(subst .PHONY: all clean ifndef PY -PY=2 +PY := $(word 2, $(subst ., ,$(shell python --version 2>&1))) endif all: diff --git a/extensions/custom_type.rs b/extensions/custom_type.rs index 5026931c..d1a33b72 100644 --- a/extensions/custom_type.rs +++ b/extensions/custom_type.rs @@ -4,18 +4,18 @@ #[macro_use] extern crate cpython; -use cpython::{PythonObject, PyObject, PyRustObject, PyResult}; +use cpython::{Python, PyObject, PyRustObject, PyResult}; -py_module_initializer!(custom_type, |_py, m| { - try!(m.add("__doc__", "Module documentation string")); - try!(m.add_type::("MyType") +py_module_initializer!(custom_type, |py, m| { + try!(m.add("__doc__", "Module documentation string", py)); + try!(m.add_type::("MyType", py) .add("a", py_method!(a())) .finish()); Ok(()) }); -fn a<'p>(slf: &PyRustObject<'p, i32>) -> PyResult<'p, PyObject<'p>> { - println!("a() was called with self={:?}", slf.get()); - Ok(slf.python().None()) +fn a(py: Python, slf: &PyRustObject) -> PyResult { + println!("a() was called with self={:?}", slf.get(py)); + Ok(py.None()) } diff --git a/extensions/hello.rs b/extensions/hello.rs index 407052d1..d63278d5 100644 --- a/extensions/hello.rs +++ b/extensions/hello.rs @@ -6,27 +6,27 @@ use cpython::{PyObject, PyResult, Python, PyTuple, PyDict}; -py_module_initializer!(hello, |_py, m| { - try!(m.add("__doc__", "Module documentation string")); - try!(m.add("run", py_fn!(run))); - try!(m.add("val", py_fn!(val()))); +py_module_initializer!(hello, |py, m| { + try!(m.add("__doc__", "Module documentation string", py)); + try!(m.add("run", py_fn!(run), py)); + try!(m.add("val", py_fn!(val()), py)); Ok(()) }); -fn run<'p>(py: Python<'p>, args: &PyTuple<'p>, kwargs: Option<&PyDict<'p>>) -> PyResult<'p, PyObject<'p>> { +fn run(py: Python, args: &PyTuple, kwargs: Option<&PyDict>) -> PyResult { println!("Rust says: Hello Python!"); - for arg in args { + for arg in args.as_slice() { println!("Rust got {}", arg); } if let Some(kwargs) = kwargs { - for (key, val) in kwargs.items() { + for (key, val) in kwargs.items(py) { println!("{} = {}", key, val); } } Ok(py.None()) } -fn val<'p>(_: Python<'p>) -> PyResult<'p, i32> { +fn val(_: Python) -> PyResult { Ok(42) } diff --git a/extensions/inheritance.rs b/extensions/inheritance.rs index 1aa03d4a..0520fc51 100644 --- a/extensions/inheritance.rs +++ b/extensions/inheritance.rs @@ -4,15 +4,15 @@ #[macro_use] extern crate cpython; -py_module_initializer!(inheritance, |_py, m| { - try!(m.add("__doc__", "Module documentation string")); +py_module_initializer!(inheritance, |py, m| { + try!(m.add("__doc__", "Module documentation string", py)); let base_class = try!( - m.add_type::<()>("BaseClass") + m.add_type::<()>("BaseClass", py) .doc("Type doc string") .finish()); for i in 1..10 { try!( - m.add_type::<()>(&format!("C{}", i)) + m.add_type::<()>(&format!("C{}", i), py) .base(&base_class) .doc(&format!("Derived class #{}", i)) .finish()); diff --git a/src/argparse.rs b/src/argparse.rs index 86e85067..9e33d835 100644 --- a/src/argparse.rs +++ b/src/argparse.rs @@ -42,16 +42,16 @@ pub struct ParamDescription<'a> { /// * kwargs: Keyword arguments /// * output: Output array that receives the arguments. /// Must have same length as `params` and must be initialized to `None`. -pub fn parse_args<'p>( +pub fn parse_args( fname: Option<&str>, params: &[ParamDescription], - args: &PyTuple<'p>, kwargs: Option<&PyDict<'p>>, - output: &mut[Option>] -) -> PyResult<'p, ()> + args: &PyTuple, kwargs: Option<&PyDict>, + output: &mut[Option], + py: Python +) -> PyResult<()> { assert!(params.len() == output.len()); - let py = args.python(); let nargs = args.len(); - let nkeywords = kwargs.map_or(0, |d| d.len()); + let nkeywords = kwargs.map_or(0, |d| d.len(py)); if nargs + nkeywords > params.len() { return Err(err::PyErr::new::(py, format!("{}{} takes at most {} argument{} ({} given)", @@ -65,7 +65,7 @@ pub fn parse_args<'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(p.name)) { + match kwargs.and_then(|d| d.get_item(p.name, py)) { Some(kwarg) => { *out = Some(kwarg); used_keywords += 1; @@ -77,7 +77,7 @@ pub fn parse_args<'p>( }, None => { if i < nargs { - *out = Some(args.get_item(i)); + *out = Some(args.get_item(i, py)); } else { *out = None; if !p.is_optional { @@ -91,8 +91,8 @@ pub fn parse_args<'p>( } if used_keywords != nkeywords { // check for extraneous keyword arguments - for (key, _value) in kwargs.unwrap().items() { - let key = try!(PyString::extract(&key)); + for (key, _value) in kwargs.unwrap().items(py) { + let key = try!(PyString::extract(&key, py)); if !params.iter().any(|p| p.name == key) { return Err(err::PyErr::new::(py, format!("'{}' is an invalid keyword argument for this function", @@ -106,11 +106,11 @@ pub fn parse_args<'p>( #[doc(hidden)] #[macro_export] macro_rules! py_argparse_extract { - ( $iter:expr, ( ) $body:block ) => { $body }; - ( $iter:expr, ( $pname:ident : $ptype:ty ) $body:block) => { - match <$ptype as $crate::ExtractPyObject>::prepare_extract($iter.next().unwrap().as_ref().unwrap()) { + ( $iter:expr, $py:ident, ( ) $body:block ) => { $body }; + ( $iter:expr, $py:ident, ( $pname:ident : $ptype:ty ) $body:block) => { + match <$ptype as $crate::ExtractPyObject>::prepare_extract($iter.next().unwrap().as_ref().unwrap(), $py) { Ok(prepared) => { - match <$ptype as $crate::ExtractPyObject>::extract(&prepared) { + match <$ptype as $crate::ExtractPyObject>::extract(&prepared, $py) { Ok($pname) => $body, Err(e) => Err(e) } @@ -118,9 +118,9 @@ macro_rules! py_argparse_extract { Err(e) => Err(e) } }; - ( $iter:expr, ( $pname:ident : $ptype:ty , $($r:tt)+ ) $body:block) => { - py_argparse_extract!($iter, ($pname: $ptype) { - py_argparse_extract!( $iter, ( $($r)* ) $body) + ( $iter:expr, $py: ident, ( $pname:ident : $ptype:ty , $($r:tt)+ ) $body:block) => { + py_argparse_extract!($iter, $py, ($pname: $ptype) { + py_argparse_extract!( $iter, $py, ( $($r)* ) $body) }) } } @@ -149,7 +149,7 @@ macro_rules! py_argparse_snd { /// If extraction fails, `py_argparse!()` returns a failed `PyResult` without evaluating `body`. #[macro_export] macro_rules! py_argparse { - ($fname:expr, $args:expr, $kwargs:expr, ($( $pname:ident : $ptype:ty ),*) $body:block) => {{ + ($fname:expr, $args:expr, $kwargs:expr, $py:expr, ($( $pname:ident : $ptype:ty ),*) $body:block) => {{ const PARAMS: &'static [$crate::argparse::ParamDescription<'static>] = &[ $( $crate::argparse::ParamDescription { @@ -158,13 +158,14 @@ macro_rules! py_argparse { } ),* ]; + let py: $crate::Python = $py; let mut output = [$( py_argparse_snd!($pname, None) ),*]; - match $crate::argparse::parse_args($fname, PARAMS, $args, $kwargs, &mut output) { + match $crate::argparse::parse_args($fname, PARAMS, $args, $kwargs, &mut output, py) { Ok(()) => { // We can't use experimental slice pattern syntax in macros //let &[$(ref $pname),*] = &output; let mut iter = output.iter(); - let ret = py_argparse_extract!( iter, ( $( $pname : $ptype ),* ) $body ); + let ret = py_argparse_extract!( iter, py, ( $( $pname : $ptype ),* ) $body ); assert!(iter.next() == None); ret }, @@ -184,7 +185,7 @@ mod test { let py = gil_guard.python(); let mut called = false; let tuple = ("abc", 42).to_py_object(py); - py_argparse!(None, &tuple, None, (x: &str, y: i32) { + py_argparse!(None, &tuple, None, py, (x: &str, y: i32) { assert_eq!(x, "abc"); assert_eq!(y, 42); called = true; diff --git a/src/conversion.rs b/src/conversion.rs index 9535dad8..fb28784d 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -18,24 +18,25 @@ use std; use ffi; -use python::{Python, PythonObject, PythonObjectWithCheckedDowncast, ToPythonPointer}; +use python::{Python, PythonObject, PythonObjectWithCheckedDowncast, PyClone}; use objects::PyObject; use err::PyResult; /// Conversion trait that allows various objects to be converted into Python objects. -pub trait ToPyObject<'p> { - type ObjectType : PythonObject<'p>; +pub trait ToPyObject { + type ObjectType : PythonObject; /// Converts self into a Python object. - fn to_py_object(&self, py: Python<'p>) -> Self::ObjectType; + fn to_py_object(&self, py: Python) -> Self::ObjectType; /// Converts self into a Python object. /// /// May be more efficient than `to_py_object` in some cases because /// it can move out of the input object. #[inline] - fn into_py_object(self, py: Python<'p>) -> Self::ObjectType - where Self: Sized { + fn into_py_object(self, py: Python) -> Self::ObjectType + where Self: Sized + { self.to_py_object(py) } @@ -45,8 +46,9 @@ pub trait ToPyObject<'p> { /// May be more efficient than `to_py_object` because it does not need /// to touch any reference counts when the input object already is a Python object. #[inline] - fn with_borrowed_ptr(&self, py: Python<'p>, f: F) -> R - where F: FnOnce(*mut ffi::PyObject) -> R { + fn with_borrowed_ptr(&self, py: Python, f: F) -> R + where F: FnOnce(*mut ffi::PyObject) -> R + { let obj = self.to_py_object(py).into_object(); f(obj.as_ptr()) } @@ -89,49 +91,48 @@ pub trait ToPyObject<'p> { /// /// In cases where the result does not depend on the `'prepared` lifetime, /// the inherent method `PyObject::extract()` can be used. -pub trait ExtractPyObject<'python, 'source, 'prepared> : Sized { - type Prepared : 'source; +pub trait ExtractPyObject<'prepared> : Sized { + type Prepared : 'static; - fn prepare_extract(obj: &'source PyObject<'python>) -> PyResult<'python, Self::Prepared>; + fn prepare_extract<'a, 'p>(obj: &'a PyObject, py: Python<'p>) -> PyResult; - fn extract(prepared: &'prepared Self::Prepared) -> PyResult<'python, Self>; + fn extract<'p>(prepared: &'prepared Self::Prepared, py: Python<'p>) -> PyResult; } -impl <'python, 'source, 'prepared, T> ExtractPyObject<'python, 'source, 'prepared> for T -where T: PythonObjectWithCheckedDowncast<'python>, - 'python: 'source +impl <'prepared, T> ExtractPyObject<'prepared> for T +where T: PythonObjectWithCheckedDowncast { - - type Prepared = &'source PyObject<'python>; + type Prepared = PyObject; #[inline] - fn prepare_extract(obj: &'source PyObject<'python>) -> PyResult<'python, Self::Prepared> { - Ok(obj) + fn prepare_extract(obj: &PyObject, py: Python) -> PyResult { + Ok(obj.clone_ref(py)) } #[inline] - fn extract(&obj: &'prepared &'source PyObject<'python>) -> PyResult<'python, T> { - Ok(try!(obj.clone().cast_into())) + fn extract(obj: &'prepared Self::Prepared, py: Python) -> PyResult { + Ok(try!(obj.clone_ref(py).cast_into(py))) } } // ToPyObject for references -impl <'p, 's, T: ?Sized> ToPyObject<'p> for &'s T where T: ToPyObject<'p> { +impl <'a, T: ?Sized> ToPyObject for &'a T where T: ToPyObject { type ObjectType = T::ObjectType; #[inline] - fn to_py_object(&self, py: Python<'p>) -> T::ObjectType { + fn to_py_object(&self, py: Python) -> T::ObjectType { ::to_py_object(*self, py) } #[inline] - fn into_py_object(self, py: Python<'p>) -> T::ObjectType { + fn into_py_object(self, py: Python) -> T::ObjectType { ::to_py_object(self, py) } #[inline] - fn with_borrowed_ptr(&self, py: Python<'p>, f: F) -> R - where F: FnOnce(*mut ffi::PyObject) -> R { + fn with_borrowed_ptr(&self, py: Python, f: F) -> R + where F: FnOnce(*mut ffi::PyObject) -> R + { ::with_borrowed_ptr(*self, py, f) } } diff --git a/src/err.rs b/src/err.rs index 71bb9ae8..1dc5c86b 100644 --- a/src/err.rs +++ b/src/err.rs @@ -17,7 +17,7 @@ // DEALINGS IN THE SOFTWARE. use std; -use python::{PythonObject, Python, ToPythonPointer, PythonObjectDowncastError, PythonObjectWithTypeObject}; +use python::{PythonObject, ToPythonPointer, Python, PythonObjectDowncastError, PythonObjectWithTypeObject, PyClone}; use objects::{PyObject, PyType, exc}; #[cfg(feature="python27-sys")] use objects::oldstyle::PyClass; @@ -27,36 +27,36 @@ use conversion::ToPyObject; use std::ffi::CString; /// Represents a Python exception that was raised. -#[derive(Clone, Debug)] -pub struct PyErr<'p> { +#[derive(Debug)] +pub struct PyErr { /// The type of the exception. This should be either a `PyClass` or a `PyType`. - pub ptype : PyObject<'p>, + pub ptype : PyObject, /// The value of the exception. /// /// This can be either an instance of `ptype`, /// a tuple of arguments to be passed to `ptype`'s constructor, /// or a single argument to be passed to `ptype`'s constructor. /// Call `PyErr::instance()` to get the exception instance in all cases. - pub pvalue : Option>, + pub pvalue : Option, /// The `PyTraceBack` object associated with the error. - pub ptraceback : Option> + pub ptraceback : Option } /// Represents the result of a Python call. -pub type PyResult<'p, T> = Result>; +pub type PyResult = Result; -impl <'p> PyErr<'p> { +impl PyErr { /// Gets whether an error is present in the Python interpreter's global state. #[inline] - pub fn occurred(_ : Python<'p>) -> bool { + pub fn occurred(_ : Python) -> bool { unsafe { !ffi::PyErr_Occurred().is_null() } } /// Retrieves the current error from the Python interpreter's global state. /// The error is cleared from the Python interpreter. /// If no error is set, returns a `SystemError`. - pub fn fetch(py : Python<'p>) -> PyErr<'p> { + pub fn fetch(py : Python) -> PyErr { unsafe { let mut ptype : *mut ffi::PyObject = std::mem::uninitialized(); let mut pvalue : *mut ffi::PyObject = std::mem::uninitialized(); @@ -66,7 +66,7 @@ impl <'p> PyErr<'p> { } } - unsafe fn new_from_ffi_tuple(py: Python<'p>, ptype: *mut ffi::PyObject, pvalue: *mut ffi::PyObject, ptraceback: *mut ffi::PyObject) -> PyErr<'p> { + unsafe fn new_from_ffi_tuple(py: Python, ptype: *mut ffi::PyObject, pvalue: *mut ffi::PyObject, ptraceback: *mut ffi::PyObject) -> PyErr { // Note: must not panic to ensure all owned pointers get acquired correctly, // and because we mustn't panic in normalize(). PyErr { @@ -88,13 +88,13 @@ impl <'p> PyErr<'p> { /// * any other value: the exception instance will be created using python `T(value)` /// /// Panics if `T` is not a python class derived from `BaseException`. - pub fn new(py: Python<'p>, value: V) -> PyErr<'p> - where T: PythonObjectWithTypeObject<'p>, V: ToPyObject<'p> + pub fn new(py: Python, value: V) -> PyErr + where T: PythonObjectWithTypeObject, V: ToPyObject { PyErr::new_helper(py.get_type::(), value.to_py_object(py).into_object()) } - fn new_helper(ty: PyType<'p>, value: PyObject<'p>) -> PyErr<'p> { + fn new_helper(ty: PyType, value: PyObject) -> PyErr { assert!(unsafe { ffi::PyExceptionClass_Check(ty.as_object().as_ptr()) } != 0); PyErr { ptype: ty.into_object(), @@ -108,12 +108,11 @@ impl <'p> PyErr<'p> { /// `obj` must be an Python exception instance, the PyErr will use that instance. /// If `obj` is a Python exception type object, the PyErr will (lazily) create a new instance of that type. /// Otherwise, a `TypeError` is created instead. - pub fn from_instance(obj: O) -> PyErr<'p> where O: PythonObject<'p> { - PyErr::from_instance_helper(obj.into_object()) + pub fn from_instance(obj: O, py: Python) -> PyErr where O: PythonObject { + PyErr::from_instance_helper(obj.into_object(), py) } - fn from_instance_helper(obj: PyObject<'p>) -> PyErr<'p> { - let py = obj.python(); + fn from_instance_helper(obj: PyObject, py: Python) -> PyErr { if unsafe { ffi::PyExceptionInstance_Check(obj.as_ptr()) } != 0 { PyErr { ptype: unsafe { PyObject::from_borrowed_ptr(py, ffi::PyExceptionInstance_Class(obj.as_ptr())) }, @@ -139,7 +138,7 @@ impl <'p> PyErr<'p> { /// `exc` is the exception type; usually one of the standard exceptions like `PyExc::runtime_error()`. /// `value` is the exception instance, or a tuple of arguments to pass to the exception constructor. #[inline] - pub fn new_lazy_init(exc: PyType<'p>, value: Option>) -> PyErr<'p> { + pub fn new_lazy_init(exc: PyType, value: Option) -> PyErr { PyErr { ptype: exc.into_object(), pvalue: value, @@ -148,14 +147,14 @@ impl <'p> PyErr<'p> { } /// Print a standard traceback to sys.stderr. - pub fn print(self) { - self.restore(); + pub fn print(self, py: Python) { + self.restore(py); unsafe { ffi::PyErr_PrintEx(0) } } /// Print a standard traceback to sys.stderr. - pub fn print_and_set_sys_last_vars(self) { - self.restore(); + pub fn print_and_set_sys_last_vars(self, py: Python) { + self.restore(py); unsafe { ffi::PyErr_PrintEx(1) } } @@ -163,28 +162,27 @@ impl <'p> PyErr<'p> { /// If `exc` is a class object, this also returns `true` when `self` is an instance of a subclass. /// If `exc` is a tuple, all exceptions in the tuple (and recursively in subtuples) are searched for a match. #[inline] - pub fn matches(&self, exc: &PyObject) -> bool { + pub fn matches(&self, exc: &PyObject, _py: Python) -> bool { unsafe { ffi::PyErr_GivenExceptionMatches(self.ptype.as_ptr(), exc.as_ptr()) != 0 } } /// Normalizes the error. This ensures that the exception value is an instance of the exception type. - pub fn normalize(&mut self) { + pub fn normalize(&mut self, py: Python) { // The normalization helper function involves temporarily moving out of the &mut self, // which requires some unsafe trickery: unsafe { - std::ptr::write(self, std::ptr::read(self).into_normalized()); + std::ptr::write(self, std::ptr::read(self).into_normalized(py)); } // This is safe as long as normalized() doesn't unwind due to a panic. } /// Helper function for normalizing the error by deconstructing and reconstructing the PyErr. /// Must not panic for safety in normalize() - fn into_normalized(self) -> PyErr<'p> { + fn into_normalized(self, py: Python) -> PyErr { let PyErr { ptype, pvalue, ptraceback } = self; - let py = ptype.python(); let mut ptype = ptype.steal_ptr(); - let mut pvalue = pvalue.steal_ptr(); - let mut ptraceback = ptraceback.steal_ptr(); + let mut pvalue = pvalue.steal_ptr(py); + let mut ptraceback = ptraceback.steal_ptr(py); unsafe { ffi::PyErr_NormalizeException(&mut ptype, &mut pvalue, &mut ptraceback); PyErr::new_from_ffi_tuple(py, ptype, pvalue, ptraceback) @@ -195,52 +193,50 @@ impl <'p> PyErr<'p> { /// /// If the exception type is an old-style class, returns `oldstyle::PyClass`. #[cfg(feature="python27-sys")] - pub fn get_type(&self) -> PyType<'p> { - let py = self.ptype.python(); - match self.ptype.clone().cast_into::() { - Ok(t) => t, + pub fn get_type(&self, py: Python) -> PyType { + match self.ptype.cast_as::(py) { + Ok(t) => t.clone_ref(py), Err(_) => - match self.ptype.cast_as::() { + match self.ptype.cast_as::(py) { Ok(_) => py.get_type::(), - Err(_) => py.None().get_type().clone() + Err(_) => py.None().get_type().clone_ref(py) } } } /// Retrieves the exception type. #[cfg(not(feature="python27-sys"))] - pub fn get_type(&self) -> PyType<'p> { - let py = self.ptype.python(); - match self.ptype.clone().cast_into::() { - Ok(t) => t, - Err(_) => py.None().get_type().clone() + pub fn get_type(&self, py: Python) -> PyType { + match self.ptype.cast_as::(py) { + Ok(t) => t.clone_ref(py), + Err(_) => py.None().get_type().clone_ref(py) } } /// Retrieves the exception instance for this error. /// This method takes `&mut self` because the error might need /// to be normalized in order to create the exception instance. - pub fn instance(&mut self) -> PyObject<'p> { - self.normalize(); + pub fn instance(&mut self, py: Python) -> PyObject { + self.normalize(py); match self.pvalue { - Some(ref instance) => instance.clone(), - None => self.ptype.python().None() + Some(ref instance) => instance.clone_ref(py), + None => py.None() } } /// Writes the error back to the Python interpreter's global state. /// This is the opposite of `PyErr::fetch()`. #[inline] - pub fn restore(self) { + pub fn restore(self, py: Python) { let PyErr { ptype, pvalue, ptraceback } = self; unsafe { - ffi::PyErr_Restore(ptype.steal_ptr(), pvalue.steal_ptr(), ptraceback.steal_ptr()) + ffi::PyErr_Restore(ptype.steal_ptr(), pvalue.steal_ptr(py), ptraceback.steal_ptr(py)) } } /// Issue a warning message. /// May return a PyErr if warnings-as-errors is enabled. - pub fn warn(py: Python<'p>, category: &PyObject, message: &str, stacklevel: i32) -> PyResult<'p, ()> { + pub fn warn(py: Python, category: &PyObject, message: &str, stacklevel: i32) -> PyResult<()> { let message = CString::new(message).unwrap(); unsafe { error_on_minusone(py, ffi::PyErr_WarnEx(category.as_ptr(), message.as_ptr(), stacklevel as ffi::Py_ssize_t)) @@ -249,8 +245,8 @@ impl <'p> PyErr<'p> { } /// Converts `PythonObjectDowncastError` to Python `TypeError`. -impl <'p> std::convert::From> for PyErr<'p> { - fn from(err: PythonObjectDowncastError<'p>) -> PyErr<'p> { +impl <'p> std::convert::From> for PyErr { + fn from(err: PythonObjectDowncastError<'p>) -> PyErr { PyErr::new_lazy_init(err.0.get_type::(), None) } } @@ -281,23 +277,23 @@ pub unsafe fn from_owned_ptr_or_panic(py : Python, p : *mut ffi::PyObject) -> Py } } -pub unsafe fn result_cast_from_owned_ptr<'p, T>(py : Python<'p>, p : *mut ffi::PyObject) -> PyResult<'p, T> - where T: ::python::PythonObjectWithCheckedDowncast<'p> +pub unsafe fn result_cast_from_owned_ptr(py : Python, p : *mut ffi::PyObject) -> PyResult + where T: ::python::PythonObjectWithCheckedDowncast { if p.is_null() { Err(PyErr::fetch(py)) } else { - Ok(try!(PyObject::from_owned_ptr(py, p).cast_into())) + Ok(try!(PyObject::from_owned_ptr(py, p).cast_into(py))) } } -pub unsafe fn cast_from_owned_ptr_or_panic<'p, T>(py : Python<'p>, p : *mut ffi::PyObject) -> T - where T: ::python::PythonObjectWithCheckedDowncast<'p> +pub unsafe fn cast_from_owned_ptr_or_panic(py : Python, p : *mut ffi::PyObject) -> T + where T: ::python::PythonObjectWithCheckedDowncast { if p.is_null() { panic_after_error(py); } else { - PyObject::from_owned_ptr(py, p).cast_into().unwrap() + PyObject::from_owned_ptr(py, p).cast_into(py).unwrap() } } @@ -320,7 +316,7 @@ mod tests { fn set_typeerror() { let gil = Python::acquire_gil(); let py = gil.python(); - PyErr::new_lazy_init(py.get_type::(), None).restore(); + PyErr::new_lazy_init(py.get_type::(), None).restore(py); assert!(PyErr::occurred(py)); drop(PyErr::fetch(py)); } diff --git a/src/function.rs b/src/function.rs index ce320c5d..9c350771 100644 --- a/src/function.rs +++ b/src/function.rs @@ -55,7 +55,7 @@ macro_rules! py_fn { return $crate::PythonObject::into_object(obj).steal_ptr(); } Err(e) => { - e.restore(); + e.restore(py); return ::std::ptr::null_mut(); } } @@ -91,7 +91,7 @@ macro_rules! py_fn { Some(kwargs) => Some(<$crate::PyDict as $crate::PythonObject>::unchecked_downcast_from(kwargs)), None => None }; - match py_argparse!(Some(stringify!($f)), &args, kwargs.as_ref(), + match py_argparse!(Some(stringify!($f)), &args, kwargs.as_ref(), py, ( $($pname : $ptype),* ) { $f( py, $($pname),* ) }) { Ok(val) => { @@ -99,7 +99,7 @@ macro_rules! py_fn { return $crate::PythonObject::into_object(obj).steal_ptr(); } Err(e) => { - e.restore(); + e.restore(py); return ::std::ptr::null_mut(); } } @@ -122,6 +122,9 @@ macro_rules! py_fn { }}); } +/// Result type of the `py_fn!()` macro. +/// +/// Use the `ToPyObject` implementation to create a python callable object. pub struct PyFn(*mut ffi::PyMethodDef); #[inline] @@ -129,10 +132,10 @@ pub unsafe fn py_fn_impl(def: *mut ffi::PyMethodDef) -> PyFn { PyFn(def) } -impl <'p> ToPyObject<'p> for PyFn { - type ObjectType = PyObject<'p>; +impl ToPyObject for PyFn { + type ObjectType = PyObject; - fn to_py_object(&self, py: Python<'p>) -> PyObject<'p> { + fn to_py_object(&self, py: Python) -> PyObject { unsafe { err::from_owned_ptr_or_panic(py, ffi::PyCFunction_New(self.0, ptr::null_mut())) } diff --git a/src/lib.rs b/src/lib.rs index 68dd2a05..0db0c7a9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -69,11 +69,11 @@ //! let py = gil.python(); //! //! let sys = py.import("sys").unwrap(); -//! let version: String = sys.get("version").unwrap().extract().unwrap(); +//! let version: String = sys.get("version", py).unwrap().extract(py).unwrap(); //! //! let os = py.import("os").unwrap(); -//! let getenv = os.get("getenv").unwrap(); -//! let user: String = getenv.call(("USER",), None).unwrap().extract().unwrap(); +//! let getenv = os.get("getenv", py).unwrap(); +//! let user: String = getenv.call(("USER",), None, py).unwrap().extract(py).unwrap(); //! //! println!("Hello {}, I'm Python {}", user, version); //! } @@ -93,7 +93,7 @@ extern crate python3_sys as ffi; pub use ffi::Py_ssize_t; pub use err::{PyErr, PyResult}; pub use objects::*; -pub use python::{Python, PythonObject, PythonObjectWithCheckedDowncast, PythonObjectWithTypeObject}; +pub use python::{Python, PythonObject, PythonObjectWithCheckedDowncast, PythonObjectWithTypeObject, PyClone, PyDrop}; pub use pythonrun::{GILGuard, GILProtected, prepare_freethreaded_python}; pub use conversion::{ExtractPyObject, ToPyObject}; pub use objectprotocol::{ObjectProtocol}; @@ -172,12 +172,12 @@ pub mod _detail { /// use cpython::{Python, PyResult, PyObject}; /// /// py_module_initializer!(example, |py, m| { -/// try!(m.add("__doc__", "Module documentation string")); -/// try!(m.add("run", py_fn!(run()))); +/// try!(m.add("__doc__", "Module documentation string", py)); +/// try!(m.add("run", py_fn!(run()), py)); /// Ok(()) /// }); /// -/// fn run<'p>(py: Python<'p>) -> PyResult<'p, PyObject<'p>> { +/// fn run(py: Python) -> PyResult { /// println!("Rust says: Hello Python!"); /// Ok(py.None()) /// } @@ -204,7 +204,7 @@ macro_rules! py_module_initializer { #[allow(non_snake_case)] pub unsafe extern "C" fn [ init $name ]() { // Nest init function so that $body isn't in unsafe context - fn init<'pmisip>($py_id: $crate::Python<'pmisip>, $m_id: &$crate::PyModule<'pmisip>) -> $crate::PyResult<'pmisip, ()> { + fn init($py_id: $crate::Python, $m_id: &$crate::PyModule) -> $crate::PyResult<()> { $body } let name = concat!(stringify!($name), "\0").as_ptr() as *const _; @@ -218,7 +218,7 @@ macro_rules! py_module_initializer { #[cfg(feature="python27-sys")] pub unsafe fn py_module_initializer_impl( name: *const libc::c_char, - init: for<'p> fn(Python<'p>, &PyModule<'p>) -> PyResult<'p, ()> + init: fn(Python, &PyModule) -> PyResult<()> ) { abort_on_panic!({ let py = Python::assume_gil_acquired(); @@ -226,16 +226,16 @@ pub unsafe fn py_module_initializer_impl( let module = ffi::Py_InitModule(name, ptr::null_mut()); if module.is_null() { return; } - let module = match PyObject::from_borrowed_ptr(py, module).cast_into::() { + let module = match PyObject::from_borrowed_ptr(py, module).cast_into::(py) { Ok(m) => m, Err(e) => { - PyErr::from(e).restore(); + PyErr::from(e).restore(py); return; } }; match init(py, &module) { Ok(()) => (), - Err(e) => e.restore() + Err(e) => e.restore(py) } }) } @@ -248,7 +248,7 @@ macro_rules! py_module_initializer { #[allow(non_snake_case)] pub unsafe extern "C" fn [ PyInit_ $name ]() -> *mut $crate::_detail::ffi::PyObject { // Nest init function so that $body isn't in unsafe context - fn init<'pmisip>($py_id: $crate::Python<'pmisip>, $m_id: &$crate::PyModule<'pmisip>) -> $crate::PyResult<'pmisip, ()> { + fn init($py_id: $crate::Python, $m_id: &$crate::PyModule) -> $crate::PyResult<()> { $body } static mut module_def: $crate::_detail::ffi::PyModuleDef = $crate::_detail::ffi::PyModuleDef { @@ -275,7 +275,7 @@ macro_rules! py_module_initializer { #[cfg(feature="python3-sys")] pub unsafe fn py_module_initializer_impl( def: *mut ffi::PyModuleDef, - init: for<'p> fn(Python<'p>, &PyModule<'p>) -> PyResult<'p, ()> + init: fn(Python, &PyModule) -> PyResult<()> ) -> *mut ffi::PyObject { abort_on_panic!({ let py = Python::assume_gil_acquired(); @@ -283,17 +283,17 @@ pub unsafe fn py_module_initializer_impl( let module = ffi::PyModule_Create(def); if module.is_null() { return module; } - let module = match PyObject::from_owned_ptr(py, module).cast_into::() { + let module = match PyObject::from_owned_ptr(py, module).cast_into::(py) { Ok(m) => m, Err(e) => { - PyErr::from(e).restore(); + PyErr::from(e).restore(py); return ptr::null_mut(); } }; match init(py, &module) { Ok(()) => module.into_object().steal_ptr(), Err(e) => { - e.restore(); + e.restore(py); return ptr::null_mut(); } } diff --git a/src/objectprotocol.rs b/src/objectprotocol.rs index 2146c28e..77a9ecfe 100644 --- a/src/objectprotocol.rs +++ b/src/objectprotocol.rs @@ -20,18 +20,18 @@ use std::fmt; use std::cmp::Ordering; use ffi; use libc; -use python::{PythonObject, ToPythonPointer}; +use python::{Python, PythonObject, ToPythonPointer}; use objects::{PyObject, PyTuple, PyDict, PyString}; use conversion::ToPyObject; use err::{PyErr, PyResult, self}; /// Trait that contains methods -pub trait ObjectProtocol<'p> : PythonObject<'p> { +pub trait ObjectProtocol : PythonObject { /// Determines whether this object has the given attribute. /// This is equivalent to the Python expression 'hasattr(self, attr_name)'. #[inline] - fn hasattr(&self, attr_name: N) -> PyResult<'p, bool> where N: ToPyObject<'p> { - attr_name.with_borrowed_ptr(self.python(), |attr_name| unsafe { + fn hasattr(&self, attr_name: N, py: Python) -> PyResult where N: ToPyObject { + attr_name.with_borrowed_ptr(py, |attr_name| unsafe { Ok(ffi::PyObject_HasAttr(self.as_ptr(), attr_name) != 0) }) } @@ -39,8 +39,7 @@ pub trait ObjectProtocol<'p> : PythonObject<'p> { /// Retrieves an attribute value. /// This is equivalent to the Python expression 'self.attr_name'. #[inline] - fn getattr(&self, attr_name: N) -> PyResult<'p, PyObject<'p>> where N: ToPyObject<'p> { - let py = self.python(); + fn getattr(&self, attr_name: N, py: Python) -> PyResult where N: ToPyObject { attr_name.with_borrowed_ptr(py, |attr_name| unsafe { err::result_from_owned_ptr(py, ffi::PyObject_GetAttr(self.as_ptr(), attr_name)) @@ -50,10 +49,9 @@ pub trait ObjectProtocol<'p> : PythonObject<'p> { /// Sets an attribute value. /// This is equivalent to the Python expression 'self.attr_name = value'. #[inline] - fn setattr(&self, attr_name: N, value: V) -> PyResult<'p, ()> - where N: ToPyObject<'p>, V: ToPyObject<'p> + fn setattr(&self, attr_name: N, value: V, py: Python) -> PyResult<()> + where N: ToPyObject, V: ToPyObject { - let py = self.python(); attr_name.with_borrowed_ptr(py, move |attr_name| value.with_borrowed_ptr(py, |value| unsafe { err::error_on_minusone(py, @@ -64,8 +62,7 @@ pub trait ObjectProtocol<'p> : PythonObject<'p> { /// Deletes an attribute. /// This is equivalent to the Python expression 'del self.attr_name'. #[inline] - fn delattr(&self, attr_name: N) -> PyResult<'p, ()> where N: ToPyObject<'p> { - let py = self.python(); + fn delattr(&self, attr_name: N, py: Python) -> PyResult<()> where N: ToPyObject { attr_name.with_borrowed_ptr(py, |attr_name| unsafe { err::error_on_minusone(py, ffi::PyObject_DelAttr(self.as_ptr(), attr_name)) @@ -75,8 +72,7 @@ pub trait ObjectProtocol<'p> : PythonObject<'p> { /// Compares two Python objects. /// This is equivalent to the Python expression 'cmp(self, other)'. #[cfg(feature="python27-sys")] - fn compare(&self, other: O) -> PyResult<'p, Ordering> where O: ToPyObject<'p> { - let py = self.python(); + fn compare(&self, other: O, py: Python) -> PyResult where O: ToPyObject { other.with_borrowed_ptr(py, |other| unsafe { let mut result : libc::c_int = -1; try!(err::error_on_minusone(py, @@ -94,18 +90,18 @@ pub trait ObjectProtocol<'p> : PythonObject<'p> { /// Compute the string representation of self. /// This is equivalent to the Python expression 'repr(self)'. #[inline] - fn repr(&self) -> PyResult<'p, PyString<'p>> { + fn repr(&self, py: Python) -> PyResult { unsafe { - err::result_cast_from_owned_ptr(self.python(), ffi::PyObject_Repr(self.as_ptr())) + err::result_cast_from_owned_ptr(py, 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) -> PyResult<'p, PyString<'p>> { + fn str(&self, py: Python) -> PyResult { unsafe { - err::result_cast_from_owned_ptr(self.python(), ffi::PyObject_Str(self.as_ptr())) + err::result_cast_from_owned_ptr(py, ffi::PyObject_Str(self.as_ptr())) } } @@ -113,15 +109,15 @@ pub trait ObjectProtocol<'p> : PythonObject<'p> { /// This is equivalent to the Python expression 'unistr(self)'. #[inline] #[cfg(feature="python27-sys")] - fn unistr(&self) -> PyResult<'p, ::objects::PyUnicode<'p>> { + fn unistr(&self, py: Python) -> PyResult<::objects::PyUnicode> { unsafe { - err::result_cast_from_owned_ptr(self.python(), ffi::PyObject_Unicode(self.as_ptr())) + err::result_cast_from_owned_ptr(py, ffi::PyObject_Unicode(self.as_ptr())) } } /// Determines whether this object is callable. #[inline] - fn is_callable(&self) -> bool { + fn is_callable(&self, _py: Python) -> bool { unsafe { ffi::PyCallable_Check(self.as_ptr()) != 0 } @@ -130,9 +126,9 @@ pub trait ObjectProtocol<'p> : PythonObject<'p> { /// Calls the object. /// This is equivalent to the Python expression: 'self(*args, **kwargs)' #[inline] - fn call(&self, args: A, kwargs: Option<&PyDict<'p>>) -> PyResult<'p, PyObject<'p>> - where A: ToPyObject<'p, ObjectType=PyTuple<'p>> { - let py = self.python(); + fn call(&self, args: A, kwargs: Option<&PyDict>, py: Python) -> PyResult + where A: ToPyObject + { args.with_borrowed_ptr(py, |args| unsafe { err::result_from_owned_ptr(py, ffi::PyObject_Call(self.as_ptr(), args, kwargs.as_ptr())) }) @@ -141,18 +137,19 @@ pub trait ObjectProtocol<'p> : PythonObject<'p> { /// Calls a method on the object. /// This is equivalent to the Python expression: 'self.name(*args, **kwargs)' #[inline] - fn call_method(&self, name: &str, args: A, kwargs: Option<&PyDict<'p>>) -> PyResult<'p, PyObject<'p>> - where A: ToPyObject<'p, ObjectType=PyTuple<'p>> { - try!(self.getattr(name)).call(args, kwargs) + fn call_method(&self, name: &str, args: A, kwargs: Option<&PyDict>, py: Python) -> PyResult + where A: ToPyObject + { + try!(self.getattr(name, py)).call(args, kwargs, py) } /// Retrieves the hash code of the object. /// This is equivalent to the Python expression: 'hash(self)' #[inline] - fn hash(&self) -> PyResult<'p, ::Py_hash_t> { + fn hash(&self, py: Python) -> PyResult<::Py_hash_t> { let v = unsafe { ffi::PyObject_Hash(self.as_ptr()) }; if v == -1 { - Err(PyErr::fetch(self.python())) + Err(PyErr::fetch(py)) } else { Ok(v) } @@ -161,10 +158,10 @@ pub trait ObjectProtocol<'p> : PythonObject<'p> { /// Returns whether the object is considered to be true. /// This is equivalent to the Python expression: 'not not self' #[inline] - fn is_true(&self) -> PyResult<'p, bool> { + fn is_true(&self, py: Python) -> PyResult { let v = unsafe { ffi::PyObject_IsTrue(self.as_ptr()) }; if v == -1 { - Err(PyErr::fetch(self.python())) + Err(PyErr::fetch(py)) } else { Ok(v != 0) } @@ -173,10 +170,10 @@ pub trait ObjectProtocol<'p> : PythonObject<'p> { /// Returns the length of the sequence or mapping. /// This is equivalent to the Python expression: 'len(self)' #[inline] - fn len(&self) -> PyResult<'p, usize> { + fn len(&self, py: Python) -> PyResult { let v = unsafe { ffi::PyObject_Size(self.as_ptr()) }; if v == -1 { - Err(PyErr::fetch(self.python())) + Err(PyErr::fetch(py)) } else { Ok(v as usize) } @@ -184,8 +181,7 @@ pub trait ObjectProtocol<'p> : PythonObject<'p> { /// This is equivalent to the Python expression: 'self[key]' #[inline] - fn get_item(&self, key: K) -> PyResult<'p, PyObject<'p>> where K: ToPyObject<'p> { - let py = self.python(); + fn get_item(&self, key: K, py: Python) -> PyResult where K: ToPyObject { key.with_borrowed_ptr(py, |key| unsafe { err::result_from_owned_ptr(py, ffi::PyObject_GetItem(self.as_ptr(), key)) @@ -195,8 +191,7 @@ pub trait ObjectProtocol<'p> : PythonObject<'p> { /// Sets an item value. /// This is equivalent to the Python expression 'self[key] = value'. #[inline] - fn set_item(&self, key: K, value: V) -> PyResult<'p, ()> where K: ToPyObject<'p>, V: ToPyObject<'p> { - let py = self.python(); + fn set_item(&self, key: K, value: V, py: Python) -> 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, @@ -207,41 +202,44 @@ pub trait ObjectProtocol<'p> : PythonObject<'p> { /// Deletes an item. /// This is equivalent to the Python expression 'del self[key]'. #[inline] - fn del_item(&self, key: K) -> PyResult<'p, ()> where K: ToPyObject<'p> { - let py = self.python(); + fn del_item(&self, key: K, py: Python) -> PyResult<()> where K: ToPyObject { key.with_borrowed_ptr(py, |key| unsafe { err::error_on_minusone(py, ffi::PyObject_DelItem(self.as_ptr(), key)) }) } - /// Takes an object and returns an iterator for it. +/* /// 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. #[cfg(feature="python27-sys")] #[inline] - fn iter(&self) -> PyResult<'p, ::objects::PyIterator<'p>> { + fn iter(&self, py: Python) -> PyResult<::objects::PyIterator<'p>> { unsafe { err::result_cast_from_owned_ptr(self.python(), ffi::PyObject_GetIter(self.as_ptr())) } + }*/ +} + +impl ObjectProtocol for PyObject {} + +impl fmt::Debug for PyObject { + fn fmt(&self, f : &mut fmt::Formatter) -> Result<(), fmt::Error> { + // TODO: we shouldn't use fmt::Error when repr() fails + let gil_guard = Python::acquire_gil(); + let py = gil_guard.python(); + let repr_obj = try!(self.repr(py).map_err(|_| fmt::Error)); + f.write_str(&repr_obj.to_string_lossy(py)) } } -impl <'p> ObjectProtocol<'p> for PyObject<'p> {} - -impl <'p> fmt::Debug for PyObject<'p> { +impl fmt::Display for PyObject { fn fmt(&self, f : &mut fmt::Formatter) -> Result<(), fmt::Error> { - use objectprotocol::ObjectProtocol; - let repr_obj = try!(self.repr().map_err(|_| fmt::Error)); - f.write_str(&repr_obj.to_string_lossy()) - } -} - -impl <'p> fmt::Display for PyObject<'p> { - fn fmt(&self, f : &mut fmt::Formatter) -> Result<(), fmt::Error> { - use objectprotocol::ObjectProtocol; - let str_obj = try!(self.str().map_err(|_| fmt::Error)); - f.write_str(&str_obj.to_string_lossy()) + // TODO: we shouldn't use fmt::Error when str() fails + let gil_guard = Python::acquire_gil(); + let py = gil_guard.python(); + let str_obj = try!(self.str(py).map_err(|_| fmt::Error)); + f.write_str(&str_obj.to_string_lossy(py)) } } @@ -250,7 +248,7 @@ mod test { use std; use python::{Python, PythonObject}; use conversion::ToPyObject; - use objects::{PySequence, PyList, PyTuple}; + use objects::{/*PySequence, */PyList, PyTuple}; #[test] fn test_debug_string() { diff --git a/src/objects/boolobject.rs b/src/objects/boolobject.rs index 8c43e712..0dcf5d62 100644 --- a/src/objects/boolobject.rs +++ b/src/objects/boolobject.rs @@ -1,39 +1,39 @@ use ffi; -use python::{Python, ToPythonPointer}; +use python::Python; use err::PyResult; use super::PyObject; use conversion::{ExtractPyObject, ToPyObject}; /// Represents a Python `bool`. -pub struct PyBool<'p>(PyObject<'p>); +pub struct PyBool(PyObject); pyobject_newtype!(PyBool, PyBool_Check, PyBool_Type); -impl <'p> PyBool<'p> { +impl PyBool { /// Depending on `val`, returns `py.True()` or `py.False()`. #[inline] - pub fn get(py: Python<'p>, val: bool) -> PyBool<'p> { + pub fn get(py: Python, val: bool) -> PyBool { if val { py.True() } else { py.False() } } /// Gets whether this boolean is `true`. #[inline] pub fn is_true(&self) -> bool { - self.as_ptr() == unsafe { ::ffi::Py_True() } + self.0.as_ptr() == unsafe { ::ffi::Py_True() } } } /// Converts a rust `bool` to a Python `bool`. -impl <'p> ToPyObject<'p> for bool { - type ObjectType = PyBool<'p>; +impl ToPyObject for bool { + type ObjectType = PyBool; #[inline] - fn to_py_object(&self, py: Python<'p>) -> PyBool<'p> { + fn to_py_object(&self, py: Python) -> PyBool { PyBool::get(py, *self) } #[inline] - fn with_borrowed_ptr(&self, _py: Python<'p>, f: F) -> R + fn with_borrowed_ptr(&self, _py: Python, f: F) -> R where F: FnOnce(*mut ffi::PyObject) -> R { // Avoid unnecessary Py_INCREF/Py_DECREF pair @@ -44,7 +44,7 @@ impl <'p> ToPyObject<'p> for bool { /// Converts a Python `bool` to a rust `bool`. /// /// Fails with `TypeError` if the input is not a Python `bool`. -extract!(obj to bool => { - Ok(try!(obj.cast_as::()).is_true()) +extract!(obj to bool; py => { + Ok(try!(obj.cast_as::(py)).is_true()) }); diff --git a/src/objects/dict.rs b/src/objects/dict.rs index a666de65..3c5573f0 100644 --- a/src/objects/dict.rs +++ b/src/objects/dict.rs @@ -17,22 +17,22 @@ // DEALINGS IN THE SOFTWARE. use ffi; -use python::{Python, ToPythonPointer, PythonObject}; +use python::{Python, PythonObject}; use conversion::ToPyObject; use objects::{PyObject, PyList}; use err::{self, PyResult, PyErr}; use std::{mem, collections, hash, cmp}; /// Represents a Python `dict`. -pub struct PyDict<'p>(PyObject<'p>); +pub struct PyDict(PyObject); pyobject_newtype!(PyDict, PyDict_Check, PyDict_Type); -impl <'p> PyDict<'p> { +impl PyDict { /// Creates a new empty dictionary. /// /// May panic when running out of memory. - pub fn new(py: Python<'p>) -> PyDict<'p> { + pub fn new(py: Python) -> PyDict { unsafe { err::cast_from_owned_ptr_or_panic(py, ffi::PyDict_New()) } @@ -40,32 +40,30 @@ impl <'p> PyDict<'p> { /// Return a new dictionary that contains the same key-value pairs as self. /// Corresponds to `dict(self)` in Python. - pub fn copy(&self) -> PyResult<'p, PyDict<'p>> { - let py = self.python(); + pub fn copy(&self, py: Python) -> PyResult { unsafe { - err::result_cast_from_owned_ptr(py, ffi::PyDict_Copy(self.as_ptr())) + err::result_cast_from_owned_ptr(py, ffi::PyDict_Copy(self.0.as_ptr())) } } /// Empty an existing dictionary of all key-value pairs. #[inline] - pub fn clear(&self) { - unsafe { ffi::PyDict_Clear(self.as_ptr()) } + pub fn clear(&self, _py: Python) { + unsafe { ffi::PyDict_Clear(self.0.as_ptr()) } } /// Return the number of items in the dictionary. /// This is equivalent to len(p) on a dictionary. #[inline] - pub fn len(&self) -> usize { - unsafe { ffi::PyDict_Size(self.as_ptr()) as usize } + pub fn len(&self, _py: Python) -> usize { + unsafe { ffi::PyDict_Size(self.0.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(&self, key: K) -> PyResult<'p, bool> where K: ToPyObject<'p> { - let py = self.python(); + pub fn contains(&self, key: K, py: Python) -> PyResult where K: ToPyObject { key.with_borrowed_ptr(py, |key| unsafe { - match ffi::PyDict_Contains(self.as_ptr(), key) { + match ffi::PyDict_Contains(self.0.as_ptr(), key) { 1 => Ok(true), 0 => Ok(false), _ => Err(PyErr::fetch(py)) @@ -75,56 +73,51 @@ impl <'p> PyDict<'p> { /// Gets an item from the dictionary. /// Returns None if the item is not present, or if an error occurs. - pub fn get_item(&self, key: K) -> Option> where K: ToPyObject<'p> { - let py = self.python(); + pub fn get_item(&self, key: K, py: Python) -> Option where K: ToPyObject { key.with_borrowed_ptr(py, |key| unsafe { PyObject::from_borrowed_ptr_opt(py, - ffi::PyDict_GetItem(self.as_ptr(), key)) + ffi::PyDict_GetItem(self.0.as_ptr(), key)) }) } /// Sets an item value. /// This is equivalent to the Python expression `self[key] = value`. - pub fn set_item(&self, key: K, value: V) -> PyResult<'p, ()> where K: ToPyObject<'p>, V: ToPyObject<'p> { - let py = self.python(); + pub fn set_item(&self, key: K, value: V, py: Python) -> 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::PyDict_SetItem(self.as_ptr(), key, value)) + ffi::PyDict_SetItem(self.0.as_ptr(), key, value)) })) } /// Deletes an item. /// This is equivalent to the Python expression `del self[key]`. - pub fn del_item(&self, key: K) -> PyResult<'p, ()> where K: ToPyObject<'p> { - let py = self.python(); + pub fn del_item(&self, key: K, py: Python) -> PyResult<()> where K: ToPyObject { key.with_borrowed_ptr(py, |key| unsafe { err::error_on_minusone(py, - ffi::PyDict_DelItem(self.as_ptr(), key)) + ffi::PyDict_DelItem(self.0.as_ptr(), key)) }) } // List of dict items. // This is equivalent to the python expression `list(dict.items())`. - pub fn items_list(&self) -> PyList<'p> { - let py = self.python(); + pub fn items_list(&self, py: Python) -> PyList { unsafe { - err::cast_from_owned_ptr_or_panic(py, ffi::PyDict_Items(self.as_ptr())) + err::cast_from_owned_ptr_or_panic(py, ffi::PyDict_Items(self.0.as_ptr())) } } /// Returns the list of (key,value) pairs in this dictionary. - pub fn items(&self) -> Vec<(PyObject<'p>, PyObject<'p>)> { + pub fn items(&self, py: Python) -> 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 py = self.python(); - let mut vec = Vec::with_capacity(self.len()); + let mut vec = Vec::with_capacity(self.len(py)); 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 { + while ffi::PyDict_Next(self.0.as_ptr(), &mut pos, &mut key, &mut value) != 0 { vec.push((PyObject::from_borrowed_ptr(py, key), PyObject::from_borrowed_ptr(py, value))); } @@ -133,31 +126,31 @@ impl <'p> PyDict<'p> { } } -impl <'p, K, V> ToPyObject<'p> for collections::HashMap - where K: hash::Hash+cmp::Eq+ToPyObject<'p>, - V: ToPyObject<'p> +impl ToPyObject for collections::HashMap + where K: hash::Hash+cmp::Eq+ToPyObject, + V: ToPyObject { - type ObjectType = PyDict<'p>; + type ObjectType = PyDict; - fn to_py_object(&self, py: Python<'p>) -> PyDict<'p> { + fn to_py_object(&self, py: Python) -> PyDict { let dict = PyDict::new(py); - for (key, value) in self.iter() { - dict.set_item(key, value).unwrap(); + for (key, value) in self { + dict.set_item(key, value, py).unwrap(); }; dict } } -impl <'p, K, V> ToPyObject<'p> for collections::BTreeMap - where K: cmp::Eq+ToPyObject<'p>, - V: ToPyObject<'p> +impl ToPyObject for collections::BTreeMap + where K: cmp::Eq+ToPyObject, + V: ToPyObject { - type ObjectType = PyDict<'p>; + type ObjectType = PyDict; - fn to_py_object(&self, py: Python<'p>) -> PyDict<'p> { + fn to_py_object(&self, py: Python) -> PyDict { let dict = PyDict::new(py); - for (key, value) in self.iter() { - dict.set_item(key, value).unwrap(); + for (key, value) in self { + dict.set_item(key, value, py).unwrap(); }; dict } @@ -177,10 +170,10 @@ mod test { let py = gil.python(); let mut v = HashMap::new(); let dict = v.to_py_object(py); - assert_eq!(0, dict.len()); + assert_eq!(0, dict.len(py)); v.insert(7, 32); let dict2 = v.to_py_object(py); - assert_eq!(1, dict2.len()); + assert_eq!(1, dict2.len(py)); } #[test] @@ -190,8 +183,8 @@ mod test { let mut v = HashMap::new(); v.insert(7, 32); let dict = v.to_py_object(py); - assert_eq!(true, dict.contains(7i32).unwrap()); - assert_eq!(false, dict.contains(8i32).unwrap()); + assert_eq!(true, dict.contains(7i32, py).unwrap()); + assert_eq!(false, dict.contains(8i32, py).unwrap()); } #[test] @@ -201,8 +194,8 @@ mod test { let mut v = HashMap::new(); v.insert(7, 32); let dict = v.to_py_object(py); - assert_eq!(32, dict.get_item(7i32).unwrap().extract::().unwrap()); - assert_eq!(None, dict.get_item(8i32)); + assert_eq!(32, dict.get_item(7i32, py).unwrap().extract::(py).unwrap()); + assert_eq!(None, dict.get_item(8i32, py)); } #[test] @@ -212,10 +205,10 @@ mod test { let mut v = HashMap::new(); v.insert(7, 32); let dict = v.to_py_object(py); - 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::().unwrap()); - assert_eq!(123i32, dict.get_item(8i32).unwrap().extract::().unwrap()); + assert!(dict.set_item(7i32, 42i32, py).is_ok()); // change + assert!(dict.set_item(8i32, 123i32, py).is_ok()); // insert + assert_eq!(42i32, dict.get_item(7i32, py).unwrap().extract::(py).unwrap()); + assert_eq!(123i32, dict.get_item(8i32, py).unwrap().extract::(py).unwrap()); } #[test] @@ -225,8 +218,8 @@ mod test { let mut v = HashMap::new(); v.insert(7, 32); let dict = v.to_py_object(py); - assert!(dict.set_item(7i32, 42i32).is_ok()); // change - assert!(dict.set_item(8i32, 123i32).is_ok()); // insert + assert!(dict.set_item(7i32, 42i32, py).is_ok()); // change + assert!(dict.set_item(8i32, 123i32, py).is_ok()); // insert assert_eq!(32i32, *v.get(&7i32).unwrap()); // not updated! assert_eq!(None, v.get(&8i32)); } @@ -239,9 +232,9 @@ mod test { let mut v = HashMap::new(); v.insert(7, 32); let dict = v.to_py_object(py); - assert!(dict.del_item(7i32).is_ok()); - assert_eq!(0, dict.len()); - assert_eq!(None, dict.get_item(7i32)); + assert!(dict.del_item(7i32, py).is_ok()); + assert_eq!(0, dict.len(py)); + assert_eq!(None, dict.get_item(7i32, py)); } #[test] @@ -251,10 +244,11 @@ mod test { let mut v = HashMap::new(); v.insert(7, 32); let dict = v.to_py_object(py); - assert!(dict.del_item(7i32).is_ok()); // change + assert!(dict.del_item(7i32, py).is_ok()); // change assert_eq!(32i32, *v.get(&7i32).unwrap()); // not updated! } +/* #[test] fn test_items_list() { let gil = Python::acquire_gil(); @@ -267,7 +261,7 @@ mod test { // 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().into_iter() { + for el in dict.items_list(py) { let tuple = el.cast_into::().unwrap(); key_sum += tuple.get_item(0).extract::().unwrap(); value_sum += tuple.get_item(1).extract::().unwrap(); @@ -275,6 +269,7 @@ mod test { assert_eq!(7 + 8 + 9, key_sum); assert_eq!(32 + 42 + 123, value_sum); } +*/ #[test] fn test_items() { @@ -288,9 +283,9 @@ mod test { // 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().into_iter() { - key_sum += key.extract::().unwrap(); - value_sum += value.extract::().unwrap(); + for (key, value) in dict.items(py) { + key_sum += key.extract::(py).unwrap(); + value_sum += value.extract::(py).unwrap(); } assert_eq!(7 + 8 + 9, key_sum); assert_eq!(32 + 42 + 123, value_sum); diff --git a/src/objects/exc.rs b/src/objects/exc.rs index b8f02f37..baad70ac 100644 --- a/src/objects/exc.rs +++ b/src/objects/exc.rs @@ -24,44 +24,48 @@ use std::str::Utf8Error; use std::mem; use std::ffi::CStr; use ffi; -use python::{Python, ToPythonPointer, PythonObject, PythonObjectWithCheckedDowncast, PythonObjectDowncastError, PythonObjectWithTypeObject}; +use python::{Python, PythonObject, PythonObjectWithCheckedDowncast, PythonObjectDowncastError, PythonObjectWithTypeObject}; use err::{self, PyResult}; use super::object::PyObject; use super::typeobject::PyType; macro_rules! exc_type( ($name:ident, $exc_name:ident) => ( - pub struct $name<'p>(PyObject<'p>); + pub struct $name(PyObject); pyobject_newtype!($name); - impl <'p> PythonObjectWithCheckedDowncast<'p> for $name<'p> { + impl PythonObjectWithCheckedDowncast for $name { #[inline] - fn downcast_from(obj : PyObject<'p>) -> Result<$name<'p>, PythonObjectDowncastError<'p>> { + fn downcast_from<'p>(obj : PyObject, py: Python<'p>) + -> Result<$name, PythonObjectDowncastError<'p>> + { unsafe { if ffi::PyObject_TypeCheck(obj.as_ptr(), ffi::$exc_name as *mut ffi::PyTypeObject) != 0 { Ok(PythonObject::unchecked_downcast_from(obj)) } else { - Err(PythonObjectDowncastError(obj.python())) + Err(PythonObjectDowncastError(py)) } } } #[inline] - fn downcast_borrow_from<'a>(obj : &'a ::objects::object::PyObject<'p>) -> Result<&'a $name<'p>, PythonObjectDowncastError<'p>> { + fn downcast_borrow_from<'a, 'p>(obj: &'a PyObject, py: Python<'p>) + -> Result<&'a $name, PythonObjectDowncastError<'p>> + { unsafe { if ffi::PyObject_TypeCheck(obj.as_ptr(), ffi::$exc_name as *mut ffi::PyTypeObject) != 0 { Ok(PythonObject::unchecked_downcast_borrow_from(obj)) } else { - Err(PythonObjectDowncastError(obj.python())) + Err(PythonObjectDowncastError(py)) } } } } - impl <'p> PythonObjectWithTypeObject<'p> for $name<'p> { + impl PythonObjectWithTypeObject for $name { #[inline] - fn type_object(py: Python<'p>) -> PyType<'p> { + fn type_object(py: Python) -> PyType { unsafe { PyType::from_type_ptr(py, ffi::$exc_name as *mut ffi::PyTypeObject) } } } @@ -103,8 +107,8 @@ exc_type!(UnicodeDecodeError, PyExc_UnicodeDecodeError); exc_type!(UnicodeEncodeError, PyExc_UnicodeEncodeError); exc_type!(UnicodeTranslateError, PyExc_UnicodeTranslateError); -impl<'p> UnicodeDecodeError<'p> { - pub fn new(py: Python<'p>, encoding: &CStr, input: &[u8], range: Range, reason: &CStr) -> PyResult<'p, UnicodeDecodeError<'p>> { +impl UnicodeDecodeError { + pub fn new(py: Python, encoding: &CStr, input: &[u8], range: Range, reason: &CStr) -> PyResult { unsafe { let input: &[c_char] = mem::transmute(input); err::result_cast_from_owned_ptr(py, @@ -113,7 +117,7 @@ impl<'p> UnicodeDecodeError<'p> { } } - pub fn new_utf8(py: Python<'p>, input: &[u8], err: Utf8Error) -> PyResult<'p, UnicodeDecodeError<'p>> { + pub fn new_utf8(py: Python, input: &[u8], err: Utf8Error) -> PyResult { let pos = err.valid_up_to(); UnicodeDecodeError::new(py, cstr!("utf-8"), input, pos .. input.len(), cstr!("invalid utf-8")) } diff --git a/src/objects/iterator.rs b/src/objects/iterator.rs index e725d88b..5d429638 100644 --- a/src/objects/iterator.rs +++ b/src/objects/iterator.rs @@ -16,20 +16,19 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -use python::{PythonObject, ToPythonPointer}; +use python::{Python, PythonObject, ToPythonPointer}; use objects::PyObject; use err::{PyErr, PyResult}; use ffi; -pub struct PyIterator<'p>(PyObject<'p>); +pub struct PyIterator(PyObject); pyobject_newtype!(PyIterator, PyIter_Check); -impl <'p> PyIterator<'p> { +impl PyIterator { /// Retrieves the next item from an iterator. /// Returns `None` when the iterator is exhausted. - pub fn iter_next(&self) -> PyResult<'p, Option>> { - let py = self.python(); + pub fn iter_next(&self, py: Python) -> PyResult> { match unsafe { PyObject::from_owned_ptr_opt(py, ffi::PyIter_Next(self.as_ptr())) } { Some(obj) => Ok(Some(obj)), None => { diff --git a/src/objects/list.rs b/src/objects/list.rs index 1dd54352..2ea30f17 100644 --- a/src/objects/list.rs +++ b/src/objects/list.rs @@ -23,18 +23,18 @@ use ffi::{self, Py_ssize_t}; use conversion::{ToPyObject, ExtractPyObject}; /// Represents a Python `list`. -pub struct PyList<'p>(PyObject<'p>); +pub struct PyList(PyObject); pyobject_newtype!(PyList, PyList_Check, PyList_Type); -impl <'p> PyList<'p> { +impl PyList { /// Construct a new list with the given elements. - pub fn new(py: Python<'p>, elements: &[PyObject<'p>]) -> PyList<'p> { + pub fn new(py: Python, elements: &[PyObject]) -> PyList { unsafe { let ptr = ffi::PyList_New(elements.len() as Py_ssize_t); let t = err::result_from_owned_ptr(py, ptr).unwrap().unchecked_cast_into::(); for (i, e) in elements.iter().enumerate() { - ffi::PyList_SetItem(ptr, i as Py_ssize_t, e.clone().steal_ptr()); + ffi::PyList_SetItem(ptr, i as Py_ssize_t, e.steal_ptr(py)); } t } @@ -42,42 +42,43 @@ impl <'p> PyList<'p> { /// Gets the length of the list. #[inline] - pub fn len(&self) -> usize { + pub fn len(&self, _py: Python) -> usize { // non-negative Py_ssize_t should always fit into Rust usize unsafe { - ffi::PyList_Size(self.as_ptr()) as usize + ffi::PyList_Size(self.0.as_ptr()) as usize } } /// Gets the item at the specified index. /// /// Panics if the index is out of range. - pub fn get_item(&self, index: usize) -> PyObject<'p> { - assert!(index < self.len()); + pub fn get_item(&self, index: usize, py: Python) -> PyObject { + assert!(index < self.len(py)); unsafe { - PyObject::from_borrowed_ptr(self.python(), ffi::PyList_GetItem(self.as_ptr(), index as Py_ssize_t)) + PyObject::from_borrowed_ptr(py, ffi::PyList_GetItem(self.0.as_ptr(), index as Py_ssize_t)) } } /// Sets the item at the specified index. /// /// Panics if the index is out of range. - pub fn set_item(&self, index: usize, item: PyObject<'p>) { - let r = unsafe { ffi::PyList_SetItem(self.as_ptr(), index as Py_ssize_t, item.steal_ptr()) }; + pub fn set_item(&self, index: usize, item: PyObject, _py: Python) { + let r = unsafe { ffi::PyList_SetItem(self.0.as_ptr(), index as Py_ssize_t, item.steal_ptr()) }; assert!(r == 0); } /// Inserts an item at the specified index. /// /// Panics if the index is out of range. - pub fn insert_item(&self, index: usize, item: PyObject<'p>) { - let r = unsafe { ffi::PyList_Insert(self.as_ptr(), index as Py_ssize_t, item.as_ptr()) }; + pub fn insert_item(&self, index: usize, item: PyObject, _py: Python) { + let r = unsafe { ffi::PyList_Insert(self.0.as_ptr(), index as Py_ssize_t, item.as_ptr()) }; assert!(r == 0); } } -impl <'p> IntoIterator for PyList<'p> { - type Item = PyObject<'p>; +/* +impl <'p> IntoIterator for PyList { + type Item = PyObject; type IntoIter = PyListIterator<'p>; #[inline] @@ -86,8 +87,8 @@ impl <'p> IntoIterator for PyList<'p> { } } -impl <'a, 'p> IntoIterator for &'a PyList<'p> { - type Item = PyObject<'p>; +impl <'a, 'p> IntoIterator for &'a PyList { + type Item = PyObject; type IntoIter = PyListIterator<'p>; #[inline] @@ -98,15 +99,15 @@ impl <'a, 'p> IntoIterator for &'a PyList<'p> { /// Used by `impl IntoIterator for &PyList`. pub struct PyListIterator<'p> { - list: PyList<'p>, + list: PyList, index: usize } impl <'p> Iterator for PyListIterator<'p> { - type Item = PyObject<'p>; + type Item = PyObject; #[inline] - fn next(&mut self) -> Option> { + fn next(&mut self) -> Option { if self.index < self.list.len() { let item = self.list.get_item(self.index); self.index += 1; @@ -119,16 +120,17 @@ impl <'p> Iterator for PyListIterator<'p> { // Note: we cannot implement size_hint because the length of the list // might change during the iteration. } +*/ -impl <'p, T> ToPyObject<'p> for [T] where T: ToPyObject<'p> { - type ObjectType = PyList<'p>; +impl ToPyObject for [T] where T: ToPyObject { + type ObjectType = PyList; - fn to_py_object(&self, py: Python<'p>) -> PyList<'p> { + fn to_py_object(&self, py: Python) -> PyList { unsafe { let ptr = ffi::PyList_New(self.len() as Py_ssize_t); let t = err::cast_from_owned_ptr_or_panic(py, ptr); for (i, e) in self.iter().enumerate() { - let obj = e.to_py_object(py); + let obj = e.to_py_object(py).into_object(); ffi::PyList_SetItem(ptr, i as Py_ssize_t, obj.steal_ptr()); } t @@ -136,28 +138,28 @@ impl <'p, T> ToPyObject<'p> for [T] where T: ToPyObject<'p> { } } -impl <'python, 'source, 'prepared, T> ExtractPyObject<'python, 'source, 'prepared> - for Vec - where T: for<'s, 'p> ExtractPyObject<'python, 's, 'p>, - 'python : 'source +impl <'prepared, T> ExtractPyObject<'prepared> for Vec + where T: ExtractPyObject<'prepared> { + type Prepared = Vec; - type Prepared = &'source PyObject<'python>; - - #[inline] - fn prepare_extract(obj: &'source PyObject<'python>) -> PyResult<'python, Self::Prepared> { - Ok(obj) - } - - #[inline] - fn extract(&obj: &'prepared &'source PyObject<'python>) -> PyResult<'python, Vec> { - let list = try!(obj.cast_as::()); - let mut v = Vec::with_capacity(list.len()); - for i in 0 .. list.len() { - v.push(try!(list.get_item(i).extract::())); + fn prepare_extract(obj: &PyObject, py: Python) -> PyResult { + let list = try!(obj.cast_as::(py)); + let len = list.len(py); + let mut v = Vec::with_capacity(len); + for i in 0 .. len { + v.push(try!(T::prepare_extract(&list.get_item(i, py), py))); } Ok(v) } + + fn extract(prepared: &'prepared Self::Prepared, py: Python) -> PyResult> { + let mut v = Vec::with_capacity(prepared.len()); + for prepared_elem in prepared { + v.push(try!(T::extract(prepared_elem, py))); + } + Ok(v) + } } #[cfg(test)] @@ -173,7 +175,7 @@ mod test { let py = gil.python(); let v = vec![1,2,3,4]; let list = v.to_py_object(py); - assert_eq!(4, list.len()); + assert_eq!(4, list.len(py)); } #[test] @@ -182,10 +184,10 @@ mod test { let py = gil.python(); let v = vec![2, 3, 5, 7]; let list = v.to_py_object(py); - assert_eq!(2, list.get_item(0).extract::().unwrap()); - assert_eq!(3, list.get_item(1).extract::().unwrap()); - assert_eq!(5, list.get_item(2).extract::().unwrap()); - assert_eq!(7, list.get_item(3).extract::().unwrap()); + assert_eq!(2, list.get_item(0, py).extract::(py).unwrap()); + assert_eq!(3, list.get_item(1, py).extract::(py).unwrap()); + assert_eq!(5, list.get_item(2, py).extract::(py).unwrap()); + assert_eq!(7, list.get_item(3, py).extract::(py).unwrap()); } #[test] @@ -195,9 +197,9 @@ mod test { let v = vec![2, 3, 5, 7]; let list = v.to_py_object(py); let val = 42i32.to_py_object(py).into_object(); - assert_eq!(2, list.get_item(0).extract::().unwrap()); - list.set_item(0, val); - assert_eq!(42, list.get_item(0).extract::().unwrap()); + assert_eq!(2, list.get_item(0, py).extract::(py).unwrap()); + list.set_item(0, val, py); + assert_eq!(42, list.get_item(0, py).extract::(py).unwrap()); } #[test] @@ -207,14 +209,15 @@ mod test { let v = vec![2, 3, 5, 7]; let list = v.to_py_object(py); let val = 42i32.to_py_object(py).into_object(); - assert_eq!(4, list.len()); - assert_eq!(2, list.get_item(0).extract::().unwrap()); - list.insert_item(0, val); - assert_eq!(5, list.len()); - assert_eq!(42, list.get_item(0).extract::().unwrap()); - assert_eq!(2, list.get_item(1).extract::().unwrap()); + assert_eq!(4, list.len(py)); + assert_eq!(2, list.get_item(0, py).extract::(py).unwrap()); + list.insert_item(0, val, py); + assert_eq!(5, list.len(py)); + assert_eq!(42, list.get_item(0, py).extract::(py).unwrap()); + assert_eq!(2, list.get_item(1, py).extract::(py).unwrap()); } +/* #[test] fn test_iter() { let gil = Python::acquire_gil(); @@ -223,7 +226,7 @@ mod test { let list = v.to_py_object(py); let mut idx = 0; for el in list { - assert_eq!(v[idx], el.extract::().unwrap()); + assert_eq!(v[idx], el.extract::(py).unwrap()); idx += 1; } assert_eq!(idx, v.len()); @@ -242,6 +245,7 @@ mod test { } assert_eq!(idx, v.len()); } + */ /*#[test] fn test_extract() { diff --git a/src/objects/mod.rs b/src/objects/mod.rs index 7dadb302..22892b7c 100644 --- a/src/objects/mod.rs +++ b/src/objects/mod.rs @@ -44,26 +44,24 @@ pub use self::sequence::PySequence; /// `T: ToPyObject` is expected. macro_rules! pyobject_to_pyobject( ($name: ident) => ( - impl <'p, 's> ::conversion::ToPyObject<'p> for $name<'s> { - type ObjectType = $name<'p>; + impl ::conversion::ToPyObject for $name { + type ObjectType = $name; #[inline] - fn to_py_object(&self, py: ::python::Python<'p>) -> $name<'p> { - self.clone().into_py_object(py) + fn to_py_object(&self, py: ::python::Python) -> $name { + ::python::PyClone::clone_ref(self, py) } #[inline] - fn into_py_object(self, _py: ::python::Python<'p>) -> $name<'p> { - // Transmute the lifetime. - // This is safe, because both lifetime variables represent the same lifetime: - // that of the python GIL acquisition. - unsafe { ::std::mem::transmute(self) } + fn into_py_object(self, _py: ::python::Python) -> $name { + self } #[inline] - fn with_borrowed_ptr(&self, _py: ::python::Python<'p>, f: F) -> R - where F: FnOnce(*mut ffi::PyObject) -> R { - f(self.as_ptr()) + fn with_borrowed_ptr(&self, _py: ::python::Python, f: F) -> R + where F: FnOnce(*mut ffi::PyObject) -> R + { + f(::python::PythonObject::as_object(self).as_ptr()) } } ) @@ -71,70 +69,56 @@ macro_rules! pyobject_to_pyobject( macro_rules! pyobject_newtype( ($name: ident) => ( - /// Clone returns another reference to the Python object, - /// thus incrementing the reference count by 1. - impl <'p> Clone for $name<'p> { - #[inline] - fn clone(&self) -> Self { - $name(self.0.clone()) - } - } - pyobject_to_pyobject!($name); - impl <'p> ::python::PythonObject<'p> for $name<'p> { + impl ::python::PythonObject for $name { #[inline] - fn as_object(&self) -> &::objects::object::PyObject<'p> { + fn as_object(&self) -> &::objects::object::PyObject { &self.0 } #[inline] - fn into_object(self) -> ::objects::object::PyObject<'p> { + fn into_object(self) -> ::objects::object::PyObject { self.0 } /// Unchecked downcast from PyObject to Self. /// Undefined behavior if the input object does not have the expected type. #[inline] - unsafe fn unchecked_downcast_from(obj: ::objects::object::PyObject<'p>) -> Self { + unsafe fn unchecked_downcast_from(obj: ::objects::object::PyObject) -> Self { $name(obj) } /// Unchecked downcast from PyObject to Self. /// Undefined behavior if the input object does not have the expected type. #[inline] - unsafe fn unchecked_downcast_borrow_from<'a>(obj: &'a ::objects::object::PyObject<'p>) -> &'a Self { + unsafe fn unchecked_downcast_borrow_from<'a>(obj: &'a ::objects::object::PyObject) -> &'a Self { ::std::mem::transmute(obj) } - - #[inline] - fn python(&self) -> ::python::Python<'p> { - self.0.python() - } } ); ($name: ident, $checkfunction: ident) => ( pyobject_newtype!($name); - impl <'p> ::python::PythonObjectWithCheckedDowncast<'p> for $name<'p> { + impl ::python::PythonObjectWithCheckedDowncast for $name { #[inline] - fn downcast_from(obj : ::objects::object::PyObject<'p>) -> Result<$name<'p>, ::python::PythonObjectDowncastError<'p>> { + fn downcast_from<'p>(obj: ::objects::object::PyObject, py: ::python::Python<'p>) -> Result<$name, ::python::PythonObjectDowncastError<'p>> { unsafe { - if ::ffi::$checkfunction(::python::ToPythonPointer::as_ptr(&obj)) != 0 { + if ::ffi::$checkfunction(obj.as_ptr()) != 0 { Ok($name(obj)) } else { - Err(::python::PythonObjectDowncastError(::python::PythonObject::python(&obj))) + Err(::python::PythonObjectDowncastError(py)) } } } #[inline] - fn downcast_borrow_from<'a>(obj : &'a ::objects::object::PyObject<'p>) -> Result<&'a $name<'p>, ::python::PythonObjectDowncastError<'p>> { + fn downcast_borrow_from<'a, 'p>(obj: &'a ::objects::object::PyObject, py: ::python::Python<'p>) -> Result<&'a $name, ::python::PythonObjectDowncastError<'p>> { unsafe { - if ::ffi::$checkfunction(::python::ToPythonPointer::as_ptr(obj)) != 0 { + if ::ffi::$checkfunction(obj.as_ptr()) != 0 { Ok(::std::mem::transmute(obj)) } else { - Err(::python::PythonObjectDowncastError(::python::PythonObject::python(obj))) + Err(::python::PythonObjectDowncastError(py)) } } } @@ -143,9 +127,9 @@ macro_rules! pyobject_newtype( ($name: ident, $checkfunction: ident, $typeobject: ident) => ( pyobject_newtype!($name, $checkfunction); - impl <'p> ::python::PythonObjectWithTypeObject<'p> for $name<'p> { + impl ::python::PythonObjectWithTypeObject for $name { #[inline] - fn type_object(py: ::python::Python<'p>) -> ::objects::typeobject::PyType<'p> { + fn type_object(py: ::python::Python) -> ::objects::typeobject::PyType { unsafe { ::objects::typeobject::PyType::from_type_ptr(py, &mut ::ffi::$typeobject) } } } @@ -153,21 +137,18 @@ macro_rules! pyobject_newtype( ); macro_rules! extract( - ($obj:ident to $t:ty => $body: block) => { - impl <'python, 'source, 'prepared> - ::conversion::ExtractPyObject<'python, 'source, 'prepared> + ($obj:ident to $t:ty; $py:ident => $body: block) => { + impl <'prepared> ::conversion::ExtractPyObject<'prepared> for $t - where 'python: 'source { - - type Prepared = &'source PyObject<'python>; + type Prepared = PyObject; #[inline] - fn prepare_extract(obj: &'source PyObject<'python>) -> PyResult<'python, Self::Prepared> { - Ok(obj) + fn prepare_extract(obj: &PyObject, py: Python) -> PyResult { + Ok(::python::PyClone::clone_ref(obj, py)) } - fn extract(&$obj: &'prepared &'source PyObject<'python>) -> PyResult<'python, Self> { + fn extract($obj: &'prepared PyObject, $py: Python) -> PyResult { $body } } @@ -192,3 +173,4 @@ pub mod exc; pub mod oldstyle; mod tests; + diff --git a/src/objects/module.rs b/src/objects/module.rs index 8b848ca5..77f0096c 100644 --- a/src/objects/module.rs +++ b/src/objects/module.rs @@ -19,7 +19,7 @@ use std; use ffi; use libc::c_char; -use python::{Python, PythonObject, ToPythonPointer}; +use python::{Python, PythonObject}; use objectprotocol::ObjectProtocol; use conversion::ToPyObject; use objects::{PyObject, PyTuple, PyDict, exc}; @@ -27,13 +27,13 @@ use err::{self, PyResult, PyErr}; use std::ffi::{CStr, CString}; /// Represents a Python module object. -pub struct PyModule<'p>(PyObject<'p>); +pub struct PyModule(PyObject); pyobject_newtype!(PyModule, PyModule_Check, PyModule_Type); -impl <'p> PyModule<'p> { +impl PyModule { /// Create a new module object with the `__name__` attribute set to name. - pub fn new(py: Python<'p>, name: &str) -> PyResult<'p, PyModule<'p>> { + pub fn new(py: Python, name: &str) -> PyResult { let name = CString::new(name).unwrap(); unsafe { err::result_cast_from_owned_ptr(py, ffi::PyModule_New(name.as_ptr())) @@ -41,7 +41,7 @@ impl <'p> PyModule<'p> { } /// Import the Python module with the specified name. - pub fn import(py: Python<'p>, name: &str) -> PyResult<'p, PyModule<'p>> { + pub fn import(py: Python, name: &str) -> PyResult { let name = CString::new(name).unwrap(); unsafe { err::result_cast_from_owned_ptr(py, ffi::PyImport_ImportModule(name.as_ptr())) @@ -50,23 +50,21 @@ impl <'p> PyModule<'p> { /// 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) -> PyDict<'p> { - let py = self.python(); + pub fn dict(&self, py: Python) -> PyDict { unsafe { - let r = PyObject::from_borrowed_ptr(py, ffi::PyModule_GetDict(self.as_ptr())); + let r = PyObject::from_borrowed_ptr(py, ffi::PyModule_GetDict(self.0.as_ptr())); r.unchecked_cast_into::() } } - unsafe fn str_from_ptr<'a>(&'a self, ptr: *const c_char) -> PyResult<'p, &'a str> { - let py = self.python(); + unsafe fn str_from_ptr<'a>(&'a self, ptr: *const c_char, py: Python) -> PyResult<&'a str> { if ptr == std::ptr::null() { Err(PyErr::fetch(py)) } 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(try!(exc::UnicodeDecodeError::new_utf8(py, slice, e)))) + Err(e) => Err(PyErr::from_instance(try!(exc::UnicodeDecodeError::new_utf8(py, slice, e)), py)) } } } @@ -74,35 +72,36 @@ impl <'p> PyModule<'p> { /// Gets the module name. /// /// May fail if the module does not have a `__name__` attribute. - pub fn name<'a>(&'a self) -> PyResult<'p, &'a str> { - unsafe { self.str_from_ptr(ffi::PyModule_GetName(self.as_ptr())) } + pub fn name<'a>(&'a self, py: Python) -> PyResult<&'a str> { + unsafe { self.str_from_ptr(ffi::PyModule_GetName(self.0.as_ptr()), py) } } /// Gets the module filename. /// /// May fail if the module does not have a `__file__` attribute. - pub fn filename<'a>(&'a self) -> PyResult<'p, &'a str> { - unsafe { self.str_from_ptr(ffi::PyModule_GetFilename(self.as_ptr())) } + pub fn filename<'a>(&'a self, py: Python) -> PyResult<&'a str> { + unsafe { self.str_from_ptr(ffi::PyModule_GetFilename(self.0.as_ptr()), py) } } /// Gets a member from the module. /// This is equivalent to the Python expression: `getattr(module, name)` - pub fn get(&self, name: &str) -> PyResult<'p, PyObject<'p>> { - self.as_object().getattr(name) + pub fn get(&self, name: &str, py: Python) -> PyResult { + self.as_object().getattr(name, py) } /// Calls a function in the module. /// This is equivalent to the Python expression: `getattr(module, name)(*args, **kwargs)` - pub fn call(&self, name: &str, args: A, kwargs: Option<&PyDict<'p>>) -> PyResult<'p, PyObject<'p>> - where A: ToPyObject<'p, ObjectType=PyTuple<'p>> { - try!(self.as_object().getattr(name)).call(args, kwargs) + pub fn call(&self, name: &str, args: A, kwargs: Option<&PyDict>, py: Python) -> PyResult + where A: ToPyObject + { + try!(self.as_object().getattr(name, py)).call(args, kwargs, py) } /// Adds a member to the module. /// /// This is a convenience function which can be used from the module's initialization function. - pub fn add(&self, name: &str, value: V) -> PyResult<'p, ()> where V: ToPyObject<'p> { - self.dict().set_item(name, value) + pub fn add(&self, name: &str, value: V, py: Python) -> PyResult<()> where V: ToPyObject { + self.as_object().setattr(name, value, py) } /// Adds a new extension type to the module. @@ -110,9 +109,9 @@ impl <'p> PyModule<'p> { /// This is a convenience function that creates a new `PyRustTypeBuilder` and /// sets `new_type.__module__` to this module's name. /// The new type will be added to this module when `finish()` is called on the builder. - pub fn add_type(&self, name: &str) -> ::rustobject::typebuilder::PyRustTypeBuilder<'p, T> - where T: 'p + Send { - ::rustobject::typebuilder::new_typebuilder_for_module(self, name) + pub fn add_type<'p, T>(&self, name: &str, py: Python<'p>) -> ::rustobject::typebuilder::PyRustTypeBuilder<'p, T> + where T: 'static + Send { + ::rustobject::typebuilder::new_typebuilder_for_module(self, name, py) } } diff --git a/src/objects/num.rs b/src/objects/num.rs index 78fcd2f8..2971373e 100644 --- a/src/objects/num.rs +++ b/src/objects/num.rs @@ -19,7 +19,7 @@ extern crate num; use libc::{c_long, c_double}; -use python::{Python, PythonObject, ToPythonPointer}; +use python::{Python, PythonObject, PyClone}; use err::{self, PyResult, PyErr}; use super::object::PyObject; use super::exc; @@ -38,7 +38,7 @@ use conversion::{ToPyObject, ExtractPyObject}; /// and [extract](struct.PyObject.html#method.extract) /// with the primitive Rust integer types. #[cfg(feature="python27-sys")] -pub struct PyInt<'p>(PyObject<'p>); +pub struct PyInt(PyObject); #[cfg(feature="python27-sys")] pyobject_newtype!(PyInt, PyInt_Check, PyInt_Type); @@ -50,7 +50,7 @@ pyobject_newtype!(PyInt, PyInt_Check, PyInt_Type); /// by using [ToPyObject](trait.ToPyObject.html) /// and [extract](struct.PyObject.html#method.extract) /// with the primitive Rust integer types. -pub struct PyLong<'p>(PyObject<'p>); +pub struct PyLong(PyObject); pyobject_newtype!(PyLong, PyLong_Check, PyLong_Type); /// Represents a Python `float` object. @@ -59,46 +59,46 @@ pyobject_newtype!(PyLong, PyLong_Check, PyLong_Type); /// by using [ToPyObject](trait.ToPyObject.html) /// and [extract](struct.PyObject.html#method.extract) /// with `f32`/`f64`. -pub struct PyFloat<'p>(PyObject<'p>); +pub struct PyFloat(PyObject); pyobject_newtype!(PyFloat, PyFloat_Check, PyFloat_Type); #[cfg(feature="python27-sys")] -impl <'p> PyInt<'p> { +impl PyInt { /// Creates a new Python `int` object. - pub fn new(py: Python<'p>, val: c_long) -> PyInt<'p> { + pub fn new(py: Python, val: c_long) -> PyInt { unsafe { err::cast_from_owned_ptr_or_panic(py, ffi::PyInt_FromLong(val)) } } /// Gets the value of this integer. - pub fn value(&self) -> c_long { - unsafe { ffi::PyInt_AS_LONG(self.as_ptr()) } + pub fn value(&self, _py: Python) -> c_long { + unsafe { ffi::PyInt_AS_LONG(self.0.as_ptr()) } } } -impl <'p> PyFloat<'p> { +impl PyFloat { /// Creates a new Python `float` object. - pub fn new(py: Python<'p>, val: c_double) -> PyFloat<'p> { + pub fn new(py: Python, val: c_double) -> PyFloat { unsafe { err::cast_from_owned_ptr_or_panic(py, ffi::PyFloat_FromDouble(val)) } } /// Gets the value of this float. - pub fn value(&self) -> c_double { - unsafe { ffi::PyFloat_AsDouble(self.as_ptr()) } + pub fn value(&self, _py: Python) -> c_double { + unsafe { ffi::PyFloat_AsDouble(self.0.as_ptr()) } } } macro_rules! int_fits_c_long( ($rust_type:ty) => ( #[cfg(feature="python27-sys")] - impl <'p> ToPyObject<'p> for $rust_type { - type ObjectType = PyInt<'p>; + impl ToPyObject for $rust_type { + type ObjectType = PyInt; - fn to_py_object(&self, py: Python<'p>) -> PyInt<'p> { + fn to_py_object(&self, py: Python) -> PyInt { unsafe { err::cast_from_owned_ptr_or_panic(py, ffi::PyInt_FromLong(*self as c_long)) @@ -107,10 +107,10 @@ macro_rules! int_fits_c_long( } #[cfg(feature="python3-sys")] - impl <'p> ToPyObject<'p> for $rust_type { - type ObjectType = PyLong<'p>; + impl ToPyObject for $rust_type { + type ObjectType = PyLong; - fn to_py_object(&self, py: Python<'p>) -> PyLong<'p> { + fn to_py_object(&self, py: Python) -> PyLong { unsafe { err::cast_from_owned_ptr_or_panic(py, ffi::PyLong_FromLong(*self as c_long)) @@ -118,8 +118,7 @@ macro_rules! int_fits_c_long( } } - extract!(obj to $rust_type => { - let py = obj.python(); + extract!(obj to $rust_type; py => { let val = unsafe { ffi::PyLong_AsLong(obj.as_ptr()) }; if val == -1 && PyErr::occurred(py) { return Err(PyErr::fetch(py)); @@ -135,18 +134,17 @@ macro_rules! int_fits_c_long( macro_rules! int_fits_larger_int( ($rust_type:ty, $larger_type:ty) => ( - impl <'p> ToPyObject<'p> for $rust_type { - type ObjectType = <$larger_type as ToPyObject<'p>>::ObjectType; + impl ToPyObject for $rust_type { + type ObjectType = <$larger_type as ToPyObject>::ObjectType; #[inline] - fn to_py_object(&self, py: Python<'p>) -> <$larger_type as ToPyObject<'p>>::ObjectType { + fn to_py_object(&self, py: Python) -> <$larger_type as ToPyObject>::ObjectType { (*self as $larger_type).to_py_object(py) } } - extract!(obj to $rust_type => { - let py = obj.python(); - let val = try!(obj.extract::<$larger_type>()); + extract!(obj to $rust_type; py => { + let val = try!(obj.extract::<$larger_type>(py)); match num::traits::cast::<$larger_type, $rust_type>(val) { Some(v) => Ok(v), None => Err(overflow_error(py)) @@ -156,28 +154,27 @@ macro_rules! int_fits_larger_int( ); -fn err_if_invalid_value<'p, T: PartialEq, F: Fn() -> T> - (obj: &PyObject<'p>, invalid_value: T, func: F) -> PyResult<'p, T> { - let py = obj.python(); - let v = func(); - if v == invalid_value && PyErr::occurred(py) { +fn err_if_invalid_value<'p, T: PartialEq> + (py: Python, invalid_value: T, actual_value: T) -> PyResult +{ + if actual_value == invalid_value && PyErr::occurred(py) { Err(PyErr::fetch(py)) } else { - Ok(v) + Ok(actual_value) } } macro_rules! int_convert_u64_or_i64 ( ($rust_type:ty, $pylong_from_ll_or_ull:expr, $pylong_as_ull_or_ull:expr) => ( - impl <'p> ToPyObject<'p> for $rust_type { + impl <'p> ToPyObject for $rust_type { #[cfg(feature="python27-sys")] - type ObjectType = PyObject<'p>; + type ObjectType = PyObject; #[cfg(feature="python3-sys")] - type ObjectType = PyLong<'p>; + type ObjectType = PyLong; #[cfg(feature="python27-sys")] - fn to_py_object(&self, py: Python<'p>) -> PyObject<'p> { + fn to_py_object(&self, py: Python) -> PyObject { unsafe { let ptr = match num::traits::cast::<$rust_type, c_long>(*self) { Some(v) => ffi::PyInt_FromLong(v), @@ -188,32 +185,28 @@ macro_rules! int_convert_u64_or_i64 ( } #[cfg(feature="python3-sys")] - fn to_py_object(&self, py: Python<'p>) -> PyLong<'p> { + fn to_py_object(&self, py: Python) -> PyLong { unsafe { err::cast_from_owned_ptr_or_panic(py, $pylong_from_ll_or_ull(*self)) } } } - impl <'python, 'source, 'prepared> - ExtractPyObject<'python, 'source, 'prepared> for $rust_type - where 'python: 'source - { - type Prepared = &'source PyObject<'python>; + impl <'prepared> ExtractPyObject<'prepared> for $rust_type { + type Prepared = PyObject; #[inline] - fn prepare_extract(obj: &'source PyObject<'python>) -> PyResult<'python, Self::Prepared> { - Ok(obj) + fn prepare_extract(obj: &PyObject, py: Python) -> PyResult { + Ok(obj.clone_ref(py)) } #[cfg(feature="python27-sys")] - fn extract(&obj: &'prepared &'source PyObject<'python>) -> PyResult<'python, $rust_type> { - let py = obj.python(); + fn extract(obj: &'prepared PyObject, py: Python) -> PyResult<$rust_type> { let ptr = obj.as_ptr(); unsafe { if ffi::PyLong_Check(ptr) != 0 { - err_if_invalid_value(&obj, !0, || $pylong_as_ull_or_ull(obj.as_ptr()) ) + err_if_invalid_value(py, !0, $pylong_as_ull_or_ull(ptr)) } else if ffi::PyInt_Check(ptr) != 0 { match num::traits::cast::(ffi::PyInt_AS_LONG(ptr)) { Some(v) => Ok(v), @@ -221,21 +214,20 @@ macro_rules! int_convert_u64_or_i64 ( } } else { let num = try!(err::result_from_owned_ptr(py, ffi::PyNumber_Long(ptr))); - err_if_invalid_value(&num, !0, || $pylong_as_ull_or_ull(num.as_ptr()) ) + err_if_invalid_value(py, !0, $pylong_as_ull_or_ull(num.as_ptr())) } } } #[cfg(feature="python3-sys")] - fn extract(&obj: &'prepared &'source PyObject<'python>) -> PyResult<'python, $rust_type> { - let py = obj.python(); + fn extract(obj: &'prepared PyObject, py: Python) -> PyResult<$rust_type> { let ptr = obj.as_ptr(); unsafe { if ffi::PyLong_Check(ptr) != 0 { - err_if_invalid_value(&obj, !0, || $pylong_as_ull_or_ull(obj.as_ptr()) ) + err_if_invalid_value(py, !0, $pylong_as_ull_or_ull(ptr)) } else { let num = try!(err::result_from_owned_ptr(py, ffi::PyNumber_Long(ptr))); - err_if_invalid_value(&num, !0, || $pylong_as_ull_or_ull(num.as_ptr()) ) + err_if_invalid_value(py, !0, $pylong_as_ull_or_ull(num.as_ptr())) } } } @@ -273,16 +265,15 @@ int_fits_larger_int!(usize, u64); // u64 has a manual implementation as it never fits into signed long int_convert_u64_or_i64!(u64, ffi::PyLong_FromUnsignedLongLong, ffi::PyLong_AsUnsignedLongLong); -impl <'p> ToPyObject<'p> for f64 { - type ObjectType = PyFloat<'p>; +impl ToPyObject for f64 { + type ObjectType = PyFloat; - fn to_py_object(&self, py: Python<'p>) -> PyFloat<'p> { + fn to_py_object(&self, py: Python) -> PyFloat { PyFloat::new(py, *self) } } -extract!(obj to f64 => { - let py = obj.python(); +extract!(obj to f64; py => { let v = unsafe { ffi::PyFloat_AsDouble(obj.as_ptr()) }; if v == -1.0 && PyErr::occurred(py) { Err(PyErr::fetch(py)) @@ -295,16 +286,16 @@ fn overflow_error(py: Python) -> PyErr { PyErr::new_lazy_init(py.get_type::(), None) } -impl <'p> ToPyObject<'p> for f32 { - type ObjectType = PyFloat<'p>; +impl ToPyObject for f32 { + type ObjectType = PyFloat; - fn to_py_object(&self, py: Python<'p>) -> PyFloat<'p> { + fn to_py_object(&self, py: Python) -> PyFloat { PyFloat::new(py, *self as f64) } } -extract!(obj to f32 => { - Ok(try!(obj.extract::()) as f32) +extract!(obj to f32; py => { + Ok(try!(obj.extract::(py)) as f32) }); #[cfg(test)] @@ -321,7 +312,7 @@ mod test { let py = gil.python(); let val = 123 as $t1; let obj = val.to_py_object(py).into_object(); - assert_eq!(obj.extract::<$t2>().unwrap(), val as $t2); + assert_eq!(obj.extract::<$t2>(py).unwrap(), val as $t2); } ) ); @@ -350,9 +341,9 @@ mod test { let py = gil.python(); let v = std::u32::MAX; let obj = v.to_py_object(py).into_object(); - assert_eq!(v, obj.extract::().unwrap()); - assert_eq!(v as u64, obj.extract::().unwrap()); - assert!(obj.extract::().is_err()); + assert_eq!(v, obj.extract::(py).unwrap()); + assert_eq!(v as u64, obj.extract::(py).unwrap()); + assert!(obj.extract::(py).is_err()); } #[test] @@ -361,9 +352,9 @@ mod test { let py = gil.python(); let v = std::i64::MAX; let obj = v.to_py_object(py).into_object(); - assert_eq!(v, obj.extract::().unwrap()); - assert_eq!(v as u64, obj.extract::().unwrap()); - assert!(obj.extract::().is_err()); + assert_eq!(v, obj.extract::(py).unwrap()); + assert_eq!(v as u64, obj.extract::(py).unwrap()); + assert!(obj.extract::(py).is_err()); } #[test] @@ -372,9 +363,9 @@ mod test { let py = gil.python(); let v = std::i64::MIN; let obj = v.to_py_object(py).into_object(); - assert_eq!(v, obj.extract::().unwrap()); - assert!(obj.extract::().is_err()); - assert!(obj.extract::().is_err()); + assert_eq!(v, obj.extract::(py).unwrap()); + assert!(obj.extract::(py).is_err()); + assert!(obj.extract::(py).is_err()); } #[test] @@ -384,7 +375,7 @@ mod test { let v = std::u64::MAX; let obj = v.to_py_object(py).into_object(); println!("{:?}", obj); - assert_eq!(v, obj.extract::().unwrap()); - assert!(obj.extract::().is_err()); + assert_eq!(v, obj.extract::(py).unwrap()); + assert!(obj.extract::(py).is_err()); } } diff --git a/src/objects/object.rs b/src/objects/object.rs index 83be9b30..7b2458e4 100644 --- a/src/objects/object.rs +++ b/src/objects/object.rs @@ -18,9 +18,9 @@ use std::mem; use ffi; -use python::{Python, PythonObject, PythonObjectWithCheckedDowncast, PythonObjectWithTypeObject, PythonObjectDowncastError, ToPythonPointer}; +use python::{Python, PythonObject, PythonObjectWithCheckedDowncast, PythonObjectWithTypeObject, PythonObjectDowncastError}; use objects::PyType; -use err::PyErr; +use err::PyResult; /// Represents a reference to a Python object. /// @@ -41,117 +41,102 @@ use err::PyErr; /// Most of the interesting methods are provided by the [ObjectProtocol trait](trait.ObjectProtocol.html). #[unsafe_no_drop_flag] #[repr(C)] -pub struct PyObject<'p> { - // PyObject<'p> owns one reference to the *PyObject - // ptr is not null (except possibly due to #[unsafe_no_drop_flag]) - ptr: *mut ffi::PyObject, - py : Python<'p> +pub struct PyObject { + // PyObject owns one reference to the *PyObject + // ptr is not null + ptr: *mut ffi::PyObject } /// Dropping a `PyObject` decrements the reference count on the object by 1. -impl <'p> Drop for PyObject<'p> { +impl Drop for PyObject { #[inline] fn drop(&mut self) { - // TODO: remove if and change Py_XDECREF to Py_DECREF when #[unsafe_no_drop_flag] disappears + // TODO: remove `if` when #[unsafe_no_drop_flag] disappears if self.ptr as usize != mem::POST_DROP_USIZE { - unsafe { ffi::Py_XDECREF(self.ptr); } + let _gil_guard = Python::acquire_gil(); + unsafe { ffi::Py_DECREF(self.ptr); } } } } -/// Clone returns another reference to the Python object, -/// thus incrementing the reference count by 1. -impl <'p> Clone for PyObject<'p> { - #[inline] - fn clone(&self) -> PyObject<'p> { - unsafe { ffi::Py_INCREF(self.ptr) }; - PyObject { ptr: self.ptr, py: self.py } - } -} - pyobject_to_pyobject!(PyObject); -impl <'p> PythonObject<'p> for PyObject<'p> { +impl PythonObject for PyObject { #[inline] - fn as_object<'a>(&'a self) -> &'a PyObject<'p> { + fn as_object(&self) -> &PyObject { self } - + #[inline] - fn into_object(self) -> PyObject<'p> { + fn into_object(self) -> PyObject { self } - + #[inline] - unsafe fn unchecked_downcast_from(o: PyObject<'p>) -> PyObject<'p> { + unsafe fn unchecked_downcast_from(o: PyObject) -> PyObject { o } - + #[inline] - unsafe fn unchecked_downcast_borrow_from<'a>(o: &'a PyObject<'p>) -> &'a PyObject<'p> { + unsafe fn unchecked_downcast_borrow_from(o: &PyObject) -> &PyObject { o } - - #[inline] - fn python(&self) -> Python<'p> { - self.py - } } -impl <'p> PythonObjectWithCheckedDowncast<'p> for PyObject<'p> { +impl PythonObjectWithCheckedDowncast for PyObject { #[inline] - fn downcast_from(obj: PyObject<'p>) -> Result, PythonObjectDowncastError<'p>> { + fn downcast_from<'p>(obj: PyObject, _py: Python<'p>) -> Result> { Ok(obj) } - + #[inline] - fn downcast_borrow_from<'a>(obj: &'a PyObject<'p>) -> Result<&'a PyObject<'p>, PythonObjectDowncastError<'p>> { + fn downcast_borrow_from<'a, 'p>(obj: &'a PyObject, _py: Python<'p>) -> Result<&'a PyObject, PythonObjectDowncastError<'p>> { Ok(obj) } } -impl <'p> PythonObjectWithTypeObject<'p> for PyObject<'p> { +impl PythonObjectWithTypeObject for PyObject { #[inline] - fn type_object(py: Python<'p>) -> PyType<'p> { + fn type_object(py: Python) -> PyType { unsafe { PyType::from_type_ptr(py, &mut ffi::PyBaseObject_Type) } } } -impl <'p> PyObject<'p> { +impl PyObject { /// Creates a PyObject instance for the given FFI pointer. /// This moves ownership over the pointer into the PyObject. /// Undefined behavior if the pointer is NULL or invalid. #[inline] - pub unsafe fn from_owned_ptr(py : Python<'p>, ptr : *mut ffi::PyObject) -> PyObject<'p> { + pub unsafe fn from_owned_ptr(_py : Python, ptr : *mut ffi::PyObject) -> PyObject { debug_assert!(!ptr.is_null() && ffi::Py_REFCNT(ptr) > 0); - PyObject { py: py, ptr: ptr } + PyObject { ptr: ptr } } - + /// Creates a PyObject instance for the given FFI pointer. /// Calls Py_INCREF() on the ptr. /// Undefined behavior if the pointer is NULL or invalid. #[inline] - pub unsafe fn from_borrowed_ptr(py : Python<'p>, ptr : *mut ffi::PyObject) -> PyObject<'p> { + pub unsafe fn from_borrowed_ptr(_py : Python, ptr : *mut ffi::PyObject) -> PyObject { debug_assert!(!ptr.is_null() && ffi::Py_REFCNT(ptr) > 0); ffi::Py_INCREF(ptr); - PyObject { py: py, ptr: ptr } + PyObject { ptr: ptr } } /// Creates a PyObject instance for the given FFI pointer. /// This moves ownership over the pointer into the PyObject. /// Returns None for null pointers; undefined behavior if the pointer is invalid. #[inline] - pub unsafe fn from_owned_ptr_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option> { + pub unsafe fn from_owned_ptr_opt(py: Python, ptr: *mut ffi::PyObject) -> Option { if ptr.is_null() { None } else { Some(PyObject::from_owned_ptr(py, ptr)) } } - + /// Returns None for null pointers; undefined behavior if the pointer is invalid. #[inline] - pub unsafe fn from_borrowed_ptr_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option> { + pub unsafe fn from_borrowed_ptr_opt(py: Python, ptr: *mut ffi::PyObject) -> Option { if ptr.is_null() { None } else { @@ -179,7 +164,7 @@ impl <'p> PyObject<'p> { /// Transmutes an owned FFI pointer to `&PyObject`. /// Undefined behavior if the pointer is NULL or invalid. #[inline] - pub unsafe fn borrow_from_owned_ptr<'a>(_py : Python<'p>, ptr : &'a *mut ffi::PyObject) -> &'a PyObject<'p> { + pub unsafe fn borrow_from_owned_ptr<'a>(ptr : &'a *mut ffi::PyObject) -> &'a PyObject { debug_assert!(!ptr.is_null() && ffi::Py_REFCNT(*ptr) > 0); mem::transmute(ptr) } @@ -187,46 +172,53 @@ impl <'p> PyObject<'p> { /// 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>(_py : Python<'p>, ptr : &'a [*mut ffi::PyObject]) -> &'a [PyObject<'p>] { + pub unsafe fn borrow_from_owned_ptr_slice<'a>(ptr : &'a [*mut ffi::PyObject]) -> &'a [PyObject] { mem::transmute(ptr) } /// Gets the reference count of this Python object. #[inline] - pub fn get_refcnt(&self) -> usize { - unsafe { ffi::Py_REFCNT(self.as_ptr()) as usize } + pub fn get_refcnt(&self, _py: Python) -> usize { + unsafe { ffi::Py_REFCNT(self.ptr) as usize } } /// Gets the Python type object for this object's type. #[inline] - pub fn get_type(&self) -> &PyType<'p> { + pub fn get_type(&self) -> &PyType { unsafe { - let t : &*mut ffi::PyTypeObject = &(*self.as_ptr()).ob_type; - mem::transmute(t) + let t : &*mut ffi::PyTypeObject = &(*self.ptr).ob_type; + let t : &*mut ffi::PyObject = mem::transmute(t); + PyObject::borrow_from_owned_ptr(t).unchecked_cast_as() } } - + /// Casts the PyObject to a concrete Python object type. /// Causes undefined behavior if the object is not of the expected type. /// This is a wrapper function around `PythonObject::unchecked_downcast_from()`. #[inline] - pub unsafe fn unchecked_cast_into(self) -> T where T: PythonObject<'p> { + pub unsafe fn unchecked_cast_into(self) -> T + where T: PythonObject + { PythonObject::unchecked_downcast_from(self) } - + /// Casts the PyObject to a concrete Python object type. /// Fails with `PythonObjectDowncastError` if the object is not of the expected type. /// This is a wrapper function around `PythonObjectWithCheckedDowncast::downcast_from()`. #[inline] - pub fn cast_into(self) -> Result> where T: PythonObjectWithCheckedDowncast<'p> { - PythonObjectWithCheckedDowncast::downcast_from(self) + pub fn cast_into<'p, T>(self, py: Python<'p>) -> Result> + where T: PythonObjectWithCheckedDowncast + { + PythonObjectWithCheckedDowncast::downcast_from(self, py) } /// Casts the PyObject to a concrete Python object type. /// Causes undefined behavior if the object is not of the expected type. /// This is a wrapper function around `PythonObject::unchecked_downcast_borrow_from()`. #[inline] - pub unsafe fn unchecked_cast_as<'s, T>(&'s self) -> &'s T where T: PythonObject<'p> { + pub unsafe fn unchecked_cast_as<'s, T>(&'s self) -> &'s T + where T: PythonObject + { PythonObject::unchecked_downcast_borrow_from(self) } @@ -234,46 +226,35 @@ impl <'p> PyObject<'p> { /// Fails with `PythonObjectDowncastError` if the object is not of the expected type. /// This is a wrapper function around `PythonObjectWithCheckedDowncast::downcast_borrow_from()`. #[inline] - pub fn cast_as<'s, T>(&'s self) -> Result<&'s T, PythonObjectDowncastError<'p>> where T: PythonObjectWithCheckedDowncast<'p> { - PythonObjectWithCheckedDowncast::downcast_borrow_from(self) + pub fn cast_as<'s, 'p, T>(&'s self, py: Python<'p>) -> Result<&'s T, PythonObjectDowncastError<'p>> + where T: PythonObjectWithCheckedDowncast + { + PythonObjectWithCheckedDowncast::downcast_borrow_from(self, py) } - + /// Extracts some type from the Python object. /// This is a wrapper function around `FromPyObject::from_py_object()`. #[inline] - pub fn extract<'s, T>(&'s self) -> Result> - where T: for<'prep> ::conversion::ExtractPyObject<'p, 's, 'prep> { - let prepared = try!(::prepare_extract(self)); - ::extract(&prepared) + pub fn extract(&self, py: Python) -> PyResult + where T: for<'prep> ::conversion::ExtractPyObject<'prep> + { + let prepared = try!(::prepare_extract(self, py)); + ::extract(&prepared, py) } } /// PyObject implements the `==` operator using reference equality: /// `obj1 == obj2` in rust is equivalent to `obj1 is obj2` in Python. -impl <'p> PartialEq for PyObject<'p> { +impl PartialEq for PyObject { #[inline] - fn eq(&self, o : &PyObject<'p>) -> bool { + fn eq(&self, o : &PyObject) -> bool { self.ptr == o.ptr } } /// PyObject implements the `==` operator using reference equality: /// `obj1 == obj2` in rust is equivalent to `obj1 is obj2` in Python. -impl <'p> Eq for PyObject<'p> { } - -impl <'p> ToPythonPointer for PyObject<'p> { - // forward to inherit methods - #[inline] - fn as_ptr(&self) -> *mut ffi::PyObject { - PyObject::as_ptr(self) - } - - #[inline] - fn steal_ptr(self) -> *mut ffi::PyObject { - PyObject::steal_ptr(self) - } -} - +impl Eq for PyObject { } #[test] fn test_sizeof() { diff --git a/src/objects/oldstyle.rs b/src/objects/oldstyle.rs index 75bb5bc6..213dfa75 100644 --- a/src/objects/oldstyle.rs +++ b/src/objects/oldstyle.rs @@ -19,7 +19,7 @@ //! This module contains support for old-style classes. Only available in Python 2.x. use ffi; -use python::{PythonObject, ToPythonPointer}; +use python::{Python, PythonObject, ToPythonPointer}; use conversion::ToPyObject; use err::{self, PyResult}; use super::object::PyObject; @@ -29,36 +29,37 @@ use super::dict::PyDict; /// Represents an old-style Python class. /// /// Only available with Python 2.x. -pub struct PyClass<'p>(PyObject<'p>); +pub struct PyClass(PyObject); pyobject_newtype!(PyClass, PyClass_Check, PyClass_Type); /// Represents an old-style Python instance. /// /// Only available with Python 2.x. -pub struct PyInstance<'p>(PyObject<'p>); +pub struct PyInstance(PyObject); pyobject_newtype!(PyInstance, PyInstance_Check, PyInstance_Type); -impl <'p> PyClass<'p> { +impl PyClass { /// Return true if self is a subclass of base. - pub fn is_subclass_of(&self, base: &PyClass<'p>) -> bool { + pub fn is_subclass_of(&self, base: &PyClass, _py: Python) -> bool { unsafe { ffi::PyClass_IsSubclass(self.as_ptr(), base.as_ptr()) != 0 } } /// Create a new instance of the class. /// The parameters args and kw are used as the positional and keyword parameters to the object’s constructor. - pub fn create_instance(&self, args: T, kw: Option<&PyDict<'p>>) -> PyResult<'p, PyInstance<'p>> - where T: ToPyObject<'p, ObjectType=PyTuple<'p>> { - args.with_borrowed_ptr(self.python(), |args| unsafe { - err::result_cast_from_owned_ptr(self.python(), + pub fn create_instance(&self, args: T, kw: Option<&PyDict>, py: Python) -> PyResult + where T: ToPyObject + { + args.with_borrowed_ptr(py, |args| unsafe { + err::result_cast_from_owned_ptr(py, ffi::PyInstance_New(self.as_ptr(), args, kw.as_ptr())) }) } /// Create a new instance of a specific class without calling its constructor. /// The dict parameter will be used as the object’s __dict__. - pub fn create_instance_raw(&self, dict: PyDict<'p>) -> PyResult<'p, PyInstance<'p>> { + pub fn create_instance_raw(&self, dict: &PyDict, py: Python) -> PyResult { unsafe { - err::result_cast_from_owned_ptr(self.python(), + err::result_cast_from_owned_ptr(py, ffi::PyInstance_NewRaw(self.as_ptr(), dict.as_object().as_ptr())) } } diff --git a/src/objects/sequence.rs b/src/objects/sequence.rs index e9492998..853a3b14 100644 --- a/src/objects/sequence.rs +++ b/src/objects/sequence.rs @@ -18,23 +18,24 @@ use std::mem; use ffi; -use python::{PythonObject, ToPythonPointer}; +use python::{Python, PythonObject, ToPythonPointer, PyClone}; +use conversion::ToPyObject; use objects::{PyObject, PyList, PyTuple}; use ffi::Py_ssize_t; use err; -use err::{PyErr, PyResult, result_from_owned_ptr}; +use err::{PyErr, PyResult, result_from_owned_ptr, result_cast_from_owned_ptr}; -pub struct PySequence<'p>(PyObject<'p>); +pub struct PySequence(PyObject); pyobject_newtype!(PySequence, PySequence_Check); -impl <'p> PySequence<'p> { +impl PySequence { /// Returns the number of objects in sequence. This is equivalent to Python `len()`. #[inline] - pub fn len(&self) -> PyResult<'p, isize> { - let v = unsafe { ffi::PySequence_Size(self.as_ptr()) }; + pub fn len(&self, py: Python) -> PyResult { + let v = unsafe { ffi::PySequence_Size(self.0.as_ptr()) }; if v == -1 { - Err(PyErr::fetch(self.python())) + Err(PyErr::fetch(py)) } else { Ok(v as isize) } @@ -42,9 +43,8 @@ impl <'p> PySequence<'p> { /// Return the concatenation of o1 and o2. Equivalent to python `o1 + o2` #[inline] - pub fn concat(&self, other: &PySequence<'p>) -> PyResult<'p, PyObject<'p>> { + pub fn concat(&self, other: &PySequence, py: Python) -> PyResult { unsafe { - let py = self.python(); err::result_from_owned_ptr(py, ffi::PySequence_Concat(self.as_ptr(), other.as_ptr())) } } @@ -53,18 +53,16 @@ impl <'p> PySequence<'p> { /// Equivalent to python `o * count` /// NB: Python accepts negative counts; it returns an empty Sequence. #[inline] - pub fn repeat(&self, count: isize) -> PyResult<'p, PyObject<'p>> { + pub fn repeat(&self, count: isize, py: Python) -> PyResult { unsafe { - let py = self.python(); err::result_from_owned_ptr(py, 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` #[inline] - pub fn in_place_concat(&self, other: &PySequence<'p>) -> PyResult<'p, PyObject<'p>> { + pub fn in_place_concat(&self, other: &PySequence, py: Python) -> PyResult { unsafe { - let py = self.python(); result_from_owned_ptr(py, ffi::PySequence_InPlaceConcat(self.as_ptr(), other.as_ptr())) } } @@ -73,9 +71,8 @@ impl <'p> PySequence<'p> { /// Equivalent to python `o *= count` /// NB: Python accepts negative counts; it empties the Sequence. #[inline] - pub fn in_place_repeat(&self, count: isize) -> PyResult<'p, PyObject<'p>> { + pub fn in_place_repeat(&self, count: isize, py: Python) -> PyResult { unsafe { - let py = self.python(); result_from_owned_ptr(py, ffi::PySequence_InPlaceRepeat(self.as_ptr(), count as Py_ssize_t)) } @@ -83,8 +80,7 @@ impl <'p> PySequence<'p> { /// Return the ith element of the Sequence. Equivalent to python `o[index]` #[inline] - pub fn get_item(&self, index: isize) -> PyResult<'p, PyObject<'p>> { - let py = self.python(); + pub fn get_item(&self, index: isize, py: Python) -> PyResult { unsafe { result_from_owned_ptr(py, ffi::PySequence_GetItem(self.as_ptr(), index as Py_ssize_t)) @@ -94,9 +90,8 @@ impl <'p> PySequence<'p> { /// 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, begin : isize, end : isize) -> PyResult<'p, PyObject<'p>> { + pub fn get_slice(&self, begin : isize, end : isize, py: Python) -> PyResult { unsafe { - let py = self.python(); result_from_owned_ptr(py, ffi::PySequence_GetSlice(self.as_ptr(), begin as Py_ssize_t, end as Py_ssize_t)) } @@ -105,9 +100,9 @@ impl <'p> PySequence<'p> { /// Assign object v to the ith element of o. /// Equivalent to Python statement `o[i] = v` #[inline] - pub fn set_item(&self, i: isize, v: &PyObject<'p>) -> PyResult<'p, ()> { + pub fn set_item(&self, i: isize, v: &PyObject, py: Python) -> PyResult<()> { unsafe { - err::error_on_minusone(self.python(), + err::error_on_minusone(py, ffi::PySequence_SetItem(self.as_ptr(), i as Py_ssize_t, v.as_ptr())) } } @@ -115,9 +110,9 @@ impl <'p> PySequence<'p> { /// Delete the ith element of object o. /// Python statement `del o[i]` #[inline] - pub fn del_item(&self, i: isize) -> PyResult<'p, ()> { + pub fn del_item(&self, i: isize, py: Python) -> PyResult<()> { unsafe { - err::error_on_minusone(self.python(), + err::error_on_minusone(py, ffi::PySequence_DelItem(self.as_ptr(), i as Py_ssize_t)) } } @@ -125,9 +120,9 @@ impl <'p> PySequence<'p> { /// 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, i1: isize, i2: isize, v: &PyObject<'p>) -> PyResult<'p, ()> { + pub fn set_slice(&self, i1: isize, i2: isize, v: &PyObject, py: Python) -> PyResult<()> { unsafe { - err::error_on_minusone(self.python(), + err::error_on_minusone(py, ffi::PySequence_SetSlice(self.as_ptr(), i1 as Py_ssize_t, i2 as Py_ssize_t, v.as_ptr())) } } @@ -135,9 +130,9 @@ impl <'p> PySequence<'p> { /// 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, i1: isize, i2: isize) -> PyResult<'p, ()> { + pub fn del_slice(&self, i1: isize, i2: isize, py: Python) -> PyResult<()> { unsafe { - err::error_on_minusone(self.python(), + err::error_on_minusone(py, ffi::PySequence_DelSlice(self.as_ptr(), i1 as Py_ssize_t, i2 as Py_ssize_t)) } } @@ -145,93 +140,100 @@ impl <'p> PySequence<'p> { /// 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(&self, v: &PyObject<'p>) -> PyResult<'p, usize> { - let v = unsafe { ffi::PySequence_Count(self.as_ptr(), v.as_ptr()) }; - if v == -1 { - Err(PyErr::fetch(self.python())) + pub fn count(&self, value: V, py: Python) -> PyResult + where V: ToPyObject + { + let r = value.with_borrowed_ptr(py, |ptr| unsafe { + ffi::PySequence_Count(self.as_ptr(), ptr) + }); + if r == -1 { + Err(PyErr::fetch(py)) } else { - Ok(v as usize) + Ok(r as usize) } } /// Determine if o contains value. this is equivalent to the Python expression `value in o` #[inline] - pub fn contains(&self, v: &PyObject<'p>) -> PyResult<'p, bool> { - let v = unsafe { ffi::PySequence_Contains(self.as_ptr(), v.as_ptr()) }; - match v { + pub fn contains(&self, value: V, py: Python) -> PyResult + where V: ToPyObject + { + let r = value.with_borrowed_ptr(py, |ptr| unsafe { + ffi::PySequence_Contains(self.as_ptr(), ptr) + }); + match r { 0 => Ok(false), 1 => Ok(true), - _ => Err(PyErr::fetch(self.python())) + _ => Err(PyErr::fetch(py)) } } /// Return the first index i for which o[i] == value. /// This is equivalent to the Python expression `o.index(value)` #[inline] - pub fn index(&self, v: &PyObject<'p>) -> PyResult<'p, usize> { - let v = unsafe { ffi::PySequence_Index(self.as_ptr(), v.as_ptr()) }; - if v == -1 { - Err(PyErr::fetch(self.python())) + pub fn index(&self, value: V, py: Python) -> PyResult + where V: ToPyObject + { + let r = value.with_borrowed_ptr(py, |ptr| unsafe { + ffi::PySequence_Index(self.as_ptr(), ptr) + }); + if r == -1 { + Err(PyErr::fetch(py)) } else { - Ok(v as usize) + Ok(r as usize) } } /// Return a fresh list based on the Sequence. #[inline] - pub fn list(&self) -> PyResult<'p, PyList<'p>> { - let v = try!(unsafe { - let py = self.python(); - result_from_owned_ptr(py, ffi::PySequence_List(self.as_ptr())) - }); - Ok(unsafe { v.unchecked_cast_into::() } ) + pub fn list(&self, py: Python) -> PyResult { + unsafe { + result_cast_from_owned_ptr(py, ffi::PySequence_List(self.as_ptr())) + } } /// Return a fresh tuple based on the Sequence. #[inline] - pub fn tuple(&self) -> PyResult<'p, PyTuple<'p>> { - let v = try!(unsafe { - let py = self.python(); - result_from_owned_ptr(py, ffi::PySequence_Tuple(self.as_ptr())) - }); - Ok(unsafe {v.unchecked_cast_into::() } ) + pub fn tuple(&self, py: Python) -> PyResult { + unsafe { + result_cast_from_owned_ptr(py, ffi::PySequence_Tuple(self.as_ptr())) + } + } + + #[inline] + pub fn iter<'p>(&self, py: Python<'p>) -> PySequenceIterator<'p> { + PySequenceIterator { + sequence: self.clone_ref(py), + index: 0, + py: py + } + } + + #[inline] + pub fn into_iter<'p>(self, py: Python<'p>) -> PySequenceIterator<'p> { + PySequenceIterator { + sequence: self, + index: 0, + py: py + } } } pub struct PySequenceIterator<'p> { - sequence : PySequence<'p>, - index : isize -} - -impl <'p> IntoIterator for PySequence<'p> { - type Item = PyObject<'p>; - type IntoIter = PySequenceIterator<'p>; - - fn into_iter(self) -> PySequenceIterator<'p> { - PySequenceIterator{ sequence: self, index: 0 } - } -} - -impl <'a, 'p> IntoIterator for &'a PySequence<'p> { - type Item = PyObject<'p>; - type IntoIter = PySequenceIterator<'p>; - - #[inline] - fn into_iter(self) -> PySequenceIterator<'p> { - PySequenceIterator{ sequence: self.clone(), index: 0 } - } + sequence : PySequence, + index : isize, + py : Python<'p> } impl <'p> Iterator for PySequenceIterator<'p> { // TODO: reconsider error reporting; maybe this should be Item = PyResult? - type Item = PyObject<'p>; + type Item = PyObject; - #[inline] - fn next(&mut self) -> Option> { + fn next(&mut self) -> Option { // can't report any errors in underlying size check so we panic. - let len = self.sequence.len().unwrap(); + let len = self.sequence.len(self.py).unwrap(); if self.index < len { - match self.sequence.get_item(self.index) { + match self.sequence.get_item(self.index, self.py) { Ok(item) => { self.index += 1; Some(item) @@ -256,7 +258,7 @@ mod test { let gil = Python::acquire_gil(); let py = gil.python(); let v = 42i32; - assert!(v.to_py_object(py).into_object().cast_into::().is_err()); + assert!(v.to_py_object(py).into_object().cast_into::(py).is_err()); } #[test] @@ -264,18 +266,18 @@ mod test { let gil = Python::acquire_gil(); let py = gil.python(); let v = "London Calling"; - assert!(v.to_py_object(py).into_object().cast_into::().is_ok()); + assert!(v.to_py_object(py).into_object().cast_into::(py).is_ok()); } #[test] fn test_seq_empty() { let gil = Python::acquire_gil(); let py = gil.python(); let v : Vec = vec![]; - let seq = v.to_py_object(py).into_object().cast_into::().unwrap(); - assert_eq!(0, seq.len().unwrap()); + let seq = v.to_py_object(py).into_object().cast_into::(py).unwrap(); + assert_eq!(0, seq.len(py).unwrap()); let needle = 7i32.to_py_object(py).into_object(); - assert_eq!(false, seq.contains(&needle).unwrap()); + assert_eq!(false, seq.contains(&needle, py).unwrap()); } #[test] @@ -283,17 +285,17 @@ mod test { let gil = Python::acquire_gil(); let py = gil.python(); let v : Vec = vec![1, 1, 2, 3, 5, 8]; - let seq = v.to_py_object(py).into_object().cast_into::().unwrap(); - assert_eq!(6, seq.len().unwrap()); + let seq = v.to_py_object(py).into_object().cast_into::(py).unwrap(); + assert_eq!(6, seq.len(py).unwrap()); let bad_needle = 7i32.to_py_object(py).into_object(); - assert_eq!(false, seq.contains(&bad_needle).unwrap()); + assert_eq!(false, seq.contains(&bad_needle, py).unwrap()); let good_needle = 8i32.to_py_object(py).into_object(); - assert_eq!(true, seq.contains(&good_needle).unwrap()); + assert_eq!(true, seq.contains(&good_needle, py).unwrap()); let type_coerced_needle = 8f32.to_py_object(py).into_object(); - assert_eq!(true, seq.contains(&type_coerced_needle).unwrap()); + assert_eq!(true, seq.contains(&type_coerced_needle, py).unwrap()); } #[test] @@ -301,19 +303,19 @@ mod test { let gil = Python::acquire_gil(); let py = gil.python(); let v : Vec = vec![1, 1, 2, 3, 5, 8]; - let seq = v.to_py_object(py).into_object().cast_into::().unwrap(); - assert_eq!(1, seq.get_item(0).unwrap().extract::().unwrap()); - assert_eq!(1, seq.get_item(1).unwrap().extract::().unwrap()); - assert_eq!(2, seq.get_item(2).unwrap().extract::().unwrap()); - assert_eq!(3, seq.get_item(3).unwrap().extract::().unwrap()); - assert_eq!(5, seq.get_item(4).unwrap().extract::().unwrap()); - assert_eq!(8, seq.get_item(5).unwrap().extract::().unwrap()); - assert_eq!(8, seq.get_item(-1).unwrap().extract::().unwrap()); - assert_eq!(5, seq.get_item(-2).unwrap().extract::().unwrap()); - assert_eq!(3, seq.get_item(-3).unwrap().extract::().unwrap()); - assert_eq!(2, seq.get_item(-4).unwrap().extract::().unwrap()); - assert_eq!(1, seq.get_item(-5).unwrap().extract::().unwrap()); - //assert!(seq.get_item(5).unwrap().extract::().is_err()); // panics. + let seq = v.to_py_object(py).into_object().cast_into::(py).unwrap(); + assert_eq!(1, seq.get_item(0, py).unwrap().extract::(py).unwrap()); + assert_eq!(1, seq.get_item(1, py).unwrap().extract::(py).unwrap()); + assert_eq!(2, seq.get_item(2, py).unwrap().extract::(py).unwrap()); + assert_eq!(3, seq.get_item(3, py).unwrap().extract::(py).unwrap()); + assert_eq!(5, seq.get_item(4, py).unwrap().extract::(py).unwrap()); + assert_eq!(8, seq.get_item(5, py).unwrap().extract::(py).unwrap()); + assert_eq!(8, seq.get_item(-1, py).unwrap().extract::(py).unwrap()); + assert_eq!(5, seq.get_item(-2, py).unwrap().extract::(py).unwrap()); + assert_eq!(3, seq.get_item(-3, py).unwrap().extract::(py).unwrap()); + assert_eq!(2, seq.get_item(-4, py).unwrap().extract::(py).unwrap()); + assert_eq!(1, seq.get_item(-5, py).unwrap().extract::(py).unwrap()); + assert!(seq.get_item(10, py).is_err()); } // fn test_get_slice() {} @@ -325,22 +327,22 @@ mod test { let gil = Python::acquire_gil(); let py = gil.python(); let v : Vec = vec![1, 1, 2, 3, 5, 8]; - let seq = v.to_py_object(py).into_object().cast_into::().unwrap(); - assert!(seq.del_item(10).is_err()); - assert_eq!(1, seq.get_item(0).unwrap().extract::().unwrap()); - assert!(seq.del_item(0).is_ok()); - assert_eq!(1, seq.get_item(0).unwrap().extract::().unwrap()); - assert!(seq.del_item(0).is_ok()); - assert_eq!(2, seq.get_item(0).unwrap().extract::().unwrap()); - assert!(seq.del_item(0).is_ok()); - assert_eq!(3, seq.get_item(0).unwrap().extract::().unwrap()); - assert!(seq.del_item(0).is_ok()); - assert_eq!(5, seq.get_item(0).unwrap().extract::().unwrap()); - assert!(seq.del_item(0).is_ok()); - assert_eq!(8, seq.get_item(0).unwrap().extract::().unwrap()); - assert!(seq.del_item(0).is_ok()); - assert_eq!(0, seq.len().unwrap()); - assert!(seq.del_item(0).is_err()); + let seq = v.to_py_object(py).into_object().cast_into::(py).unwrap(); + assert!(seq.del_item(10, py).is_err()); + assert_eq!(1, seq.get_item(0, py).unwrap().extract::(py).unwrap()); + assert!(seq.del_item(0, py).is_ok()); + assert_eq!(1, seq.get_item(0, py).unwrap().extract::(py).unwrap()); + assert!(seq.del_item(0, py).is_ok()); + assert_eq!(2, seq.get_item(0, py).unwrap().extract::(py).unwrap()); + assert!(seq.del_item(0, py).is_ok()); + assert_eq!(3, seq.get_item(0, py).unwrap().extract::(py).unwrap()); + assert!(seq.del_item(0, py).is_ok()); + assert_eq!(5, seq.get_item(0, py).unwrap().extract::(py).unwrap()); + assert!(seq.del_item(0, py).is_ok()); + assert_eq!(8, seq.get_item(0, py).unwrap().extract::(py).unwrap()); + assert!(seq.del_item(0, py).is_ok()); + assert_eq!(0, seq.len(py).unwrap()); + assert!(seq.del_item(0, py).is_err()); } #[test] @@ -348,13 +350,13 @@ mod test { let gil = Python::acquire_gil(); let py = gil.python(); let v : Vec = vec![1, 1, 2, 3, 5, 8]; - let seq = v.to_py_object(py).into_object().cast_into::().unwrap(); - assert_eq!(0, seq.index(&1i32.to_py_object(py).into_object()).unwrap()); - assert_eq!(2, seq.index(&2i32.to_py_object(py).into_object()).unwrap()); - assert_eq!(3, seq.index(&3i32.to_py_object(py).into_object()).unwrap()); - assert_eq!(4, seq.index(&5i32.to_py_object(py).into_object()).unwrap()); - assert_eq!(5, seq.index(&8i32.to_py_object(py).into_object()).unwrap()); - assert!(seq.index(&42i32.to_py_object(py).into_object()).is_err()); + let seq = v.to_py_object(py).into_object().cast_into::(py).unwrap(); + assert_eq!(0, seq.index(1i32, py).unwrap()); + assert_eq!(2, seq.index(2i32, py).unwrap()); + assert_eq!(3, seq.index(3i32, py).unwrap()); + assert_eq!(4, seq.index(5i32, py).unwrap()); + assert_eq!(5, seq.index(8i32, py).unwrap()); + assert!(seq.index(42i32, py).is_err()); } #[test] @@ -362,24 +364,25 @@ mod test { let gil = Python::acquire_gil(); let py = gil.python(); let v : Vec = vec![1, 1, 2, 3, 5, 8]; - let seq = v.to_py_object(py).into_object().cast_into::().unwrap(); - assert_eq!(2, seq.count(&1i32.to_py_object(py).into_object()).unwrap()); - assert_eq!(1, seq.count(&2i32.to_py_object(py).into_object()).unwrap()); - assert_eq!(1, seq.count(&3i32.to_py_object(py).into_object()).unwrap()); - assert_eq!(1, seq.count(&5i32.to_py_object(py).into_object()).unwrap()); - assert_eq!(1, seq.count(&8i32.to_py_object(py).into_object()).unwrap()); - assert_eq!(0, seq.count(&42i32.to_py_object(py).into_object()).unwrap()); + let seq = v.to_py_object(py).into_object().cast_into::(py).unwrap(); + assert_eq!(2, seq.count(1i32, py).unwrap()); + assert_eq!(1, seq.count(2i32, py).unwrap()); + assert_eq!(1, seq.count(3i32, py).unwrap()); + assert_eq!(1, seq.count(5i32, py).unwrap()); + assert_eq!(1, seq.count(8i32, py).unwrap()); + assert_eq!(0, seq.count(42i32, py).unwrap()); } +/* #[test] fn test_seq_iter() { let gil = Python::acquire_gil(); let py = gil.python(); let v : Vec = vec![1, 1, 2, 3, 5, 8]; - let seq = v.to_py_object(py).into_object().cast_into::().unwrap(); + let seq = v.to_py_object(py).into_object().cast_into::(py).unwrap(); let mut idx = 0; for el in seq { - assert_eq!(v[idx], el.extract::().unwrap()); + assert_eq!(v[idx], el.extract::(py).unwrap()); idx += 1; } assert_eq!(idx, v.len()); @@ -398,19 +401,20 @@ mod test { } assert_eq!(idx, v.len()); } +*/ #[test] fn test_seq_strings() { let gil = Python::acquire_gil(); let py = gil.python(); let v = vec!["It", "was", "the", "worst", "of", "times"]; - let seq = v.to_py_object(py).into_object().cast_into::().unwrap(); + let seq = v.to_py_object(py).into_object().cast_into::(py).unwrap(); - let bad_needle = "blurst".to_py_object(py).into_object(); - assert_eq!(false, seq.contains(&bad_needle).unwrap()); + let bad_needle = "blurst".to_py_object(py); + assert_eq!(false, seq.contains(bad_needle, py).unwrap()); - let good_needle = "worst".to_py_object(py).into_object(); - assert_eq!(true, seq.contains(&good_needle).unwrap()); + let good_needle = "worst".to_py_object(py); + assert_eq!(true, seq.contains(good_needle, py).unwrap()); } #[test] @@ -418,14 +422,13 @@ mod test { let gil = Python::acquire_gil(); let py = gil.python(); let v : Vec = vec![1, 2, 3]; - let seq = v.to_py_object(py).into_object().cast_into::().unwrap(); - let concat_seq = seq.concat(&seq).unwrap().cast_into::().unwrap(); - assert_eq!(6, concat_seq.len().unwrap()); + let seq = v.to_py_object(py).into_object().cast_into::(py).unwrap(); + let concat_seq = seq.concat(&seq, py).unwrap().cast_into::(py).unwrap(); + assert_eq!(6, concat_seq.len(py).unwrap()); let concat_v : Vec = vec![1, 2, 3, 1, 2, 3]; - for (el, cc) in seq.into_iter().zip(concat_v) { - assert_eq!(cc, el.extract::().unwrap()); + for (el, cc) in seq.into_iter(py).zip(concat_v) { + assert_eq!(cc, el.extract::(py).unwrap()); } - } #[test] @@ -433,16 +436,13 @@ mod test { let gil = Python::acquire_gil(); let py = gil.python(); let v = "string"; - let seq = v.to_py_object(py).into_object().cast_into::().unwrap(); - let concat_seq = seq.concat(&seq).unwrap().cast_into::().unwrap(); - assert_eq!(12, concat_seq.len().unwrap()); - /* - let concat_v = "stringstring".to_owned(); - for (el, cc) in seq.into_iter().zip(concat_v.as_bytes().into_iter()) { - // This fails as extract doesn't support &str as it wants a numeric type. - assert_eq!(*cc, el.extract::().unwrap()); - } - */ + let seq = v.to_py_object(py).into_object().cast_into::(py).unwrap(); + let concat_seq = seq.concat(&seq, py).unwrap().cast_into::(py).unwrap(); + assert_eq!(12, concat_seq.len(py).unwrap()); + /*let concat_v = "stringstring".to_owned(); + for (el, cc) in seq.into_iter(py).zip(concat_v.chars()) { + assert_eq!(cc, el.extract::(py).unwrap()); TODO: extract::() is not implemented + }*/ } #[test] @@ -450,12 +450,12 @@ mod test { let gil = Python::acquire_gil(); let py = gil.python(); let v = vec!["foo", "bar"]; - let seq = v.to_py_object(py).into_object().cast_into::().unwrap(); - let repeat_seq = seq.repeat(3).unwrap().cast_into::().unwrap(); - assert_eq!(6, repeat_seq.len().unwrap()); + let seq = v.to_py_object(py).into_object().cast_into::(py).unwrap(); + let repeat_seq = seq.repeat(3, py).unwrap().cast_into::(py).unwrap(); + assert_eq!(6, repeat_seq.len(py).unwrap()); let repeated = vec!["foo", "bar", "foo", "bar", "foo", "bar"]; - for (el, rpt) in seq.into_iter().zip(repeated.iter()) { - assert_eq!(*rpt, el.extract::().unwrap()); + for (el, rpt) in seq.into_iter(py).zip(repeated.iter()) { + assert_eq!(*rpt, el.extract::(py).unwrap()); } } @@ -464,8 +464,8 @@ mod test { let gil = Python::acquire_gil(); let py = gil.python(); let v = vec!["foo", "bar"]; - let seq = v.to_py_object(py).into_object().cast_into::().unwrap(); - assert!(seq.list().is_ok()); + let seq = v.to_py_object(py).into_object().cast_into::(py).unwrap(); + assert!(seq.list(py).is_ok()); } #[test] @@ -473,8 +473,8 @@ mod test { let gil = Python::acquire_gil(); let py = gil.python(); let v = "foo"; - let seq = v.to_py_object(py).into_object().cast_into::().unwrap(); - assert!(seq.list().is_ok()); + let seq = v.to_py_object(py).into_object().cast_into::(py).unwrap(); + assert!(seq.list(py).is_ok()); } #[test] @@ -482,8 +482,8 @@ mod test { let gil = Python::acquire_gil(); let py = gil.python(); let v = ("foo", "bar"); - let seq = v.to_py_object(py).into_object().cast_into::().unwrap(); - assert!(seq.tuple().is_ok()); + let seq = v.to_py_object(py).into_object().cast_into::(py).unwrap(); + assert!(seq.tuple(py).is_ok()); } #[test] @@ -491,7 +491,7 @@ mod test { let gil = Python::acquire_gil(); let py = gil.python(); let v = vec!["foo", "bar"]; - let seq = v.to_py_object(py).into_object().cast_into::().unwrap(); - assert!(seq.tuple().is_ok()); + let seq = v.to_py_object(py).into_object().cast_into::(py).unwrap(); + assert!(seq.tuple(py).is_ok()); } } diff --git a/src/objects/string.rs b/src/objects/string.rs index 37f3f2b7..4b7e0616 100644 --- a/src/objects/string.rs +++ b/src/objects/string.rs @@ -22,18 +22,18 @@ use std::ascii::AsciiExt; use std::borrow::Cow; use libc::c_char; use ffi; -use python::{Python, PythonObject, ToPythonPointer}; +use python::{Python, PythonObject, PyClone, ToPythonPointer}; use super::{exc, PyObject}; use err::{self, PyResult, PyErr}; use conversion::{ExtractPyObject, ToPyObject}; /// Represents a Python byte string. /// Corresponds to `str` in Python 2, and `bytes` in Python 3. -pub struct PyBytes<'p>(PyObject<'p>); +pub struct PyBytes(PyObject); /// Represents a Python unicode string. /// Corresponds to `unicode` in Python 2, and `str` in Python 3. -pub struct PyUnicode<'p>(PyObject<'p>); +pub struct PyUnicode(PyObject); pyobject_newtype!(PyBytes, PyBytes_Check, PyBytes_Type); pyobject_newtype!(PyUnicode, PyUnicode_Check, PyUnicode_Type); @@ -43,12 +43,12 @@ pub use PyBytes as PyString; #[cfg(feature="python3-sys")] pub use PyUnicode as PyString; -impl <'p> PyBytes<'p> { +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<'p>, s: &[u8]) -> PyBytes<'p> { + pub fn new(py: Python, s: &[u8]) -> PyBytes { let ptr = s.as_ptr() as *const c_char; let len = s.len() as ffi::Py_ssize_t; unsafe { @@ -58,7 +58,7 @@ impl <'p> PyBytes<'p> { } /// Gets the Python string data as byte slice. - pub fn as_slice(&self) -> &[u8] { + pub fn as_slice(&self, _py: Python) -> &[u8] { unsafe { let buffer = ffi::PyBytes_AsString(self.as_ptr()) as *const u8; let length = ffi::PyBytes_Size(self.as_ptr()) as usize; @@ -67,9 +67,9 @@ impl <'p> PyBytes<'p> { } } -impl <'p> PyUnicode<'p> { +impl PyUnicode { /// Creates a new unicode string object from the Rust string. - pub fn new(py: Python<'p>, s: &str) -> PyUnicode<'p> { + pub fn new(py: Python, s: &str) -> PyUnicode { let ptr = s.as_ptr() as *const c_char; let len = s.len() as ffi::Py_ssize_t; unsafe { @@ -81,7 +81,7 @@ impl <'p> PyUnicode<'p> { /* Note: 'as_slice removed temporarily, we need to reconsider // whether we really should expose the platform-dependent Py_UNICODE to user code. #[cfg(feature="python27-sys")] - pub fn as_slice(&self) -> &[ffi::Py_UNICODE] { + pub fn as_slice(&self, py: Python) -> &[ffi::Py_UNICODE] { unsafe { let buffer = ffi::PyUnicode_AS_UNICODE(self.as_ptr()) as *const _; let length = ffi::PyUnicode_GET_SIZE(self.as_ptr()) as usize; @@ -93,14 +93,13 @@ impl <'p> PyUnicode<'p> { /// /// Returns a `UnicodeDecodeError` if the input contains invalid code points. #[cfg(feature="python27-sys")] - pub fn to_string(&self) -> PyResult<'p, Cow> { - let py = self.python(); + pub fn to_string(&self, py: Python) -> PyResult> { let bytes: PyBytes = unsafe { try!(err::result_cast_from_owned_ptr(py, ffi::PyUnicode_AsUTF8String(self.as_ptr()))) }; - match str::from_utf8(bytes.as_slice()) { + match str::from_utf8(bytes.as_slice(py)) { Ok(s) => Ok(Cow::Owned(s.to_owned())), - Err(e) => Err(PyErr::from_instance(try!(exc::UnicodeDecodeError::new_utf8(py, bytes.as_slice(), e)))) + Err(e) => Err(PyErr::from_instance(try!(exc::UnicodeDecodeError::new_utf8(py, bytes.as_slice(py), e)), py)) } } @@ -108,23 +107,22 @@ impl <'p> PyUnicode<'p> { /// /// Any invalid code points are replaced with U+FFFD REPLACEMENT CHARACTER. #[cfg(feature="python27-sys")] - pub fn to_string_lossy(&self) -> Cow { + pub fn to_string_lossy(&self, py: Python) -> Cow { // TODO: test how this function handles lone surrogates or otherwise invalid code points - let py = self.python(); let bytes: PyBytes = unsafe { err::result_cast_from_owned_ptr(py, ffi::PyUnicode_AsUTF8String(self.as_ptr())) .ok().expect("Error in PyUnicode_AsUTF8String") }; - Cow::Owned(String::from_utf8_lossy(bytes.as_slice()).into_owned()) + Cow::Owned(String::from_utf8_lossy(bytes.as_slice(py)).into_owned()) } #[cfg(feature="python3-sys")] - fn to_utf8_bytes(&self) -> PyResult<'p, &[u8]> { + fn to_utf8_bytes(&self, py: Python) -> PyResult<&[u8]> { unsafe { let mut length = 0; let data = ffi::PyUnicode_AsUTF8AndSize(self.as_ptr(), &mut length); if data.is_null() { - Err(PyErr::fetch(self.python())) + Err(PyErr::fetch(py)) } else { Ok(std::slice::from_raw_parts(data as *const u8, length as usize)) } @@ -135,12 +133,11 @@ impl <'p> PyUnicode<'p> { /// /// Returns a `UnicodeDecodeError` if the input contains invalid code points. #[cfg(feature="python3-sys")] - pub fn to_string(&self) -> PyResult<'p, Cow> { - let py = self.python(); - let bytes = try!(self.to_utf8_bytes()); + pub fn to_string(&self, py: Python) -> PyResult> { + let bytes = try!(self.to_utf8_bytes(py)); match str::from_utf8(bytes) { Ok(s) => Ok(Cow::Borrowed(s)), - Err(e) => Err(PyErr::from_instance(try!(exc::UnicodeDecodeError::new_utf8(py, bytes, e)))) + Err(e) => Err(PyErr::from_instance(try!(exc::UnicodeDecodeError::new_utf8(py, bytes, e)), py)) } } @@ -148,15 +145,15 @@ impl <'p> PyUnicode<'p> { /// /// Any invalid code points are replaced with U+FFFD REPLACEMENT CHARACTER. #[cfg(feature="python3-sys")] - pub fn to_string_lossy(&self) -> Cow { - let bytes = self.to_utf8_bytes().expect("Error in PyUnicode_AsUTF8AndSize"); + pub fn to_string_lossy(&self, py: Python) -> Cow { + let bytes = self.to_utf8_bytes(py).expect("Error in PyUnicode_AsUTF8AndSize"); String::from_utf8_lossy(bytes) } } // On PyString (i.e. PyBytes in 2.7, PyUnicode otherwise), put static methods // for extraction as Cow: -impl <'p> PyString<'p> { +impl PyString { /// Extract a rust string from the Python object. /// /// In Python 2.7, accepts both byte strings and unicode strings. @@ -167,12 +164,11 @@ impl <'p> PyString<'p> { /// Returns `TypeError` if the input is not one of the accepted types. /// Returns `UnicodeDecodeError` if the input is not valid unicode. #[cfg(feature="python27-sys")] - pub fn extract<'a>(o: &'a PyObject<'p>) -> PyResult<'p, Cow<'a, str>> { - let py = o.python(); - if let Ok(s) = o.cast_as::() { - s.to_string() - } else if let Ok(u) = o.cast_as::() { - u.to_string() + pub fn extract<'a>(o: &'a PyObject, py: Python) -> PyResult> { + if let Ok(s) = o.cast_as::(py) { + s.to_string(py) + } else if let Ok(u) = o.cast_as::(py) { + u.to_string(py) } else { Err(PyErr::new_lazy_init(py.get_type::(), None)) } @@ -188,12 +184,11 @@ impl <'p> PyString<'p> { /// Returns `TypeError` if the input is not one of the accepted types. /// Any invalid code points are replaced with U+FFFD REPLACEMENT CHARACTER. #[cfg(feature="python27-sys")] - pub fn extract_lossy<'a>(o: &'a PyObject<'p>) -> PyResult<'p, Cow<'a, str>> { - let py = o.python(); - if let Ok(s) = o.cast_as::() { - Ok(s.to_string_lossy()) - } else if let Ok(u) = o.cast_as::() { - Ok(u.to_string_lossy()) + pub fn extract_lossy<'a>(o: &'a PyObject, py: Python) -> PyResult> { + if let Ok(s) = o.cast_as::(py) { + Ok(s.to_string_lossy(py)) + } else if let Ok(u) = o.cast_as::(py) { + Ok(u.to_string_lossy(py)) } else { Err(PyErr::new_lazy_init(py.get_type::(), None)) } @@ -209,10 +204,9 @@ impl <'p> PyString<'p> { /// Returns `TypeError` if the input is not one of the accepted types. /// Returns `UnicodeDecodeError` if the input is not valid unicode. #[cfg(feature="python3-sys")] - pub fn extract<'a>(o: &'a PyObject<'p>) -> PyResult<'p, Cow<'a, str>> { - let py = o.python(); - if let Ok(u) = o.cast_as::() { - u.to_string() + pub fn extract<'a>(o: &'a PyObject, py: Python) -> PyResult> { + if let Ok(u) = o.cast_as::(py) { + u.to_string(py) } else { Err(PyErr::new_lazy_init(py.get_type::(), None)) } @@ -228,10 +222,9 @@ impl <'p> PyString<'p> { /// Returns `TypeError` if the input is not one of the accepted types. /// Any invalid code points are replaced with U+FFFD REPLACEMENT CHARACTER. #[cfg(feature="python3-sys")] - pub fn extract_lossy<'a>(o: &'a PyObject<'p>) -> PyResult<'p, Cow<'a, str>> { - let py = o.python(); - if let Ok(u) = o.cast_as::() { - Ok(u.to_string_lossy()) + pub fn extract_lossy<'a>(o: &'a PyObject, py: Python) -> PyResult> { + if let Ok(u) = o.cast_as::(py) { + Ok(u.to_string_lossy(py)) } else { Err(PyErr::new_lazy_init(py.get_type::(), None)) } @@ -247,11 +240,10 @@ impl <'p> PyString<'p> { /// /// Returns a `UnicodeDecodeError` if the input is not valid unicode. #[cfg(feature="python27-sys")] - pub fn to_string(&self) -> PyResult<'p, Cow> { - let py = self.python(); - match str::from_utf8(self.as_slice()) { + pub fn to_string(&self, py: Python) -> PyResult> { + match str::from_utf8(self.as_slice(py)) { Ok(s) => Ok(Cow::Borrowed(s)), - Err(e) => Err(PyErr::from_instance(try!(exc::UnicodeDecodeError::new_utf8(py, self.as_slice(), e)))) + Err(e) => Err(PyErr::from_instance(try!(exc::UnicodeDecodeError::new_utf8(py, self.as_slice(py), e)), py)) } } @@ -262,8 +254,8 @@ impl <'p> PyString<'p> { /// /// Any invalid UTF-8 sequences are replaced with U+FFFD REPLACEMENT CHARACTER. #[cfg(feature="python27-sys")] - pub fn to_string_lossy(&self) -> Cow { - String::from_utf8_lossy(self.as_slice()) + pub fn to_string_lossy(&self, py: Python) -> Cow { + String::from_utf8_lossy(self.as_slice(py)) } } @@ -277,15 +269,15 @@ impl <'p> PyString<'p> { /// Note that `str::ObjectType` differs based on Python version: /// In Python 2.7, it is `PyObject` (`object` is the common base class of `str` and `unicode`). /// In Python 3.x, it is `PyUnicode`. -impl <'p> ToPyObject<'p> for str { +impl ToPyObject for str { #[cfg(feature="python27-sys")] - type ObjectType = PyObject<'p>; + type ObjectType = PyObject; #[cfg(feature="python3-sys")] - type ObjectType = PyUnicode<'p>; + type ObjectType = PyUnicode; #[cfg(feature="python27-sys")] - fn to_py_object(&self, py : Python<'p>) -> PyObject<'p> { + fn to_py_object(&self, py : Python) -> PyObject { if self.is_ascii() { PyBytes::new(py, self.as_bytes()).into_object() } else { @@ -295,7 +287,7 @@ impl <'p> ToPyObject<'p> for str { #[cfg(feature="python3-sys")] #[inline] - fn to_py_object(&self, py : Python<'p>) -> PyUnicode<'p> { + fn to_py_object(&self, py : Python) -> PyUnicode { PyUnicode::new(py, self) } } @@ -307,11 +299,11 @@ impl <'p> ToPyObject<'p> for str { /// Note that `str::ObjectType` differs based on Python version: /// In Python 2.7, it is `PyObject` (`object` is the common base class of `str` and `unicode`). /// In Python 3.x, it is `PyUnicode`. -impl <'p> ToPyObject<'p> for String { - type ObjectType = >::ObjectType; +impl ToPyObject for String { + type ObjectType = ::ObjectType; #[inline] - fn to_py_object(&self, py: Python<'p>) -> Self::ObjectType { + fn to_py_object(&self, py: Python) -> Self::ObjectType { ::to_py_object(self, py) } } @@ -319,29 +311,42 @@ impl <'p> ToPyObject<'p> for String { /// Allows extracting strings from Python objects. /// Accepts Python `str` and `unicode` objects. /// In Python 2.7, `str` is expected to be UTF-8 encoded. -extract!(obj to String => { - PyString::extract(obj).map(|s| s.into_owned()) +extract!(obj to String; py => { + PyString::extract(obj, py).map(|s| s.into_owned()) }); /// Allows extracting strings from Python objects. /// Accepts Python `str` and `unicode` objects. /// In Python 2.7, `str` is expected to be UTF-8 encoded. -extract!(obj to Cow<'source, str> => { - PyString::extract(obj) +extract!(obj to Cow<'prepared, str>; py => { + PyString::extract(obj, py) }); -impl <'python, 'source, 'prepared> ExtractPyObject<'python, 'source, 'prepared> for &'prepared str { +enum PreparedString { + Extracted(String), + BorrowFrom(PyObject) +} - type Prepared = Cow<'source, str>; +impl <'prepared> ExtractPyObject<'prepared> for &'prepared str { + type Prepared = PreparedString; - #[inline] - fn prepare_extract(obj: &'source PyObject<'python>) -> PyResult<'python, Self::Prepared> { - PyString::extract(obj) + fn prepare_extract(obj: &PyObject, py: Python) -> PyResult { + match try!(PyString::extract(obj, py)) { + Cow::Owned(s) => Ok(PreparedString::Extracted(s)), + Cow::Borrowed(_) => Ok(PreparedString::BorrowFrom(obj.clone_ref(py))) + } } - #[inline] - fn extract(cow: &'prepared Cow<'source, str>) -> PyResult<'python, Self> { - Ok(cow) + fn extract(prepared: &'prepared PreparedString, py: Python) -> PyResult { + match *prepared { + PreparedString::Extracted(ref s) => Ok(s), + PreparedString::BorrowFrom(ref obj) => { + match try!(PyString::extract(obj, py)) { + Cow::Owned(_) => panic!("Failed to borrow from python object"), + Cow::Borrowed(s) => Ok(s) + } + } + } } } @@ -356,7 +361,7 @@ mod test { let py = gil.python(); let s = "\u{1F30F}"; let py_string = s.to_py_object(py).into_object(); - assert_eq!(s, py_string.extract::().unwrap()); + assert_eq!(s, py_string.extract::(py).unwrap()); } #[test] @@ -365,8 +370,8 @@ mod test { let py = gil.python(); let s = "Hello Python"; let py_string = s.to_py_object(py).into_object(); - let prepared = <&str>::prepare_extract(&py_string).unwrap(); - assert_eq!(s, <&str>::extract(&prepared).unwrap()); + let prepared = <&str>::prepare_extract(&py_string, py).unwrap(); + assert_eq!(s, <&str>::extract(&prepared, py).unwrap()); } } diff --git a/src/objects/tests.rs b/src/objects/tests.rs index 9bb55fe7..11efb0eb 100644 --- a/src/objects/tests.rs +++ b/src/objects/tests.rs @@ -29,8 +29,8 @@ fn test_hashmap_to_python() { let py_map = map.to_py_object(py); - assert!(py_map.len() == 1); - assert!( py_map.get_item(1).unwrap().extract::().unwrap() == 1); + assert!(py_map.len(py) == 1); + assert!( py_map.get_item(1, py).unwrap().extract::(py).unwrap() == 1); } #[test] @@ -43,6 +43,7 @@ fn test_btreemap_to_python() { let py_map = map.to_py_object(py); - assert!(py_map.len() == 1); - assert!( py_map.get_item(1).unwrap().extract::().unwrap() == 1); + assert!(py_map.len(py) == 1); + assert!( py_map.get_item(1, py).unwrap().extract::(py).unwrap() == 1); } + diff --git a/src/objects/tuple.rs b/src/objects/tuple.rs index 29e1330f..2bc68df1 100644 --- a/src/objects/tuple.rs +++ b/src/objects/tuple.rs @@ -25,26 +25,26 @@ use conversion::{ToPyObject, ExtractPyObject}; use std::slice; /// Represents a Python tuple object. -pub struct PyTuple<'p>(PyObject<'p>); +pub struct PyTuple(PyObject); pyobject_newtype!(PyTuple, PyTuple_Check, PyTuple_Type); -impl <'p> PyTuple<'p> { +impl PyTuple { /// Construct a new tuple with the given elements. - pub fn new(py: Python<'p>, elements: &[PyObject<'p>]) -> PyTuple<'p> { + pub fn new(py: Python, elements: &[PyObject]) -> PyTuple { unsafe { let len = elements.len(); let ptr = ffi::PyTuple_New(len as Py_ssize_t); let t = err::result_cast_from_owned_ptr::(py, ptr).unwrap(); for (i, e) in elements.iter().enumerate() { - ffi::PyTuple_SetItem(ptr, i as Py_ssize_t, e.clone().steal_ptr()); + ffi::PyTuple_SetItem(ptr, i as Py_ssize_t, e.steal_ptr(py)); } t } } /// Retrieves the empty tuple. - pub fn empty(py: Python<'p>) -> PyTuple<'p> { + pub fn empty(py: Python) -> PyTuple { unsafe { err::result_cast_from_owned_ptr::(py, ffi::PyTuple_New(0)).unwrap() } @@ -53,29 +53,30 @@ impl <'p> PyTuple<'p> { /// Gets the length of the tuple. #[inline] pub fn len(&self) -> usize { - // non-negative Py_ssize_t should always fit into Rust uint + // Safe despite not taking a `Python`, because tuples are immutable. unsafe { - ffi::PyTuple_GET_SIZE(self.as_ptr()) as usize + // non-negative Py_ssize_t should always fit into Rust uint + ffi::PyTuple_GET_SIZE(self.0.as_ptr()) as usize } } /// Gets the item at the specified index. /// /// Panics if the index is out of range. - pub fn get_item(&self, index: usize) -> PyObject<'p> { + pub fn get_item(&self, index: usize, py: Python) -> PyObject { assert!(index < self.len()); unsafe { - PyObject::from_borrowed_ptr(self.python(), ffi::PyTuple_GET_ITEM(self.as_ptr(), index as Py_ssize_t)) + PyObject::from_borrowed_ptr(py, ffi::PyTuple_GET_ITEM(self.0.as_ptr(), index as Py_ssize_t)) } } #[inline] - pub fn as_slice<'a>(&'a self) -> &'a [PyObject<'p>] { + 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. unsafe { - let ptr = self.as_ptr() as *mut ffi::PyTupleObject; - PyObject::borrow_from_owned_ptr_slice(self.python(), + let ptr = self.0.as_ptr() as *mut ffi::PyTupleObject; + PyObject::borrow_from_owned_ptr_slice( slice::from_raw_parts( (*ptr).ob_item.as_ptr(), self.len())) @@ -83,17 +84,18 @@ impl <'p> PyTuple<'p> { } } -impl <'p> IntoIterator for PyTuple<'p> { - type Item = PyObject<'p>; - type IntoIter = PyTupleIterator<'p>; +/* +impl IntoIterator for PyTuple { + type Item = PyObject; + type IntoIter = PyTupleIterator; #[inline] - fn into_iter(self) -> PyTupleIterator<'p> { + fn into_iter(self) -> PyTupleIterator { PyTupleIterator { index: 0, end: self.len(), tuple: self } } } -impl <'a, 'p> IntoIterator for &'a PyTuple<'p> { +impl <'a> IntoIterator for &'a PyTuple { type Item = PyObject<'p>; type IntoIter = PyTupleIterator<'p>; @@ -136,9 +138,9 @@ impl <'p> ExactSizeIterator for PyTupleIterator<'p> { self.end - self.index } } +*/ -fn wrong_tuple_length<'p>(t: &PyTuple<'p>, expected_length: usize) -> PyErr<'p> { - let py = t.python(); +fn wrong_tuple_length(t: &PyTuple, expected_length: usize, py: Python) -> PyErr { let msg = format!("Expected tuple of length {}, but got tuple of length {}.", expected_length, t.len()); PyErr::new_lazy_init(py.get_type::(), Some(msg.to_py_object(py).into_object())) } @@ -146,23 +148,23 @@ fn wrong_tuple_length<'p>(t: &PyTuple<'p>, expected_length: usize) -> PyErr<'p> macro_rules! id (($a:expr) => ($a)); macro_rules! tuple_conversion ({$length:expr,$(($refN:ident, $n:tt, $T:ident)),+} => ( - impl <'p, $($T: ToPyObject<'p>),+> ToPyObject<'p> for ($($T,)+) { - type ObjectType = PyTuple<'p>; + impl <'p, $($T: ToPyObject),+> ToPyObject for ($($T,)+) { + type ObjectType = PyTuple; - fn to_py_object(&self, py: Python<'p>) -> PyTuple<'p> { + fn to_py_object(&self, py: Python) -> PyTuple { PyTuple::new(py, &[ $(id!(self.$n.to_py_object(py)).into_object(),)+ ]) } - fn into_py_object(self, py: Python<'p>) -> PyTuple<'p> { + fn into_py_object(self, py: Python) -> PyTuple { PyTuple::new(py, &[ $(id!(self.$n.into_py_object(py)).into_object(),)+ ]) } } - /* TODO: reimplement this without slice matching + /*TODO: reimplement this without slice matching impl <'p, 's, $($T: FromPyObject<'p, 's>),+> FromPyObject<'p, 's> for ($($T,)+) { fn from_py_object(s : &'s PyObject<'p>) -> PyResult<'p, ($($T,)+)> { let t = try!(s.cast_as::()); @@ -173,8 +175,7 @@ macro_rules! tuple_conversion ({$length:expr,$(($refN:ident, $n:tt, $T:ident)),+ _ => Err(wrong_tuple_length(t, 2)) } } - } - */ + }*/ )); tuple_conversion!(1, (ref0, 0, A)); @@ -202,27 +203,28 @@ tuple_conversion!(9, (ref0, 0, A), (ref1, 1, B), (ref2, 2, C), (ref3, 3, D), /// let gil_guard = cpython::Python::acquire_gil(); /// let py = gil_guard.python(); /// let os = py.import("os").unwrap(); -/// let pid = os.call("get_pid", cpython::NoArgs, None); +/// let pid = os.call("get_pid", cpython::NoArgs, None, py); /// ``` +#[derive(Copy, Clone, Debug)] pub struct NoArgs; /// Converts `NoArgs` to an empty Python tuple. -impl <'p> ToPyObject<'p> for NoArgs { - type ObjectType = PyTuple<'p>; +impl ToPyObject for NoArgs { + type ObjectType = PyTuple; - fn to_py_object(&self, py: Python<'p>) -> PyTuple<'p> { + fn to_py_object(&self, py: Python) -> PyTuple { PyTuple::empty(py) } } /// Returns `Ok(NoArgs)` if the input is an empty Python tuple. /// Otherwise, returns an error. -extract!(obj to NoArgs => { - let t = try!(obj.cast_as::()); +extract!(obj to NoArgs; py => { + let t = try!(obj.cast_as::(py)); if t.len() == 0 { Ok(NoArgs) } else { - Err(wrong_tuple_length(t, 0)) + Err(wrong_tuple_length(t, 0, py)) } }); diff --git a/src/objects/typeobject.rs b/src/objects/typeobject.rs index 43f2da5d..04d2b890 100644 --- a/src/objects/typeobject.rs +++ b/src/objects/typeobject.rs @@ -23,11 +23,11 @@ use err::{PyResult, result_from_owned_ptr}; use ffi; /// Represents a reference to a Python type object. -pub struct PyType<'p>(PyObject<'p>); +pub struct PyType(PyObject); pyobject_newtype!(PyType, PyType_Check, PyType_Type); -impl <'p> PyType<'p> { +impl PyType { /// Retrieves the underlying FFI pointer associated with this Python object. #[inline] pub fn as_type_ptr(&self) -> *mut ffi::PyTypeObject { @@ -37,39 +37,39 @@ impl <'p> PyType<'p> { /// Retrieves the PyType instance for the given FFI pointer. /// Undefined behavior if the pointer is NULL or invalid. #[inline] - pub unsafe fn from_type_ptr<'a>(py: Python<'p>, p: *mut ffi::PyTypeObject) -> PyType<'p> { + pub unsafe fn from_type_ptr(py: Python, p: *mut ffi::PyTypeObject) -> PyType { PyObject::from_borrowed_ptr(py, p as *mut ffi::PyObject).unchecked_cast_into::() } /// Return true if self is a subtype of b. #[inline] - pub fn is_subtype_of(&self, b : &PyType<'p>) -> bool { + pub fn is_subtype_of(&self, b : &PyType, _: Python) -> bool { unsafe { ffi::PyType_IsSubtype(self.as_type_ptr(), b.as_type_ptr()) != 0 } } /// Return true if obj is an instance of self. #[inline] - pub fn is_instance(&self, obj : &PyObject<'p>) -> bool { + pub fn is_instance(&self, obj : &PyObject, _: Python) -> bool { unsafe { ffi::PyObject_TypeCheck(obj.as_ptr(), self.as_type_ptr()) != 0 } } /// Calls the type object, thus creating a new instance. /// This is equivalent to the Python expression: `self(*args, **kwargs)` #[inline] - pub fn call(&self, args: A, kwargs: Option<&PyDict<'p>>) -> PyResult<'p, PyObject<'p>> - where A: ToPyObject<'p, ObjectType=PyTuple<'p>> { - let py = self.python(); + pub fn call(&self, args: A, kwargs: Option<&PyDict>, py: Python) -> PyResult + where A: ToPyObject + { args.with_borrowed_ptr(py, |args| unsafe { result_from_owned_ptr(py, ffi::PyObject_Call(self.0.as_ptr(), args, kwargs.as_ptr())) }) } } -impl <'p> PartialEq for PyType<'p> { +impl PartialEq for PyType { #[inline] - fn eq(&self, o : &PyType<'p>) -> bool { + fn eq(&self, o : &PyType) -> bool { self.as_type_ptr() == o.as_type_ptr() } } -impl <'p> Eq for PyType<'p> { } +impl Eq for PyType { } diff --git a/src/python.rs b/src/python.rs index 015d5bd0..51dbe92a 100644 --- a/src/python.rs +++ b/src/python.rs @@ -38,66 +38,121 @@ use pythonrun::GILGuard; #[derive(Copy, Clone)] pub struct Python<'p>(PhantomData<&'p GILGuard>); -/// This trait allows retrieving the underlying FFI pointer from Python objects. -pub trait ToPythonPointer { - /// Retrieves the underlying FFI pointer (as a borrowed pointer). - fn as_ptr(&self) -> *mut ffi::PyObject; - - /// Retrieves the underlying FFI pointer as a "stolen pointer". - fn steal_ptr(self) -> *mut ffi::PyObject; -} - /// Trait implemented by all Python object types. -pub trait PythonObject<'p> : 'p + Clone + ::conversion::ToPyObject<'p> { +pub trait PythonObject : ::conversion::ToPyObject + Sized + 'static { /// Casts the Python object to PyObject. - fn as_object(&self) -> &PyObject<'p>; + fn as_object(&self) -> &PyObject; /// Casts the Python object to PyObject. - fn into_object(self) -> PyObject<'p>; + fn into_object(self) -> PyObject; /// Unchecked downcast from PyObject to Self. /// Undefined behavior if the input object does not have the expected type. - unsafe fn unchecked_downcast_from(PyObject<'p>) -> Self; + unsafe fn unchecked_downcast_from(PyObject) -> Self; /// Unchecked downcast from PyObject to Self. /// Undefined behavior if the input object does not have the expected type. - unsafe fn unchecked_downcast_borrow_from<'a>(&'a PyObject<'p>) -> &'a Self; - - /// Retrieve Python instance from an existing Python object. - #[inline] - fn python(&self) -> Python<'p> { - self.as_object().python() - } + unsafe fn unchecked_downcast_borrow_from(&PyObject) -> &Self; } // Marker type that indicates an error while downcasting pub struct PythonObjectDowncastError<'p>(pub Python<'p>); /// Trait implemented by Python object types that allow a checked downcast. -pub trait PythonObjectWithCheckedDowncast<'p> : PythonObject<'p> { +pub trait PythonObjectWithCheckedDowncast : PythonObject { /// Cast from PyObject to a concrete Python object type. - fn downcast_from(PyObject<'p>) -> Result>; - + fn downcast_from<'p>(PyObject, Python<'p>) -> Result>; + /// Cast from PyObject to a concrete Python object type. - fn downcast_borrow_from<'a>(&'a PyObject<'p>) -> Result<&'a Self, PythonObjectDowncastError<'p>>; + fn downcast_borrow_from<'a, 'p>(&'a PyObject, Python<'p>) -> Result<&'a Self, PythonObjectDowncastError<'p>>; } /// Trait implemented by Python object types that have a corresponding type object. -pub trait PythonObjectWithTypeObject<'p> : PythonObjectWithCheckedDowncast<'p> { +pub trait PythonObjectWithTypeObject : PythonObjectWithCheckedDowncast { /// Retrieves the type object for this Python object type. - fn type_object(Python<'p>) -> PyType<'p>; + fn type_object(Python) -> PyType; +} + +pub trait PyClone : Sized { + fn clone_ref(&self, Python) -> Self; +} + +impl PyClone for T where T: PythonObject { + #[inline] + fn clone_ref(&self, py: Python) -> T { + let ptr = self.as_object().as_ptr(); + unsafe { + T::unchecked_downcast_from(PyObject::from_borrowed_ptr(py, ptr)) + } + } +} + +impl PyClone for Option where T: PyClone { + #[inline] + fn clone_ref(&self, py: Python) -> Option { + match *self { + Some(ref v) => Some(v.clone_ref(py)), + None => None + } + } +} + +pub trait PyDrop : Sized { + fn release_ref(self, Python); +} + +impl PyDrop for T where T: PythonObject { + #[inline] + fn release_ref(self, _py: Python) { + let ptr = self.into_object().steal_ptr(); + unsafe { + ffi::Py_DECREF(ptr); + } + } +} + +impl PyDrop for Option where T: PyDrop { + #[inline] + fn release_ref(self, py: Python) { + match self { + Some(v) => v.release_ref(py), + None => {} + } + } +} + +/// This trait allows retrieving the underlying FFI pointer from Python objects. +pub trait ToPythonPointer { + /// Retrieves the underlying FFI pointer (as a borrowed pointer). + fn as_ptr(&self) -> *mut ffi::PyObject; + + /// Retrieves the underlying FFI pointer as a "stolen pointer". + fn steal_ptr(self, py: Python) -> *mut ffi::PyObject; } /// ToPythonPointer for borrowed Python pointers. -impl <'a, 'p, T> ToPythonPointer for &'a T where T: PythonObject<'p> { +impl ToPythonPointer for PyObject { + #[inline] + fn as_ptr(&self) -> *mut ffi::PyObject { + self.as_ptr() + } + + #[inline] + fn steal_ptr(self, _py: Python) -> *mut ffi::PyObject { + self.steal_ptr() + } +} + +/// ToPythonPointer for borrowed Python pointers. +impl <'a, T> ToPythonPointer for &'a T where T: PythonObject { #[inline] fn as_ptr(&self) -> *mut ffi::PyObject { self.as_object().as_ptr() } - + #[inline] - fn steal_ptr(self) -> *mut ffi::PyObject { - self.as_object().clone().steal_ptr() + fn steal_ptr(self, py: Python) -> *mut ffi::PyObject { + self.as_object().clone_ref(py).steal_ptr() } } @@ -110,11 +165,11 @@ impl ToPythonPointer for Option where T: ToPythonPointer { None => std::ptr::null_mut() } } - + #[inline] - fn steal_ptr(self) -> *mut ffi::PyObject { + fn steal_ptr(self, py: Python) -> *mut ffi::PyObject { match self { - Some(t) => t.steal_ptr(), + Some(t) => t.steal_ptr(py), None => std::ptr::null_mut() } } @@ -141,23 +196,24 @@ impl<'p> Python<'p> { GILGuard::acquire() } - /// Releases the GIL and allows the use of Python on other threads. - /// Unsafe because we do not ensure that existing references to Python objects - /// are not accessed within the closure. - pub unsafe fn allow_threads(self, f: F) -> T where F : FnOnce() -> T { - // TODO: we should use a type with destructor to be panic-safe, and avoid the unnecessary closure - let save = ffi::PyEval_SaveThread(); - let result = f(); - ffi::PyEval_RestoreThread(save); - result + /// Temporarily releases the GIL, thus allowing other Python threads to run. + pub fn allow_threads(self, f: F) -> T where F : Send + FnOnce() -> T { + // The `Send` bound on the closure prevents the user from + // transferring the `Python` token into the closure. + unsafe { + let save = ffi::PyEval_SaveThread(); + let result = f(); + ffi::PyEval_RestoreThread(save); + result + } } /// Evaluates a Python expression in the given context and returns the result. /// /// 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<'p>>, - locals: Option<&PyDict<'p>>) -> PyResult<'p, PyObject<'p>> { + pub fn eval(self, code: &str, globals: Option<&PyDict>, + locals: Option<&PyDict>) -> PyResult { self.run_code(code, ffi::Py_eval_input, globals, locals) } @@ -165,8 +221,8 @@ 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 run(self, code: &str, globals: Option<&PyDict<'p>>, - locals: Option<&PyDict<'p>>) -> PyResult<'p, ()> { + pub fn run(self, code: &str, globals: Option<&PyDict>, + locals: Option<&PyDict>) -> PyResult<()> { try!(self.run_code(code, ffi::Py_file_input, globals, locals)); Ok(()) } @@ -178,8 +234,8 @@ 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<'p>>, locals: Option<&PyDict<'p>>) - -> PyResult<'p, PyObject<'p>> { + globals: Option<&PyDict>, locals: Option<&PyDict>) + -> PyResult { let code = CString::new(code).unwrap(); unsafe { @@ -211,31 +267,31 @@ impl<'p> Python<'p> { /// Gets the Python builtin value `None`. #[allow(non_snake_case)] // the Python keyword starts with uppercase #[inline] - pub fn None(self) -> PyObject<'p> { + pub fn None(self) -> PyObject { unsafe { PyObject::from_borrowed_ptr(self, ffi::Py_None()) } } /// Gets the Python builtin value `True`. #[allow(non_snake_case)] // the Python keyword starts with uppercase #[inline] - pub fn True(self) -> PyBool<'p> { + pub fn True(self) -> PyBool { unsafe { PyObject::from_borrowed_ptr(self, ffi::Py_True()).unchecked_cast_into::() } } /// Gets the Python builtin value `False`. #[allow(non_snake_case)] // the Python keyword starts with uppercase #[inline] - pub fn False(self) -> PyBool<'p> { + pub fn False(self) -> PyBool { unsafe { PyObject::from_borrowed_ptr(self, ffi::Py_False()).unchecked_cast_into::() } } /// Gets the Python type object for type T. - pub fn get_type(self) -> PyType<'p> where T: PythonObjectWithTypeObject<'p> { + pub fn get_type(self) -> PyType where T: PythonObjectWithTypeObject { T::type_object(self) } /// Import the Python module with the specified name. - pub fn import(self, name : &str) -> PyResult<'p, PyModule<'p>> { + pub fn import(self, name : &str) -> PyResult { PyModule::import(self, name) } } @@ -256,16 +312,16 @@ mod test { let py = gil.python(); // Make sure builtin names are accessible - let v: i32 = py.eval("min(1, 2)", None, None).unwrap().extract().unwrap(); + let v: i32 = py.eval("min(1, 2)", None, None).unwrap().extract(py).unwrap(); assert_eq!(v, 1); let d = PyDict::new(py); - d.set_item("foo", 13).unwrap(); + d.set_item("foo", 13, py).unwrap(); // Inject our own local namespace - let v: i32 = py.eval("foo + 29", None, Some(&d)).unwrap().extract().unwrap(); + let v: i32 = py.eval("foo + 29", None, Some(&d)).unwrap().extract(py).unwrap(); assert_eq!(v, 42); } diff --git a/src/rustobject/method.rs b/src/rustobject/method.rs index 722c7320..7e185747 100644 --- a/src/rustobject/method.rs +++ b/src/rustobject/method.rs @@ -26,7 +26,7 @@ use err; /// Creates a Python instance method descriptor that invokes a Rust function. /// /// As arguments, takes the name of a rust function with the signature -/// `for<'p> fn(&PyRustObject<'p, T>, &PyTuple<'p>) -> PyResult<'p, R>` +/// `fn(&PyRustObject, &PyTuple, Python) -> PyResult` /// for some `R` that implements `ToPyObject`. /// /// Returns a type that implements `typebuilder::TypeMember>` @@ -41,9 +41,8 @@ use err; /// PyTuple, PyRustObject, PyRustTypeBuilder}; /// use cpython::{exc}; /// -/// fn mul<'p>(slf: &PyRustObject<'p, i32>, arg: i32) -> PyResult<'p, i32> { -/// let py = slf.python(); -/// match slf.get().checked_mul(arg) { +/// fn mul(py: Python, slf: &PyRustObject, arg: i32) -> PyResult { +/// match slf.get(py).checked_mul(arg) { /// Some(val) => Ok(val), /// None => Err(PyErr::new_lazy_init(py.get_type::(), None)) /// } @@ -51,11 +50,12 @@ use err; /// /// fn main() { /// let gil = Python::acquire_gil(); -/// let multiplier_type = PyRustTypeBuilder::::new(gil.python(), "Multiplier") +/// let py = gil.python(); +/// let multiplier_type = PyRustTypeBuilder::::new(py, "Multiplier") /// .add("mul", py_method!(mul(arg: i32))) /// .finish().unwrap(); -/// let obj = multiplier_type.create_instance(3, ()).into_object(); -/// let result = obj.call_method("mul", &(4,), None).unwrap().extract::().unwrap(); +/// let obj = multiplier_type.create_instance(3, (), py).into_object(); +/// let result = obj.call_method("mul", &(4,), None, py).unwrap().extract::(py).unwrap(); /// assert_eq!(result, 12); /// } /// ``` @@ -78,7 +78,11 @@ macro_rules! py_method { Some(kwargs) => Some(<$crate::PyDict as $crate::PythonObject>::unchecked_downcast_from(kwargs)), None => None }; - match $f(&slf, &args, kwargs.as_ref()) { + let ret: $crate::PyResult<_> = $f(py, &slf, &args, kwargs.as_ref()); + $crate::PyDrop::release_ref(kwargs, py); + $crate::PyDrop::release_ref(args, py); + $crate::PyDrop::release_ref(slf, py); + match ret { Ok(val) => { let obj = $crate::ToPyObject::into_py_object(val, py); return $crate::PythonObject::into_object(obj).steal_ptr(); @@ -122,15 +126,19 @@ macro_rules! py_method { Some(kwargs) => Some(<$crate::PyDict as $crate::PythonObject>::unchecked_downcast_from(kwargs)), None => None }; - match py_argparse!(Some(stringify!($f)), &args, kwargs.as_ref(), - ( $($pname : $ptype),* ) { $f( &slf, $($pname),* ) }) - { + let ret: $crate::PyResult<_> = + py_argparse!(Some(stringify!($f)), &args, kwargs.as_ref(), py, + ( $($pname : $ptype),* ) { $f( py, &slf, $($pname),* ) }); + $crate::PyDrop::release_ref(kwargs, py); + $crate::PyDrop::release_ref(args, py); + $crate::PyDrop::release_ref(slf, py); + match ret { Ok(val) => { let obj = $crate::ToPyObject::into_py_object(val, py); return $crate::PythonObject::into_object(obj).steal_ptr(); } Err(e) => { - e.restore(); + e.restore(py); return ::std::ptr::null_mut(); } } @@ -159,15 +167,16 @@ pub struct MethodDescriptor(*mut ffi::PyMethodDef, marker::PhantomData // corresponds to the T in the function signature. - pub unsafe fn py_method_impl<'p, T, R>( + pub unsafe fn py_method_impl( def: *mut ffi::PyMethodDef, - _f: fn(&T, &PyTuple<'p>, Option<&PyDict<'p>>) -> err::PyResult<'p, R> + _f: fn(Python, &T, &PyTuple, Option<&PyDict>) -> err::PyResult ) -> MethodDescriptor { MethodDescriptor(def, marker::PhantomData) } @@ -186,53 +195,53 @@ pub mod py_method_impl { => { $crate::_detail::py_method_impl::py_method_impl_3($def, $f) }; } - pub unsafe fn py_method_impl_0<'p, T, R>( + pub unsafe fn py_method_impl_0( def: *mut ffi::PyMethodDef, - _f: fn(&T) -> err::PyResult<'p, R> + _f: fn(Python, &T) -> err::PyResult ) -> MethodDescriptor { MethodDescriptor(def, marker::PhantomData) } - pub unsafe fn py_method_impl_1<'p, T, P1, R>( + pub unsafe fn py_method_impl_1( def: *mut ffi::PyMethodDef, - _f: fn(&T, P1) -> err::PyResult<'p, R> + _f: fn(Python, &T, P1) -> err::PyResult ) -> MethodDescriptor { MethodDescriptor(def, marker::PhantomData) } - pub unsafe fn py_method_impl_2<'p, T, P1, P2, R>( + pub unsafe fn py_method_impl_2( def: *mut ffi::PyMethodDef, - _f: fn(&T, P1, P2) -> err::PyResult<'p, R> + _f: fn(Python, &T, P1, P2) -> err::PyResult ) -> MethodDescriptor { MethodDescriptor(def, marker::PhantomData) } - pub unsafe fn py_method_impl_3<'p, T, P1, P2, P3, R>( + pub unsafe fn py_method_impl_3( def: *mut ffi::PyMethodDef, - _f: fn(&T, P1, P2, P3) -> err::PyResult<'p, R> + _f: fn(Python, &T, P1, P2, P3) -> err::PyResult ) -> MethodDescriptor { MethodDescriptor(def, marker::PhantomData) } - pub unsafe fn py_method_impl_4<'p, T, P1, P2, P3, P4, R>( + pub unsafe fn py_method_impl_4( def: *mut ffi::PyMethodDef, - _f: fn(&T, P1, P2, P3, P4) -> err::PyResult<'p, R> + _f: fn(Python, &T, P1, P2, P3, P4) -> err::PyResult ) -> MethodDescriptor { MethodDescriptor(def, marker::PhantomData) } } -impl <'p, T> TypeMember<'p, T> for MethodDescriptor where T: PythonObject<'p> { +impl TypeMember for MethodDescriptor where T: PythonObject { #[inline] - fn to_descriptor(&self, ty: &PyType<'p>, _name: &str) -> PyObject<'p> { + fn to_descriptor(&self, ty: &PyType, _name: &str, py: Python) -> PyObject { unsafe { - err::from_owned_ptr_or_panic(ty.python(), + err::from_owned_ptr_or_panic(py, ffi::PyDescr_NewMethod(ty.as_type_ptr(), self.0)) } } #[inline] - fn into_box(self, _py: Python<'p>) -> Box + 'p> { + fn into_box(self, _py: Python) -> Box> { Box::new(self) } } @@ -241,7 +250,7 @@ impl <'p, T> TypeMember<'p, T> for MethodDescriptor where T: PythonObject<'p> /// Creates a Python class method descriptor that invokes a Rust function. /// /// As arguments, takes the name of a rust function with the signature -/// `for<'p> fn(&PyType<'p>, &PyTuple<'p>) -> PyResult<'p, T>` +/// `fn(&PyType, &PyTuple, Python) -> PyResult` /// for some `T` that implements `ToPyObject`. /// /// Returns a type that implements `typebuilder::TypeMember>` @@ -256,17 +265,18 @@ impl <'p, T> TypeMember<'p, T> for MethodDescriptor where T: PythonObject<'p> /// PyTuple, PyType, PyRustTypeBuilder, NoArgs}; /// use cpython::{exc}; /// -/// fn method<'p>(py: Python<'p>) -> PyResult<'p, i32> { +/// fn method(py: Python) -> PyResult { /// Ok(42) /// } /// /// fn main() { /// let gil = Python::acquire_gil(); -/// let my_type = PyRustTypeBuilder::::new(gil.python(), "MyType") +/// let py = gil.python(); +/// let my_type = PyRustTypeBuilder::::new(py, "MyType") /// .add("method", py_class_method!(method())) /// .finish().unwrap(); -/// let result = my_type.as_object().call_method("method", NoArgs, None).unwrap(); -/// assert_eq!(42, result.extract::().unwrap()); +/// let result = my_type.as_object().call_method("method", NoArgs, None, py).unwrap(); +/// assert_eq!(42, result.extract::(py).unwrap()); /// } /// ``` #[macro_export] @@ -288,7 +298,11 @@ macro_rules! py_class_method { Some(kwargs) => Some(<$crate::PyDict as $crate::PythonObject>::unchecked_downcast_from(kwargs)), None => None }; - match $f(&slf, &args, kwargs.as_ref()) { + let ret: $crate::PyResult<_> = $f(&slf, &args, kwargs.as_ref(), py); + $crate::PyDrop::release_ref(kwargs, py); + $crate::PyDrop::release_ref(args, py); + $crate::PyDrop::release_ref(slf, py); + match ret { Ok(val) => { let obj = $crate::ToPyObject::into_py_object(val, py); return $crate::PythonObject::into_object(obj).steal_ptr(); @@ -334,15 +348,19 @@ macro_rules! py_class_method { Some(kwargs) => Some(<$crate::PyDict as $crate::PythonObject>::unchecked_downcast_from(kwargs)), None => None }; - match py_argparse!(Some(stringify!($f)), &args, kwargs.as_ref(), - ( $($pname : $ptype),* ) { $f( py, $($pname),* ) }) - { + let ret: $crate::PyResult<_> = + py_argparse!(Some(stringify!($f)), &args, kwargs.as_ref(), py, + ( $($pname : $ptype),* ) { $f( py, $($pname),* ) }); + $crate::PyDrop::release_ref(kwargs, py); + $crate::PyDrop::release_ref(args, py); + $crate::PyDrop::release_ref(slf, py); + match ret { Ok(val) => { let obj = $crate::ToPyObject::into_py_object(val, py); return $crate::PythonObject::into_object(obj).steal_ptr(); } Err(e) => { - e.restore(); + e.restore(py); return ::std::ptr::null_mut(); } } @@ -374,17 +392,17 @@ pub unsafe fn py_class_method_impl(def: *mut ffi::PyMethodDef) -> ClassMethodDes ClassMethodDescriptor(def) } -impl <'p, T> TypeMember<'p, T> for ClassMethodDescriptor where T: PythonObject<'p> { +impl TypeMember for ClassMethodDescriptor where T: PythonObject { #[inline] - fn to_descriptor(&self, ty: &PyType<'p>, _name: &str) -> PyObject<'p> { + fn to_descriptor(&self, ty: &PyType, _name: &str, py: Python) -> PyObject { unsafe { - err::from_owned_ptr_or_panic(ty.python(), + err::from_owned_ptr_or_panic(py, ffi::PyDescr_NewClassMethod(ty.as_type_ptr(), self.0)) } } #[inline] - fn into_box(self, _py: Python<'p>) -> Box + 'p> { + fn into_box(self, _py: Python) -> Box> { Box::new(self) } } diff --git a/src/rustobject/mod.rs b/src/rustobject/mod.rs index 900e8a90..5bc86c5b 100644 --- a/src/rustobject/mod.rs +++ b/src/rustobject/mod.rs @@ -18,7 +18,7 @@ use libc; use ffi; -use python::{Python, ToPythonPointer, PythonObject}; +use python::{Python, ToPythonPointer, PythonObject, PyClone}; use conversion::ToPyObject; use objects::{PyObject, PyType}; use std::{mem, ops, ptr, marker}; @@ -30,25 +30,25 @@ pub mod method; mod tests; /// A PythonObject that is usable as a base type with PyTypeBuilder::base(). -pub trait PythonBaseObject<'p> : PythonObject<'p> { +pub trait PythonBaseObject : PythonObject { /// Gets the size of the object, in bytes. fn size() -> usize; - type InitType : 'p; + type InitType; /// Allocates a new object (usually by calling ty->tp_alloc), /// and initializes it using init_val. /// `ty` must be derived from the Self type, and the resulting object /// must be of type `ty`. - unsafe fn alloc(ty: &PyType<'p>, init_val: Self::InitType) -> PyResult<'p, Self>; + unsafe fn alloc(ty: &PyType, init_val: Self::InitType, py: Python) -> PyResult; /// Calls the rust destructor for the object and frees the memory /// (usually by calling ptr->ob_type->tp_free). /// This function is used as tp_dealloc implementation. - unsafe fn dealloc(ptr: *mut ffi::PyObject); + unsafe fn dealloc(ptr: *mut ffi::PyObject, py: Python); } -impl <'p> PythonBaseObject<'p> for PyObject<'p> { +impl PythonBaseObject for PyObject { #[inline] fn size() -> usize { mem::size_of::() @@ -56,13 +56,12 @@ impl <'p> PythonBaseObject<'p> for PyObject<'p> { type InitType = (); - unsafe fn alloc(ty: &PyType<'p>, _init_val: ()) -> PyResult<'p, PyObject<'p>> { - let py = ty.python(); + unsafe fn alloc(ty: &PyType, _init_val: (), py: Python) -> PyResult { let ptr = ffi::PyType_GenericAlloc(ty.as_type_ptr(), 0); err::result_from_owned_ptr(py, ptr) } - unsafe fn dealloc(ptr: *mut ffi::PyObject) { + unsafe fn dealloc(ptr: *mut ffi::PyObject, _py: Python) { // Unfortunately, there is no PyType_GenericFree, so // we have to manually un-do the work of PyType_GenericAlloc: let ty = ffi::Py_TYPE(ptr); @@ -84,13 +83,13 @@ impl <'p> PythonBaseObject<'p> for PyObject<'p> { /// Note that this type effectively acts like `Rc`, /// except that the reference counting is done by the Python runtime. #[repr(C)] -pub struct PyRustObject<'p, T, B = PyObject<'p>> where T: 'static, B: PythonBaseObject<'p> { - obj: PyObject<'p>, +pub struct PyRustObject where T: 'static + Send, B: PythonBaseObject { + obj: PyObject, /// The PyRustObject acts like a shared reference to the contained T. - t: marker::PhantomData<&'p (T, B)> + t: marker::PhantomData<&'static (T, B)> } -impl <'p, T, B> PyRustObject<'p, T, B> where T: 'static + Send, B: PythonBaseObject<'p> { +impl PyRustObject where T: 'static + Send, B: PythonBaseObject { #[inline] // this function can usually be reduced to a compile-time constant fn offset() -> usize { let align = mem::align_of::(); @@ -100,13 +99,21 @@ impl <'p, T, B> PyRustObject<'p, T, B> where T: 'static + Send, B: PythonBaseObj /// Gets a reference to this object, but of the base class type. #[inline] - pub fn base(&self) -> &B { + pub fn as_base(&self) -> &B { unsafe { B::unchecked_downcast_borrow_from(&self.obj) } } + /// Gets a reference to this object, but of the base class type. + #[inline] + pub fn into_base(self) -> B { + unsafe { B::unchecked_downcast_from(self.obj) } + } + /// Gets a reference to the rust value stored in this Python object. #[inline] - pub fn get(&self) -> &T { + pub fn get<'a>(&'a self, _py: Python<'a>) -> &'a T { + // We require the `Python` token to access the contained value, + // because `PyRustObject` is `Sync` even if `T` is `!Sync`. let offset = PyRustObject::::offset() as isize; unsafe { let ptr = (self.obj.as_ptr() as *mut u8).offset(offset) as *mut T; @@ -115,7 +122,7 @@ impl <'p, T, B> PyRustObject<'p, T, B> where T: 'static + Send, B: PythonBaseObj } } -impl <'p, T, B> PythonBaseObject<'p> for PyRustObject<'p, T, B> where T: 'static + Send, B: PythonBaseObject<'p> { +impl PythonBaseObject for PyRustObject where T: 'static + Send, B: PythonBaseObject { #[inline] fn size() -> usize { PyRustObject::::offset() + mem::size_of::() @@ -123,65 +130,55 @@ impl <'p, T, B> PythonBaseObject<'p> for PyRustObject<'p, T, B> where T: 'static type InitType = (T, B::InitType); - unsafe fn alloc(ty: &PyType<'p>, (val, base_val): Self::InitType) -> PyResult<'p, Self> { - let obj = try!(B::alloc(ty, base_val)); + unsafe fn alloc(ty: &PyType, (val, base_val): Self::InitType, py: Python) -> PyResult { + let obj = try!(B::alloc(ty, base_val, py)); let offset = PyRustObject::::offset() as isize; ptr::write((obj.as_object().as_ptr() as *mut u8).offset(offset) as *mut T, val); Ok(Self::unchecked_downcast_from(obj.into_object())) } - unsafe fn dealloc(obj: *mut ffi::PyObject) { + unsafe fn dealloc(obj: *mut ffi::PyObject, py: Python) { let offset = PyRustObject::::offset() as isize; ptr::read_and_drop((obj as *mut u8).offset(offset) as *mut T); - B::dealloc(obj) + B::dealloc(obj, py) } } -impl <'p, T, B> Clone for PyRustObject<'p, T, B> where T: 'static + Send, B: PythonBaseObject<'p> { - #[inline] - fn clone(&self) -> Self { - PyRustObject { - obj: self.obj.clone(), - t: marker::PhantomData - } - } -} - -impl <'p, 's, T, B> ToPyObject<'p> for PyRustObject<'s, T, B> where T: 'static + Send, B: PythonBaseObject<'s> { - type ObjectType = PyObject<'p>; +impl ToPyObject for PyRustObject where T: 'static + Send, B: PythonBaseObject { + type ObjectType = PyObject; #[inline] - fn to_py_object(&self, py: Python<'p>) -> PyObject<'p> { - self.as_object().to_py_object(py) + fn to_py_object(&self, py: Python) -> PyObject { + self.obj.clone_ref(py) } #[inline] - fn into_py_object(self, py: Python<'p>) -> PyObject<'p> { - self.into_object().into_py_object(py) + fn into_py_object(self, _py: Python) -> PyObject { + self.into_object() } #[inline] - fn with_borrowed_ptr(&self, _py: Python<'p>, f: F) -> R + fn with_borrowed_ptr(&self, _py: Python, f: F) -> R where F: FnOnce(*mut ffi::PyObject) -> R { - f(self.as_ptr()) + f(self.obj.as_ptr()) } } -impl <'p, T, B> PythonObject<'p> for PyRustObject<'p, T, B> where T: 'static + Send, B: PythonBaseObject<'p> { +impl PythonObject for PyRustObject where T: 'static + Send, B: PythonBaseObject { #[inline] - fn as_object(&self) -> &PyObject<'p> { + fn as_object(&self) -> &PyObject { &self.obj } #[inline] - fn into_object(self) -> PyObject<'p> { + fn into_object(self) -> PyObject { self.obj } /// Unchecked downcast from PyObject to Self. /// Undefined behavior if the input object does not have the expected type. #[inline] - unsafe fn unchecked_downcast_from(obj: PyObject<'p>) -> Self { + unsafe fn unchecked_downcast_from(obj: PyObject) -> Self { PyRustObject { obj: obj, t: marker::PhantomData @@ -191,7 +188,7 @@ impl <'p, T, B> PythonObject<'p> for PyRustObject<'p, T, B> where T: 'static + S /// Unchecked downcast from PyObject to Self. /// Undefined behavior if the input object does not have the expected type. #[inline] - unsafe fn unchecked_downcast_borrow_from<'a>(obj: &'a PyObject<'p>) -> &'a Self { + unsafe fn unchecked_downcast_borrow_from<'a>(obj: &'a PyObject) -> &'a Self { mem::transmute(obj) } } @@ -200,74 +197,64 @@ impl <'p, T, B> PythonObject<'p> for PyRustObject<'p, T, B> where T: 'static + S /// Serves as a Python type object, and can be used to construct /// `PyRustObject` instances. #[repr(C)] -pub struct PyRustType<'p, T, B = PyObject<'p>> where T: 'p + Send, B: PythonBaseObject<'p> { - type_obj: PyType<'p>, - phantom: marker::PhantomData<&'p (B, T)> +pub struct PyRustType where T: 'static + Send, B: PythonBaseObject { + type_obj: PyType, + phantom: marker::PhantomData<&'static (B, T)> } -impl <'p, T, B> PyRustType<'p, T, B> where T: 'p + Send, B: PythonBaseObject<'p> { +impl PyRustType where T: 'static + Send, B: PythonBaseObject { /// Creates a PyRustObject instance from a value. - pub fn create_instance(&self, val: T, base_val: B::InitType) -> PyRustObject<'p, T, B> { + pub fn create_instance(&self, val: T, base_val: B::InitType, py: Python) -> PyRustObject { unsafe { - PythonBaseObject::alloc(&self.type_obj, (val, base_val)).unwrap() + PythonBaseObject::alloc(&self.type_obj, (val, base_val), py).unwrap() } } } -impl <'p, T, B> ops::Deref for PyRustType<'p, T, B> where T: 'p + Send, B: PythonBaseObject<'p> { - type Target = PyType<'p>; +impl ops::Deref for PyRustType where T: 'static + Send, B: PythonBaseObject { + type Target = PyType; #[inline] - fn deref(&self) -> &PyType<'p> { + fn deref(&self) -> &PyType { &self.type_obj } } -impl <'p, T> Clone for PyRustType<'p, T> where T: 'p + Send { - #[inline] - fn clone(&self) -> Self { - PyRustType { - type_obj: self.type_obj.clone(), - phantom: marker::PhantomData - } - } -} - -impl <'p, 's, T> ToPyObject<'p> for PyRustType<'s, T> where T: 's + Send { - type ObjectType = PyType<'p>; +impl ToPyObject for PyRustType where T: 'static + Send, B: PythonBaseObject { + type ObjectType = PyType; #[inline] - fn to_py_object(&self, py: Python<'p>) -> PyType<'p> { - self.type_obj.to_py_object(py) + fn to_py_object(&self, py: Python) -> PyType { + self.type_obj.clone_ref(py) } #[inline] - fn into_py_object(self, py: Python<'p>) -> PyType<'p> { - self.type_obj.into_py_object(py) + fn into_py_object(self, _py: Python) -> PyType { + self.type_obj } #[inline] - fn with_borrowed_ptr(&self, _py: Python<'p>, f: F) -> R + fn with_borrowed_ptr(&self, _py: Python, f: F) -> R where F: FnOnce(*mut ffi::PyObject) -> R { - f(self.as_ptr()) + f(self.as_object().as_ptr()) } } -impl <'p, T> PythonObject<'p> for PyRustType<'p, T> where T: 'p + Send { +impl PythonObject for PyRustType where T: 'static + Send, B: PythonBaseObject { #[inline] - fn as_object(&self) -> &PyObject<'p> { + fn as_object(&self) -> &PyObject { self.type_obj.as_object() } #[inline] - fn into_object(self) -> PyObject<'p> { + fn into_object(self) -> PyObject { self.type_obj.into_object() } /// Unchecked downcast from PyObject to Self. /// Undefined behavior if the input object does not have the expected type. #[inline] - unsafe fn unchecked_downcast_from(obj: PyObject<'p>) -> Self { + unsafe fn unchecked_downcast_from(obj: PyObject) -> Self { PyRustType { type_obj: PyType::unchecked_downcast_from(obj), phantom: marker::PhantomData @@ -277,7 +264,7 @@ impl <'p, T> PythonObject<'p> for PyRustType<'p, T> where T: 'p + Send { /// Unchecked downcast from PyObject to Self. /// Undefined behavior if the input object does not have the expected type. #[inline] - unsafe fn unchecked_downcast_borrow_from<'a>(obj: &'a PyObject<'p>) -> &'a Self { + unsafe fn unchecked_downcast_borrow_from<'a>(obj: &'a PyObject) -> &'a Self { mem::transmute(obj) } } diff --git a/src/rustobject/tests.rs b/src/rustobject/tests.rs index ef2ed640..ad89b29b 100644 --- a/src/rustobject/tests.rs +++ b/src/rustobject/tests.rs @@ -37,7 +37,7 @@ fn rustobject_calls_drop() { let t = PyRustTypeBuilder::::new(py, "TypeWithDrop").finish().unwrap(); let drop_called = Arc::new(AtomicBool::new(false)); - let inst = t.create_instance(MyObj { drop_called: drop_called.clone() }, ()); + let inst = t.create_instance(MyObj { drop_called: drop_called.clone() }, (), py); assert!(drop_called.load(Ordering::Relaxed) == false); drop(inst); assert!(drop_called.load(Ordering::Relaxed) == true); @@ -49,7 +49,7 @@ fn no_init_from_python() { let gil = Python::acquire_gil(); let py = gil.python(); let t = PyRustTypeBuilder::::new(py, "MyType").finish().unwrap(); - assert!(t.call(&NoArgs, None).is_err()); + assert!(t.call(&NoArgs, None, py).is_err()); } @@ -60,10 +60,10 @@ fn heaptype_refcount() { let t = PyRustTypeBuilder::::new(py, "MyType").finish().unwrap(); // TODO: investigate why the refcnt isn't 1. //assert_eq!(1, t.as_object().get_refcnt()); - let old_refcnt = t.as_object().get_refcnt(); - let inst = t.create_instance(1, ()); - assert_eq!(old_refcnt + 1, t.as_object().get_refcnt()); + let old_refcnt = t.as_object().get_refcnt(py); + let inst = t.create_instance(1, (), py); + assert_eq!(old_refcnt + 1, t.as_object().get_refcnt(py)); drop(inst); - assert_eq!(old_refcnt, t.as_object().get_refcnt()); + assert_eq!(old_refcnt, t.as_object().get_refcnt(py)); } diff --git a/src/rustobject/typebuilder.rs b/src/rustobject/typebuilder.rs index 785da926..448067a0 100644 --- a/src/rustobject/typebuilder.rs +++ b/src/rustobject/typebuilder.rs @@ -20,7 +20,7 @@ use std::{ptr, marker}; use std::ffi::{CStr, CString}; use libc; use ffi; -use python::{Python, ToPythonPointer, PythonObject}; +use python::{Python, ToPythonPointer, PythonObject, PyClone}; use conversion::ToPyObject; use objects::{PyObject, PyType, PyString, PyModule, PyDict}; use err::{self, PyResult}; @@ -29,12 +29,12 @@ use super::{PythonBaseObject, PyRustObject, PyRustType}; #[repr(C)] #[must_use] -pub struct PyRustTypeBuilder<'p, T, B = PyObject<'p>> where T: 'static + Send, B: PythonBaseObject<'p> { +pub struct PyRustTypeBuilder<'p, T, B = PyObject> where T: 'static + Send, B: PythonBaseObject { // In Python 2.7, we can create a new PyHeapTypeObject and fill it. /// The python type object under construction. #[cfg(feature="python27-sys")] - type_obj: PyType<'p>, + type_obj: PyType, /// The full PyHeapTypeObject under construction. #[cfg(feature="python27-sys")] ht: *mut ffi::PyHeapTypeObject, @@ -53,25 +53,25 @@ pub struct PyRustTypeBuilder<'p, T, B = PyObject<'p>> where T: 'static + Send, B slots: Vec, /// Maintains owned reference for base type object #[cfg(feature="python3-sys")] - tp_base: Option>, + tp_base: Option, /// List of future type members #[cfg(feature="python3-sys")] - members: Vec<(String, Box> + 'p>)>, + members: Vec<(String, Box>>)>, /// The documentation string. doc_str: Option, /// The module to which the new type should be added. - target_module: Option>, + target_module: Option, /// Whether PyTypeBuilder::base() might be called can_change_base: bool, py: Python<'p>, phantom: marker::PhantomData<&'p (B, T)> } -pub fn new_typebuilder_for_module<'p, T>(m: &PyModule<'p>, name: &str) -> PyRustTypeBuilder<'p, T> +pub fn new_typebuilder_for_module<'p, T>(m: &PyModule, name: &str, py: Python<'p>) -> PyRustTypeBuilder<'p, T> where T: 'static + Send { - let b = PyRustTypeBuilder::new(m.python(), name); - PyRustTypeBuilder { target_module: Some(m.clone()), .. b } + let b = PyRustTypeBuilder::new(py, name); + PyRustTypeBuilder { target_module: Some(m.clone_ref(py)), .. b } } unsafe extern "C" fn disabled_tp_new_callback @@ -82,10 +82,11 @@ unsafe extern "C" fn disabled_tp_new_callback ptr::null_mut() } -unsafe extern "C" fn tp_dealloc_callback<'p, T, B>(obj: *mut ffi::PyObject) - where T: 'static + Send, B: PythonBaseObject<'p> { +unsafe extern "C" fn tp_dealloc_callback(obj: *mut ffi::PyObject) + where T: 'static + Send, B: PythonBaseObject { abort_on_panic!({ - PyRustObject::::dealloc(obj) + let py = Python::assume_gil_acquired(); + PyRustObject::::dealloc(obj, py) }); } @@ -105,7 +106,7 @@ impl <'p, T> PyRustTypeBuilder<'p, T> where T: 'static + Send { let ht = obj as *mut ffi::PyHeapTypeObject; // flags must be set first, before the GC traverses the object (*ht).ht_type.tp_flags = ffi::Py_TPFLAGS_DEFAULT | ffi::Py_TPFLAGS_HEAPTYPE; - (*ht).ht_name = PyString::new(py, name.as_bytes()).steal_ptr(); + (*ht).ht_name = PyString::new(py, name.as_bytes()).steal_ptr(py); (*ht).ht_type.tp_name = ffi::PyString_AS_STRING((*ht).ht_name); (*ht).ht_type.tp_new = Some(disabled_tp_new_callback); PyRustTypeBuilder { @@ -142,9 +143,9 @@ impl <'p, T> PyRustTypeBuilder<'p, T> where T: 'static + Send { /// Sets the base class that this type is inheriting from. #[cfg(feature="python27-sys")] - pub fn base(self, base_type: &PyRustType<'p, T2, B2>) - -> PyRustTypeBuilder<'p, T, PyRustObject<'p, T2, B2>> - where T2: 'static + Send, B2: PythonBaseObject<'p> + pub fn base(self, base_type: &PyRustType) + -> PyRustTypeBuilder<'p, T, PyRustObject> + where T2: 'static + Send, B2: PythonBaseObject { assert!(self.can_change_base, "base() must be called before any members are added to the type"); @@ -166,9 +167,9 @@ impl <'p, T> PyRustTypeBuilder<'p, T> where T: 'static + Send { /// Sets the base class that this type is inheriting from. #[cfg(feature="python3-sys")] - pub fn base(self, base_type: &PyRustType<'p, T2, B2>) - -> PyRustTypeBuilder<'p, T, PyRustObject<'p, T2, B2>> - where T2: 'static + Send, B2: PythonBaseObject<'p> + pub fn base(self, base_type: &PyRustType) + -> PyRustTypeBuilder<'p, T, PyRustObject> + where T2: 'static + Send, B2: PythonBaseObject { // Ensure we can't change the base after any callbacks are registered. assert!(self.can_change_base && self.members.len() == 0, @@ -178,7 +179,7 @@ impl <'p, T> PyRustTypeBuilder<'p, T> where T: 'static + Send { name: self.name, flags: self.flags, slots: self.slots, - tp_base: Some(base_type_obj.clone()), + tp_base: Some(base_type_obj.clone_ref(self.py)), members: Vec::new(), target_module: self.target_module, doc_str: self.doc_str, @@ -189,14 +190,14 @@ impl <'p, T> PyRustTypeBuilder<'p, T> where T: 'static + Send { } } -impl <'p, T, B> PyRustTypeBuilder<'p, T, B> where T: 'static + Send, B: PythonBaseObject<'p> { +impl <'p, T, B> PyRustTypeBuilder<'p, T, B> where T: 'static + Send, B: PythonBaseObject { /// Retrieves the type dictionary of the type being built. #[cfg(feature="python27-sys")] - fn dict(&self) -> PyDict<'p> { + fn dict(&self) -> PyDict { unsafe { if (*self.ht).ht_type.tp_dict.is_null() { - (*self.ht).ht_type.tp_dict = PyDict::new(self.py).steal_ptr(); + (*self.ht).ht_type.tp_dict = PyDict::new(self.py).steal_ptr(self.py); } PyDict::unchecked_downcast_from(PyObject::from_borrowed_ptr(self.py, (*self.ht).ht_type.tp_dict)) } @@ -210,16 +211,16 @@ impl <'p, T, B> PyRustTypeBuilder<'p, T, B> where T: 'static + Send, B: PythonBa /// Adds a new member to the type. #[cfg(feature="python27-sys")] pub fn add(mut self, name: &str, val: M) -> Self - where M: TypeMember<'p, PyRustObject<'p, T, B>> { + where M: TypeMember> { self.can_change_base = false; - self.dict().set_item(name, val.to_descriptor(&self.type_obj, name)).unwrap(); + self.dict().set_item(name, val.to_descriptor(&self.type_obj, name, self.py), self.py).unwrap(); self } /// Adds a new member to the type. #[cfg(feature="python3-sys")] pub fn add(mut self, name: &str, val: M) -> Self - where M: TypeMember<'p, PyRustObject<'p, T, B>> { + where M: TypeMember> { self.can_change_base = false; self.members.push((name.to_owned(), val.into_box(self.py))); self @@ -227,7 +228,7 @@ impl <'p, T, B> PyRustTypeBuilder<'p, T, B> where T: 'static + Send, B: PythonBa /// Finalize construction of the new type. #[cfg(feature="python27-sys")] - pub fn finish(self) -> PyResult<'p, PyRustType<'p, T, B>> { + pub fn finish(self) -> PyResult> { let py = self.py; unsafe { (*self.ht).ht_type.tp_basicsize = PyRustObject::::size() as ffi::Py_ssize_t; @@ -239,12 +240,12 @@ impl <'p, T, B> PyRustTypeBuilder<'p, T, B> where T: 'static + Send, B: PythonBa } if let Some(m) = self.target_module { // Set module name for new type - if let Ok(mod_name) = m.name() { - try!(self.type_obj.as_object().setattr("__module__", mod_name)); + if let Ok(mod_name) = m.name(py) { + try!(self.type_obj.as_object().setattr("__module__", mod_name, py)); } // Register the new type in the target module let name = unsafe { PyObject::from_borrowed_ptr(py, (*self.ht).ht_name) }; - try!(m.dict().set_item(name, self.type_obj.as_object())); + try!(m.dict(py).set_item(name, self.type_obj.as_object(), py)); } Ok(PyRustType { type_obj: self.type_obj, @@ -254,7 +255,7 @@ impl <'p, T, B> PyRustTypeBuilder<'p, T, B> where T: 'static + Send, B: PythonBa /// Finalize construction of the new type. #[cfg(feature="python3-sys")] - pub fn finish(mut self) -> PyResult<'p, PyRustType<'p, T, B>> { + pub fn finish(mut self) -> PyResult> { // push some more slots self.slots.push(ffi::PyType_Slot { slot: ffi::Py_tp_dealloc, @@ -277,19 +278,19 @@ impl <'p, T, B> PyRustTypeBuilder<'p, T, B> where T: 'static + Send, B: PythonBa self.py, &self.name, PyRustObject::::size(), self.flags, &mut self.slots) }); for (name, member) in self.members { - let descr = member.to_descriptor(&type_obj, &name); - try!(type_obj.as_object().setattr(name, descr)); + let descr = member.to_descriptor(&type_obj, &name, self.py); + try!(type_obj.as_object().setattr(name, descr, self.py)); } if let Some(m) = self.target_module { // Set module name for new type - if let Ok(mod_name) = m.name() { - try!(type_obj.as_object().setattr("__module__", mod_name)); + if let Ok(mod_name) = m.name(self.py) { + try!(type_obj.as_object().setattr("__module__", mod_name, self.py)); } // Register the new type in the target module unsafe { try!(err::error_on_minusone(self.py, ffi::PyDict_SetItemString( - m.dict().as_object().as_ptr(), + m.dict(self.py).as_object().as_ptr(), self.name.as_ptr(), type_obj.as_object().as_ptr()) )); @@ -325,7 +326,7 @@ unsafe fn create_type_from_slots<'p>( basicsize: usize, flags: libc::c_uint, slots: &mut Vec -) -> PyResult<'p, PyType<'p>> +) -> PyResult { // ensure the necessary slots are set: if !slots.iter().any(|s| s.slot == ffi::Py_tp_new) { @@ -349,29 +350,29 @@ unsafe fn create_type_from_slots<'p>( /// Represents something that can be added as a member to a Python class/type. /// /// T: type of rust class used for instances of the Python class/type. -pub trait TypeMember<'p, T> where T: PythonObject<'p> { +pub trait TypeMember where T: PythonObject { /// Convert the type member into a python object /// that can be stored in the type dict. - fn to_descriptor(&self, ty: &PyType<'p>, name: &str) -> PyObject<'p>; + fn to_descriptor(&self, ty: &PyType, name: &str, py: Python) -> PyObject; /// Put the type member into a box with lifetime `'p` so that /// it can be used at a later point in time. /// /// `PyRustTypeBuilder:add()` may use this function to store the member, /// with `into_descriptor()` being called from the `finish()` method. - fn into_box(self, py: Python<'p>) -> Box + 'p>; + fn into_box(self, py: Python) -> Box>; } // TODO: does this cause trouble for coherence? -impl <'p, T, S> TypeMember<'p, T> for S where T: PythonObject<'p>, S: ToPyObject<'p> { +impl TypeMember for S where T: PythonObject, S: ToPyObject { #[inline] - fn to_descriptor(&self, ty: &PyType<'p>, _name: &str) -> PyObject<'p> { - self.to_py_object(ty.python()).into_object() + fn to_descriptor(&self, _ty: &PyType, _name: &str, py: Python) -> PyObject { + self.to_py_object(py).into_object() } #[inline] - fn into_box(self, py: Python<'p>) -> Box + 'p> { + fn into_box(self, py: Python) -> Box> { Box::new(self.into_py_object(py).into_object()) } }