This commit is contained in:
Nikolay Kim 2017-05-21 14:20:24 -07:00
parent 9abc69f5c4
commit 56d93249ab
3 changed files with 141 additions and 0 deletions

View File

@ -90,6 +90,8 @@ pub use pyo3cls::*;
pub mod ffi;
pub use ffi::{Py_ssize_t, Py_hash_t};
mod pyptr;
pub use pyptr::{Py, PyPtr};
pub use err::{PyErr, PyResult};
pub use objects::*;
pub use python::{Python, PythonObject,

138
src/pyptr.rs Normal file
View File

@ -0,0 +1,138 @@
// Copyright (c) 2017-present PyO3 Project and Contributors
use std;
use std::marker::PhantomData;
use std::os::raw::c_int;
use std::ops::Deref;
use ffi;
use err::PyResult;
use python::Python;
use class::{BaseObject, PyTypeObject};
use objects::{PyObject, PyType};
pub struct PyPtr<T> {
inner: *mut ffi::PyObject,
_t: PhantomData<T>,
}
impl<T> PyPtr<T> {
fn as_ref<'p>(&self, _py: Python<'p>) -> Py<'p, T> {
Py{inner: self.inner, _t: PhantomData, _py: PhantomData}
}
fn into_ref<'p>(self, _py: Python<'p>) -> Py<'p, T> {
Py{inner: self.inner, _t: PhantomData, _py: PhantomData}
}
}
pub struct Py<'p, T> {
inner: *mut ffi::PyObject,
_t: PhantomData<T>,
_py: PhantomData<Python<'p>>,
}
impl<'p, T> Py<'p, T> where T: BaseObject + PyTypeObject {
fn new(py: Python<'p>, value: T) -> PyResult<Py<'p, T>> {
unsafe {
let obj = try!(Py::<T>::alloc(py, value));
Ok(Py{inner: obj, _t: PhantomData, _py: PhantomData})
}
}
unsafe fn alloc(py: Python, value: T) -> PyResult<*mut ffi::PyObject>
{
let ty = py.get_type::<T>();
let obj = try!(PyObject::alloc(py, &ty, ()));
let align = std::mem::align_of::<T>();
let bs = <T as BaseObject>::size();
// round base_size up to next multiple of align
let offset = (bs + align - 1) / align * align;
let ptr = (obj.as_ptr() as *mut u8).offset(offset as isize) as *mut T;
std::ptr::write(ptr, value);
Ok(obj.as_ptr())
}
unsafe fn dealloc(py: Python, obj: *mut ffi::PyObject) {
let align = std::mem::align_of::<T>();
let bs = <T as BaseObject>::size();
// round base_size up to next multiple of align
let offset = (bs + align - 1) / align * align;
let ptr = (obj as *mut u8).offset(offset as isize) as *mut T;
std::ptr::drop_in_place(ptr);
PyObject::dealloc(py, obj)
}
#[inline]
pub fn as_ref(&self) -> &'p T {
let align = std::mem::align_of::<T>();
let bs = <T as BaseObject>::size();
// round base_size up to next multiple of align
let offset = (bs + align - 1) / align * align;
unsafe {
let ptr = (self.inner as *mut u8).offset(offset as isize) as *mut T;
ptr.as_ref().unwrap()
}
}
#[inline]
pub fn as_mut(&self) -> &'p mut T {
let align = std::mem::align_of::<T>();
let bs = <T as BaseObject>::size();
// round base_size up to next multiple of align
let offset = (bs + align - 1) / align * align;
unsafe {
let ptr = (self.inner as *mut u8).offset(offset as isize) as *mut T;
ptr.as_mut().unwrap()
}
}
/// Creates a PyPtr instance. Calls Py_INCREF() on the ptr.
#[inline]
pub fn as_ptr(&self) -> PyPtr<T> {
unsafe {
ffi::Py_INCREF(self.inner);
}
PyPtr { inner: self.inner, _t: PhantomData }
}
/// Consumes a Py<T> instance and creates a PyPtr instance.
/// Ownership moves over to the PyPtr<T> instance, Does not call Py_INCREF() on the ptr.
#[inline]
pub fn into_ptr(self) -> PyPtr<T> {
PyPtr { inner: self.inner, _t: PhantomData }
}
}
impl<'p, T> Deref for Py<'p, T> where T: BaseObject {
type Target = T;
fn deref(&self) -> &T {
let align = std::mem::align_of::<T>();
let bs = <T as BaseObject>::size();
// round base_size up to next multiple of align
let offset = (bs + align - 1) / align * align;
unsafe {
let ptr = (self.inner as *mut u8).offset(offset as isize) as *mut T;
ptr.as_ref().unwrap()
}
}
}

View File

@ -26,6 +26,7 @@ use objects::{PyObject, PyType, PyBool, PyDict, PyModule};
use err::{self, PyErr, PyResult};
use pythonrun::GILGuard;
/// Marker type that indicates that the GIL is currently held.
///
/// The 'Python' struct is a zero-size marker struct that is required for most Python operations.