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: Supported Rust version:
* Rust 1.17.0-nightly or later * Rust 1.20.0-nightly or later
* On Windows, we require rustc 1.17.0-nightly * On Windows, we require rustc 1.20.0-nightly
## Usage ## 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 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. 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 Because all Python objects potentially have multiple owners, the
concept of Rust mutability does not apply to Python objects. 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 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 { pub trait IntoPyObject {
/// Converts self into a Python object. (Consumes self) /// 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: /// Normal usage is through the `PyObject::extract` helper method:
/// ```let obj: PyObject = ...; /// ```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 /// Note: depending on the implementation, the lifetime of the extracted result may
/// depend on the lifetime of the `obj` or the `prepared` variable. /// depend on the lifetime of the `obj` or the `prepared` variable.
/// ///

View file

@ -7,7 +7,7 @@ use std::error::Error;
use libc; use libc;
use ffi; use ffi;
use python::{ToPyPointer, IntoPyPointer, Python, PyClone}; use python::{ToPyPointer, IntoPyPointer, Python};
use PyObject; use PyObject;
use objects::{PyObjectRef, PyType, exc}; use objects::{PyObjectRef, PyType, exc};
use instance::Py; use instance::Py;
@ -347,10 +347,12 @@ impl PyErr {
} }
pub fn clone_ref(&self, py: Python) -> 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 { PyErr {
ptype: self.ptype.clone_ref(py), ptype: self.ptype.clone_ref(py),
pvalue: self.pvalue.clone_ref(py), pvalue: v,
ptraceback: self.ptraceback.clone_ref(py), 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 { pub trait PyObjectWithToken: Sized {
fn py(&self) -> Python; fn py(&self) -> Python;
} }
#[doc(hidden)]
pub trait PyNativeType: PyObjectWithToken {} pub trait PyNativeType: PyObjectWithToken {}
/// Trait implements objet reference extraction from python managed pointer.
pub trait AsPyRef<T>: Sized { pub trait AsPyRef<T>: Sized {
/// Return reference to object.
fn as_ref(&self, py: Python) -> &T; fn as_ref(&self, py: Python) -> &T;
/// Return mutable reference to object.
fn as_mut(&self, py: Python) -> &mut T; 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 fn with<F, R>(&self, f: F) -> R where F: FnOnce(Python, &T) -> R
{ {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
@ -45,6 +51,7 @@ pub trait AsPyRef<T>: Sized {
f(py, self.as_ref(py)) 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 fn with_mut<F, R>(&self, f: F) -> R where F: FnOnce(Python, &mut T) -> R
{ {
let gil = Python::acquire_gil(); 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)] #[derive(Debug)]
pub struct Py<T>(pub *mut ffi::PyObject, std::marker::PhantomData<T>); 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) 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] #[inline]
pub fn from_owned_ptr_or_panic(ptr: *mut ffi::PyObject) -> Py<T> 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> { pub fn clone_ref(&self, _py: Python) -> Py<T> {
unsafe { Py::from_borrowed_ptr(self.0) } 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, 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>`. /// Returns `Py<T>`.
pub fn new<F>(py: Python, f: F) -> PyResult<Py<T>> pub fn new<F>(py: Python, f: F) -> PyResult<Py<T>>
where F: FnOnce(::PyToken) -> T, where F: FnOnce(::PyToken) -> T,
T: PyObjectAlloc<T> T: PyObjectAlloc<T>
{ {
let ob = f(PyToken(PhantomData)); let ob = f(PyToken(PhantomData));
@ -171,7 +171,7 @@ impl<T> Py<T> where T: PyTypeInfo,
Ok(ob) 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` /// Returns references to `T`
pub fn new_ref<F>(py: Python, f: F) -> PyResult<&T> pub fn new_ref<F>(py: Python, f: F) -> PyResult<&T>
where F: FnOnce(::PyToken) -> 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` /// Returns mutable references to `T`
pub fn new_mut<F>(py: Python, f: F) -> PyResult<&mut T> pub fn new_mut<F>(py: Python, f: F) -> PyResult<&mut T>
where F: FnOnce(::PyToken) -> 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> { impl<T> ToPyObject for Py<T> {
/// Converts `Py` instance -> PyObject.
fn to_object(&self, py: Python) -> PyObject { fn to_object(&self, py: Python) -> PyObject {
unsafe { unsafe {
PyObject::from_borrowed_ptr(py, self.as_ptr()) PyObject::from_borrowed_ptr(py, self.as_ptr())

View file

@ -6,9 +6,6 @@
//! In Python, all objects are implicitly reference counted. //! In Python, all objects are implicitly reference counted.
//! In rust, we will use the `PyObject` type to represent a reference to a Python object. //! 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 //! Because all Python objects potentially have multiple owners, the
//! concept of Rust mutability does not apply to Python objects. //! 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 //! 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 objects::*;
pub use objectprotocol::ObjectProtocol; pub use objectprotocol::ObjectProtocol;
pub use object::PyObject; pub use object::PyObject;
pub use python::{Python, ToPyPointer, IntoPyPointer, PyClone, pub use python::{Python, ToPyPointer, IntoPyPointer,
PyMutDowncastFrom, PyDowncastFrom, PyDowncastInto}; PyMutDowncastFrom, PyDowncastFrom, PyDowncastInto};
pub use pythonrun::{GILGuard, prepare_freethreaded_python, prepare_pyo3_library}; pub use pythonrun::{GILGuard, prepare_freethreaded_python, prepare_pyo3_library};
pub use instance::{PyToken, PyObjectWithToken, AsPyRef, Py, PyNativeType}; pub use instance::{PyToken, PyObjectWithToken, AsPyRef, Py, PyNativeType};
@ -167,7 +164,7 @@ pub use class::*;
/// Procedural macros /// Procedural macros
pub mod py { pub mod py {
pub use pyo3cls::*; pub use pyo3cls::{proto, class, methods};
#[cfg(Py_3)] #[cfg(Py_3)]
pub use pyo3cls::mod3init as modinit; pub use pyo3cls::mod3init as modinit;
@ -194,6 +191,7 @@ mod object;
mod objects; mod objects;
mod objectprotocol; mod objectprotocol;
mod pythonrun; mod pythonrun;
#[doc(hidden)]
pub mod callback; pub mod callback;
pub mod typeob; pub mod typeob;
#[doc(hidden)] #[doc(hidden)]

View file

@ -8,10 +8,10 @@ use err::{PyErr, PyResult, PyDowncastError};
use instance::{AsPyRef, PyObjectWithToken}; use instance::{AsPyRef, PyObjectWithToken};
use objects::{PyObjectRef, PyDict}; use objects::{PyObjectRef, PyDict};
use conversion::{ToPyObject, IntoPyObject, IntoPyTuple, FromPyObject}; 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)] #[derive(Debug)]
pub struct PyObject(*mut ffi::PyObject); pub struct PyObject(*mut ffi::PyObject);
@ -123,6 +123,13 @@ impl PyObject {
unsafe { ffi::Py_REFCNT(self.0) } 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. /// Returns whether the object is considered to be None.
/// This is equivalent to the Python expression: 'is None' /// This is equivalent to the Python expression: 'is None'
#[inline] #[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 impl IntoPyObject for PyObject
{ {
#[inline] #[inline]

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -16,19 +16,19 @@ use python::{Python, ToPyPointer};
use objectprotocol::ObjectProtocol; use objectprotocol::ObjectProtocol;
use super::{PyObjectRef, PyStringData}; use super::{PyObjectRef, PyStringData};
/// Represents a Python string. /// Represents a Python `string`.
pub struct PyString(PyObject); pub struct PyString(PyObject);
pyobject_convert!(PyString); pyobject_convert!(PyString);
pyobject_nativetype!(PyString, PyBaseString_Type, PyBaseString_Check); pyobject_nativetype!(PyString, PyBaseString_Type, PyBaseString_Check);
/// Represents a Python unicode string. /// Represents a Python `unicode string`.
pub struct PyUnicode(PyObject); pub struct PyUnicode(PyObject);
pyobject_convert!(PyUnicode); pyobject_convert!(PyUnicode);
pyobject_nativetype!(PyUnicode, PyUnicode_Type, PyUnicode_Check); 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); pub struct PyBytes(PyObject);
pyobject_convert!(PyBytes); pyobject_convert!(PyBytes);

View file

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

View file

@ -12,7 +12,7 @@ use err::{PyErr, PyResult};
use instance::PyObjectWithToken; use instance::PyObjectWithToken;
use typeob::PyTypeObject; use typeob::PyTypeObject;
/// Represents a reference to a Python type object. /// Represents a reference to a Python `type object`.
pub struct PyType(PyObject); pub struct PyType(PyObject);
pyobject_convert!(PyType); 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> { impl<'p> Python<'p> {
/// Retrieve Python instance under the assumption that the GIL is already acquired at this point, /// 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; use class::methods::PyMethodDefType;
/// Basic python type information /// Python type information.
/// Implementing this trait for custom struct is enough to make it compatible with
/// python object system
pub trait PyTypeInfo { pub trait PyTypeInfo {
/// Type of objects to store in PyObject struct /// Type of objects to store in PyObject struct
type Type; 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> { pub trait PyObjectAlloc<T> {
/// Allocates a new object (usually by calling ty->tp_alloc), /// 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); 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 { 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> { default unsafe fn alloc(py: Python, value: T) -> PyResult<*mut ffi::PyObject> {
// TODO: remove this // TODO: remove this
<T as PyTypeObject>::init_type(py); <T as PyTypeObject>::init_type(py);
@ -98,9 +94,6 @@ impl<T> PyObjectAlloc<T> for T where T : PyTypeInfo {
Ok(obj) 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) { default unsafe fn dealloc(_py: Python, obj: *mut ffi::PyObject) {
let ptr = (obj as *mut u8).offset(<Self as PyTypeInfo>::offset()) as *mut T; let ptr = (obj as *mut u8).offset(<Self as PyTypeInfo>::offset()) as *mut T;
std::ptr::drop_in_place(ptr); 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>, pub fn initialize_type<'p, T>(py: Python<'p>,
module_name: Option<&str>, module_name: Option<&str>,
type_object: &mut ffi::PyTypeObject) -> PyResult<&'p PyType> type_object: &mut ffi::PyTypeObject) -> PyResult<&'p PyType>