diff --git a/guide/src/overview.md b/guide/src/overview.md index dc4f5a22..36bf32e2 100644 --- a/guide/src/overview.md +++ b/guide/src/overview.md @@ -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 diff --git a/src/conversion.rs b/src/conversion.rs index 5d166a35..add41310 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -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::(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. /// diff --git a/src/err.rs b/src/err.rs index 61a3c7f5..c5c7d000 100644 --- a/src/err.rs +++ b/src/err.rs @@ -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, } } diff --git a/src/instance.rs b/src/instance.rs index e20e3d14..89a413a9 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -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: 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(&self, f: F) -> R where F: FnOnce(Python, &T) -> R { let gil = Python::acquire_gil(); @@ -45,6 +51,7 @@ pub trait AsPyRef: Sized { f(py, self.as_ref(py)) } + /// Acquire python gil and call closure with mutable object reference. fn with_mut(&self, f: F) -> R where F: FnOnce(Python, &mut T) -> R { let gil = Python::acquire_gil(); @@ -76,7 +83,7 @@ pub trait AsPyRef: 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(pub *mut ffi::PyObject, std::marker::PhantomData); @@ -96,7 +103,9 @@ impl Py { Py(ptr, std::marker::PhantomData) } - /// Cast from ffi::PyObject ptr to a concrete object. + /// Creates a `Py` 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 { @@ -142,25 +151,16 @@ impl Py { pub fn clone_ref(&self, _py: Python) -> Py { unsafe { Py::from_borrowed_ptr(self.0) } } - - /// Casts the `Py` imstance to a concrete Python object type. - /// Fails with `PyDowncastError` if the object is not of the expected type. - #[inline] - pub fn cast_into(self, py: Python) -> Result - where D: PyDowncastInto - { - ::downcast_into(py, self) - } } impl Py 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`. pub fn new(py: Python, f: F) -> PyResult> - where F: FnOnce(::PyToken) -> T, - T: PyObjectAlloc + where F: FnOnce(::PyToken) -> T, + T: PyObjectAlloc { let ob = f(PyToken(PhantomData)); @@ -171,7 +171,7 @@ impl Py 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(py: Python, f: F) -> PyResult<&T> where F: FnOnce(::PyToken) -> T, @@ -185,7 +185,7 @@ impl Py 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(py: Python, f: F) -> PyResult<&mut T> where F: FnOnce(::PyToken) -> T, @@ -234,6 +234,7 @@ impl AsPyRef for Py where T: PyTypeInfo + PyNativeType { } impl ToPyObject for Py { + /// Converts `Py` instance -> PyObject. fn to_object(&self, py: Python) -> PyObject { unsafe { PyObject::from_borrowed_ptr(py, self.as_ptr()) diff --git a/src/lib.rs b/src/lib.rs index ee7d93d1..95d27f6f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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)] diff --git a/src/object.rs b/src/object.rs index cfb51ca9..5b0f4ffb 100644 --- a/src/object.rs +++ b/src/object.rs @@ -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] diff --git a/src/objectprotocol.rs b/src/objectprotocol.rs index c4d7e51d..1999554c 100644 --- a/src/objectprotocol.rs +++ b/src/objectprotocol.rs @@ -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 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 { diff --git a/src/objects/bytearray.rs b/src/objects/bytearray.rs index 05e74022..1f5746c0 100644 --- a/src/objects/bytearray.rs +++ b/src/objects/bytearray.rs @@ -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); diff --git a/src/objects/module.rs b/src/objects/module.rs index ecb216ec..ee454010 100644 --- a/src/objects/module.rs +++ b/src/objects/module.rs @@ -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); diff --git a/src/objects/slice.rs b/src/objects/slice.rs index 3df735a9..5156c859 100644 --- a/src/objects/slice.rs +++ b/src/objects/slice.rs @@ -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); diff --git a/src/objects/string.rs b/src/objects/string.rs index de4a5f38..2d0044dc 100644 --- a/src/objects/string.rs +++ b/src/objects/string.rs @@ -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); diff --git a/src/objects/string2.rs b/src/objects/string2.rs index 0ea39156..9991c500 100644 --- a/src/objects/string2.rs +++ b/src/objects/string2.rs @@ -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); diff --git a/src/objects/tuple.rs b/src/objects/tuple.rs index a4889465..909aff19 100644 --- a/src/objects/tuple.rs +++ b/src/objects/tuple.rs @@ -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); diff --git a/src/objects/typeobject.rs b/src/objects/typeobject.rs index 014f5a9b..41d08e4d 100644 --- a/src/objects/typeobject.rs +++ b/src/objects/typeobject.rs @@ -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); diff --git a/src/python.rs b/src/python.rs index 0404e6c1..3cc0c0d3 100644 --- a/src/python.rs +++ b/src/python.rs @@ -101,21 +101,6 @@ impl IntoPyPointer for Option where T: IntoPyPointer { } } -pub trait PyClone { - - fn clone_ref(&self, py: Python) -> Self; - -} - -impl PyClone for Option where T: PyClone { - fn clone_ref(&self, py: Python) -> Option { - 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, diff --git a/src/typeob.rs b/src/typeob.rs index 1284b604..5d41e4ea 100644 --- a/src/typeob.rs +++ b/src/typeob.rs @@ -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 { /// Allocates a new object (usually by calling ty->tp_alloc), @@ -79,11 +78,8 @@ pub trait PyObjectAlloc { unsafe fn dealloc(py: Python, obj: *mut ffi::PyObject); } -/// A Python object allocator that is usable as a base type for #[class] impl PyObjectAlloc 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 ::init_type(py); @@ -98,9 +94,6 @@ impl PyObjectAlloc 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(::offset()) as *mut T; std::ptr::drop_in_place(ptr); @@ -152,6 +145,7 @@ impl PyTypeObject for T where T: PyObjectAlloc + 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>