annotate rust/pyo3-sharedref/src/lib.rs @ 52640:78b2894cd58c

rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety We take the existing doc-comment from rust-cpython and make it compile (validated by `cargo test`). With the added explanations, the ordinary comment was no longer useful, we could therefore remove it. The new explanation stresses that "not leaking the internal faked reference" is definitely not enough, because the problem is about *all references* that can be derived from it. We ended up duplicating the explanation, because that is a way to ensure that people do not miss it. Also, it was a bit misleading that the previous example was for `try_borrow_mut()`, so we made a similar, simpler one for `try_borrow()`.
author Georges Racinet <georges.racinet@cloudcrane.io>
date Mon, 16 Dec 2024 13:08:55 +0100
parents 76a0bdb0e4ca
children 189491cea922
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
1 // Copyright (c) 2019 Raphaël Gomès <rgomes@octobus.net>,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
2 // Yuya Nishihara <yuya@tcha.org>
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
3 // 2024 Georges Racinet <georges.racinet@cloudcrane.io>
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
4 //
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
5 // Permission is hereby granted, free of charge, to any person obtaining a copy
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
6 // of this software and associated documentation files (the "Software"), to
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
7 // deal in the Software without restriction, including without limitation the
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
8 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
9 // sell copies of the Software, and to permit persons to whom the Software is
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
10 // furnished to do so, subject to the following conditions:
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
11 //
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
12 // The above copyright notice and this permission notice shall be included in
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
13 // all copies or substantial portions of the Software.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
14 //
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
20 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
21 // IN THE SOFTWARE.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
22
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
23 //! Utility to share Rust reference across Python objects.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
24
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
25 use pyo3::exceptions::PyRuntimeError;
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
26 use pyo3::prelude::*;
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
27
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
28 use std::ops::{Deref, DerefMut};
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
29 use std::sync::atomic::{AtomicUsize, Ordering};
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
30 use std::sync::{
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
31 RwLock, RwLockReadGuard, RwLockWriteGuard, TryLockError, TryLockResult,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
32 };
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
33
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
34 /// A mutable memory location shareable immutably across Python objects.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
35 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
36 /// This data structure is meant to be used as a field in a Python class
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
37 /// definition.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
38 /// It provides interior mutability in a way that allows it to be immutably
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
39 /// referenced by other Python objects defined in Rust than its owner, in
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
40 /// a more general form than references to the whole data.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
41 /// These immutable references are stored in the referencing Python objects as
52636
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
42 /// [`SharedByPyObject`] fields.
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
43 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
44 /// The primary use case is to implement a Python iterator over a Rust
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
45 /// iterator: since a Python object cannot hold a lifetime-bound object,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
46 /// `Iter<'a, T>` cannot be a data field of the Python iterator object.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
47 /// While `&'a T` can be replaced with [`std::sync::Arc`], this is typically
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
48 /// not suited for more complex objects that are created from such references
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
49 /// and re-expose the lifetime on their types, such as iterators.
52636
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
50 /// The [`PyShareableRef::share_immutable()`] and
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
51 /// [`SharedByPyObject::map()`] methods provide a way around this issue.
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
52 ///
52635
c25d345f5aa5 rust-pyo3-sharedref: renamed PySharedRefCell to PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52634
diff changeset
53 /// [`PyShareable`] is [`Sync`]. It works internally with locks and
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
54 /// a "generation" counter that keeps track of mutations.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
55 ///
52635
c25d345f5aa5 rust-pyo3-sharedref: renamed PySharedRefCell to PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52634
diff changeset
56 /// [`PyShareable`] is merely a data struct to be stored in its
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
57 /// owner Python object.
52635
c25d345f5aa5 rust-pyo3-sharedref: renamed PySharedRefCell to PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52634
diff changeset
58 /// Any further operation will be performed through [`PyShareableRef`], which
c25d345f5aa5 rust-pyo3-sharedref: renamed PySharedRefCell to PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52634
diff changeset
59 /// is a lifetime-bound reference to the [`PyShareable`].
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
60 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
61 /// # Example
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
62 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
63 /// ```
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
64 /// use pyo3::prelude::*;
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
65 /// use pyo3_sharedref::*;
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
66 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
67 /// use pyo3::ffi::c_str;
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
68 /// use pyo3::types::PyDictMethods;
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
69 /// use pyo3::types::{PyDict, PyTuple};
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
70 /// use std::collections::{hash_set::Iter as IterHashSet, HashSet};
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
71 /// use pyo3::exceptions::PyRuntimeError;
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
72 /// use std::ffi::CStr;
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
73 /// use std::vec::Vec;
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
74 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
75 /// #[pyclass(sequence)]
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
76 /// struct Set {
52635
c25d345f5aa5 rust-pyo3-sharedref: renamed PySharedRefCell to PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52634
diff changeset
77 /// rust_set: PyShareable<HashSet<i32>>,
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
78 /// }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
79 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
80 /// #[pymethods]
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
81 /// impl Set {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
82 /// #[new]
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
83 /// fn new(values: &Bound<'_, PyTuple>) -> PyResult<Self> {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
84 /// let as_vec = values.extract::<Vec<i32>>()?;
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
85 /// let s: HashSet<_> = as_vec.iter().copied().collect();
52633
d85514a88706 rust-pyo3-sharedref: reworked constructors
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52631
diff changeset
86 /// Ok(Self { rust_set: s.into() })
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
87 /// }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
88 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
89 /// fn __iter__(slf: &Bound<'_, Self>) -> SetIterator {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
90 /// SetIterator::new(slf)
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
91 /// }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
92 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
93 /// fn add(slf: &Bound<'_, Self>, i: i32) -> PyResult<()> {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
94 /// let rust_set = &slf.borrow().rust_set;
52633
d85514a88706 rust-pyo3-sharedref: reworked constructors
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52631
diff changeset
95 /// let shared_ref = unsafe { rust_set.borrow_with_owner(slf) };
52634
d1e304025b90 rust-pyo3-sharedref: replaced borrow/borrow_mut with RwLock namings
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52633
diff changeset
96 /// let mut set_ref = shared_ref.write();
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
97 /// set_ref.insert(i);
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
98 /// Ok(())
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
99 /// }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
100 /// }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
101 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
102 /// #[pyclass]
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
103 /// struct SetIterator {
52636
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
104 /// rust_iter: SharedByPyObject<IterHashSet<'static, i32>>,
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
105 /// }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
106 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
107 /// #[pymethods]
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
108 /// impl SetIterator {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
109 /// #[new]
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
110 /// fn new(s: &Bound<'_, Set>) -> Self {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
111 /// let py = s.py();
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
112 /// let rust_set = &s.borrow().rust_set;
52637
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
113 /// let iter = unsafe { rust_set.share_map(s, |o| o.iter()) };
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
114 /// Self {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
115 /// rust_iter: iter.into(),
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
116 /// }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
117 /// }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
118 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
119 /// fn __iter__(slf: PyRef<'_, Self>) -> PyRef<'_, Self> {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
120 /// slf
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
121 /// }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
122 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
123 /// fn __next__(mut slf: PyRefMut<'_, Self>) -> PyResult<Option<i32>> {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
124 /// let py = slf.py();
52636
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
125 /// let shared = &mut slf.rust_iter;
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
126 /// let mut inner = unsafe { shared.try_borrow_mut(py) }?;
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
127 /// Ok(inner.next().copied())
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
128 /// }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
129 /// }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
130 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
131 /// /// a shortcut similar to `[pyo3::py_run!]`, allowing inspection of PyErr
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
132 /// fn py_run(statement: &CStr, locals: &Bound<'_, PyDict>) -> PyResult<()> {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
133 /// locals.py().run(statement, None, Some(locals))
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
134 /// }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
135 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
136 /// # pyo3::prepare_freethreaded_python();
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
137 /// Python::with_gil(|py| {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
138 /// let tuple = PyTuple::new(py, vec![2, 1, 2])?;
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
139 /// let set = Bound::new(py, Set::new(&tuple)?)?;
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
140 /// let iter = Bound::new(py, Set::__iter__(&set))?;
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
141 /// let locals = PyDict::new(py);
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
142 /// locals.set_item("rust_set", set).unwrap();
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
143 /// locals.set_item("rust_iter", iter).unwrap();
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
144 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
145 /// /// iterating on our Rust set just works
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
146 /// py_run(
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
147 /// c_str!("assert sorted(i for i in rust_iter) == [1, 2]"),
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
148 /// &locals,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
149 /// )?;
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
150 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
151 /// /// however, if any mutation occurs on the Rust set, the iterator
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
152 /// /// becomes invalid. Attempts to use it raise `RuntimeError`.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
153 /// py_run(c_str!("rust_set.add(3)"), &locals)?;
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
154 /// let err = py_run(c_str!("next(rust_iter)"), &locals).unwrap_err();
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
155 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
156 /// let exc_repr = format!("{:?}", err.value(py));
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
157 /// assert_eq!(
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
158 /// exc_repr,
52636
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
159 /// "RuntimeError('Cannot access to shared reference after mutation')"
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
160 /// );
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
161 /// # Ok::<(), PyErr>(())
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
162 /// })
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
163 /// # .expect("This example should not return an error");
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
164 /// ```
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
165 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
166 /// The borrow rules are enforced dynamically in a similar manner to the
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
167 /// Python iterator.
52635
c25d345f5aa5 rust-pyo3-sharedref: renamed PySharedRefCell to PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52634
diff changeset
168 ///
c25d345f5aa5 rust-pyo3-sharedref: renamed PySharedRefCell to PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52634
diff changeset
169 /// [`PyShareable`] is merely a data struct to be stored in a Python object.
c25d345f5aa5 rust-pyo3-sharedref: renamed PySharedRefCell to PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52634
diff changeset
170 /// Any further operation will be performed through [PyShareableRef], which is
c25d345f5aa5 rust-pyo3-sharedref: renamed PySharedRefCell to PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52634
diff changeset
171 /// a lifetime-bound reference to the [`PyShareable`].
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
172 #[derive(Debug)]
52635
c25d345f5aa5 rust-pyo3-sharedref: renamed PySharedRefCell to PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52634
diff changeset
173 pub struct PyShareable<T: ?Sized> {
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
174 state: PySharedState,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
175 data: RwLock<T>,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
176 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
177
52637
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
178 impl<T: 'static> PyShareable<T> {
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
179 /// Borrows the shared data and its state, keeping a reference
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
180 /// on the owner Python object.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
181 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
182 /// # Safety
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
183 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
184 /// The `data` must be owned by the `owner`. Otherwise, calling
52636
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
185 /// `share_immutable()` on the shared ref would create an invalid
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
186 /// reference.
52633
d85514a88706 rust-pyo3-sharedref: reworked constructors
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52631
diff changeset
187 pub unsafe fn borrow_with_owner<'py>(
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
188 &'py self,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
189 owner: &'py Bound<'py, PyAny>,
52635
c25d345f5aa5 rust-pyo3-sharedref: renamed PySharedRefCell to PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52634
diff changeset
190 ) -> PyShareableRef<'py, T> {
c25d345f5aa5 rust-pyo3-sharedref: renamed PySharedRefCell to PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52634
diff changeset
191 PyShareableRef {
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
192 owner,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
193 state: &self.state,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
194 data: &self.data,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
195 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
196 }
52637
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
197
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
198 /// Share for other Python objects
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
199 ///
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
200 /// # Safety
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
201 ///
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
202 /// The `data` must be owned by the `owner`. Otherwise, the resulting
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
203 /// [`SharedByPyObject`] would contain an invalid reference.
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
204 pub unsafe fn share<'py>(
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
205 &'py self,
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
206 owner: &'py Bound<'py, PyAny>,
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
207 ) -> SharedByPyObject<&'static T> {
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
208 self.borrow_with_owner(owner).share_immutable()
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
209 }
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
210
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
211 /// Share for other Python objects, transforming the inner data
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
212 /// with a closure
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
213 ///
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
214 /// # Safety
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
215 ///
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
216 /// The `data` must be owned by the `owner`. Otherwise, the resulting
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
217 /// [`SharedByPyObject`] would contain an invalid reference.
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
218 pub unsafe fn share_map<'py, U>(
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
219 &'py self,
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
220 owner: &'py Bound<'py, PyAny>,
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
221 f: impl FnOnce(&'static T) -> U,
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
222 ) -> SharedByPyObject<U> {
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
223 self.share(owner).map(owner.py(), f)
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
224 }
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
225
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
226 /// # Safety
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
227 ///
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
228 /// The `data` must be owned by the `owner`. Otherwise, the resulting
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
229 /// [`SharedByPyObject`] would contain an invalid reference.
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
230 pub unsafe fn try_share<'py>(
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
231 &'py self,
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
232 owner: &'py Bound<'py, PyAny>,
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
233 ) -> Result<SharedByPyObject<&'static T>, TryShareError> {
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
234 self.borrow_with_owner(owner).try_share_immutable()
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
235 }
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
236
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
237 /// # Safety
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
238 ///
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
239 /// The `data` must be owned by the `owner`. Otherwise, the resulting
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
240 /// [`SharedByPyObject`] would contain an invalid reference.
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
241 pub unsafe fn try_share_map<'py, U>(
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
242 &'py self,
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
243 owner: &'py Bound<'py, PyAny>,
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
244 f: impl FnOnce(&'static T) -> U,
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
245 ) -> Result<SharedByPyObject<U>, TryShareError> {
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
246 Ok(self.try_share(owner)?.map(owner.py(), f))
a945845137b1 rust-pyo3-sharedref: share/map methods on PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52636
diff changeset
247 }
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
248 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
249
52635
c25d345f5aa5 rust-pyo3-sharedref: renamed PySharedRefCell to PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52634
diff changeset
250 impl<T> From<T> for PyShareable<T> {
52633
d85514a88706 rust-pyo3-sharedref: reworked constructors
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52631
diff changeset
251 fn from(value: T) -> Self {
d85514a88706 rust-pyo3-sharedref: reworked constructors
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52631
diff changeset
252 Self {
d85514a88706 rust-pyo3-sharedref: reworked constructors
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52631
diff changeset
253 state: PySharedState::new(),
d85514a88706 rust-pyo3-sharedref: reworked constructors
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52631
diff changeset
254 data: value.into(),
d85514a88706 rust-pyo3-sharedref: reworked constructors
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52631
diff changeset
255 }
d85514a88706 rust-pyo3-sharedref: reworked constructors
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52631
diff changeset
256 }
d85514a88706 rust-pyo3-sharedref: reworked constructors
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52631
diff changeset
257 }
d85514a88706 rust-pyo3-sharedref: reworked constructors
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52631
diff changeset
258
52636
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
259 /// Errors that can happen in `share_immutable()`
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
260 #[derive(Debug, PartialEq, Eq)]
52636
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
261 pub enum TryShareError {
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
262 /// The inner lock is poisoned and we do not want to implement recovery
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
263 InnerLockPoisoned,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
264 /// The inner lock would block and we are expecting to take it immediately
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
265 InnerLockWouldBlock,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
266 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
267
52636
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
268 impl<T> From<TryLockError<T>> for TryShareError {
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
269 fn from(e: TryLockError<T>) -> Self {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
270 match e {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
271 TryLockError::Poisoned(_) => Self::InnerLockPoisoned,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
272 TryLockError::WouldBlock => Self::InnerLockWouldBlock,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
273 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
274 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
275 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
276
52635
c25d345f5aa5 rust-pyo3-sharedref: renamed PySharedRefCell to PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52634
diff changeset
277 /// A reference to [`PyShareable`] and its legit owner Python object.
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
278 ///
52635
c25d345f5aa5 rust-pyo3-sharedref: renamed PySharedRefCell to PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52634
diff changeset
279 /// This is a lifetime-bound reference to the [PyShareable] data field,
c25d345f5aa5 rust-pyo3-sharedref: renamed PySharedRefCell to PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52634
diff changeset
280 /// and could be created by an automatically generated accessor when
c25d345f5aa5 rust-pyo3-sharedref: renamed PySharedRefCell to PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52634
diff changeset
281 /// we make one.
c25d345f5aa5 rust-pyo3-sharedref: renamed PySharedRefCell to PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52634
diff changeset
282 pub struct PyShareableRef<'py, T: 'py + ?Sized> {
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
283 owner: &'py Bound<'py, PyAny>,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
284 state: &'py PySharedState,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
285 data: &'py RwLock<T>, // TODO perhaps this needs Pin
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
286 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
287
52635
c25d345f5aa5 rust-pyo3-sharedref: renamed PySharedRefCell to PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52634
diff changeset
288 impl<'py, T: ?Sized> PyShareableRef<'py, T> {
52634
d1e304025b90 rust-pyo3-sharedref: replaced borrow/borrow_mut with RwLock namings
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52633
diff changeset
289 /// Take the lock on the wrapped value for read-only operations.
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
290 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
291 /// # Panics
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
292 ///
52634
d1e304025b90 rust-pyo3-sharedref: replaced borrow/borrow_mut with RwLock namings
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52633
diff changeset
293 /// Panics if the lock is currently held for write operations.
d1e304025b90 rust-pyo3-sharedref: replaced borrow/borrow_mut with RwLock namings
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52633
diff changeset
294 pub fn read(&self) -> RwLockReadGuard<'py, T> {
d1e304025b90 rust-pyo3-sharedref: replaced borrow/borrow_mut with RwLock namings
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52633
diff changeset
295 self.try_read().expect("already mutably borrowed")
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
296 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
297
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
298 /// Immutably borrows the wrapped value, returning an error if the value
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
299 /// is currently mutably borrowed.
52634
d1e304025b90 rust-pyo3-sharedref: replaced borrow/borrow_mut with RwLock namings
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52633
diff changeset
300 pub fn try_read(&self) -> TryLockResult<RwLockReadGuard<'py, T>> {
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
301 // state isn't involved since
52634
d1e304025b90 rust-pyo3-sharedref: replaced borrow/borrow_mut with RwLock namings
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52633
diff changeset
302 // - data.try_read() would fail if self is mutably borrowed,
d1e304025b90 rust-pyo3-sharedref: replaced borrow/borrow_mut with RwLock namings
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52633
diff changeset
303 // - and data.try_write() would fail while self is borrowed.
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
304 self.data.try_read()
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
305 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
306
52634
d1e304025b90 rust-pyo3-sharedref: replaced borrow/borrow_mut with RwLock namings
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52633
diff changeset
307 /// Take the lock on the wrapped value for write operations.
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
308 ///
52636
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
309 /// Any existing shared references will be invalidated.
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
310 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
311 /// # Panics
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
312 ///
52634
d1e304025b90 rust-pyo3-sharedref: replaced borrow/borrow_mut with RwLock namings
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52633
diff changeset
313 /// Panics if the lock is currently held.
d1e304025b90 rust-pyo3-sharedref: replaced borrow/borrow_mut with RwLock namings
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52633
diff changeset
314 pub fn write(&self) -> RwLockWriteGuard<'py, T> {
d1e304025b90 rust-pyo3-sharedref: replaced borrow/borrow_mut with RwLock namings
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52633
diff changeset
315 self.try_write().expect("already borrowed")
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
316 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
317
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
318 /// Mutably borrows the wrapped value, returning an error if the value
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
319 /// is currently borrowed.
52634
d1e304025b90 rust-pyo3-sharedref: replaced borrow/borrow_mut with RwLock namings
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52633
diff changeset
320 pub fn try_write(&self) -> TryLockResult<RwLockWriteGuard<'py, T>> {
52636
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
321 // the value may be immutably borrowed through SharedByPyObject
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
322 if self.state.current_borrow_count(self.py()) > 0 {
52636
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
323 // propagate borrow-by-shared state to data to get BorrowMutError
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
324 let _dummy = self.data.read();
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
325 let _unused = self.data.try_write()?;
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
326 unreachable!("BorrowMutError should have been returned");
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
327 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
328
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
329 let data_ref = self.data.try_write()?;
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
330 self.state.increment_generation(self.py());
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
331 Ok(data_ref)
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
332 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
333
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
334 /// Creates an immutable reference which is not bound to lifetime.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
335 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
336 /// # Panics
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
337 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
338 /// Panics if the value is currently mutably borrowed.
52636
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
339 pub fn share_immutable(&self) -> SharedByPyObject<&'static T> {
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
340 self.try_share_immutable()
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
341 .expect("already mutably borrowed")
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
342 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
343
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
344 /// Creates an immutable reference which is not bound to lifetime,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
345 /// returning an error if the value is currently mutably borrowed.
52636
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
346 pub fn try_share_immutable(
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
347 &self,
52636
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
348 ) -> Result<SharedByPyObject<&'static T>, TryShareError> {
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
349 // make sure self.data isn't mutably borrowed; otherwise the
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
350 // generation number wouldn't be trusted.
52634
d1e304025b90 rust-pyo3-sharedref: replaced borrow/borrow_mut with RwLock namings
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52633
diff changeset
351 let data_ref = self.try_read()?;
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
352
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
353 // keep reference to the owner so the data and state are alive,
52634
d1e304025b90 rust-pyo3-sharedref: replaced borrow/borrow_mut with RwLock namings
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52633
diff changeset
354 // but the data pointer can be invalidated by write().
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
355 // the state wouldn't since it is immutable.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
356 let state_ptr: *const PySharedState = self.state;
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
357 let data_ptr: *const T = &*data_ref;
52636
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
358 Ok(SharedByPyObject::<&'static T> {
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
359 owner: self.owner.clone().unbind(),
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
360 state: unsafe { &*state_ptr },
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
361 generation: self.state.current_generation(self.py()),
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
362 data: unsafe { &*data_ptr },
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
363 })
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
364 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
365
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
366 /// Retrieve the GIL handle
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
367 fn py(&self) -> Python<'py> {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
368 // Since this is a smart pointer implying the GIL lifetime,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
369 // we might as well use `assume_gil_acquired`, but the method
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
370 // of `Bound` does it for us.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
371 self.owner.py()
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
372 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
373 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
374
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
375 /// The shared state between Python and Rust
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
376 ///
52635
c25d345f5aa5 rust-pyo3-sharedref: renamed PySharedRefCell to PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52634
diff changeset
377 /// `PySharedState` is owned by `PyShareable`, and is shared across its
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
378 /// derived references. The consistency of these references are guaranteed
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
379 /// as follows:
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
380 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
381 /// - The immutability of `PycCass` object fields. Any mutation of
52635
c25d345f5aa5 rust-pyo3-sharedref: renamed PySharedRefCell to PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52634
diff changeset
382 /// [`PyShareable`] is allowed only through its `write()`.
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
383 /// - The `py: Python<'_>` token, which makes sure that any data access is
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
384 /// synchronized by the GIL.
52635
c25d345f5aa5 rust-pyo3-sharedref: renamed PySharedRefCell to PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52634
diff changeset
385 /// - The underlying `RefCell`, which prevents `PyShareable` value from being
52636
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
386 /// directly borrowed or shared while it is mutably borrowed.
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
387 /// - The `borrow_count`, which is the number of references borrowed from
52636
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
388 /// `SharedByPyObject`. Just like `RefCell`, mutation is prohibited while
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
389 /// `SharedByPyObject` is borrowed.
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
390 /// - The `generation` counter, which increments on `write()`.
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
391 /// `SharedByPyObject`
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
392 #[derive(Debug)]
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
393 struct PySharedState {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
394 // The counter variable could be Cell<usize> since any operation on
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
395 // PySharedState is synchronized by the GIL, but being "atomic" makes
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
396 // PySharedState inherently Sync. The ordering requirement doesn't
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
397 // matter thanks to the GIL. That's why Ordering::Relaxed is used
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
398 // everywhere.
52636
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
399 /// The number of immutable references borrowed through shared reference.
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
400 borrow_count: AtomicUsize,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
401 /// The mutation counter of the underlying value.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
402 generation: AtomicUsize,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
403 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
404
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
405 impl PySharedState {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
406 const fn new() -> PySharedState {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
407 PySharedState {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
408 borrow_count: AtomicUsize::new(0),
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
409 generation: AtomicUsize::new(0),
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
410 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
411 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
412
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
413 fn current_borrow_count(&self, _py: Python) -> usize {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
414 self.borrow_count.load(Ordering::Relaxed)
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
415 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
416
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
417 fn increase_borrow_count(&self, _py: Python) {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
418 // this wraps around if there are more than usize::MAX borrowed
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
419 // references, which shouldn't happen due to memory limit.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
420 self.borrow_count.fetch_add(1, Ordering::Relaxed);
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
421 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
422
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
423 fn decrease_borrow_count(&self, _py: Python) {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
424 let prev_count = self.borrow_count.fetch_sub(1, Ordering::Relaxed);
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
425 assert!(prev_count > 0);
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
426 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
427
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
428 fn current_generation(&self, _py: Python) -> usize {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
429 self.generation.load(Ordering::Relaxed)
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
430 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
431
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
432 fn increment_generation(&self, py: Python) {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
433 assert_eq!(self.current_borrow_count(py), 0);
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
434 // this wraps around to the same value if mutably borrowed
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
435 // usize::MAX times, which wouldn't happen in practice.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
436 self.generation.fetch_add(1, Ordering::Relaxed);
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
437 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
438 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
439
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
440 /// Helper to keep the borrow count updated while the shared object is
52635
c25d345f5aa5 rust-pyo3-sharedref: renamed PySharedRefCell to PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52634
diff changeset
441 /// immutably borrowed without using the `RwLock` interface.
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
442 struct BorrowPyShared<'a> {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
443 py: Python<'a>,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
444 state: &'a PySharedState,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
445 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
446
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
447 impl<'a> BorrowPyShared<'a> {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
448 fn new(py: Python<'a>, state: &'a PySharedState) -> BorrowPyShared<'a> {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
449 state.increase_borrow_count(py);
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
450 BorrowPyShared { py, state }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
451 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
452 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
453
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
454 impl<'a> Drop for BorrowPyShared<'a> {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
455 fn drop(&mut self) {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
456 self.state.decrease_borrow_count(self.py);
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
457 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
458 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
459
52635
c25d345f5aa5 rust-pyo3-sharedref: renamed PySharedRefCell to PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52634
diff changeset
460 /// An immutable reference to [`PyShareable`] value, not bound to lifetime.
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
461 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
462 /// The reference will be invalidated once the original value is mutably
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
463 /// borrowed.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
464 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
465 /// # Safety
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
466 ///
52636
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
467 /// Even though [`SharedByPyObject`] tries to enforce the real lifetime of the
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
468 /// underlying object, the object having the artificial `'static` lifetime
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
469 /// may be exposed to your Rust code. You must be careful to not make a bare
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
470 /// reference outlive the actual object lifetime.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
471 ///
52640
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
472 /// See [`Self::try_borrow_mut()`] for an example of the kind of trouble that
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
473 /// can arise.
52636
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
474 pub struct SharedByPyObject<T: ?Sized> {
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
475 owner: PyObject,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
476 state: &'static PySharedState,
52636
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
477 /// Generation counter of data `T` captured when SharedByPyObject is
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
478 /// created.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
479 generation: usize,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
480 /// Underlying data of artificial lifetime, which is valid only when
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
481 /// state.generation == self.generation.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
482 data: T,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
483 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
484
52636
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
485 // DO NOT implement Deref for SharedByPyObject<T>! Dereferencing
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
486 // SharedByPyObject without taking Python GIL wouldn't be safe. Also, the
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
487 // underling reference is invalid if generation != state.generation.
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
488
52636
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
489 impl<T: ?Sized> SharedByPyObject<T> {
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
490 // No panicking version of borrow() and borrow_mut() are implemented
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
491 // because the underlying value is supposed to be mutated in Python
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
492 // world, and the Rust library designer can't prevent it.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
493
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
494 /// Immutably borrows the wrapped value.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
495 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
496 /// Borrowing fails if the underlying reference has been invalidated.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
497 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
498 /// # Safety
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
499 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
500 /// The lifetime of the innermost object is artificial. Do not obtain and
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
501 /// copy it out of the borrow scope.
52640
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
502 ///
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
503 /// The lifetime of the innermost object is artificial. Do not obtain and
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
504 /// copy it out of the borrow scope. More generally, the returned `&T`
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
505 /// may have a method returning an inner reference, which would typically
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
506 /// be `'static` and not safe without the `owner` Python object, so the
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
507 /// problem might be less obvious than in the example below.
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
508 ///
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
509 /// The following example does compile and illustrates the problem.
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
510 /// In this case, the data is a `Vec<String>` and the leaked reference
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
511 /// `&'static str`, which points to some element of the vector. This
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
512 /// illustrates that the leaks are not necessarily to the whole of the
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
513 /// shared data.
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
514 ///
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
515 /// ```no_run
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
516 /// # use pyo3::prelude::*;
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
517 /// # use pyo3_sharedref::PyShareable;
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
518 /// #[pyclass]
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
519 /// struct Owner {
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
520 /// value: PyShareable<Vec<String>>
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
521 /// }
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
522 ///
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
523 /// #[pymethods]
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
524 /// impl Owner {
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
525 /// #[new]
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
526 /// fn new(s: &str) -> Self {
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
527 /// let split: Vec<_> = s.split(' ').map(String::from).collect();
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
528 /// Self { value: split.into() }
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
529 /// }
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
530 /// }
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
531 ///
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
532 /// const EMPTY: &'static str = "";
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
533 ///
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
534 /// let mut outer = EMPTY;
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
535 /// Python::with_gil(|py| {
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
536 /// let owner = Bound::new(py, Owner::new("hello")).unwrap();
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
537 /// let shareable = &owner.borrow().value;
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
538 /// let shared = unsafe { shareable.share(&owner) };
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
539 /// {
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
540 /// let inner = unsafe { shared.try_borrow(py) }.unwrap();
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
541 /// outer = &inner[0]; // Bad, &'static str does outlive the scope
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
542 /// }
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
543 /// });
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
544 /// ```
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
545 pub unsafe fn try_borrow<'a>(
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
546 &'a self,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
547 py: Python<'a>,
52636
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
548 ) -> PyResult<SharedByPyObjectRef<'a, T>> {
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
549 self.validate_generation(py)?;
52636
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
550 Ok(SharedByPyObjectRef {
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
551 _borrow: BorrowPyShared::new(py, self.state),
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
552 data: &self.data,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
553 })
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
554 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
555
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
556 /// Mutably borrows the wrapped value.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
557 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
558 /// Borrowing fails if the underlying reference has been invalidated.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
559 ///
52640
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
560 /// Typically `T` would be an iterator obtained by the [`Self::map`]
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
561 /// method.
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
562 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
563 /// # Safety
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
564 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
565 /// The lifetime of the innermost object is artificial. Do not obtain and
52640
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
566 /// copy it out of the borrow scope. More generally, the returned `&T`
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
567 /// may have a method returning an inner reference, which would typically
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
568 /// be `'static` and not safe without the `owner` Python object, so the
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
569 /// problem might be less obvious than in the example below.
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
570 ///
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
571 /// The following example does compile and illustrates the problem.
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
572 /// It is very close to the example given in [`Self::try_borrow`] because
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
573 /// the problem does not arise from the mutability of the reference
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
574 /// returned by this function.
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
575 ///
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
576 /// In this case, the data is a `Vec<String>` and the leaked reference
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
577 /// `&'static str`, which points to some element of the vector. This
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
578 /// illustrates that the leaks are not necessarily to the whole of the
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
579 /// shared data.
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
580 ///
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
581 /// ```no_run
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
582 /// # use pyo3::prelude::*;
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
583 /// # use pyo3_sharedref::PyShareable;
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
584 /// #[pyclass]
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
585 /// struct Owner {
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
586 /// value: PyShareable<Vec<String>>
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
587 /// }
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
588 ///
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
589 /// #[pymethods]
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
590 /// impl Owner {
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
591 /// #[new]
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
592 /// fn new(s: &str) -> Self {
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
593 /// let split: Vec<_> = s.split(' ').map(String::from).collect();
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
594 /// Self { value: split.into() }
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
595 /// }
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
596 /// }
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
597 ///
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
598 /// const EMPTY: &'static str = "";
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
599 ///
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
600 /// let mut outer = EMPTY;
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
601 /// Python::with_gil(|py| {
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
602 /// let owner = Bound::new(py, Owner::new("hello")).unwrap();
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
603 /// let shareable = &owner.borrow().value;
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
604 /// let shared = unsafe { shareable.share(&owner) };
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
605 /// let mut shared_iter = unsafe { shared.map(py, |o| o.iter()) };
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
606 /// {
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
607 /// let mut iter = unsafe {
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
608 /// shared_iter.try_borrow_mut(py)
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
609 /// }.unwrap();
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
610 /// let inner = iter.next().unwrap(); // Good, in borrow scope
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
611 /// outer = inner; // Bad, &'static str does outlive the scope
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
612 /// }
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
613 /// });
78b2894cd58c rust-pyo3-sharedref: demonstrate SharedByPyObject borrow unsafety
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52639
diff changeset
614 /// ```
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
615 pub unsafe fn try_borrow_mut<'a>(
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
616 &'a mut self,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
617 py: Python<'a>,
52636
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
618 ) -> PyResult<SharedByPyObjectRefMut<'a, T>> {
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
619 self.validate_generation(py)?;
52636
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
620 Ok(SharedByPyObjectRefMut {
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
621 _borrow: BorrowPyShared::new(py, self.state),
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
622 data: &mut self.data,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
623 })
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
624 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
625
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
626 fn validate_generation(&self, py: Python) -> PyResult<()> {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
627 if self.state.current_generation(py) == self.generation {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
628 Ok(())
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
629 } else {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
630 Err(PyRuntimeError::new_err(
52636
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
631 "Cannot access to shared reference after mutation",
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
632 ))
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
633 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
634 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
635 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
636
52636
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
637 impl<T> SharedByPyObject<T> {
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
638 /// Converts the inner value by the given function.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
639 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
640 /// Typically `T` is a static reference to a collection, and `U` is an
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
641 /// iterator of that collection.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
642 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
643 /// # Panics
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
644 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
645 /// Panics if the underlying reference has been invalidated.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
646 ///
52636
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
647 /// This is typically called immediately after the `SharedByPyObject` is
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
648 /// obtained. At this time, the reference must be valid and no panic
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
649 /// would occur.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
650 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
651 /// # Safety
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
652 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
653 /// The lifetime of the object passed in to the function `f` is artificial.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
654 /// It's typically a static reference, but is valid only while the
52636
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
655 /// corresponding `SharedByPyObject` is alive. Do not copy it out of the
52639
76a0bdb0e4ca rust-pyo3-sharedref: demonstrating unsafety of map()
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52637
diff changeset
656 /// function call. For example, the following does compile:
76a0bdb0e4ca rust-pyo3-sharedref: demonstrating unsafety of map()
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52637
diff changeset
657 ///
76a0bdb0e4ca rust-pyo3-sharedref: demonstrating unsafety of map()
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52637
diff changeset
658 /// ```no_run
76a0bdb0e4ca rust-pyo3-sharedref: demonstrating unsafety of map()
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52637
diff changeset
659 /// # use pyo3::prelude::*;
76a0bdb0e4ca rust-pyo3-sharedref: demonstrating unsafety of map()
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52637
diff changeset
660 /// # use pyo3_sharedref::PyShareable;
76a0bdb0e4ca rust-pyo3-sharedref: demonstrating unsafety of map()
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52637
diff changeset
661 /// #[pyclass]
76a0bdb0e4ca rust-pyo3-sharedref: demonstrating unsafety of map()
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52637
diff changeset
662 /// struct Owner {
76a0bdb0e4ca rust-pyo3-sharedref: demonstrating unsafety of map()
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52637
diff changeset
663 /// value: PyShareable<String>
76a0bdb0e4ca rust-pyo3-sharedref: demonstrating unsafety of map()
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52637
diff changeset
664 /// }
76a0bdb0e4ca rust-pyo3-sharedref: demonstrating unsafety of map()
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52637
diff changeset
665 ///
76a0bdb0e4ca rust-pyo3-sharedref: demonstrating unsafety of map()
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52637
diff changeset
666 /// #[pymethods]
76a0bdb0e4ca rust-pyo3-sharedref: demonstrating unsafety of map()
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52637
diff changeset
667 /// impl Owner {
76a0bdb0e4ca rust-pyo3-sharedref: demonstrating unsafety of map()
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52637
diff changeset
668 /// #[new]
76a0bdb0e4ca rust-pyo3-sharedref: demonstrating unsafety of map()
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52637
diff changeset
669 /// fn new(s: &str) -> Self {
76a0bdb0e4ca rust-pyo3-sharedref: demonstrating unsafety of map()
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52637
diff changeset
670 /// Self { value: s.to_owned().into() }
76a0bdb0e4ca rust-pyo3-sharedref: demonstrating unsafety of map()
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52637
diff changeset
671 /// }
76a0bdb0e4ca rust-pyo3-sharedref: demonstrating unsafety of map()
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52637
diff changeset
672 /// }
76a0bdb0e4ca rust-pyo3-sharedref: demonstrating unsafety of map()
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52637
diff changeset
673 ///
76a0bdb0e4ca rust-pyo3-sharedref: demonstrating unsafety of map()
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52637
diff changeset
674 /// const EMPTY: &'static str = "";
76a0bdb0e4ca rust-pyo3-sharedref: demonstrating unsafety of map()
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52637
diff changeset
675 ///
76a0bdb0e4ca rust-pyo3-sharedref: demonstrating unsafety of map()
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52637
diff changeset
676 /// let mut outer = EMPTY;
76a0bdb0e4ca rust-pyo3-sharedref: demonstrating unsafety of map()
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52637
diff changeset
677 /// Python::with_gil(|py| {
76a0bdb0e4ca rust-pyo3-sharedref: demonstrating unsafety of map()
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52637
diff changeset
678 /// let owner = Bound::new(py, Owner::new("hello")).unwrap();
76a0bdb0e4ca rust-pyo3-sharedref: demonstrating unsafety of map()
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52637
diff changeset
679 /// let shareable = &owner.borrow().value;
76a0bdb0e4ca rust-pyo3-sharedref: demonstrating unsafety of map()
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52637
diff changeset
680 /// let shared = unsafe { shareable.share(&owner) };
76a0bdb0e4ca rust-pyo3-sharedref: demonstrating unsafety of map()
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52637
diff changeset
681 ///
76a0bdb0e4ca rust-pyo3-sharedref: demonstrating unsafety of map()
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52637
diff changeset
682 /// unsafe { shared.map(py, |o| { outer = o }) }; // Bad
76a0bdb0e4ca rust-pyo3-sharedref: demonstrating unsafety of map()
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52637
diff changeset
683 /// });
76a0bdb0e4ca rust-pyo3-sharedref: demonstrating unsafety of map()
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52637
diff changeset
684 /// ```
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
685 pub unsafe fn map<U>(
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
686 self,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
687 py: Python,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
688 f: impl FnOnce(T) -> U,
52636
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
689 ) -> SharedByPyObject<U> {
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
690 // Needs to test the generation value to make sure self.data reference
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
691 // is still intact.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
692 self.validate_generation(py)
52636
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
693 .expect("map() over invalidated shared reference");
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
694
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
695 // f() could make the self.data outlive. That's why map() is unsafe.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
696 // In order to make this function safe, maybe we'll need a way to
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
697 // temporarily restrict the lifetime of self.data and translate the
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
698 // returned object back to Something<'static>.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
699 let new_data = f(self.data);
52636
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
700 SharedByPyObject {
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
701 owner: self.owner,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
702 state: self.state,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
703 generation: self.generation,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
704 data: new_data,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
705 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
706 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
707 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
708
52636
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
709 /// An immutably borrowed reference to a shared value.
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
710 pub struct SharedByPyObjectRef<'a, T: 'a + ?Sized> {
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
711 _borrow: BorrowPyShared<'a>,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
712 data: &'a T,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
713 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
714
52636
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
715 impl<'a, T: ?Sized> Deref for SharedByPyObjectRef<'a, T> {
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
716 type Target = T;
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
717
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
718 fn deref(&self) -> &T {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
719 self.data
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
720 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
721 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
722
52636
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
723 /// A mutably borrowed reference to a shared value.
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
724 pub struct SharedByPyObjectRefMut<'a, T: 'a + ?Sized> {
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
725 _borrow: BorrowPyShared<'a>,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
726 data: &'a mut T,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
727 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
728
52636
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
729 impl<'a, T: ?Sized> Deref for SharedByPyObjectRefMut<'a, T> {
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
730 type Target = T;
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
731
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
732 fn deref(&self) -> &T {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
733 self.data
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
734 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
735 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
736
52636
4a73eb3923ac rust-pyo3-sharedref: renamed UnsafePyLeaked to SharedByPyObject
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52635
diff changeset
737 impl<'a, T: ?Sized> DerefMut for SharedByPyObjectRefMut<'a, T> {
52631
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
738 fn deref_mut(&mut self) -> &mut T {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
739 self.data
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
740 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
741 }