2015-01-05 16:05:53 +00:00
|
|
|
use std;
|
2015-03-08 14:29:44 +00:00
|
|
|
use std::marker::PhantomData;
|
2015-01-05 16:05:53 +00:00
|
|
|
use ffi;
|
2015-01-11 17:56:59 +00:00
|
|
|
use objects::{PyObject, PyType, PyBool, PyModule};
|
|
|
|
use err::PyResult;
|
2015-01-04 23:07:31 +00:00
|
|
|
use pythonrun::GILGuard;
|
2015-03-08 14:29:44 +00:00
|
|
|
|
|
|
|
// Dummy struct representing the global state in the python interpreter.
|
|
|
|
struct PythonInterpreterState;
|
|
|
|
impl !Sync for PythonInterpreterState {}
|
2015-01-05 16:05:53 +00:00
|
|
|
|
2015-04-18 22:39:04 +00:00
|
|
|
/// Marker type that indicates that the GIL is currently held.
|
|
|
|
///
|
2015-01-05 16:05:53 +00:00
|
|
|
/// The 'Python' struct is a zero-size marker struct that is required for most python operations.
|
|
|
|
/// This is used to indicate that the operation accesses/modifies the python interpreter state,
|
2015-04-18 22:39:04 +00:00
|
|
|
/// and thus can only be called if the python interpreter is initialized and the
|
|
|
|
/// python global interpreter lock (GIL) is acquired.
|
|
|
|
/// The lifetime `'p` represents the lifetime of the python interpreter.
|
|
|
|
///
|
|
|
|
/// You can imagine the GIL to be a giant `Mutex<PythonInterpreterState>`.
|
|
|
|
/// The type `Python<'p>` then acts like a reference `&'p PythonInterpreterState`.
|
2015-04-17 20:13:15 +00:00
|
|
|
#[derive(Copy, Clone)]
|
2015-03-08 14:29:44 +00:00
|
|
|
pub struct Python<'p>(PhantomData<&'p PythonInterpreterState>);
|
2015-01-05 16:05:53 +00:00
|
|
|
|
2015-04-18 22:39:04 +00:00
|
|
|
/// This trait allows retrieving the underlying FFI pointer from python objects.
|
2015-01-07 00:40:48 +00:00
|
|
|
pub trait ToPythonPointer {
|
|
|
|
/// Retrieves the underlying FFI pointer (as a borrowed pointer).
|
|
|
|
fn as_ptr(&self) -> *mut ffi::PyObject;
|
|
|
|
|
2015-04-18 22:39:04 +00:00
|
|
|
/// Retrieves the underlying FFI pointer as a "stolen pointer".
|
2015-01-07 00:40:48 +00:00
|
|
|
fn steal_ptr(self) -> *mut ffi::PyObject;
|
|
|
|
}
|
|
|
|
|
2015-01-04 23:07:31 +00:00
|
|
|
/// Trait implemented by all python object types.
|
2015-01-07 00:40:48 +00:00
|
|
|
pub trait PythonObject<'p> : 'p + Clone + ToPythonPointer {
|
2015-01-04 23:07:31 +00:00
|
|
|
/// Casts the python object to PyObject.
|
|
|
|
fn as_object(&self) -> &PyObject<'p>;
|
2015-01-07 00:40:48 +00:00
|
|
|
|
|
|
|
/// Casts the python object to PyObject.
|
|
|
|
fn into_object(self) -> PyObject<'p>;
|
2015-01-04 23:07:31 +00:00
|
|
|
|
2015-01-07 00:40:48 +00:00
|
|
|
/// Unchecked downcast from PyObject to Self.
|
2015-01-05 15:34:12 +00:00
|
|
|
/// Undefined behavior if the input object does not have the expected type.
|
2015-01-07 00:40:48 +00:00
|
|
|
unsafe fn unchecked_downcast_from(PyObject<'p>) -> Self;
|
2015-01-05 15:34:12 +00:00
|
|
|
|
2015-01-07 00:40:48 +00:00
|
|
|
/// 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;
|
2015-01-04 23:07:31 +00:00
|
|
|
|
|
|
|
/// Retrieve python instance from an existing python object.
|
|
|
|
#[inline]
|
|
|
|
fn python(&self) -> Python<'p> {
|
|
|
|
self.as_object().python()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-18 22:39:04 +00:00
|
|
|
// Marker type that indicates an error while downcasting
|
2015-01-07 00:40:48 +00:00
|
|
|
pub struct PythonObjectDowncastError<'p>(pub Python<'p>);
|
|
|
|
|
2015-01-04 23:07:31 +00:00
|
|
|
/// Trait implemented by python object types that allow a checked downcast.
|
2015-01-05 15:34:12 +00:00
|
|
|
pub trait PythonObjectWithCheckedDowncast<'p> : PythonObject<'p> {
|
2015-01-08 08:19:35 +00:00
|
|
|
/// Cast from PyObject to a concrete python object type.
|
2015-01-07 00:40:48 +00:00
|
|
|
fn downcast_from(PyObject<'p>) -> Result<Self, PythonObjectDowncastError<'p>>;
|
|
|
|
|
2015-01-08 08:19:35 +00:00
|
|
|
/// Cast from PyObject to a concrete python object type.
|
2015-01-07 00:40:48 +00:00
|
|
|
fn downcast_borrow_from<'a>(&'a PyObject<'p>) -> Result<&'a Self, PythonObjectDowncastError<'p>>;
|
2015-01-05 15:34:12 +00:00
|
|
|
}
|
2015-01-04 23:07:31 +00:00
|
|
|
|
2015-01-05 15:34:12 +00:00
|
|
|
/// Trait implemented by python object types that have a corresponding type object.
|
|
|
|
pub trait PythonObjectWithTypeObject<'p> : PythonObjectWithCheckedDowncast<'p> {
|
2015-01-04 23:07:31 +00:00
|
|
|
/// Retrieves the type object for this python object type.
|
2015-04-18 18:17:25 +00:00
|
|
|
fn type_object(Python<'p>) -> PyType<'p>;
|
2015-01-07 00:40:48 +00:00
|
|
|
}
|
|
|
|
|
2015-01-11 03:21:05 +00:00
|
|
|
/// ToPythonPointer for borrowed python pointers.
|
|
|
|
impl <'a, 'p, T> ToPythonPointer for &'a T where T: PythonObject<'p> {
|
|
|
|
#[inline]
|
|
|
|
fn as_ptr(&self) -> *mut ffi::PyObject {
|
|
|
|
(**self).as_ptr()
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn steal_ptr(self) -> *mut ffi::PyObject {
|
|
|
|
(*self).clone().steal_ptr()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-01-07 00:40:48 +00:00
|
|
|
/// Convert None into a null pointer.
|
|
|
|
impl <T> ToPythonPointer for Option<T> where T: ToPythonPointer {
|
|
|
|
#[inline]
|
|
|
|
fn as_ptr(&self) -> *mut ffi::PyObject {
|
|
|
|
match *self {
|
|
|
|
Some(ref t) => t.as_ptr(),
|
|
|
|
None => std::ptr::null_mut()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn steal_ptr(self) -> *mut ffi::PyObject {
|
|
|
|
match self {
|
|
|
|
Some(t) => t.steal_ptr(),
|
|
|
|
None => std::ptr::null_mut()
|
|
|
|
}
|
|
|
|
}
|
2015-01-04 23:07:31 +00:00
|
|
|
}
|
|
|
|
|
2015-01-05 16:05:53 +00:00
|
|
|
impl<'p> Python<'p> {
|
|
|
|
/// Retrieve python instance under the assumption that the GIL is already acquired at this point,
|
2015-01-04 23:07:31 +00:00
|
|
|
/// and stays acquired for the lifetime 'p
|
|
|
|
#[inline]
|
2015-01-05 16:05:53 +00:00
|
|
|
pub unsafe fn assume_gil_acquired() -> Python<'p> {
|
2015-03-08 14:29:44 +00:00
|
|
|
Python(PhantomData)
|
2015-01-05 16:05:53 +00:00
|
|
|
}
|
|
|
|
|
2015-01-04 23:07:31 +00:00
|
|
|
/// Acquires the global interpreter lock, which allows access to the Python runtime.
|
|
|
|
/// If the python runtime is not already initialized, this function will initialize it.
|
|
|
|
/// Note that in this case, the python runtime will not have any main thread, and will
|
|
|
|
/// not deliver signals like KeyboardInterrupt.
|
|
|
|
#[inline]
|
|
|
|
pub fn acquire_gil() -> GILGuard {
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2015-04-18 20:20:19 +00:00
|
|
|
/// Gets the python builtin value `None`.
|
2015-01-05 16:05:53 +00:00
|
|
|
#[allow(non_snake_case)] // the python keyword starts with uppercase
|
|
|
|
#[inline]
|
2015-01-07 00:40:48 +00:00
|
|
|
pub fn None(self) -> PyObject<'p> {
|
|
|
|
unsafe { PyObject::from_borrowed_ptr(self, ffi::Py_None()) }
|
2015-01-05 16:05:53 +00:00
|
|
|
}
|
|
|
|
|
2015-04-18 20:20:19 +00:00
|
|
|
/// Gets the python builtin value `True`.
|
2015-01-05 16:05:53 +00:00
|
|
|
#[allow(non_snake_case)] // the python keyword starts with uppercase
|
|
|
|
#[inline]
|
2015-01-07 00:40:48 +00:00
|
|
|
pub fn True(self) -> PyBool<'p> {
|
|
|
|
unsafe { PyObject::from_borrowed_ptr(self, ffi::Py_True()).unchecked_cast_into::<PyBool>() }
|
2015-01-05 16:05:53 +00:00
|
|
|
}
|
|
|
|
|
2015-04-18 20:20:19 +00:00
|
|
|
/// Gets the python builtin value `False`.
|
2015-01-05 16:05:53 +00:00
|
|
|
#[allow(non_snake_case)] // the python keyword starts with uppercase
|
|
|
|
#[inline]
|
2015-01-07 00:40:48 +00:00
|
|
|
pub fn False(self) -> PyBool<'p> {
|
|
|
|
unsafe { PyObject::from_borrowed_ptr(self, ffi::Py_False()).unchecked_cast_into::<PyBool>() }
|
2015-01-05 16:05:53 +00:00
|
|
|
}
|
2015-04-18 20:20:19 +00:00
|
|
|
|
|
|
|
/// Gets the python type object for type T.
|
2015-01-07 00:40:48 +00:00
|
|
|
pub fn get_type<T>(self) -> PyType<'p> where T: PythonObjectWithTypeObject<'p> {
|
2015-04-18 18:17:25 +00:00
|
|
|
T::type_object(self)
|
2015-01-04 04:50:28 +00:00
|
|
|
}
|
2015-01-11 17:56:59 +00:00
|
|
|
|
|
|
|
/// Import the python module with the specified name.
|
2015-04-18 20:20:19 +00:00
|
|
|
pub fn import(self, name : &str) -> PyResult<'p, PyModule<'p>> {
|
2015-01-11 17:56:59 +00:00
|
|
|
PyModule::import(self, name)
|
|
|
|
}
|
2015-01-04 04:50:28 +00:00
|
|
|
}
|
2015-01-05 16:05:53 +00:00
|
|
|
|
2015-04-18 22:39:04 +00:00
|
|
|
impl <'p> std::fmt::Debug for PythonObjectDowncastError<'p> {
|
|
|
|
fn fmt(&self, f : &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
|
|
|
f.write_str("PythonObjectDowncastError")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|