pyo3/src/conversion.rs

140 lines
5.3 KiB
Rust
Raw Normal View History

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;
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
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-01-05 20:14:01 +00:00
type ObjectType : PythonObject<'p> = PyObject<'p>;
2015-01-11 17:56:59 +00:00
2015-06-27 20:45:35 +00:00
/// Converts self into a Python object.
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]
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]
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.
pub trait FromPyObject<'p> {
fn from_py_object(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-06-27 20:45:35 +00:00
// This allows using existing Python objects in code that generically expects a value
// convertible to a Python object.
/// Identity conversion: allows using existing `PyObject` instances where
/// `ToPyObject` is expected.
impl <'p, 's> ToPyObject<'p> for PyObject<'s> {
2015-04-18 20:20:19 +00:00
type ObjectType = PyObject<'p>;
2015-01-11 17:56:59 +00:00
#[inline]
fn to_py_object(&self, py: Python<'p>) -> PyObject<'p> {
self.clone().into_py_object(py)
2015-01-11 17:56:59 +00:00
}
#[inline]
fn into_py_object(self, py: Python<'p>) -> PyObject<'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) }
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) -> R
where F: FnOnce(*mut ffi::PyObject) -> R {
2015-01-11 17:56:59 +00:00
f(self.as_ptr())
}
2015-01-05 16:05:53 +00:00
}
impl <'p, T> FromPyObject<'p> for T where T: PythonObjectWithCheckedDowncast<'p> {
2015-01-05 16:05:53 +00:00
#[inline]
fn from_py_object(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-06-27 20:45:35 +00:00
// This allows using existing Python objects in code that generically expects a value
// convertible to a Python object.
impl <'p, 's, T: ?Sized> ToPyObject<'p> for &'s T where T: ToPyObject<'p> {
type ObjectType = T::ObjectType;
2015-01-04 19:11:18 +00:00
#[inline]
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]
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]
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