Skip to content

Commit 0e3f7cb

Browse files
committed
More documents for PyCell
1 parent d3d61c6 commit 0e3f7cb

File tree

1 file changed

+125
-10
lines changed

1 file changed

+125
-10
lines changed

src/pycell.rs

Lines changed: 125 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,11 @@ impl<T: PyClass> PyCellInner<T> {
101101
/// [Interior Mutability Pattern](https://doc.rust-lang.org/book/ch15-05-interior-mutability.html)
102102
/// like [std::cell::RefCell](https://doc.rust-lang.org/std/cell/struct.RefCell.html).
103103
///
104+
/// # Examples
105+
///
104106
/// In most cases, `PyCell` is hidden behind `#[pymethods]`.
105107
/// However, you can construct `&PyCell` directly to test your pyclass in Rust code.
108+
///
106109
/// ```
107110
/// # use pyo3::prelude::*;
108111
/// #[pyclass]
@@ -121,23 +124,25 @@ impl<T: PyClass> PyCellInner<T> {
121124
/// // you can expose PyCell to Python snippets
122125
/// pyo3::py_run!(py, book_cell, "assert book_cell.name[-6:] == 'Castle'");
123126
/// ```
124-
/// You can also use `slf: &PyCell<Self>` as an alternative `self` receiver of `#[pymethod]`.
127+
/// You can use `slf: &PyCell<Self>` as an alternative `self` receiver of `#[pymethod]`,
128+
/// though you rarely need it.
125129
/// ```
126130
/// # use pyo3::prelude::*;
127131
/// use std::collections::HashMap;
128132
/// #[pyclass]
129133
/// #[derive(Default)]
130134
/// struct Counter {
131-
/// data: HashMap<String, usize>,
135+
/// counter: HashMap<String, usize>
132136
/// }
133137
/// #[pymethods]
134138
/// impl Counter {
139+
/// // You can use &mut self here, but now we use &PyCell for demonstration
135140
/// fn increment(slf: &PyCell<Self>, name: String) -> PyResult<usize> {
136141
/// let mut slf_mut = slf.try_borrow_mut()?;
137-
/// // Now a mutable reference exists so we cannot another one
142+
/// // Now a mutable reference exists so we cannot get another one
138143
/// assert!(slf.try_borrow().is_err());
139144
/// assert!(slf.try_borrow_mut().is_err());
140-
/// let counter = slf_mut.data.entry(name).or_insert(0);
145+
/// let counter = slf_mut.counter.entry(name).or_insert(0);
141146
/// *counter += 1;
142147
/// Ok(*counter)
143148
/// }
@@ -156,6 +161,7 @@ pub struct PyCell<T: PyClass> {
156161

157162
impl<T: PyClass> PyCell<T> {
158163
/// Make new `PyCell` on the Python heap and returns the reference of it.
164+
///
159165
pub fn new(py: Python, value: impl Into<PyClassInitializer<T>>) -> PyResult<&Self>
160166
where
161167
T::BaseLayout: crate::type_object::PyObjectSizedLayout<T::BaseType>,
@@ -167,14 +173,50 @@ impl<T: PyClass> PyCell<T> {
167173
}
168174
}
169175

176+
/// Immutably borrows the value `T`. This borrow lasts untill the returned `PyRef` exists.
177+
///
178+
/// # Panics
179+
///
180+
/// Panics if the value is currently mutably borrowed. For a non-panicking variant, use
181+
/// [`try_borrow`](#method.try_borrow).
170182
pub fn borrow(&self) -> PyRef<'_, T> {
171183
self.try_borrow().expect("Already mutably borrowed")
172184
}
173185

186+
/// Mutably borrows the value `T`. This borrow lasts untill the returned `PyRefMut` exists.
187+
///
188+
/// # Panics
189+
///
190+
/// Panics if the value is currently mutably borrowed. For a non-panicking variant, use
191+
/// [`try_borrow_mut`](#method.try_borrow_mut).
174192
pub fn borrow_mut(&self) -> PyRefMut<'_, T> {
175193
self.try_borrow_mut().expect("Already borrowed")
176194
}
177195

196+
/// Immutably borrows the value `T`, returning an error if the value is currently
197+
/// mutably borrowed. This borrow lasts untill the returned `PyRef` exists.
198+
///
199+
/// This is the non-panicking variant of [`borrow`](#method.borrow).
200+
///
201+
/// # Examples
202+
///
203+
/// ```
204+
/// # use pyo3::prelude::*;
205+
/// #[pyclass]
206+
/// struct Class {}
207+
/// let gil = Python::acquire_gil();
208+
/// let py = gil.python();
209+
/// let c = PyCell::new(py, Class {}).unwrap();
210+
/// {
211+
/// let m = c.borrow_mut();
212+
/// assert!(c.try_borrow().is_err());
213+
/// }
214+
///
215+
/// {
216+
/// let m = c.borrow();
217+
/// assert!(c.try_borrow().is_ok());
218+
/// }
219+
/// ```
178220
pub fn try_borrow(&self) -> Result<PyRef<'_, T>, PyBorrowError> {
179221
let flag = self.inner.get_borrow_flag();
180222
if flag == BorrowFlag::HAS_MUTABLE_BORROW {
@@ -185,6 +227,27 @@ impl<T: PyClass> PyCell<T> {
185227
}
186228
}
187229

230+
/// Mutably borrows the value `T`, returning an error if the value is currently borrowed.
231+
/// This borrow lasts untill the returned `PyRefMut` exists.
232+
///
233+
/// This is the non-panicking variant of [`borrow_mut`](#method.borrow_mut).
234+
///
235+
/// # Examples
236+
///
237+
/// ```
238+
/// # use pyo3::prelude::*;
239+
/// #[pyclass]
240+
/// struct Class {}
241+
/// let gil = Python::acquire_gil();
242+
/// let py = gil.python();
243+
/// let c = PyCell::new(py, Class {}).unwrap();
244+
/// {
245+
/// let m = c.borrow();
246+
/// assert!(c.try_borrow_mut().is_err());
247+
/// }
248+
///
249+
/// assert!(c.try_borrow_mut().is_ok());
250+
/// ```
188251
pub fn try_borrow_mut(&self) -> Result<PyRefMut<'_, T>, PyBorrowMutError> {
189252
if self.inner.get_borrow_flag() != BorrowFlag::UNUSED {
190253
Err(PyBorrowMutError { _private: () })
@@ -194,6 +257,35 @@ impl<T: PyClass> PyCell<T> {
194257
}
195258
}
196259

260+
/// Immutably borrows the value `T`, returning an error if the value is
261+
/// currently mutably borrowed.
262+
///
263+
/// # Safety
264+
///
265+
/// This method is unsafe because it does not return a `PyRef`,
266+
/// thus leaving the borrow flag untouched. Mutably borrowing the `PyCell`
267+
/// while the reference returned by this method is alive is undefined behaviour.
268+
///
269+
/// # Examples
270+
///
271+
/// ```
272+
/// # use pyo3::prelude::*;
273+
/// #[pyclass]
274+
/// struct Class {}
275+
/// let gil = Python::acquire_gil();
276+
/// let py = gil.python();
277+
/// let c = PyCell::new(py, Class {}).unwrap();
278+
///
279+
/// {
280+
/// let m = c.borrow_mut();
281+
/// assert!(unsafe { c.try_borrow_unguarded() }.is_err());
282+
/// }
283+
///
284+
/// {
285+
/// let m = c.borrow();
286+
/// assert!(unsafe { c.try_borrow_unguarded() }.is_ok());
287+
/// }
288+
/// ```
197289
pub unsafe fn try_borrow_unguarded(&self) -> Result<&T, PyBorrowError> {
198290
if self.inner.get_borrow_flag() == BorrowFlag::HAS_MUTABLE_BORROW {
199291
Err(PyBorrowError { _private: () })
@@ -202,12 +294,35 @@ impl<T: PyClass> PyCell<T> {
202294
}
203295
}
204296

205-
pub unsafe fn try_borrow_mut_unguarded(&self) -> Result<&mut T, PyBorrowMutError> {
206-
if self.inner.get_borrow_flag() != BorrowFlag::UNUSED {
207-
Err(PyBorrowMutError { _private: () })
208-
} else {
209-
Ok(&mut *self.inner.value.get())
210-
}
297+
/// Replaces the wrapped value with a new one, returning the old value,
298+
///
299+
/// # Panics
300+
///
301+
/// Panics if the value is currently borrowed.
302+
#[inline]
303+
pub fn replace(&self, t: T) -> T {
304+
std::mem::replace(&mut *self.borrow_mut(), t)
305+
}
306+
307+
/// Replaces the wrapped value with a new one computed from `f`, returning the old value.
308+
///
309+
/// # Panics
310+
///
311+
/// Panics if the value is currently borrowed.
312+
pub fn replace_with<F: FnOnce(&mut T) -> T>(&self, f: F) -> T {
313+
let mut_borrow = &mut *self.borrow_mut();
314+
let replacement = f(mut_borrow);
315+
std::mem::replace(mut_borrow, replacement)
316+
}
317+
318+
/// Swaps the wrapped value of `self` with the wrapped value of `other`.
319+
///
320+
/// # Panics
321+
///
322+
/// Panics if the value in either `PyCell` is currently borrowed.
323+
#[inline]
324+
pub fn swap(&self, other: &Self) {
325+
std::mem::swap(&mut *self.borrow_mut(), &mut *other.borrow_mut())
211326
}
212327

213328
pub(crate) unsafe fn internal_new(py: Python) -> PyResult<*mut Self>

0 commit comments

Comments
 (0)