diff --git a/guide/src/class.md b/guide/src/class.md index 92721a848be..5ccafb4f036 100644 --- a/guide/src/class.md +++ b/guide/src/class.md @@ -122,10 +122,10 @@ like [std::cell::RefCell](https://doc.rust-lang.org/std/cell/struct.RefCell.html Users who are familiar with `RefCell` can use `PyCell` just like `RefCell`. -For users who doesn't know `RefCell` well, we repeat the Rust's borrowing rule here: +For users who doesn't know `RefCell` well, here we repeat the Rust's borrowing rule: - At any given time, you can have either (but not both of) one mutable reference or any number of immutable references. - References must always be valid. -`PyCell` ensures these borrowing rules by managing a reference counter. +`PyCell` ensures these borrowing rules by tracking references at runtime. TODO: link to the API document diff --git a/src/pycell.rs b/src/pycell.rs index 3d28a1c2020..802d4d90709 100644 --- a/src/pycell.rs +++ b/src/pycell.rs @@ -1,4 +1,4 @@ -//! Traits and structs for `#[pyclass]`. +//! Includes `PyCell` implementation. use crate::conversion::{AsPyPointer, FromPyPointer, ToPyObject}; use crate::pyclass_init::PyClassInitializer; use crate::pyclass_slots::{PyClassDict, PyClassWeakRef}; @@ -90,12 +90,19 @@ impl PyCellInner { } } -// TODO(kngwyu): Mutability example -/// `PyCell` represents the concrete layout of `T: PyClass` when it is converted -/// to a Python class. +/// `PyCell` is the container type for [`PyClass`](trait.PyClass.html). /// -/// You can use it to test your `#[pyclass]` correctly works. +/// From Python side, `PyCell` is the concrete layout of `T: PyClass` in the Python heap, +/// which means we can convert `*const PyClass` to `*mut ffi::PyObject`. /// +/// From Rust side, `PyCell` is the mutable container of `T`. +/// Since `PyCell` is always on the Python heap, we don't have the ownership of it. +/// Thus, to mutate the data behind `&PyCell` safely, we employ the +/// [Interior Mutability Pattern](https://doc.rust-lang.org/book/ch15-05-interior-mutability.html) +/// like [std::cell::RefCell](https://doc.rust-lang.org/std/cell/struct.RefCell.html). +/// +/// In most cases, `PyCell` is hidden behind `#[pymethods]`. +/// However, you can construct `&PyCell` directly to test your pyclass in Rust code. /// ``` /// # use pyo3::prelude::*; /// # use pyo3::{py_run, PyCell}; @@ -112,6 +119,7 @@ impl PyCellInner { /// author: "Philip Kindred Dick", /// }; /// let book_cell = PyCell::new(py, book).unwrap(); +/// // you can expose PyCell to Python snippets /// py_run!(py, book_cell, "assert book_cell.name[-6:] == 'Castle'"); /// ``` #[repr(C)] @@ -254,6 +262,9 @@ impl fmt::Debug for PyCell { } } +/// Wraps a borrowed reference to a value in a `PyCell`. +/// +/// See the [`PyCell`](struct.PyCell.html) documentation for more. pub struct PyRef<'p, T: PyClass> { inner: &'p PyCellInner, } @@ -319,6 +330,9 @@ impl fmt::Debug for PyRef<'_, T> { } } +/// Wraps a mutable borrowed reference to a value in a `PyCell`. +/// +/// See the [`PyCell`](struct.PyCell.html) documentation for more. pub struct PyRefMut<'p, T: PyClass> { inner: &'p PyCellInner, }