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!
This commit is contained in:
Daniel Grunwald 2015-10-25 17:55:29 +01:00
parent d33a4b68fc
commit 44611991c3
32 changed files with 1139 additions and 1114 deletions

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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:

View File

@ -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::<i32>("MyType")
py_module_initializer!(custom_type, |py, m| {
try!(m.add("__doc__", "Module documentation string", py));
try!(m.add_type::<i32>("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<i32>) -> PyResult<PyObject> {
println!("a() was called with self={:?}", slf.get(py));
Ok(py.None())
}

View File

@ -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<PyObject> {
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<i32> {
Ok(42)
}

View File

@ -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());

View File

@ -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<PyObject<'p>>]
) -> PyResult<'p, ()>
args: &PyTuple, kwargs: Option<&PyDict>,
output: &mut[Option<PyObject>],
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::<exc::TypeError, _>(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::<exc::TypeError, _>(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;

View File

@ -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<F, R>(&self, py: Python<'p>, f: F) -> R
where F: FnOnce(*mut ffi::PyObject) -> R {
fn with_borrowed_ptr<F, R>(&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<Self::Prepared>;
fn extract(prepared: &'prepared Self::Prepared) -> PyResult<'python, Self>;
fn extract<'p>(prepared: &'prepared Self::Prepared, py: Python<'p>) -> PyResult<Self>;
}
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<Self::Prepared> {
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<T> {
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 {
<T as ToPyObject>::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 {
<T as ToPyObject>::to_py_object(self, py)
}
#[inline]
fn with_borrowed_ptr<F, R>(&self, py: Python<'p>, f: F) -> R
where F: FnOnce(*mut ffi::PyObject) -> R {
fn with_borrowed_ptr<F, R>(&self, py: Python, f: F) -> R
where F: FnOnce(*mut ffi::PyObject) -> R
{
<T as ToPyObject>::with_borrowed_ptr(*self, py, f)
}
}

View File

@ -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<PyObject<'p>>,
pub pvalue : Option<PyObject>,
/// The `PyTraceBack` object associated with the error.
pub ptraceback : Option<PyObject<'p>>
pub ptraceback : Option<PyObject>
}
/// Represents the result of a Python call.
pub type PyResult<'p, T> = Result<T, PyErr<'p>>;
pub type PyResult<T> = Result<T, PyErr>;
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<T, V>(py: Python<'p>, value: V) -> PyErr<'p>
where T: PythonObjectWithTypeObject<'p>, V: ToPyObject<'p>
pub fn new<T, V>(py: Python, value: V) -> PyErr
where T: PythonObjectWithTypeObject, V: ToPyObject
{
PyErr::new_helper(py.get_type::<T>(), 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<O>(obj: O) -> PyErr<'p> where O: PythonObject<'p> {
PyErr::from_instance_helper(obj.into_object())
pub fn from_instance<O>(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<PyObject<'p>>) -> PyErr<'p> {
pub fn new_lazy_init(exc: PyType, value: Option<PyObject>) -> 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::<PyType>() {
Ok(t) => t,
pub fn get_type(&self, py: Python) -> PyType {
match self.ptype.cast_as::<PyType>(py) {
Ok(t) => t.clone_ref(py),
Err(_) =>
match self.ptype.cast_as::<PyClass>() {
match self.ptype.cast_as::<PyClass>(py) {
Ok(_) => py.get_type::<PyClass>(),
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::<PyType>() {
Ok(t) => t,
Err(_) => py.None().get_type().clone()
pub fn get_type(&self, py: Python) -> PyType {
match self.ptype.cast_as::<PyType>(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<PythonObjectDowncastError<'p>> for PyErr<'p> {
fn from(err: PythonObjectDowncastError<'p>) -> PyErr<'p> {
impl <'p> std::convert::From<PythonObjectDowncastError<'p>> for PyErr {
fn from(err: PythonObjectDowncastError<'p>) -> PyErr {
PyErr::new_lazy_init(err.0.get_type::<exc::TypeError>(), 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<T>(py : Python, p : *mut ffi::PyObject) -> PyResult<T>
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<T>(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::<exc::TypeError>(), None).restore();
PyErr::new_lazy_init(py.get_type::<exc::TypeError>(), None).restore(py);
assert!(PyErr::occurred(py));
drop(PyErr::fetch(py));
}

View File

@ -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()))
}

View File

@ -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<PyObject> {
/// 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::<PyModule>() {
let module = match PyObject::from_borrowed_ptr(py, module).cast_into::<PyModule>(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::<PyModule>() {
let module = match PyObject::from_owned_ptr(py, module).cast_into::<PyModule>(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();
}
}

View File

@ -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<N>(&self, attr_name: N) -> PyResult<'p, bool> where N: ToPyObject<'p> {
attr_name.with_borrowed_ptr(self.python(), |attr_name| unsafe {
fn hasattr<N>(&self, attr_name: N, py: Python) -> PyResult<bool> 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<N>(&self, attr_name: N) -> PyResult<'p, PyObject<'p>> where N: ToPyObject<'p> {
let py = self.python();
fn getattr<N>(&self, attr_name: N, py: Python) -> PyResult<PyObject> 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<N, V>(&self, attr_name: N, value: V) -> PyResult<'p, ()>
where N: ToPyObject<'p>, V: ToPyObject<'p>
fn setattr<N, V>(&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<N>(&self, attr_name: N) -> PyResult<'p, ()> where N: ToPyObject<'p> {
let py = self.python();
fn delattr<N>(&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<O>(&self, other: O) -> PyResult<'p, Ordering> where O: ToPyObject<'p> {
let py = self.python();
fn compare<O>(&self, other: O, py: Python) -> PyResult<Ordering> 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<PyString> {
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<PyString> {
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<A>(&self, args: A, kwargs: Option<&PyDict<'p>>) -> PyResult<'p, PyObject<'p>>
where A: ToPyObject<'p, ObjectType=PyTuple<'p>> {
let py = self.python();
fn call<A>(&self, args: A, kwargs: Option<&PyDict>, py: Python) -> PyResult<PyObject>
where A: ToPyObject<ObjectType=PyTuple>
{
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<A>(&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<A>(&self, name: &str, args: A, kwargs: Option<&PyDict>, py: Python) -> PyResult<PyObject>
where A: ToPyObject<ObjectType=PyTuple>
{
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<bool> {
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<usize> {
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<K>(&self, key: K) -> PyResult<'p, PyObject<'p>> where K: ToPyObject<'p> {
let py = self.python();
fn get_item<K>(&self, key: K, py: Python) -> PyResult<PyObject> 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<K, V>(&self, key: K, value: V) -> PyResult<'p, ()> where K: ToPyObject<'p>, V: ToPyObject<'p> {
let py = self.python();
fn set_item<K, V>(&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<K>(&self, key: K) -> PyResult<'p, ()> where K: ToPyObject<'p> {
let py = self.python();
fn del_item<K>(&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() {

View File

@ -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<F, R>(&self, _py: Python<'p>, f: F) -> R
fn with_borrowed_ptr<F, R>(&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::<PyBool>()).is_true())
extract!(obj to bool; py => {
Ok(try!(obj.cast_as::<PyBool>(py)).is_true())
});

View File

@ -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<PyDict> {
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<K>(&self, key: K) -> PyResult<'p, bool> where K: ToPyObject<'p> {
let py = self.python();
pub fn contains<K>(&self, key: K, py: Python) -> PyResult<bool> 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<K>(&self, key: K) -> Option<PyObject<'p>> where K: ToPyObject<'p> {
let py = self.python();
pub fn get_item<K>(&self, key: K, py: Python) -> Option<PyObject> 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<K, V>(&self, key: K, value: V) -> PyResult<'p, ()> where K: ToPyObject<'p>, V: ToPyObject<'p> {
let py = self.python();
pub fn set_item<K, V>(&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<K>(&self, key: K) -> PyResult<'p, ()> where K: ToPyObject<'p> {
let py = self.python();
pub fn del_item<K>(&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<K, V>
where K: hash::Hash+cmp::Eq+ToPyObject<'p>,
V: ToPyObject<'p>
impl <K, V> ToPyObject for collections::HashMap<K, V>
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<K, V>
where K: cmp::Eq+ToPyObject<'p>,
V: ToPyObject<'p>
impl <K, V> ToPyObject for collections::BTreeMap<K, V>
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::<i32>().unwrap());
assert_eq!(None, dict.get_item(8i32));
assert_eq!(32, dict.get_item(7i32, py).unwrap().extract::<i32>(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::<i32>().unwrap());
assert_eq!(123i32, dict.get_item(8i32).unwrap().extract::<i32>().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::<i32>(py).unwrap());
assert_eq!(123i32, dict.get_item(8i32, py).unwrap().extract::<i32>(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::<PyTuple>().unwrap();
key_sum += tuple.get_item(0).extract::<i32>().unwrap();
value_sum += tuple.get_item(1).extract::<i32>().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::<i32>().unwrap();
value_sum += value.extract::<i32>().unwrap();
for (key, value) in dict.items(py) {
key_sum += key.extract::<i32>(py).unwrap();
value_sum += value.extract::<i32>(py).unwrap();
}
assert_eq!(7 + 8 + 9, key_sum);
assert_eq!(32 + 42 + 123, value_sum);

View File

@ -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<usize>, reason: &CStr) -> PyResult<'p, UnicodeDecodeError<'p>> {
impl UnicodeDecodeError {
pub fn new(py: Python, encoding: &CStr, input: &[u8], range: Range<usize>, reason: &CStr) -> PyResult<UnicodeDecodeError> {
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<UnicodeDecodeError> {
let pos = err.valid_up_to();
UnicodeDecodeError::new(py, cstr!("utf-8"), input, pos .. input.len(), cstr!("invalid utf-8"))
}

View File

@ -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<PyObject<'p>>> {
let py = self.python();
pub fn iter_next(&self, py: Python) -> PyResult<Option<PyObject>> {
match unsafe { PyObject::from_owned_ptr_opt(py, ffi::PyIter_Next(self.as_ptr())) } {
Some(obj) => Ok(Some(obj)),
None => {

View File

@ -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::<PyList>();
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<PyObject<'p>> {
fn next(&mut self) -> Option<PyObject> {
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 <T> 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<T>
where T: for<'s, 'p> ExtractPyObject<'python, 's, 'p>,
'python : 'source
impl <'prepared, T> ExtractPyObject<'prepared> for Vec<T>
where T: ExtractPyObject<'prepared>
{
type Prepared = Vec<T::Prepared>;
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<T>> {
let list = try!(obj.cast_as::<PyList>());
let mut v = Vec::with_capacity(list.len());
for i in 0 .. list.len() {
v.push(try!(list.get_item(i).extract::<T>()));
fn prepare_extract(obj: &PyObject, py: Python) -> PyResult<Self::Prepared> {
let list = try!(obj.cast_as::<PyList>(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<Vec<T>> {
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::<i32>().unwrap());
assert_eq!(3, list.get_item(1).extract::<i32>().unwrap());
assert_eq!(5, list.get_item(2).extract::<i32>().unwrap());
assert_eq!(7, list.get_item(3).extract::<i32>().unwrap());
assert_eq!(2, list.get_item(0, py).extract::<i32>(py).unwrap());
assert_eq!(3, list.get_item(1, py).extract::<i32>(py).unwrap());
assert_eq!(5, list.get_item(2, py).extract::<i32>(py).unwrap());
assert_eq!(7, list.get_item(3, py).extract::<i32>(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::<i32>().unwrap());
list.set_item(0, val);
assert_eq!(42, list.get_item(0).extract::<i32>().unwrap());
assert_eq!(2, list.get_item(0, py).extract::<i32>(py).unwrap());
list.set_item(0, val, py);
assert_eq!(42, list.get_item(0, py).extract::<i32>(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::<i32>().unwrap());
list.insert_item(0, val);
assert_eq!(5, list.len());
assert_eq!(42, list.get_item(0).extract::<i32>().unwrap());
assert_eq!(2, list.get_item(1).extract::<i32>().unwrap());
assert_eq!(4, list.len(py));
assert_eq!(2, list.get_item(0, py).extract::<i32>(py).unwrap());
list.insert_item(0, val, py);
assert_eq!(5, list.len(py));
assert_eq!(42, list.get_item(0, py).extract::<i32>(py).unwrap());
assert_eq!(2, list.get_item(1, py).extract::<i32>(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::<i32>().unwrap());
assert_eq!(v[idx], el.extract::<i32>(py).unwrap());
idx += 1;
}
assert_eq!(idx, v.len());
@ -242,6 +245,7 @@ mod test {
}
assert_eq!(idx, v.len());
}
*/
/*#[test]
fn test_extract() {

View File

@ -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<F, R>(&self, _py: ::python::Python<'p>, f: F) -> R
where F: FnOnce(*mut ffi::PyObject) -> R {
f(self.as_ptr())
fn with_borrowed_ptr<F, R>(&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<Self::Prepared> {
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<Self> {
$body
}
}
@ -192,3 +173,4 @@ pub mod exc;
pub mod oldstyle;
mod tests;

View File

@ -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<PyModule> {
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<PyModule> {
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::<PyDict>()
}
}
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<PyObject> {
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<A>(&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<A>(&self, name: &str, args: A, kwargs: Option<&PyDict>, py: Python) -> PyResult<PyObject>
where A: ToPyObject<ObjectType=PyTuple>
{
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<V>(&self, name: &str, value: V) -> PyResult<'p, ()> where V: ToPyObject<'p> {
self.dict().set_item(name, value)
pub fn add<V>(&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<T>(&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)
}
}

View File

@ -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<T>
{
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<Self::Prepared> {
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::<c_long, $rust_type>(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::<exc::OverflowError>(), 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::<f64>()) as f32)
extract!(obj to f32; py => {
Ok(try!(obj.extract::<f64>(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::<u32>().unwrap());
assert_eq!(v as u64, obj.extract::<u64>().unwrap());
assert!(obj.extract::<i32>().is_err());
assert_eq!(v, obj.extract::<u32>(py).unwrap());
assert_eq!(v as u64, obj.extract::<u64>(py).unwrap());
assert!(obj.extract::<i32>(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::<i64>().unwrap());
assert_eq!(v as u64, obj.extract::<u64>().unwrap());
assert!(obj.extract::<u32>().is_err());
assert_eq!(v, obj.extract::<i64>(py).unwrap());
assert_eq!(v as u64, obj.extract::<u64>(py).unwrap());
assert!(obj.extract::<u32>(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::<i64>().unwrap());
assert!(obj.extract::<i32>().is_err());
assert!(obj.extract::<u64>().is_err());
assert_eq!(v, obj.extract::<i64>(py).unwrap());
assert!(obj.extract::<i32>(py).is_err());
assert!(obj.extract::<u64>(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::<u64>().unwrap());
assert!(obj.extract::<i64>().is_err());
assert_eq!(v, obj.extract::<u64>(py).unwrap());
assert!(obj.extract::<i64>(py).is_err());
}
}

View File

@ -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,107 +41,92 @@ 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<PyObject<'p>, PythonObjectDowncastError<'p>> {
fn downcast_from<'p>(obj: PyObject, _py: Python<'p>) -> Result<PyObject, PythonObjectDowncastError<'p>> {
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<PyObject<'p>> {
pub unsafe fn from_owned_ptr_opt(py: Python, ptr: *mut ffi::PyObject) -> Option<PyObject> {
if ptr.is_null() {
None
} else {
@ -151,7 +136,7 @@ impl <'p> PyObject<'p> {
/// 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<PyObject<'p>> {
pub unsafe fn from_borrowed_ptr_opt(py: Python, ptr: *mut ffi::PyObject) -> Option<PyObject> {
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,22 +172,23 @@ 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()
}
}
@ -210,7 +196,9 @@ impl <'p> PyObject<'p> {
/// 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<T>(self) -> T where T: PythonObject<'p> {
pub unsafe fn unchecked_cast_into<T>(self) -> T
where T: PythonObject
{
PythonObject::unchecked_downcast_from(self)
}
@ -218,15 +206,19 @@ impl <'p> PyObject<'p> {
/// 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<T>(self) -> Result<T, PythonObjectDowncastError<'p>> where T: PythonObjectWithCheckedDowncast<'p> {
PythonObjectWithCheckedDowncast::downcast_from(self)
pub fn cast_into<'p, T>(self, py: Python<'p>) -> Result<T, PythonObjectDowncastError<'p>>
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<T, PyErr<'p>>
where T: for<'prep> ::conversion::ExtractPyObject<'p, 's, 'prep> {
let prepared = try!(<T as ::conversion::ExtractPyObject>::prepare_extract(self));
<T as ::conversion::ExtractPyObject>::extract(&prepared)
pub fn extract<T>(&self, py: Python) -> PyResult<T>
where T: for<'prep> ::conversion::ExtractPyObject<'prep>
{
let prepared = try!(<T as ::conversion::ExtractPyObject>::prepare_extract(self, py));
<T as ::conversion::ExtractPyObject>::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() {

View File

@ -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 objects constructor.
pub fn create_instance<T>(&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<T>(&self, args: T, kw: Option<&PyDict>, py: Python) -> PyResult<PyInstance>
where T: ToPyObject<ObjectType=PyTuple>
{
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 objects __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<PyInstance> {
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()))
}
}

View File

@ -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<isize> {
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<PyObject> {
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<PyObject> {
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<PyObject> {
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<PyObject> {
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<PyObject> {
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<PyObject> {
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<V>(&self, value: V, py: Python) -> PyResult<usize>
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<V>(&self, value: V, py: Python) -> PyResult<bool>
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<V>(&self, value: V, py: Python) -> PyResult<usize>
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::<PyList>() } )
pub fn list(&self, py: Python) -> PyResult<PyList> {
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::<PyTuple>() } )
pub fn tuple(&self, py: Python) -> PyResult<PyTuple> {
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<PyObject>?
type Item = PyObject<'p>;
type Item = PyObject;
#[inline]
fn next(&mut self) -> Option<PyObject<'p>> {
fn next(&mut self) -> Option<PyObject> {
// 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::<PySequence>().is_err());
assert!(v.to_py_object(py).into_object().cast_into::<PySequence>(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::<PySequence>().is_ok());
assert!(v.to_py_object(py).into_object().cast_into::<PySequence>(py).is_ok());
}
#[test]
fn test_seq_empty() {
let gil = Python::acquire_gil();
let py = gil.python();
let v : Vec<i32> = vec![];
let seq = v.to_py_object(py).into_object().cast_into::<PySequence>().unwrap();
assert_eq!(0, seq.len().unwrap());
let seq = v.to_py_object(py).into_object().cast_into::<PySequence>(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<i32> = vec![1, 1, 2, 3, 5, 8];
let seq = v.to_py_object(py).into_object().cast_into::<PySequence>().unwrap();
assert_eq!(6, seq.len().unwrap());
let seq = v.to_py_object(py).into_object().cast_into::<PySequence>(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<i32> = vec![1, 1, 2, 3, 5, 8];
let seq = v.to_py_object(py).into_object().cast_into::<PySequence>().unwrap();
assert_eq!(1, seq.get_item(0).unwrap().extract::<i32>().unwrap());
assert_eq!(1, seq.get_item(1).unwrap().extract::<i32>().unwrap());
assert_eq!(2, seq.get_item(2).unwrap().extract::<i32>().unwrap());
assert_eq!(3, seq.get_item(3).unwrap().extract::<i32>().unwrap());
assert_eq!(5, seq.get_item(4).unwrap().extract::<i32>().unwrap());
assert_eq!(8, seq.get_item(5).unwrap().extract::<i32>().unwrap());
assert_eq!(8, seq.get_item(-1).unwrap().extract::<i32>().unwrap());
assert_eq!(5, seq.get_item(-2).unwrap().extract::<i32>().unwrap());
assert_eq!(3, seq.get_item(-3).unwrap().extract::<i32>().unwrap());
assert_eq!(2, seq.get_item(-4).unwrap().extract::<i32>().unwrap());
assert_eq!(1, seq.get_item(-5).unwrap().extract::<i32>().unwrap());
//assert!(seq.get_item(5).unwrap().extract::<i32>().is_err()); // panics.
let seq = v.to_py_object(py).into_object().cast_into::<PySequence>(py).unwrap();
assert_eq!(1, seq.get_item(0, py).unwrap().extract::<i32>(py).unwrap());
assert_eq!(1, seq.get_item(1, py).unwrap().extract::<i32>(py).unwrap());
assert_eq!(2, seq.get_item(2, py).unwrap().extract::<i32>(py).unwrap());
assert_eq!(3, seq.get_item(3, py).unwrap().extract::<i32>(py).unwrap());
assert_eq!(5, seq.get_item(4, py).unwrap().extract::<i32>(py).unwrap());
assert_eq!(8, seq.get_item(5, py).unwrap().extract::<i32>(py).unwrap());
assert_eq!(8, seq.get_item(-1, py).unwrap().extract::<i32>(py).unwrap());
assert_eq!(5, seq.get_item(-2, py).unwrap().extract::<i32>(py).unwrap());
assert_eq!(3, seq.get_item(-3, py).unwrap().extract::<i32>(py).unwrap());
assert_eq!(2, seq.get_item(-4, py).unwrap().extract::<i32>(py).unwrap());
assert_eq!(1, seq.get_item(-5, py).unwrap().extract::<i32>(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<i32> = vec![1, 1, 2, 3, 5, 8];
let seq = v.to_py_object(py).into_object().cast_into::<PySequence>().unwrap();
assert!(seq.del_item(10).is_err());
assert_eq!(1, seq.get_item(0).unwrap().extract::<i32>().unwrap());
assert!(seq.del_item(0).is_ok());
assert_eq!(1, seq.get_item(0).unwrap().extract::<i32>().unwrap());
assert!(seq.del_item(0).is_ok());
assert_eq!(2, seq.get_item(0).unwrap().extract::<i32>().unwrap());
assert!(seq.del_item(0).is_ok());
assert_eq!(3, seq.get_item(0).unwrap().extract::<i32>().unwrap());
assert!(seq.del_item(0).is_ok());
assert_eq!(5, seq.get_item(0).unwrap().extract::<i32>().unwrap());
assert!(seq.del_item(0).is_ok());
assert_eq!(8, seq.get_item(0).unwrap().extract::<i32>().unwrap());
assert!(seq.del_item(0).is_ok());
assert_eq!(0, seq.len().unwrap());
assert!(seq.del_item(0).is_err());
let seq = v.to_py_object(py).into_object().cast_into::<PySequence>(py).unwrap();
assert!(seq.del_item(10, py).is_err());
assert_eq!(1, seq.get_item(0, py).unwrap().extract::<i32>(py).unwrap());
assert!(seq.del_item(0, py).is_ok());
assert_eq!(1, seq.get_item(0, py).unwrap().extract::<i32>(py).unwrap());
assert!(seq.del_item(0, py).is_ok());
assert_eq!(2, seq.get_item(0, py).unwrap().extract::<i32>(py).unwrap());
assert!(seq.del_item(0, py).is_ok());
assert_eq!(3, seq.get_item(0, py).unwrap().extract::<i32>(py).unwrap());
assert!(seq.del_item(0, py).is_ok());
assert_eq!(5, seq.get_item(0, py).unwrap().extract::<i32>(py).unwrap());
assert!(seq.del_item(0, py).is_ok());
assert_eq!(8, seq.get_item(0, py).unwrap().extract::<i32>(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<i32> = vec![1, 1, 2, 3, 5, 8];
let seq = v.to_py_object(py).into_object().cast_into::<PySequence>().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::<PySequence>(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<i32> = vec![1, 1, 2, 3, 5, 8];
let seq = v.to_py_object(py).into_object().cast_into::<PySequence>().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::<PySequence>(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<i32> = vec![1, 1, 2, 3, 5, 8];
let seq = v.to_py_object(py).into_object().cast_into::<PySequence>().unwrap();
let seq = v.to_py_object(py).into_object().cast_into::<PySequence>(py).unwrap();
let mut idx = 0;
for el in seq {
assert_eq!(v[idx], el.extract::<i32>().unwrap());
assert_eq!(v[idx], el.extract::<i32>(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::<PySequence>().unwrap();
let seq = v.to_py_object(py).into_object().cast_into::<PySequence>(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<i32> = vec![1, 2, 3];
let seq = v.to_py_object(py).into_object().cast_into::<PySequence>().unwrap();
let concat_seq = seq.concat(&seq).unwrap().cast_into::<PySequence>().unwrap();
assert_eq!(6, concat_seq.len().unwrap());
let seq = v.to_py_object(py).into_object().cast_into::<PySequence>(py).unwrap();
let concat_seq = seq.concat(&seq, py).unwrap().cast_into::<PySequence>(py).unwrap();
assert_eq!(6, concat_seq.len(py).unwrap());
let concat_v : Vec<i32> = vec![1, 2, 3, 1, 2, 3];
for (el, cc) in seq.into_iter().zip(concat_v) {
assert_eq!(cc, el.extract::<i32>().unwrap());
for (el, cc) in seq.into_iter(py).zip(concat_v) {
assert_eq!(cc, el.extract::<i32>(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::<PySequence>().unwrap();
let concat_seq = seq.concat(&seq).unwrap().cast_into::<PySequence>().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::<u8>().unwrap());
}
*/
let seq = v.to_py_object(py).into_object().cast_into::<PySequence>(py).unwrap();
let concat_seq = seq.concat(&seq, py).unwrap().cast_into::<PySequence>(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::<char>(py).unwrap()); TODO: extract::<char>() 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::<PySequence>().unwrap();
let repeat_seq = seq.repeat(3).unwrap().cast_into::<PySequence>().unwrap();
assert_eq!(6, repeat_seq.len().unwrap());
let seq = v.to_py_object(py).into_object().cast_into::<PySequence>(py).unwrap();
let repeat_seq = seq.repeat(3, py).unwrap().cast_into::<PySequence>(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::<String>().unwrap());
for (el, rpt) in seq.into_iter(py).zip(repeated.iter()) {
assert_eq!(*rpt, el.extract::<String>(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::<PySequence>().unwrap();
assert!(seq.list().is_ok());
let seq = v.to_py_object(py).into_object().cast_into::<PySequence>(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::<PySequence>().unwrap();
assert!(seq.list().is_ok());
let seq = v.to_py_object(py).into_object().cast_into::<PySequence>(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::<PySequence>().unwrap();
assert!(seq.tuple().is_ok());
let seq = v.to_py_object(py).into_object().cast_into::<PySequence>(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::<PySequence>().unwrap();
assert!(seq.tuple().is_ok());
let seq = v.to_py_object(py).into_object().cast_into::<PySequence>(py).unwrap();
assert!(seq.tuple(py).is_ok());
}
}

View File

@ -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<str>> {
let py = self.python();
pub fn to_string(&self, py: Python) -> PyResult<Cow<str>> {
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<str> {
pub fn to_string_lossy(&self, py: Python) -> Cow<str> {
// 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<str>> {
let py = self.python();
let bytes = try!(self.to_utf8_bytes());
pub fn to_string(&self, py: Python) -> PyResult<Cow<str>> {
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<str> {
let bytes = self.to_utf8_bytes().expect("Error in PyUnicode_AsUTF8AndSize");
pub fn to_string_lossy(&self, py: Python) -> Cow<str> {
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<str>:
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::<PyBytes>() {
s.to_string()
} else if let Ok(u) = o.cast_as::<PyUnicode>() {
u.to_string()
pub fn extract<'a>(o: &'a PyObject, py: Python) -> PyResult<Cow<'a, str>> {
if let Ok(s) = o.cast_as::<PyBytes>(py) {
s.to_string(py)
} else if let Ok(u) = o.cast_as::<PyUnicode>(py) {
u.to_string(py)
} else {
Err(PyErr::new_lazy_init(py.get_type::<exc::TypeError>(), 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::<PyBytes>() {
Ok(s.to_string_lossy())
} else if let Ok(u) = o.cast_as::<PyUnicode>() {
Ok(u.to_string_lossy())
pub fn extract_lossy<'a>(o: &'a PyObject, py: Python) -> PyResult<Cow<'a, str>> {
if let Ok(s) = o.cast_as::<PyBytes>(py) {
Ok(s.to_string_lossy(py))
} else if let Ok(u) = o.cast_as::<PyUnicode>(py) {
Ok(u.to_string_lossy(py))
} else {
Err(PyErr::new_lazy_init(py.get_type::<exc::TypeError>(), 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::<PyUnicode>() {
u.to_string()
pub fn extract<'a>(o: &'a PyObject, py: Python) -> PyResult<Cow<'a, str>> {
if let Ok(u) = o.cast_as::<PyUnicode>(py) {
u.to_string(py)
} else {
Err(PyErr::new_lazy_init(py.get_type::<exc::TypeError>(), 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::<PyUnicode>() {
Ok(u.to_string_lossy())
pub fn extract_lossy<'a>(o: &'a PyObject, py: Python) -> PyResult<Cow<'a, str>> {
if let Ok(u) = o.cast_as::<PyUnicode>(py) {
Ok(u.to_string_lossy(py))
} else {
Err(PyErr::new_lazy_init(py.get_type::<exc::TypeError>(), 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<str>> {
let py = self.python();
match str::from_utf8(self.as_slice()) {
pub fn to_string(&self, py: Python) -> PyResult<Cow<str>> {
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<str> {
String::from_utf8_lossy(self.as_slice())
pub fn to_string_lossy(&self, py: Python) -> Cow<str> {
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 = <str as ToPyObject<'p>>::ObjectType;
impl ToPyObject for String {
type ObjectType = <str as ToPyObject>::ObjectType;
#[inline]
fn to_py_object(&self, py: Python<'p>) -> Self::ObjectType {
fn to_py_object(&self, py: Python) -> Self::ObjectType {
<str as ToPyObject>::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<Self::Prepared> {
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<Self> {
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::<String>().unwrap());
assert_eq!(s, py_string.extract::<String>(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());
}
}

View File

@ -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::<i32>().unwrap() == 1);
assert!(py_map.len(py) == 1);
assert!( py_map.get_item(1, py).unwrap().extract::<i32>(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::<i32>().unwrap() == 1);
assert!(py_map.len(py) == 1);
assert!( py_map.get_item(1, py).unwrap().extract::<i32>(py).unwrap() == 1);
}

View File

@ -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::<PyTuple>(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::<PyTuple>(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::<exc::ValueError>(), 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::<PyTuple>());
@ -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::<PyTuple>());
extract!(obj to NoArgs; py => {
let t = try!(obj.cast_as::<PyTuple>(py));
if t.len() == 0 {
Ok(NoArgs)
} else {
Err(wrong_tuple_length(t, 0))
Err(wrong_tuple_length(t, 0, py))
}
});

View File

@ -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::<PyType>()
}
/// 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<A>(&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<A>(&self, args: A, kwargs: Option<&PyDict>, py: Python) -> PyResult<PyObject>
where A: ToPyObject<ObjectType=PyTuple>
{
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 { }

View File

@ -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<Self, PythonObjectDowncastError<'p>>;
fn downcast_from<'p>(PyObject, Python<'p>) -> Result<Self, PythonObjectDowncastError<'p>>;
/// 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 <T> 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 <T> PyClone for Option<T> where T: PyClone {
#[inline]
fn clone_ref(&self, py: Python) -> Option<T> {
match *self {
Some(ref v) => Some(v.clone_ref(py)),
None => None
}
}
}
pub trait PyDrop : Sized {
fn release_ref(self, Python);
}
impl <T> 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 <T> PyDrop for Option<T> 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()
}
}
@ -112,9 +167,9 @@ impl <T> ToPythonPointer for Option<T> where T: ToPythonPointer {
}
#[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<T, F>(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<T, F>(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<PyObject> {
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<PyObject> {
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::<PyBool>() }
}
/// 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::<PyBool>() }
}
/// Gets the Python type object for type T.
pub fn get_type<T>(self) -> PyType<'p> where T: PythonObjectWithTypeObject<'p> {
pub fn get_type<T>(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> {
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);
}

View File

@ -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<T>, &PyTuple, Python) -> PyResult<R>`
/// for some `R` that implements `ToPyObject`.
///
/// Returns a type that implements `typebuilder::TypeMember<PyRustObject<T>>`
@ -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<i32>, arg: i32) -> PyResult<i32> {
/// match slf.get(py).checked_mul(arg) {
/// Some(val) => Ok(val),
/// None => Err(PyErr::new_lazy_init(py.get_type::<exc::OverflowError>(), None))
/// }
@ -51,11 +50,12 @@ use err;
///
/// fn main() {
/// let gil = Python::acquire_gil();
/// let multiplier_type = PyRustTypeBuilder::<i32>::new(gil.python(), "Multiplier")
/// let py = gil.python();
/// let multiplier_type = PyRustTypeBuilder::<i32>::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::<i32>().unwrap();
/// let obj = multiplier_type.create_instance(3, (), py).into_object();
/// let result = obj.call_method("mul", &(4,), None, py).unwrap().extract::<i32>(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<T>(*mut ffi::PyMethodDef, marker::PhantomData<fn(&T)
pub mod py_method_impl {
use ffi;
use err;
use python::Python;
use objects::{PyTuple, PyDict};
use super::MethodDescriptor;
use std::marker;
// py_method_impl takes fn(&T) to ensure that the T in MethodDescriptor<T>
// corresponds to the T in the function signature.
pub unsafe fn py_method_impl<'p, T, R>(
pub unsafe fn py_method_impl<T, R>(
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<R>
) -> MethodDescriptor<T> {
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<T, R>(
def: *mut ffi::PyMethodDef,
_f: fn(&T) -> err::PyResult<'p, R>
_f: fn(Python, &T) -> err::PyResult<R>
) -> MethodDescriptor<T> {
MethodDescriptor(def, marker::PhantomData)
}
pub unsafe fn py_method_impl_1<'p, T, P1, R>(
pub unsafe fn py_method_impl_1<T, P1, R>(
def: *mut ffi::PyMethodDef,
_f: fn(&T, P1) -> err::PyResult<'p, R>
_f: fn(Python, &T, P1) -> err::PyResult<R>
) -> MethodDescriptor<T> {
MethodDescriptor(def, marker::PhantomData)
}
pub unsafe fn py_method_impl_2<'p, T, P1, P2, R>(
pub unsafe fn py_method_impl_2<T, P1, P2, R>(
def: *mut ffi::PyMethodDef,
_f: fn(&T, P1, P2) -> err::PyResult<'p, R>
_f: fn(Python, &T, P1, P2) -> err::PyResult<R>
) -> MethodDescriptor<T> {
MethodDescriptor(def, marker::PhantomData)
}
pub unsafe fn py_method_impl_3<'p, T, P1, P2, P3, R>(
pub unsafe fn py_method_impl_3<T, P1, P2, P3, R>(
def: *mut ffi::PyMethodDef,
_f: fn(&T, P1, P2, P3) -> err::PyResult<'p, R>
_f: fn(Python, &T, P1, P2, P3) -> err::PyResult<R>
) -> MethodDescriptor<T> {
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<T, P1, P2, P3, P4, R>(
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<R>
) -> MethodDescriptor<T> {
MethodDescriptor(def, marker::PhantomData)
}
}
impl <'p, T> TypeMember<'p, T> for MethodDescriptor<T> where T: PythonObject<'p> {
impl <T> TypeMember<T> for MethodDescriptor<T> 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<TypeMember<'p, T> + 'p> {
fn into_box(self, _py: Python) -> Box<TypeMember<T>> {
Box::new(self)
}
}
@ -241,7 +250,7 @@ impl <'p, T> TypeMember<'p, T> for MethodDescriptor<T> 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<T>`
/// for some `T` that implements `ToPyObject`.
///
/// Returns a type that implements `typebuilder::TypeMember<PyRustObject<_>>`
@ -256,17 +265,18 @@ impl <'p, T> TypeMember<'p, T> for MethodDescriptor<T> 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<i32> {
/// Ok(42)
/// }
///
/// fn main() {
/// let gil = Python::acquire_gil();
/// let my_type = PyRustTypeBuilder::<i32>::new(gil.python(), "MyType")
/// let py = gil.python();
/// let my_type = PyRustTypeBuilder::<i32>::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::<i32>().unwrap());
/// let result = my_type.as_object().call_method("method", NoArgs, None, py).unwrap();
/// assert_eq!(42, result.extract::<i32>(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 <T> TypeMember<T> 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<TypeMember<'p, T> + 'p> {
fn into_box(self, _py: Python) -> Box<TypeMember<T>> {
Box::new(self)
}
}

View File

@ -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<Self>;
/// 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::<ffi::PyObject>()
@ -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<PyObject> {
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<T>`,
/// 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<T, B = PyObject> 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 <T, B> PyRustObject<T, B> 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::<T>();
@ -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::<T, B>::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 <T, B> PythonBaseObject for PyRustObject<T, B> where T: 'static + Send, B: PythonBaseObject {
#[inline]
fn size() -> usize {
PyRustObject::<T, B>::offset() + mem::size_of::<T>()
@ -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<Self> {
let obj = try!(B::alloc(ty, base_val, py));
let offset = PyRustObject::<T, B>::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::<T, B>::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 <T, B> ToPyObject for PyRustObject<T, B> 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<F, R>(&self, _py: Python<'p>, f: F) -> R
fn with_borrowed_ptr<F, R>(&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 <T, B> PythonObject for PyRustObject<T, B> 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<T>` 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<T, B = PyObject> 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 <T, B> PyRustType<T, B> 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<T, B> {
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 <T, B> ops::Deref for PyRustType<T, B> 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 <T, B> ToPyObject for PyRustType<T, B> 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<F, R>(&self, _py: Python<'p>, f: F) -> R
fn with_borrowed_ptr<F, R>(&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 <T, B> PythonObject for PyRustType<T, B> 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)
}
}

View File

@ -37,7 +37,7 @@ fn rustobject_calls_drop() {
let t = PyRustTypeBuilder::<MyObj>::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::<i32>::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::<i32>::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));
}

View File

@ -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<ffi::PyType_Slot>,
/// Maintains owned reference for base type object
#[cfg(feature="python3-sys")]
tp_base: Option<PyType<'p>>,
tp_base: Option<PyType>,
/// List of future type members
#[cfg(feature="python3-sys")]
members: Vec<(String, Box<TypeMember<'p, PyRustObject<'p, T, B>> + 'p>)>,
members: Vec<(String, Box<TypeMember<PyRustObject<T, B>>>)>,
/// The documentation string.
doc_str: Option<CString>,
/// The module to which the new type should be added.
target_module: Option<PyModule<'p>>,
target_module: Option<PyModule>,
/// 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<T, B>(obj: *mut ffi::PyObject)
where T: 'static + Send, B: PythonBaseObject {
abort_on_panic!({
PyRustObject::<T, B>::dealloc(obj)
let py = Python::assume_gil_acquired();
PyRustObject::<T, B>::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<T2, B2>(self, base_type: &PyRustType<'p, T2, B2>)
-> PyRustTypeBuilder<'p, T, PyRustObject<'p, T2, B2>>
where T2: 'static + Send, B2: PythonBaseObject<'p>
pub fn base<T2, B2>(self, base_type: &PyRustType<T2, B2>)
-> PyRustTypeBuilder<'p, T, PyRustObject<T2, B2>>
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<T2, B2>(self, base_type: &PyRustType<'p, T2, B2>)
-> PyRustTypeBuilder<'p, T, PyRustObject<'p, T2, B2>>
where T2: 'static + Send, B2: PythonBaseObject<'p>
pub fn base<T2, B2>(self, base_type: &PyRustType<T2, B2>)
-> PyRustTypeBuilder<'p, T, PyRustObject<T2, B2>>
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<M>(mut self, name: &str, val: M) -> Self
where M: TypeMember<'p, PyRustObject<'p, T, B>> {
where M: TypeMember<PyRustObject<T, B>> {
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<M>(mut self, name: &str, val: M) -> Self
where M: TypeMember<'p, PyRustObject<'p, T, B>> {
where M: TypeMember<PyRustObject<T, B>> {
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<PyRustType<T, B>> {
let py = self.py;
unsafe {
(*self.ht).ht_type.tp_basicsize = PyRustObject::<T, B>::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<PyRustType<T, B>> {
// 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::<T, B>::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<ffi::PyType_Slot>
) -> PyResult<'p, PyType<'p>>
) -> PyResult<PyType>
{
// 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<T> 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<TypeMember<'p, T> + 'p>;
fn into_box(self, py: Python) -> Box<TypeMember<T>>;
}
// TODO: does this cause trouble for coherence?
impl <'p, T, S> TypeMember<'p, T> for S where T: PythonObject<'p>, S: ToPyObject<'p> {
impl <T, S> TypeMember<T> 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<TypeMember<'p, T> + 'p> {
fn into_box(self, py: Python) -> Box<TypeMember<T>> {
Box::new(self.into_py_object(py).into_object())
}
}