pyo3/src/python.rs

168 lines
6.2 KiB
Rust
Raw Normal View History

2015-01-05 16:05:53 +00:00
use std;
use std::marker::{NoSend, InvariantLifetime};
2015-01-05 16:05:53 +00:00
use std::ptr;
use ffi;
2015-01-11 17:56:59 +00:00
use objects::{PyObject, PyType, PyBool, PyModule};
use err::PyResult;
use pythonrun::GILGuard;
2015-01-11 17:56:59 +00:00
use cstr::CStr;
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-11 03:21:05 +00:00
//impl <'p> !Send for Python<'p> {}
2015-01-05 16:05:53 +00:00
// Trait for converting from Self to *mut ffi::PyObject
pub trait ToPythonPointer {
/// Retrieves the underlying FFI pointer (as a borrowed pointer).
fn as_ptr(&self) -> *mut ffi::PyObject;
/// Destructures the input object, moving out the ownership of the underlying FFI pointer.
fn steal_ptr(self) -> *mut ffi::PyObject;
}
/// Trait implemented by all python object types.
pub trait PythonObject<'p> : 'p + Clone + ToPythonPointer {
/// Casts the python object to PyObject.
fn as_object(&self) -> &PyObject<'p>;
/// Casts the python object to PyObject.
fn into_object(self) -> PyObject<'p>;
/// 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.
unsafe fn unchecked_downcast_from(PyObject<'p>) -> Self;
2015-01-05 15:34:12 +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;
/// Retrieve python instance from an existing python object.
#[inline]
fn python(&self) -> Python<'p> {
self.as_object().python()
}
}
// Marker type that indicates an error while downcasting
pub struct PythonObjectDowncastError<'p>(pub Python<'p>);
/// 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.
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.
fn downcast_borrow_from<'a>(&'a PyObject<'p>) -> Result<&'a Self, PythonObjectDowncastError<'p>>;
2015-01-05 15:34:12 +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> {
/// Retrieves the type object for this python object type.
2015-01-11 03:21:05 +00:00
#[unstable = "Option<&Self> will disappear when UFCS is implemented"]
fn type_object(Python<'p>, Option<&Self>) -> PyType<'p>;
}
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()
}
}
/// 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-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,
/// 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-05 16:05:53 +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) -> PyObject<'p> {
unsafe { PyObject::from_borrowed_ptr(self, ffi::Py_None()) }
2015-01-05 16:05:53 +00:00
}
/// Retrieves a reference to the 'True' constant value.
#[allow(non_snake_case)] // the python keyword starts with uppercase
#[inline]
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
}
/// Retrieves a reference to the 'False' constant value.
#[allow(non_snake_case)] // the python keyword starts with uppercase
#[inline]
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-01-04 15:32:52 +00:00
/// Retrieves a reference to the type object for type T.
#[inline]
pub fn get_type<T>(self) -> PyType<'p> where T: PythonObjectWithTypeObject<'p> {
2015-01-04 15:32:52 +00:00
let none : Option<&T> = None;
2015-01-05 15:34:12 +00:00
PythonObjectWithTypeObject::type_object(self, none)
2015-01-04 04:50:28 +00:00
}
2015-01-11 17:56:59 +00:00
/// Import the python module with the specified name.
pub fn import(self, name : &CStr) -> PyResult<'p, PyModule<'p>> {
PyModule::import(self, name)
}
2015-01-04 04:50:28 +00:00
}
2015-01-05 16:05:53 +00:00