pyo3/src/conversion.rs

124 lines
4.0 KiB
Rust
Raw Normal View History

2015-01-05 16:05:53 +00:00
use std;
use ffi;
use python::{Python, PythonObject, PythonObjectWithCheckedDowncast, ToPythonPointer};
2015-01-11 17:56:59 +00:00
use objects::{exc, PyObject, PyBool, PyTuple};
2015-01-05 15:34:12 +00:00
use err::{self, PyErr, PyResult};
2015-01-05 16:05:53 +00:00
/// ToPyObject is implemented for types that can be converted into a python object.
/// The goal is to allow methods that take a python object to take anything that
/// can be converted into a python object.
/// For example, compare calling the following method signatures:
/// fn m1(o: &PyObject) {}
/// fn m2<O>(o: &O) where O : ToPyObject {}
///
/// let o: &PyObject = ...;
/// m1(o);
/// m2(o);
///
/// let p: PyPtr<PyObject> = ...;
/// m1(*p)
/// m2(p)
///
/// let i: i32 = ...;
/// m1(*try!(i.to_py_object(py)))
/// m2(i)
2015-01-11 17:56:59 +00:00
pub trait ToPyObject<'p> {
2015-01-05 20:14:01 +00:00
type ObjectType : PythonObject<'p> = PyObject<'p>;
2015-01-11 17:56:59 +00:00
fn to_py_object(&self, py: Python<'p>) -> PyResult<'p, Self::ObjectType>;
2015-01-05 20:14:01 +00:00
#[inline]
2015-01-11 17:56:59 +00:00
fn into_py_object(self, py: Python<'p>) -> PyResult<'p, Self::ObjectType>
where Self: Sized {
self.to_py_object(py)
}
#[inline]
fn with_borrowed_ptr<F, R>(&self, py: Python<'p>, f: F) -> PyResult<'p, R>
where F: FnOnce(*mut ffi::PyObject) -> PyResult<'p, R> {
2015-01-05 20:14:01 +00:00
let obj = try!(self.to_py_object(py));
f(ToPythonPointer::as_ptr(&obj))
2015-01-05 20:14:01 +00:00
}
2015-01-11 17:56:59 +00:00
2015-01-05 20:14:01 +00:00
// FFI functions that accept a borrowed reference will use:
2015-01-11 17:56:59 +00:00
// input.with_borrowed_ptr(|obj| ffi::Call(obj)
2015-01-05 20:14:01 +00:00
// 1) input is &PyObject
2015-01-11 17:56:59 +00:00
// -> with_borrowed_ptr() just forwards to the closure
// 2) input is PyObject
// -> with_borrowed_ptr() just forwards to the closure
2015-01-05 20:14:01 +00:00
// 3) input is &str, int, ...
// -> to_py_object() allocates new python object; FFI call happens; PyPtr::drop() calls Py_DECREF()
2015-01-05 15:34:12 +00:00
2015-01-05 20:14:01 +00:00
// FFI functions that steal a reference will use:
2015-01-11 17:56:59 +00:00
// let input = try!(input.into_py_object()); ffi::Call(input.steal_ptr())
2015-01-05 20:14:01 +00:00
// 1) input is &PyObject
2015-01-11 17:56:59 +00:00
// -> into_py_object() calls Py_INCREF
// 2) input is PyObject
// -> into_py_object() is no-op
2015-01-05 20:14:01 +00:00
// 3) input is &str, int, ...
2015-01-11 17:56:59 +00:00
// -> into_py_object() allocates new python object
2015-01-05 16:05:53 +00:00
}
/// FromPyObject is implemented by various types that can be extracted from a python object.
pub trait FromPyObject<'p, 's> {
fn from_py_object(s: &'s PyObject<'p>) -> PyResult<'p, Self>;
2015-01-05 16:05:53 +00:00
}
// PyObject, PyModule etc.
// We support FromPyObject and ToPyObject for owned python references.
2015-01-05 16:05:53 +00:00
// This allows using existing python objects in code that generically expects a value
// convertible to a python object.
2015-04-18 20:20:19 +00:00
impl <'p> ToPyObject<'p> for PyObject<'p> {
type ObjectType = PyObject<'p>;
2015-01-11 17:56:59 +00:00
#[inline]
2015-04-18 20:20:19 +00:00
fn to_py_object(&self, py: Python<'p>) -> PyResult<'p, PyObject<'p>> {
2015-01-11 17:56:59 +00:00
Ok(self.clone())
}
#[inline]
2015-04-18 20:20:19 +00:00
fn into_py_object(self, py: Python<'p>) -> PyResult<'p, PyObject<'p>> {
Ok(self)
2015-01-05 16:05:53 +00:00
}
2015-01-11 17:56:59 +00:00
#[inline]
fn with_borrowed_ptr<F, R>(&self, py: Python<'p>, f: F) -> PyResult<'p, R>
where F: FnOnce(*mut ffi::PyObject) -> PyResult<'p, R> {
f(self.as_ptr())
}
2015-01-05 16:05:53 +00:00
}
impl <'p, 's, T> FromPyObject<'p, 's> for T where T: PythonObjectWithCheckedDowncast<'p> {
2015-01-05 16:05:53 +00:00
#[inline]
fn from_py_object(s : &'s PyObject<'p>) -> PyResult<'p, T> {
Ok(try!(s.clone().cast_into()))
2015-01-05 16:05:53 +00:00
}
}
// &PyObject, &PyModule etc.
// We support FromPyObject and ToPyObject for borrowed python references.
2015-01-05 16:05:53 +00:00
// This allows using existing python objects in code that generically expects a value
// convertible to a python object.
2015-01-11 17:56:59 +00:00
impl <'p, 's, T> ToPyObject<'p> for &'s T where T : ToPyObject<'p> {
type ObjectType = <T as ToPyObject<'p>>::ObjectType;
2015-01-04 19:11:18 +00:00
#[inline]
2015-01-11 17:56:59 +00:00
fn to_py_object(&self, py: Python<'p>) -> PyResult<'p, <T as ToPyObject<'p>>::ObjectType> {
(**self).to_py_object(py)
2015-01-04 19:11:18 +00:00
}
2015-01-05 16:05:53 +00:00
2015-01-11 17:56:59 +00:00
#[inline]
fn into_py_object(self, py: Python<'p>) -> PyResult<'p, <T as ToPyObject<'p>>::ObjectType> {
(*self).to_py_object(py)
2015-01-05 16:05:53 +00:00
}
2015-01-11 17:56:59 +00:00
#[inline]
fn with_borrowed_ptr<F, R>(&self, py: Python<'p>, f: F) -> PyResult<'p, R>
where F: FnOnce(*mut ffi::PyObject) -> PyResult<'p, R> {
(**self).with_borrowed_ptr(py, f)
2015-01-05 16:05:53 +00:00
}
}
2015-04-18 20:20:19 +00:00
2015-01-05 16:05:53 +00:00