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:
parent
d33a4b68fc
commit
44611991c3
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
110
src/err.rs
110
src/err.rs
|
@ -17,7 +17,7 @@
|
|||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
use std;
|
||||
use python::{PythonObject, Python, ToPythonPointer, PythonObjectDowncastError, PythonObjectWithTypeObject};
|
||||
use python::{PythonObject, ToPythonPointer, Python, PythonObjectDowncastError, PythonObjectWithTypeObject, PyClone};
|
||||
use objects::{PyObject, PyType, exc};
|
||||
#[cfg(feature="python27-sys")]
|
||||
use objects::oldstyle::PyClass;
|
||||
|
@ -27,36 +27,36 @@ use conversion::ToPyObject;
|
|||
use std::ffi::CString;
|
||||
|
||||
/// Represents a Python exception that was raised.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct PyErr<'p> {
|
||||
#[derive(Debug)]
|
||||
pub struct PyErr {
|
||||
/// The type of the exception. This should be either a `PyClass` or a `PyType`.
|
||||
pub ptype : PyObject<'p>,
|
||||
pub ptype : PyObject,
|
||||
/// The value of the exception.
|
||||
///
|
||||
/// This can be either an instance of `ptype`,
|
||||
/// a tuple of arguments to be passed to `ptype`'s constructor,
|
||||
/// or a single argument to be passed to `ptype`'s constructor.
|
||||
/// Call `PyErr::instance()` to get the exception instance in all cases.
|
||||
pub pvalue : Option<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));
|
||||
}
|
||||
|
|
|
@ -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()))
|
||||
}
|
||||
|
|
34
src/lib.rs
34
src/lib.rs
|
@ -69,11 +69,11 @@
|
|||
//! let py = gil.python();
|
||||
//!
|
||||
//! let sys = py.import("sys").unwrap();
|
||||
//! let version: String = sys.get("version").unwrap().extract().unwrap();
|
||||
//! let version: String = sys.get("version", py).unwrap().extract(py).unwrap();
|
||||
//!
|
||||
//! let os = py.import("os").unwrap();
|
||||
//! let getenv = os.get("getenv").unwrap();
|
||||
//! let user: String = getenv.call(("USER",), None).unwrap().extract().unwrap();
|
||||
//! let getenv = os.get("getenv", py).unwrap();
|
||||
//! let user: String = getenv.call(("USER",), None, py).unwrap().extract(py).unwrap();
|
||||
//!
|
||||
//! println!("Hello {}, I'm Python {}", user, version);
|
||||
//! }
|
||||
|
@ -93,7 +93,7 @@ extern crate python3_sys as ffi;
|
|||
pub use ffi::Py_ssize_t;
|
||||
pub use err::{PyErr, PyResult};
|
||||
pub use objects::*;
|
||||
pub use python::{Python, PythonObject, PythonObjectWithCheckedDowncast, PythonObjectWithTypeObject};
|
||||
pub use python::{Python, PythonObject, PythonObjectWithCheckedDowncast, PythonObjectWithTypeObject, PyClone, PyDrop};
|
||||
pub use pythonrun::{GILGuard, GILProtected, prepare_freethreaded_python};
|
||||
pub use conversion::{ExtractPyObject, ToPyObject};
|
||||
pub use objectprotocol::{ObjectProtocol};
|
||||
|
@ -172,12 +172,12 @@ pub mod _detail {
|
|||
/// use cpython::{Python, PyResult, PyObject};
|
||||
///
|
||||
/// py_module_initializer!(example, |py, m| {
|
||||
/// try!(m.add("__doc__", "Module documentation string"));
|
||||
/// try!(m.add("run", py_fn!(run())));
|
||||
/// try!(m.add("__doc__", "Module documentation string", py));
|
||||
/// try!(m.add("run", py_fn!(run()), py));
|
||||
/// Ok(())
|
||||
/// });
|
||||
///
|
||||
/// fn run<'p>(py: Python<'p>) -> PyResult<'p, PyObject<'p>> {
|
||||
/// fn run(py: Python) -> PyResult<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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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())
|
||||
});
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"))
|
||||
}
|
||||
|
|
|
@ -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 => {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,9 +18,9 @@
|
|||
|
||||
use std::mem;
|
||||
use ffi;
|
||||
use python::{Python, PythonObject, PythonObjectWithCheckedDowncast, PythonObjectWithTypeObject, PythonObjectDowncastError, ToPythonPointer};
|
||||
use python::{Python, PythonObject, PythonObjectWithCheckedDowncast, PythonObjectWithTypeObject, PythonObjectDowncastError};
|
||||
use objects::PyType;
|
||||
use err::PyErr;
|
||||
use err::PyResult;
|
||||
|
||||
/// Represents a reference to a Python object.
|
||||
///
|
||||
|
@ -41,117 +41,102 @@ use err::PyErr;
|
|||
/// Most of the interesting methods are provided by the [ObjectProtocol trait](trait.ObjectProtocol.html).
|
||||
#[unsafe_no_drop_flag]
|
||||
#[repr(C)]
|
||||
pub struct PyObject<'p> {
|
||||
// PyObject<'p> owns one reference to the *PyObject
|
||||
// ptr is not null (except possibly due to #[unsafe_no_drop_flag])
|
||||
ptr: *mut ffi::PyObject,
|
||||
py : Python<'p>
|
||||
pub struct PyObject {
|
||||
// PyObject owns one reference to the *PyObject
|
||||
// ptr is not null
|
||||
ptr: *mut ffi::PyObject
|
||||
}
|
||||
|
||||
/// Dropping a `PyObject` decrements the reference count on the object by 1.
|
||||
impl <'p> Drop for PyObject<'p> {
|
||||
impl Drop for PyObject {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
// TODO: remove if and change Py_XDECREF to Py_DECREF when #[unsafe_no_drop_flag] disappears
|
||||
// TODO: remove `if` when #[unsafe_no_drop_flag] disappears
|
||||
if self.ptr as usize != mem::POST_DROP_USIZE {
|
||||
unsafe { ffi::Py_XDECREF(self.ptr); }
|
||||
let _gil_guard = Python::acquire_gil();
|
||||
unsafe { ffi::Py_DECREF(self.ptr); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Clone returns another reference to the Python object,
|
||||
/// thus incrementing the reference count by 1.
|
||||
impl <'p> Clone for PyObject<'p> {
|
||||
#[inline]
|
||||
fn clone(&self) -> PyObject<'p> {
|
||||
unsafe { ffi::Py_INCREF(self.ptr) };
|
||||
PyObject { ptr: self.ptr, py: self.py }
|
||||
}
|
||||
}
|
||||
|
||||
pyobject_to_pyobject!(PyObject);
|
||||
|
||||
impl <'p> PythonObject<'p> for PyObject<'p> {
|
||||
impl PythonObject for PyObject {
|
||||
#[inline]
|
||||
fn as_object<'a>(&'a self) -> &'a PyObject<'p> {
|
||||
fn as_object(&self) -> &PyObject {
|
||||
self
|
||||
}
|
||||
|
||||
|
||||
#[inline]
|
||||
fn into_object(self) -> PyObject<'p> {
|
||||
fn into_object(self) -> PyObject {
|
||||
self
|
||||
}
|
||||
|
||||
|
||||
#[inline]
|
||||
unsafe fn unchecked_downcast_from(o: PyObject<'p>) -> PyObject<'p> {
|
||||
unsafe fn unchecked_downcast_from(o: PyObject) -> PyObject {
|
||||
o
|
||||
}
|
||||
|
||||
|
||||
#[inline]
|
||||
unsafe fn unchecked_downcast_borrow_from<'a>(o: &'a PyObject<'p>) -> &'a PyObject<'p> {
|
||||
unsafe fn unchecked_downcast_borrow_from(o: &PyObject) -> &PyObject {
|
||||
o
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn python(&self) -> Python<'p> {
|
||||
self.py
|
||||
}
|
||||
}
|
||||
|
||||
impl <'p> PythonObjectWithCheckedDowncast<'p> for PyObject<'p> {
|
||||
impl PythonObjectWithCheckedDowncast for PyObject {
|
||||
#[inline]
|
||||
fn downcast_from(obj: PyObject<'p>) -> Result<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 {
|
||||
Some(PyObject::from_owned_ptr(py, ptr))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Returns None for null pointers; undefined behavior if the pointer is invalid.
|
||||
#[inline]
|
||||
pub unsafe fn from_borrowed_ptr_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<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,46 +172,53 @@ impl <'p> PyObject<'p> {
|
|||
/// Transmutes a slice of owned FFI pointers to `&[PyObject]`.
|
||||
/// Undefined behavior if any pointer in the slice is NULL or invalid.
|
||||
#[inline]
|
||||
pub unsafe fn borrow_from_owned_ptr_slice<'a>(_py : Python<'p>, ptr : &'a [*mut ffi::PyObject]) -> &'a [PyObject<'p>] {
|
||||
pub unsafe fn borrow_from_owned_ptr_slice<'a>(ptr : &'a [*mut ffi::PyObject]) -> &'a [PyObject] {
|
||||
mem::transmute(ptr)
|
||||
}
|
||||
|
||||
/// Gets the reference count of this Python object.
|
||||
#[inline]
|
||||
pub fn get_refcnt(&self) -> usize {
|
||||
unsafe { ffi::Py_REFCNT(self.as_ptr()) as usize }
|
||||
pub fn get_refcnt(&self, _py: Python) -> usize {
|
||||
unsafe { ffi::Py_REFCNT(self.ptr) as usize }
|
||||
}
|
||||
|
||||
/// Gets the Python type object for this object's type.
|
||||
#[inline]
|
||||
pub fn get_type(&self) -> &PyType<'p> {
|
||||
pub fn get_type(&self) -> &PyType {
|
||||
unsafe {
|
||||
let t : &*mut ffi::PyTypeObject = &(*self.as_ptr()).ob_type;
|
||||
mem::transmute(t)
|
||||
let t : &*mut ffi::PyTypeObject = &(*self.ptr).ob_type;
|
||||
let t : &*mut ffi::PyObject = mem::transmute(t);
|
||||
PyObject::borrow_from_owned_ptr(t).unchecked_cast_as()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Casts the PyObject to a concrete Python object type.
|
||||
/// Causes undefined behavior if the object is not of the expected type.
|
||||
/// This is a wrapper function around `PythonObject::unchecked_downcast_from()`.
|
||||
#[inline]
|
||||
pub unsafe fn unchecked_cast_into<T>(self) -> T where T: PythonObject<'p> {
|
||||
pub unsafe fn unchecked_cast_into<T>(self) -> T
|
||||
where T: PythonObject
|
||||
{
|
||||
PythonObject::unchecked_downcast_from(self)
|
||||
}
|
||||
|
||||
|
||||
/// Casts the PyObject to a concrete Python object type.
|
||||
/// Fails with `PythonObjectDowncastError` if the object is not of the expected type.
|
||||
/// This is a wrapper function around `PythonObjectWithCheckedDowncast::downcast_from()`.
|
||||
#[inline]
|
||||
pub fn cast_into<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() {
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
//! This module contains support for old-style classes. Only available in Python 2.x.
|
||||
|
||||
use ffi;
|
||||
use python::{PythonObject, ToPythonPointer};
|
||||
use python::{Python, PythonObject, ToPythonPointer};
|
||||
use conversion::ToPyObject;
|
||||
use err::{self, PyResult};
|
||||
use super::object::PyObject;
|
||||
|
@ -29,36 +29,37 @@ use super::dict::PyDict;
|
|||
/// Represents an old-style Python class.
|
||||
///
|
||||
/// Only available with Python 2.x.
|
||||
pub struct PyClass<'p>(PyObject<'p>);
|
||||
pub struct PyClass(PyObject);
|
||||
pyobject_newtype!(PyClass, PyClass_Check, PyClass_Type);
|
||||
|
||||
/// Represents an old-style Python instance.
|
||||
///
|
||||
/// Only available with Python 2.x.
|
||||
pub struct PyInstance<'p>(PyObject<'p>);
|
||||
pub struct PyInstance(PyObject);
|
||||
pyobject_newtype!(PyInstance, PyInstance_Check, PyInstance_Type);
|
||||
|
||||
impl <'p> PyClass<'p> {
|
||||
impl PyClass {
|
||||
/// Return true if self is a subclass of base.
|
||||
pub fn is_subclass_of(&self, base: &PyClass<'p>) -> bool {
|
||||
pub fn is_subclass_of(&self, base: &PyClass, _py: Python) -> bool {
|
||||
unsafe { ffi::PyClass_IsSubclass(self.as_ptr(), base.as_ptr()) != 0 }
|
||||
}
|
||||
|
||||
/// Create a new instance of the class.
|
||||
/// The parameters args and kw are used as the positional and keyword parameters to the object’s constructor.
|
||||
pub fn create_instance<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 object’s __dict__.
|
||||
pub fn create_instance_raw(&self, dict: PyDict<'p>) -> PyResult<'p, PyInstance<'p>> {
|
||||
pub fn create_instance_raw(&self, dict: &PyDict, py: Python) -> PyResult<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()))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -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 { }
|
||||
|
||||
|
|
168
src/python.rs
168
src/python.rs
|
@ -38,66 +38,121 @@ use pythonrun::GILGuard;
|
|||
#[derive(Copy, Clone)]
|
||||
pub struct Python<'p>(PhantomData<&'p GILGuard>);
|
||||
|
||||
/// This trait allows retrieving the underlying FFI pointer from Python objects.
|
||||
pub trait ToPythonPointer {
|
||||
/// Retrieves the underlying FFI pointer (as a borrowed pointer).
|
||||
fn as_ptr(&self) -> *mut ffi::PyObject;
|
||||
|
||||
/// Retrieves the underlying FFI pointer as a "stolen pointer".
|
||||
fn steal_ptr(self) -> *mut ffi::PyObject;
|
||||
}
|
||||
|
||||
/// Trait implemented by all Python object types.
|
||||
pub trait PythonObject<'p> : 'p + Clone + ::conversion::ToPyObject<'p> {
|
||||
pub trait PythonObject : ::conversion::ToPyObject + Sized + 'static {
|
||||
/// Casts the Python object to PyObject.
|
||||
fn as_object(&self) -> &PyObject<'p>;
|
||||
fn as_object(&self) -> &PyObject;
|
||||
|
||||
/// Casts the Python object to PyObject.
|
||||
fn into_object(self) -> PyObject<'p>;
|
||||
fn into_object(self) -> PyObject;
|
||||
|
||||
/// Unchecked downcast from PyObject to Self.
|
||||
/// Undefined behavior if the input object does not have the expected type.
|
||||
unsafe fn unchecked_downcast_from(PyObject<'p>) -> Self;
|
||||
unsafe fn unchecked_downcast_from(PyObject) -> Self;
|
||||
|
||||
/// Unchecked downcast from PyObject to Self.
|
||||
/// Undefined behavior if the input object does not have the expected type.
|
||||
unsafe fn unchecked_downcast_borrow_from<'a>(&'a PyObject<'p>) -> &'a Self;
|
||||
|
||||
/// Retrieve Python instance from an existing Python object.
|
||||
#[inline]
|
||||
fn python(&self) -> Python<'p> {
|
||||
self.as_object().python()
|
||||
}
|
||||
unsafe fn unchecked_downcast_borrow_from(&PyObject) -> &Self;
|
||||
}
|
||||
|
||||
// Marker type that indicates an error while downcasting
|
||||
pub struct PythonObjectDowncastError<'p>(pub Python<'p>);
|
||||
|
||||
/// Trait implemented by Python object types that allow a checked downcast.
|
||||
pub trait PythonObjectWithCheckedDowncast<'p> : PythonObject<'p> {
|
||||
pub trait PythonObjectWithCheckedDowncast : PythonObject {
|
||||
/// Cast from PyObject to a concrete Python object type.
|
||||
fn downcast_from(PyObject<'p>) -> Result<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()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -110,11 +165,11 @@ impl <T> ToPythonPointer for Option<T> where T: ToPythonPointer {
|
|||
None => std::ptr::null_mut()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[inline]
|
||||
fn steal_ptr(self) -> *mut ffi::PyObject {
|
||||
fn steal_ptr(self, py: Python) -> *mut ffi::PyObject {
|
||||
match self {
|
||||
Some(t) => t.steal_ptr(),
|
||||
Some(t) => t.steal_ptr(py),
|
||||
None => std::ptr::null_mut()
|
||||
}
|
||||
}
|
||||
|
@ -141,23 +196,24 @@ impl<'p> Python<'p> {
|
|||
GILGuard::acquire()
|
||||
}
|
||||
|
||||
/// Releases the GIL and allows the use of Python on other threads.
|
||||
/// Unsafe because we do not ensure that existing references to Python objects
|
||||
/// are not accessed within the closure.
|
||||
pub unsafe fn allow_threads<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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue