2015-04-19 03:22:03 +00:00
|
|
|
// Copyright (c) 2015 Daniel Grunwald
|
|
|
|
//
|
|
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
|
|
|
// software and associated documentation files (the "Software"), to deal in the Software
|
|
|
|
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
|
|
|
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
|
|
|
// to whom the Software is furnished to do so, subject to the following conditions:
|
|
|
|
//
|
|
|
|
// The above copyright notice and this permission notice shall be included in all copies or
|
|
|
|
// substantial portions of the Software.
|
|
|
|
//
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
|
|
|
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
|
|
|
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
|
|
|
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
|
|
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
|
|
// DEALINGS IN THE SOFTWARE.
|
|
|
|
|
2015-01-05 16:05:53 +00:00
|
|
|
use std;
|
|
|
|
use ffi;
|
2015-01-07 00:40:48 +00:00
|
|
|
use python::{Python, PythonObject, PythonObjectWithCheckedDowncast, ToPythonPointer};
|
2015-06-27 21:49:53 +00:00
|
|
|
use objects::PyObject;
|
|
|
|
use err::PyResult;
|
2015-01-05 16:05:53 +00:00
|
|
|
|
2015-06-27 20:45:35 +00:00
|
|
|
/// Conversion trait that allows various objects to be converted into Python objects.
|
2015-01-11 17:56:59 +00:00
|
|
|
pub trait ToPyObject<'p> {
|
2015-07-08 20:47:56 +00:00
|
|
|
type ObjectType : PythonObject<'p>;
|
2015-01-11 17:56:59 +00:00
|
|
|
|
2015-06-27 20:45:35 +00:00
|
|
|
/// Converts self into a Python object.
|
2015-04-18 23:07:14 +00:00
|
|
|
fn to_py_object(&self, py: Python<'p>) -> Self::ObjectType;
|
2015-01-11 17:56:59 +00:00
|
|
|
|
2015-06-27 20:45:35 +00:00
|
|
|
/// Converts self into a Python object.
|
2015-04-18 22:39:04 +00:00
|
|
|
///
|
|
|
|
/// May be more efficient than `to_py_object` in some cases because
|
|
|
|
/// it can move out of the input object.
|
2015-01-05 20:14:01 +00:00
|
|
|
#[inline]
|
2015-04-18 23:07:14 +00:00
|
|
|
fn into_py_object(self, py: Python<'p>) -> Self::ObjectType
|
2015-01-11 17:56:59 +00:00
|
|
|
where Self: Sized {
|
|
|
|
self.to_py_object(py)
|
|
|
|
}
|
|
|
|
|
2015-06-27 20:45:35 +00:00
|
|
|
/// Converts self into a Python object and calls the specified closure
|
|
|
|
/// on the native FFI pointer underlying the Python object.
|
2015-04-18 22:39:04 +00:00
|
|
|
///
|
|
|
|
/// May be more efficient than `to_py_object` because it does not need
|
2015-06-27 20:45:35 +00:00
|
|
|
/// to touch any reference counts when the input object already is a Python object.
|
2015-01-11 17:56:59 +00:00
|
|
|
#[inline]
|
2015-04-18 23:07:14 +00:00
|
|
|
fn with_borrowed_ptr<F, R>(&self, py: Python<'p>, f: F) -> R
|
|
|
|
where F: FnOnce(*mut ffi::PyObject) -> R {
|
2015-06-27 17:08:28 +00:00
|
|
|
let obj = self.to_py_object(py).into_object();
|
|
|
|
f(obj.as_ptr())
|
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, ...
|
2015-06-27 20:45:35 +00:00
|
|
|
// -> to_py_object() allocates new Python object; FFI call happens; PyObject::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-06-27 20:45:35 +00:00
|
|
|
// -> into_py_object() allocates new Python object
|
2015-01-05 16:05:53 +00:00
|
|
|
}
|
|
|
|
|
2015-06-27 20:45:35 +00:00
|
|
|
/// FromPyObject is implemented by various types that can be extracted from a Python object.
|
2015-07-18 20:39:55 +00:00
|
|
|
///
|
|
|
|
/// Usage:
|
|
|
|
/// ```let obj: PyObject = ...;
|
|
|
|
/// let prepared = <TargetType as FromPyObject>::prepare_extract(&obj);
|
|
|
|
/// let extracted = try!(extract(&prepared));```
|
|
|
|
///
|
|
|
|
/// Note: depending on the implementation, the lifetime of the extracted result may
|
|
|
|
/// depend on the lifetime of the `obj` or the `prepared` variable.
|
|
|
|
///
|
|
|
|
/// For example, when extracting `&str` from a python byte string, the resulting string slice will
|
|
|
|
/// point to the existing string data (lifetime: `'source`).
|
|
|
|
/// On the other hand, when extracting `&str` from a python unicode string, the preparation step
|
|
|
|
/// will convert the string to UTF-8, and the resulting string slice will have lifetime `'prepared`.
|
|
|
|
/// Since only which of these cases applies depends on the runtime type of the python object,
|
|
|
|
/// both the `obj` and `prepared` variables must outlive the resulting string slice.
|
|
|
|
///
|
|
|
|
/// 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> {
|
|
|
|
type Prepared;
|
|
|
|
|
|
|
|
fn prepare_extract(obj: &'source PyObject<'python>) -> PyResult<'python, Self::Prepared>;
|
|
|
|
|
|
|
|
fn extract(prepared: &'prepared Self::Prepared) -> PyResult<'python, Self>;
|
2015-01-05 16:05:53 +00:00
|
|
|
}
|
|
|
|
|
2015-07-18 20:39:55 +00:00
|
|
|
impl <'python, 'source, 'prepared, T> ExtractPyObject<'python, 'source, 'prepared>
|
|
|
|
for T where T: PythonObjectWithCheckedDowncast<'python> {
|
|
|
|
|
|
|
|
type Prepared = &'source PyObject<'python>;
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn prepare_extract(obj: &'source PyObject<'python>) -> PyResult<'python, Self::Prepared> {
|
|
|
|
Ok(obj)
|
|
|
|
}
|
|
|
|
|
2015-01-05 16:05:53 +00:00
|
|
|
#[inline]
|
2015-07-18 20:39:55 +00:00
|
|
|
fn extract(&&ref obj: &'prepared Self::Prepared) -> PyResult<'python, T> {
|
|
|
|
Ok(try!(obj.clone().cast_into()))
|
2015-01-05 16:05:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-18 11:39:53 +00:00
|
|
|
// ToPyObject for references
|
2015-06-27 20:45:35 +00:00
|
|
|
impl <'p, 's, T: ?Sized> ToPyObject<'p> for &'s T where T: ToPyObject<'p> {
|
2015-04-18 23:07:14 +00:00
|
|
|
type ObjectType = T::ObjectType;
|
2015-01-04 01:54:54 +00:00
|
|
|
|
2015-01-04 19:11:18 +00:00
|
|
|
#[inline]
|
2015-04-18 23:07:14 +00:00
|
|
|
fn to_py_object(&self, py: Python<'p>) -> T::ObjectType {
|
2015-06-27 20:45:35 +00:00
|
|
|
<T as ToPyObject>::to_py_object(*self, 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]
|
2015-04-18 23:07:14 +00:00
|
|
|
fn into_py_object(self, py: Python<'p>) -> T::ObjectType {
|
2015-06-27 20:45:35 +00:00
|
|
|
<T as ToPyObject>::to_py_object(self, py)
|
2015-01-05 16:05:53 +00:00
|
|
|
}
|
|
|
|
|
2015-01-11 17:56:59 +00:00
|
|
|
#[inline]
|
2015-04-18 23:07:14 +00:00
|
|
|
fn with_borrowed_ptr<F, R>(&self, py: Python<'p>, f: F) -> R
|
|
|
|
where F: FnOnce(*mut ffi::PyObject) -> R {
|
2015-06-27 20:45:35 +00:00
|
|
|
<T as ToPyObject>::with_borrowed_ptr(*self, 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
|
|
|
|