drop PyClone trait; doc cleanups

This commit is contained in:
Nikolay Kim 2017-07-18 10:13:50 -07:00
parent dd29dbce80
commit fc1df289bd
16 changed files with 59 additions and 86 deletions

View file

@ -12,8 +12,8 @@ Supported Python versions:
Supported Rust version:
* Rust 1.17.0-nightly or later
* On Windows, we require rustc 1.17.0-nightly
* Rust 1.20.0-nightly or later
* On Windows, we require rustc 1.20.0-nightly
## Usage
@ -109,9 +109,6 @@ In Python, all objects are implicitly reference counted.
In Rust, we will use the [`PyObject`](https://pyo3.github.io/PyO3/pyo3/struct.PyObject.html) type
to represent a reference to a Python object.
The method [`clone_ref()`](https://pyo3.github.io/PyO3/pyo3/trait.PyClone.html#tymethod.clone_ref) (from trait [`PyClone`](https://pyo3.github.io/PyO3/pyo3/trait.PyClone.html)) can be used to create additional
references to the same Python object.
Because all Python objects potentially have multiple owners, the
concept of Rust mutability does not apply to Python objects.
As a result, this API will **allow mutating Python objects even if they are not stored

View file

@ -33,6 +33,8 @@ pub trait ToPyObject {
}
}
/// Conversion trait that allows various objects to be converted into `PyObject`
/// by consuming original object.
pub trait IntoPyObject {
/// Converts self into a Python object. (Consumes self)
@ -51,14 +53,14 @@ pub trait IntoPyTuple {
}
/// `FromPyObject` is implemented by various types that can be extracted from a Python object.
/// `FromPyObject` is implemented by various types that can be extracted from
/// a Python object reference.
///
/// Normal usage is through the `PyObject::extract` helper method:
/// ```let obj: PyObject = ...;
/// let value = try!(obj.extract::<TargetType>(py));
/// let value: &TargetType = obj.extract(py)?;
/// ```
///
/// TODO: update this documentation
/// Note: depending on the implementation, the lifetime of the extracted result may
/// depend on the lifetime of the `obj` or the `prepared` variable.
///

View file

@ -7,7 +7,7 @@ use std::error::Error;
use libc;
use ffi;
use python::{ToPyPointer, IntoPyPointer, Python, PyClone};
use python::{ToPyPointer, IntoPyPointer, Python};
use PyObject;
use objects::{PyObjectRef, PyType, exc};
use instance::Py;
@ -347,10 +347,12 @@ impl PyErr {
}
pub fn clone_ref(&self, py: Python) -> PyErr {
let v = if let Some(ref val) = self.pvalue { Some(val.clone_ref(py))} else { None };
let t = if let Some(ref val) = self.ptraceback { Some(val.clone_ref(py))} else { None };
PyErr {
ptype: self.ptype.clone_ref(py),
pvalue: self.pvalue.clone_ref(py),
ptraceback: self.ptraceback.clone_ref(py),
pvalue: v,
ptraceback: t,
}
}

View file

@ -24,19 +24,25 @@ impl PyToken {
}
}
/// Any instance that is managed Python can have access to `gil`.
pub trait PyObjectWithToken: Sized {
fn py(&self) -> Python;
}
#[doc(hidden)]
pub trait PyNativeType: PyObjectWithToken {}
/// Trait implements objet reference extraction from python managed pointer.
pub trait AsPyRef<T>: Sized {
/// Return reference to object.
fn as_ref(&self, py: Python) -> &T;
/// Return mutable reference to object.
fn as_mut(&self, py: Python) -> &mut T;
/// Acquire python gil and call closure with object reference.
fn with<F, R>(&self, f: F) -> R where F: FnOnce(Python, &T) -> R
{
let gil = Python::acquire_gil();
@ -45,6 +51,7 @@ pub trait AsPyRef<T>: Sized {
f(py, self.as_ref(py))
}
/// Acquire python gil and call closure with mutable object reference.
fn with_mut<F, R>(&self, f: F) -> R where F: FnOnce(Python, &mut T) -> R
{
let gil = Python::acquire_gil();
@ -76,7 +83,7 @@ pub trait AsPyRef<T>: Sized {
}
}
/// Wrapper around unsafe `*mut ffi::PyObject` pointer. Decrement ref counter on `Drop`
/// Safe wrapper around unsafe `*mut ffi::PyObject` pointer with specified type information.
#[derive(Debug)]
pub struct Py<T>(pub *mut ffi::PyObject, std::marker::PhantomData<T>);
@ -96,7 +103,9 @@ impl<T> Py<T> {
Py(ptr, std::marker::PhantomData)
}
/// Cast from ffi::PyObject ptr to a concrete object.
/// Creates a `Py<T>` instance for the given FFI pointer.
/// Panics if the pointer is `null`.
/// Undefined behavior if the pointer is invalid.
#[inline]
pub fn from_owned_ptr_or_panic(ptr: *mut ffi::PyObject) -> Py<T>
{
@ -142,25 +151,16 @@ impl<T> Py<T> {
pub fn clone_ref(&self, _py: Python) -> Py<T> {
unsafe { Py::from_borrowed_ptr(self.0) }
}
/// Casts the `Py<T>` imstance to a concrete Python object type.
/// Fails with `PyDowncastError` if the object is not of the expected type.
#[inline]
pub fn cast_into<D>(self, py: Python) -> Result<D, PyDowncastError>
where D: PyDowncastInto
{
<D as PyDowncastInto>::downcast_into(py, self)
}
}
impl<T> Py<T> where T: PyTypeInfo,
{
/// Create new instance of T and move under python management
/// Create new instance of T and move it under python management
/// Returns `Py<T>`.
pub fn new<F>(py: Python, f: F) -> PyResult<Py<T>>
where F: FnOnce(::PyToken) -> T,
T: PyObjectAlloc<T>
where F: FnOnce(::PyToken) -> T,
T: PyObjectAlloc<T>
{
let ob = f(PyToken(PhantomData));
@ -171,7 +171,7 @@ impl<T> Py<T> where T: PyTypeInfo,
Ok(ob)
}
/// Create new instance of `T` and move under python management.
/// Create new instance of `T` and move it under python management.
/// Returns references to `T`
pub fn new_ref<F>(py: Python, f: F) -> PyResult<&T>
where F: FnOnce(::PyToken) -> T,
@ -185,7 +185,7 @@ impl<T> Py<T> where T: PyTypeInfo,
}
}
/// Create new instance of `T` and move under python management.
/// Create new instance of `T` and move it under python management.
/// Returns mutable references to `T`
pub fn new_mut<F>(py: Python, f: F) -> PyResult<&mut T>
where F: FnOnce(::PyToken) -> T,
@ -234,6 +234,7 @@ impl<T> AsPyRef<T> for Py<T> where T: PyTypeInfo + PyNativeType {
}
impl<T> ToPyObject for Py<T> {
/// Converts `Py` instance -> PyObject.
fn to_object(&self, py: Python) -> PyObject {
unsafe {
PyObject::from_borrowed_ptr(py, self.as_ptr())

View file

@ -6,9 +6,6 @@
//! In Python, all objects are implicitly reference counted.
//! In rust, we will use the `PyObject` type to represent a reference to a Python object.
//!
//! The method `clone_ref()` (from trait `PyClone`) can be used to create additional
//! references to the same Python object.
//!
//! Because all Python objects potentially have multiple owners, the
//! concept of Rust mutability does not apply to Python objects.
//! As a result, this API will allow mutating Python objects even if they are not stored
@ -157,7 +154,7 @@ pub use err::{PyErr, PyResult, PyDowncastError, ToPyErr};
pub use objects::*;
pub use objectprotocol::ObjectProtocol;
pub use object::PyObject;
pub use python::{Python, ToPyPointer, IntoPyPointer, PyClone,
pub use python::{Python, ToPyPointer, IntoPyPointer,
PyMutDowncastFrom, PyDowncastFrom, PyDowncastInto};
pub use pythonrun::{GILGuard, prepare_freethreaded_python, prepare_pyo3_library};
pub use instance::{PyToken, PyObjectWithToken, AsPyRef, Py, PyNativeType};
@ -167,7 +164,7 @@ pub use class::*;
/// Procedural macros
pub mod py {
pub use pyo3cls::*;
pub use pyo3cls::{proto, class, methods};
#[cfg(Py_3)]
pub use pyo3cls::mod3init as modinit;
@ -194,6 +191,7 @@ mod object;
mod objects;
mod objectprotocol;
mod pythonrun;
#[doc(hidden)]
pub mod callback;
pub mod typeob;
#[doc(hidden)]

View file

@ -8,10 +8,10 @@ use err::{PyErr, PyResult, PyDowncastError};
use instance::{AsPyRef, PyObjectWithToken};
use objects::{PyObjectRef, PyDict};
use conversion::{ToPyObject, IntoPyObject, IntoPyTuple, FromPyObject};
use python::{Python, PyClone, ToPyPointer, IntoPyPointer};
use python::{Python, ToPyPointer, IntoPyPointer};
/// Wrapper around unsafe `*mut ffi::PyObject` pointer. Decrement ref counter on `Drop`
/// Safe wrapper around unsafe `*mut ffi::PyObject` pointer.
#[derive(Debug)]
pub struct PyObject(*mut ffi::PyObject);
@ -123,6 +123,13 @@ impl PyObject {
unsafe { ffi::Py_REFCNT(self.0) }
}
/// Clone self, Calls Py_INCREF() on the ptr.
pub fn clone_ref(&self, py: Python) -> Self {
unsafe {
PyObject::from_borrowed_ptr(py, self.as_ptr())
}
}
/// Returns whether the object is considered to be None.
/// This is equivalent to the Python expression: 'is None'
#[inline]
@ -266,14 +273,6 @@ impl PartialEq for PyObject {
}
}
impl PyClone for PyObject {
fn clone_ref(&self, py: Python) -> Self {
unsafe {
PyObject::from_borrowed_ptr(py, self.as_ptr())
}
}
}
impl IntoPyObject for PyObject
{
#[inline]

View file

@ -6,13 +6,14 @@ use std::os::raw::c_int;
use ffi;
use err::{PyErr, PyResult, PyDowncastError, self};
use python::{Python, ToPyPointer, PyDowncastFrom, PyClone};
use python::{Python, ToPyPointer, PyDowncastFrom};
use object::PyObject;
use objects::{PyObjectRef, PyDict, PyString, PyIterator, PyType};
use conversion::{ToPyObject, IntoPyTuple, FromPyObject};
use instance::PyObjectWithToken;
/// Python object model helper methods
pub trait ObjectProtocol {
/// Determines whether this object has the given attribute.
@ -136,9 +137,6 @@ pub trait ObjectProtocol {
/// Returns reference count for python object.
fn get_refcnt(&self) -> isize;
/// Clones PyObject. (utility function)
fn clone_ref(&self, ptr: &PyObject) -> PyObject;
/// Gets the Python builtin value `None`.
#[allow(non_snake_case)] // the Python keyword starts with uppercase
fn None(&self) -> PyObject;
@ -369,10 +367,6 @@ impl<T> ObjectProtocol for T where T: PyObjectWithToken + ToPyPointer {
FromPyObject::extract(self.into())
}
fn clone_ref(&self, ptr: &PyObject) -> PyObject {
ptr.clone_ref(self.py())
}
#[allow(non_snake_case)] // the Python keyword starts with uppercase
#[inline]
fn None(&self) -> PyObject {

View file

@ -8,7 +8,7 @@ use instance::PyObjectWithToken;
use python::{Python, ToPyPointer};
use err::{PyResult, PyErr};
/// Represents a Python bytearray.
/// Represents a Python `bytearray`.
pub struct PyByteArray(PyObject);
pyobject_convert!(PyByteArray);

View file

@ -16,7 +16,7 @@ use instance::PyObjectWithToken;
use err::{PyResult, PyErr, ToPyErr};
/// Represents a Python module object.
/// Represents a Python `module` object.
pub struct PyModule(PyObject);
pyobject_convert!(PyModule);

View file

@ -9,8 +9,9 @@ use ffi::{self, Py_ssize_t};
use instance::PyObjectWithToken;
use conversion::ToPyObject;
/// Represents a Python `slice`. Only `c_long` indeces supprted
/// at the moment by `PySlice` object.
/// Represents a Python `slice`.
///
/// Only `c_long` indeces supprted at the moment by `PySlice` object.
pub struct PySlice(PyObject);
pyobject_convert!(PySlice);

View file

@ -15,17 +15,17 @@ use python::{ToPyPointer, Python};
use err::{PyResult, PyErr};
use super::PyStringData;
/// Represents a Python string.
/// Represents a Python `string`.
pub struct PyString(PyObject);
pyobject_convert!(PyString);
pyobject_nativetype!(PyString, PyUnicode_Type, PyUnicode_Check);
/// Represents a Python unicode string.
/// Represents a Python `unicode string`.
/// Corresponds to `unicode` in Python 2, and `str` in Python 3.
pub use PyString as PyUnicode;
/// Represents a Python byte string.
/// Represents a Python `byte` string.
pub struct PyBytes(PyObject);
pyobject_convert!(PyBytes);

View file

@ -16,19 +16,19 @@ use python::{Python, ToPyPointer};
use objectprotocol::ObjectProtocol;
use super::{PyObjectRef, PyStringData};
/// Represents a Python string.
/// Represents a Python `string`.
pub struct PyString(PyObject);
pyobject_convert!(PyString);
pyobject_nativetype!(PyString, PyBaseString_Type, PyBaseString_Check);
/// Represents a Python unicode string.
/// Represents a Python `unicode string`.
pub struct PyUnicode(PyObject);
pyobject_convert!(PyUnicode);
pyobject_nativetype!(PyUnicode, PyUnicode_Type, PyUnicode_Check);
/// Represents a Python byte string. Corresponds to `str` in Python 2
/// Represents a Python `byte` string. Corresponds to `str` in Python 2
pub struct PyBytes(PyObject);
pyobject_convert!(PyBytes);

View file

@ -14,7 +14,7 @@ use python::{Python, ToPyPointer, IntoPyPointer};
use conversion::{FromPyObject, ToPyObject, IntoPyTuple, IntoPyObject};
use super::exc;
/// Represents a Python tuple object.
/// Represents a Python `tuple` object.
pub struct PyTuple(PyObject);
pyobject_convert!(PyTuple);

View file

@ -12,7 +12,7 @@ use err::{PyErr, PyResult};
use instance::PyObjectWithToken;
use typeob::PyTypeObject;
/// Represents a reference to a Python type object.
/// Represents a reference to a Python `type object`.
pub struct PyType(PyObject);
pyobject_convert!(PyType);

View file

@ -101,21 +101,6 @@ impl <T> IntoPyPointer for Option<T> where T: IntoPyPointer {
}
}
pub trait PyClone {
fn clone_ref(&self, py: Python) -> Self;
}
impl<T> PyClone for Option<T> where T: PyClone {
fn clone_ref(&self, py: Python) -> Option<T> {
match *self {
Some(ref p) => Some(p.clone_ref(py)),
None => None,
}
}
}
impl<'p> Python<'p> {
/// Retrieve Python instance under the assumption that the GIL is already acquired at this point,

View file

@ -15,9 +15,7 @@ use callback::AbortOnDrop;
use class::methods::PyMethodDefType;
/// Basic python type information
/// Implementing this trait for custom struct is enough to make it compatible with
/// python object system
/// Python type information.
pub trait PyTypeInfo {
/// Type of objects to store in PyObject struct
type Type;
@ -67,6 +65,7 @@ impl<'a, T: ?Sized> PyTypeInfo for &'a T where T: PyTypeInfo {
}
/// A Python object allocator that is usable as a base type for #[class]
pub trait PyObjectAlloc<T> {
/// Allocates a new object (usually by calling ty->tp_alloc),
@ -79,11 +78,8 @@ pub trait PyObjectAlloc<T> {
unsafe fn dealloc(py: Python, obj: *mut ffi::PyObject);
}
/// A Python object allocator that is usable as a base type for #[class]
impl<T> PyObjectAlloc<T> for T where T : PyTypeInfo {
/// Allocates a new object (usually by calling ty->tp_alloc),
/// and initializes it using value.
default unsafe fn alloc(py: Python, value: T) -> PyResult<*mut ffi::PyObject> {
// TODO: remove this
<T as PyTypeObject>::init_type(py);
@ -98,9 +94,6 @@ impl<T> PyObjectAlloc<T> for T where T : PyTypeInfo {
Ok(obj)
}
/// Calls the rust destructor for the object and frees the memory
/// (usually by calling ptr->ob_type->tp_free).
/// This function is used as tp_dealloc implementation.
default unsafe fn dealloc(_py: Python, obj: *mut ffi::PyObject) {
let ptr = (obj as *mut u8).offset(<Self as PyTypeInfo>::offset()) as *mut T;
std::ptr::drop_in_place(ptr);
@ -152,6 +145,7 @@ impl<T> PyTypeObject for T where T: PyObjectAlloc<T> + PyTypeInfo {
}
/// Register new type in python object system.
pub fn initialize_type<'p, T>(py: Python<'p>,
module_name: Option<&str>,
type_object: &mut ffi::PyTypeObject) -> PyResult<&'p PyType>