2015-01-05 16:05:53 +00:00
|
|
|
use std;
|
2015-01-04 23:07:31 +00:00
|
|
|
use std::kinds::marker::{NoSend, InvariantLifetime};
|
2015-01-05 16:05:53 +00:00
|
|
|
use std::ptr;
|
|
|
|
use ffi;
|
2015-01-04 23:07:31 +00:00
|
|
|
use object::PyObject;
|
2015-01-04 15:32:52 +00:00
|
|
|
use typeobject::PyType;
|
2015-01-04 23:07:31 +00:00
|
|
|
use pythonrun::GILGuard;
|
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,
|
|
|
|
/// and thus can only be called if the python interpreter is initialized and the GIL is acquired.
|
|
|
|
/// The lifetime 'p represents the lifetime of the python interpreter.
|
|
|
|
/// For example, python constants like None have the type "&'p PyObject<'p>".
|
|
|
|
/// You can imagine the GIL to be a giant "Mutex<AllPythonState>". This makes 'p the lifetime of the
|
|
|
|
/// python state protected by that mutex.
|
|
|
|
#[derive(Copy)]
|
|
|
|
pub struct Python<'p>(NoSend, InvariantLifetime<'p>);
|
|
|
|
|
2015-01-04 23:07:31 +00:00
|
|
|
/// Trait implemented by all python object types.
|
|
|
|
pub trait PythonObject<'p> : 'p {
|
|
|
|
/// Casts the python object to PyObject.
|
|
|
|
fn as_object(&self) -> &PyObject<'p>;
|
|
|
|
|
|
|
|
/// Retrieves the underlying FFI pointer associated with this python object.
|
|
|
|
#[inline]
|
|
|
|
fn as_ptr(&self) -> *mut ffi::PyObject {
|
|
|
|
self.as_object().as_ptr()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Retrieve python instance from an existing python object.
|
|
|
|
#[inline]
|
|
|
|
fn python(&self) -> Python<'p> {
|
|
|
|
self.as_object().python()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Trait implemented by python object types that allow a checked downcast.
|
|
|
|
pub trait PythonObjectDowncast<'p> : PythonObject<'p> {
|
|
|
|
// TODO: maybe add 'unsafe fn from_object_unchecked' to PythonObject/PythonObjectDowncast,
|
|
|
|
// and then implement from_object using type_object().is_instance() ?
|
|
|
|
|
|
|
|
/// Upcast from PyObject to a concrete python object type.
|
|
|
|
/// Returns None if the python object is not of the specified type.
|
|
|
|
fn from_object<'a>(&'a PyObject<'p>) -> Option<&'a Self>;
|
|
|
|
|
|
|
|
/// Retrieves the type object for this python object type.
|
|
|
|
/// Option<&Self> is necessary until UFCS is implemented.
|
|
|
|
fn type_object(Python<'p>, Option<&Self>) -> &'p PyType<'p>;
|
|
|
|
}
|
|
|
|
|
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> {
|
|
|
|
Python(NoSend, InvariantLifetime)
|
|
|
|
}
|
|
|
|
|
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-01-05 16:05:53 +00:00
|
|
|
/// Retrieves a reference to the special 'None' value.
|
|
|
|
#[allow(non_snake_case)] // the python keyword starts with uppercase
|
|
|
|
#[inline]
|
|
|
|
pub fn None(self) -> &'p PyObject<'p> {
|
|
|
|
unsafe { PyObject::from_ptr(self, ffi::Py_None()) }
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Retrieves a reference to the 'True' constant value.
|
|
|
|
#[allow(non_snake_case)] // the python keyword starts with uppercase
|
|
|
|
#[inline]
|
|
|
|
pub fn True(self) -> &'p PyObject<'p> {
|
|
|
|
unsafe { PyObject::from_ptr(self, ffi::Py_True()) }
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Retrieves a reference to the 'False' constant value.
|
|
|
|
#[allow(non_snake_case)] // the python keyword starts with uppercase
|
|
|
|
#[inline]
|
|
|
|
pub fn False(self) -> &'p PyObject<'p> {
|
|
|
|
unsafe { PyObject::from_ptr(self, ffi::Py_False()) }
|
|
|
|
}
|
|
|
|
|
2015-01-04 15:32:52 +00:00
|
|
|
/// Retrieves a reference to the type object for type T.
|
|
|
|
#[inline]
|
2015-01-04 23:07:31 +00:00
|
|
|
pub fn get_type<T>(self) -> &'p PyType<'p> where T: PythonObjectDowncast<'p> {
|
2015-01-04 15:32:52 +00:00
|
|
|
let none : Option<&T> = None;
|
2015-01-04 23:07:31 +00:00
|
|
|
PythonObjectDowncast::type_object(self, none)
|
2015-01-04 04:50:28 +00:00
|
|
|
}
|
|
|
|
}
|
2015-01-05 16:05:53 +00:00
|
|
|
|