annotate rust/pyo3-sharedref/src/lib.rs @ 52610:c25d345f5aa5

rust-pyo3-sharedref: renamed PySharedRefCell to PyShareable There were two problems with the naming: - the PyO3 version is not based on `RefCell`. Rather than calling this `SomethingRwLock` we decided it was best to consider this an implementation detail. We mentioned it in the doc earlier on, but that is merely just bringing some reassuring context to the reader, not intended to be a needed structural explanation. - the data is not shared: it is ready to be shared To keep the changeset readable, we only make the very minimal changes to the tests to make them pass, i.e., not renaming local variables (this will be done in a later move).
author Georges Racinet <georges.racinet@cloudcrane.io>
date Sun, 15 Dec 2024 15:03:27 +0100
parents d1e304025b90
children 4a73eb3923ac
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
52606
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
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
42 /// [`UnsafePyLeaked`] fields.
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.
52610
c25d345f5aa5 rust-pyo3-sharedref: renamed PySharedRefCell to PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52609
diff changeset
50 /// The [`PyShareableRef::leak_immutable()`] and [`UnsafePyLeaked::map()`]
c25d345f5aa5 rust-pyo3-sharedref: renamed PySharedRefCell to PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52609
diff changeset
51 /// methods provide a way around this issue.
52606
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
52 ///
52610
c25d345f5aa5 rust-pyo3-sharedref: renamed PySharedRefCell to PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52609
diff changeset
53 /// [`PyShareable`] is [`Sync`]. It works internally with locks and
52606
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 ///
52610
c25d345f5aa5 rust-pyo3-sharedref: renamed PySharedRefCell to PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52609
diff changeset
56 /// [`PyShareable`] is merely a data struct to be stored in its
52606
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
57 /// owner Python object.
52610
c25d345f5aa5 rust-pyo3-sharedref: renamed PySharedRefCell to PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52609
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: 52609
diff changeset
59 /// is a lifetime-bound reference to the [`PyShareable`].
52606
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 {
52610
c25d345f5aa5 rust-pyo3-sharedref: renamed PySharedRefCell to PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52609
diff changeset
77 /// rust_set: PyShareable<HashSet<i32>>,
52606
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();
52608
d85514a88706 rust-pyo3-sharedref: reworked constructors
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52606
diff changeset
86 /// Ok(Self { rust_set: s.into() })
52606
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;
52608
d85514a88706 rust-pyo3-sharedref: reworked constructors
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52606
diff changeset
95 /// let shared_ref = unsafe { rust_set.borrow_with_owner(slf) };
52609
d1e304025b90 rust-pyo3-sharedref: replaced borrow/borrow_mut with RwLock namings
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52608
diff changeset
96 /// let mut set_ref = shared_ref.write();
52606
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 {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
104 /// rust_iter: UnsafePyLeaked<IterHashSet<'static, i32>>,
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;
52608
d85514a88706 rust-pyo3-sharedref: reworked constructors
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52606
diff changeset
113 /// let shared_ref = unsafe { rust_set.borrow_with_owner(s) };
52606
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
114 /// let leaked_set = shared_ref.leak_immutable();
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
115 /// let iter = unsafe { leaked_set.map(py, |o| o.iter()) };
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
116 /// Self {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
117 /// rust_iter: iter.into(),
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 /// }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
120 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
121 /// fn __iter__(slf: PyRef<'_, Self>) -> PyRef<'_, Self> {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
122 /// slf
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
123 /// }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
124 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
125 /// 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
126 /// let py = slf.py();
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
127 /// let leaked = &mut slf.rust_iter;
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
128 /// let mut inner = unsafe { leaked.try_borrow_mut(py) }?;
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
129 /// Ok(inner.next().copied())
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 /// }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
132 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
133 /// /// 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
134 /// 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
135 /// locals.py().run(statement, None, Some(locals))
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
136 /// }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
137 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
138 /// # pyo3::prepare_freethreaded_python();
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
139 /// Python::with_gil(|py| {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
140 /// 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
141 /// let set = Bound::new(py, Set::new(&tuple)?)?;
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
142 /// let iter = Bound::new(py, Set::__iter__(&set))?;
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
143 /// let locals = PyDict::new(py);
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
144 /// locals.set_item("rust_set", set).unwrap();
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
145 /// locals.set_item("rust_iter", iter).unwrap();
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
146 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
147 /// /// iterating on our Rust set just works
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
148 /// py_run(
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
149 /// 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
150 /// &locals,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
151 /// )?;
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
152 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
153 /// /// 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
154 /// /// becomes invalid. Attempts to use it raise `RuntimeError`.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
155 /// 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
156 /// 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
157 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
158 /// let exc_repr = format!("{:?}", err.value(py));
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
159 /// assert_eq!(
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
160 /// exc_repr,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
161 /// "RuntimeError('Cannot access to leaked reference after mutation')"
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 /// # Ok::<(), PyErr>(())
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 /// # .expect("This example should not return an error");
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
166 /// ```
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
167 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
168 /// 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
169 /// Python iterator.
52610
c25d345f5aa5 rust-pyo3-sharedref: renamed PySharedRefCell to PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52609
diff changeset
170 ///
c25d345f5aa5 rust-pyo3-sharedref: renamed PySharedRefCell to PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52609
diff changeset
171 /// [`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: 52609
diff changeset
172 /// 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: 52609
diff changeset
173 /// a lifetime-bound reference to the [`PyShareable`].
52606
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
174 #[derive(Debug)]
52610
c25d345f5aa5 rust-pyo3-sharedref: renamed PySharedRefCell to PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52609
diff changeset
175 pub struct PyShareable<T: ?Sized> {
52606
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
176 state: PySharedState,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
177 data: RwLock<T>,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
178 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
179
52610
c25d345f5aa5 rust-pyo3-sharedref: renamed PySharedRefCell to PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52609
diff changeset
180 impl<T> PyShareable<T> {
52606
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
181 /// 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
182 /// on the owner Python object.
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 /// # Safety
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
185 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
186 /// The `data` must be owned by the `owner`. Otherwise, calling
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
187 /// `leak_immutable()` on the shared ref would create an invalid reference.
52608
d85514a88706 rust-pyo3-sharedref: reworked constructors
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52606
diff changeset
188 pub unsafe fn borrow_with_owner<'py>(
52606
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
189 &'py self,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
190 owner: &'py Bound<'py, PyAny>,
52610
c25d345f5aa5 rust-pyo3-sharedref: renamed PySharedRefCell to PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52609
diff changeset
191 ) -> PyShareableRef<'py, T> {
c25d345f5aa5 rust-pyo3-sharedref: renamed PySharedRefCell to PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52609
diff changeset
192 PyShareableRef {
52606
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
193 owner,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
194 state: &self.state,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
195 data: &self.data,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
196 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
197 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
198 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
199
52610
c25d345f5aa5 rust-pyo3-sharedref: renamed PySharedRefCell to PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52609
diff changeset
200 impl<T> From<T> for PyShareable<T> {
52608
d85514a88706 rust-pyo3-sharedref: reworked constructors
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52606
diff changeset
201 fn from(value: T) -> Self {
d85514a88706 rust-pyo3-sharedref: reworked constructors
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52606
diff changeset
202 Self {
d85514a88706 rust-pyo3-sharedref: reworked constructors
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52606
diff changeset
203 state: PySharedState::new(),
d85514a88706 rust-pyo3-sharedref: reworked constructors
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52606
diff changeset
204 data: value.into(),
d85514a88706 rust-pyo3-sharedref: reworked constructors
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52606
diff changeset
205 }
d85514a88706 rust-pyo3-sharedref: reworked constructors
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52606
diff changeset
206 }
d85514a88706 rust-pyo3-sharedref: reworked constructors
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52606
diff changeset
207 }
d85514a88706 rust-pyo3-sharedref: reworked constructors
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52606
diff changeset
208
52606
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
209 /// Errors that can happen in `leak_immutable()`
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
210 #[derive(Debug, PartialEq, Eq)]
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
211 pub enum TryLeakError {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
212 /// 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
213 InnerLockPoisoned,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
214 /// 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
215 InnerLockWouldBlock,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
216 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
217
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
218 impl<T> From<TryLockError<T>> for TryLeakError {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
219 fn from(e: TryLockError<T>) -> Self {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
220 match e {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
221 TryLockError::Poisoned(_) => Self::InnerLockPoisoned,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
222 TryLockError::WouldBlock => Self::InnerLockWouldBlock,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
223 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
224 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
225 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
226
52610
c25d345f5aa5 rust-pyo3-sharedref: renamed PySharedRefCell to PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52609
diff changeset
227 /// A reference to [`PyShareable`] and its legit owner Python object.
52606
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
228 ///
52610
c25d345f5aa5 rust-pyo3-sharedref: renamed PySharedRefCell to PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52609
diff changeset
229 /// 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: 52609
diff changeset
230 /// 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: 52609
diff changeset
231 /// we make one.
c25d345f5aa5 rust-pyo3-sharedref: renamed PySharedRefCell to PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52609
diff changeset
232 pub struct PyShareableRef<'py, T: 'py + ?Sized> {
52606
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
233 owner: &'py Bound<'py, PyAny>,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
234 state: &'py PySharedState,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
235 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
236 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
237
52610
c25d345f5aa5 rust-pyo3-sharedref: renamed PySharedRefCell to PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52609
diff changeset
238 impl<'py, T: ?Sized> PyShareableRef<'py, T> {
52609
d1e304025b90 rust-pyo3-sharedref: replaced borrow/borrow_mut with RwLock namings
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52608
diff changeset
239 /// Take the lock on the wrapped value for read-only operations.
52606
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
240 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
241 /// # Panics
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
242 ///
52609
d1e304025b90 rust-pyo3-sharedref: replaced borrow/borrow_mut with RwLock namings
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52608
diff changeset
243 /// 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: 52608
diff changeset
244 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: 52608
diff changeset
245 self.try_read().expect("already mutably borrowed")
52606
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
246 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
247
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
248 /// 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
249 /// is currently mutably borrowed.
52609
d1e304025b90 rust-pyo3-sharedref: replaced borrow/borrow_mut with RwLock namings
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52608
diff changeset
250 pub fn try_read(&self) -> TryLockResult<RwLockReadGuard<'py, T>> {
52606
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
251 // state isn't involved since
52609
d1e304025b90 rust-pyo3-sharedref: replaced borrow/borrow_mut with RwLock namings
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52608
diff changeset
252 // - 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: 52608
diff changeset
253 // - and data.try_write() would fail while self is borrowed.
52606
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
254 self.data.try_read()
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
255 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
256
52609
d1e304025b90 rust-pyo3-sharedref: replaced borrow/borrow_mut with RwLock namings
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52608
diff changeset
257 /// Take the lock on the wrapped value for write operations.
52606
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
258 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
259 /// Any existing leaked references will be invalidated.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
260 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
261 /// # Panics
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
262 ///
52609
d1e304025b90 rust-pyo3-sharedref: replaced borrow/borrow_mut with RwLock namings
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52608
diff changeset
263 /// 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: 52608
diff changeset
264 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: 52608
diff changeset
265 self.try_write().expect("already borrowed")
52606
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
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
268 /// 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
269 /// is currently borrowed.
52609
d1e304025b90 rust-pyo3-sharedref: replaced borrow/borrow_mut with RwLock namings
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52608
diff changeset
270 pub fn try_write(&self) -> TryLockResult<RwLockWriteGuard<'py, T>> {
52606
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
271 // the value may be immutably borrowed through UnsafePyLeaked
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
272 if self.state.current_borrow_count(self.py()) > 0 {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
273 // propagate borrow-by-leaked state to data to get BorrowMutError
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
274 let _dummy = self.data.read();
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
275 let _unused = self.data.try_write()?;
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
276 unreachable!("BorrowMutError should have been returned");
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
277 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
278
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
279 let data_ref = self.data.try_write()?;
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
280 self.state.increment_generation(self.py());
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
281 Ok(data_ref)
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
282 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
283
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
284 /// 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
285 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
286 /// # Panics
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
287 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
288 /// Panics if the value is currently mutably borrowed.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
289 pub fn leak_immutable(&self) -> UnsafePyLeaked<&'static T> {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
290 self.try_leak_immutable().expect("already mutably borrowed")
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
291 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
292
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
293 /// 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
294 /// returning an error if the value is currently mutably borrowed.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
295 pub fn try_leak_immutable(
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
296 &self,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
297 ) -> Result<UnsafePyLeaked<&'static T>, TryLeakError> {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
298 // 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
299 // generation number wouldn't be trusted.
52609
d1e304025b90 rust-pyo3-sharedref: replaced borrow/borrow_mut with RwLock namings
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52608
diff changeset
300 let data_ref = self.try_read()?;
52606
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
301
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
302 // keep reference to the owner so the data and state are alive,
52609
d1e304025b90 rust-pyo3-sharedref: replaced borrow/borrow_mut with RwLock namings
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52608
diff changeset
303 // but the data pointer can be invalidated by write().
52606
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
304 // the state wouldn't since it is immutable.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
305 let state_ptr: *const PySharedState = self.state;
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
306 let data_ptr: *const T = &*data_ref;
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
307 Ok(UnsafePyLeaked::<&'static T> {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
308 owner: self.owner.clone().unbind(),
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
309 state: unsafe { &*state_ptr },
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
310 generation: self.state.current_generation(self.py()),
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
311 data: unsafe { &*data_ptr },
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
312 })
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
313 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
314
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
315 /// Retrieve the GIL handle
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
316 fn py(&self) -> Python<'py> {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
317 // 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
318 // 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
319 // of `Bound` does it for us.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
320 self.owner.py()
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
321 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
322 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
323
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
324 /// The shared state between Python and Rust
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
325 ///
52610
c25d345f5aa5 rust-pyo3-sharedref: renamed PySharedRefCell to PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52609
diff changeset
326 /// `PySharedState` is owned by `PyShareable`, and is shared across its
52606
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
327 /// 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
328 /// as follows:
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
329 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
330 /// - The immutability of `PycCass` object fields. Any mutation of
52610
c25d345f5aa5 rust-pyo3-sharedref: renamed PySharedRefCell to PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52609
diff changeset
331 /// [`PyShareable`] is allowed only through its `write()`.
52606
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
332 /// - 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
333 /// synchronized by the GIL.
52610
c25d345f5aa5 rust-pyo3-sharedref: renamed PySharedRefCell to PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52609
diff changeset
334 /// - The underlying `RefCell`, which prevents `PyShareable` value from being
c25d345f5aa5 rust-pyo3-sharedref: renamed PySharedRefCell to PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52609
diff changeset
335 /// directly borrowed or leaked while it is mutably borrowed.
52606
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
336 /// - The `borrow_count`, which is the number of references borrowed from
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
337 /// `UnsafePyLeaked`. Just like `RefCell`, mutation is prohibited while
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
338 /// `UnsafePyLeaked` is borrowed.
52609
d1e304025b90 rust-pyo3-sharedref: replaced borrow/borrow_mut with RwLock namings
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52608
diff changeset
339 /// - The `generation` counter, which increments on `write()`. `UnsafePyLeaked`
d1e304025b90 rust-pyo3-sharedref: replaced borrow/borrow_mut with RwLock namings
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52608
diff changeset
340 /// reference is valid only if the `current_generation()` equals to the
d1e304025b90 rust-pyo3-sharedref: replaced borrow/borrow_mut with RwLock namings
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52608
diff changeset
341 /// `generation` at the time of `leak_immutable()`.
52606
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
342 #[derive(Debug)]
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
343 struct PySharedState {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
344 // 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
345 // 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
346 // PySharedState inherently Sync. The ordering requirement doesn't
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
347 // 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
348 // everywhere.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
349 /// The number of immutable references borrowed through leaked reference.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
350 borrow_count: AtomicUsize,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
351 /// The mutation counter of the underlying value.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
352 generation: AtomicUsize,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
353 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
354
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
355 impl PySharedState {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
356 const fn new() -> PySharedState {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
357 PySharedState {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
358 borrow_count: AtomicUsize::new(0),
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
359 generation: AtomicUsize::new(0),
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
360 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
361 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
362
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
363 fn current_borrow_count(&self, _py: Python) -> usize {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
364 self.borrow_count.load(Ordering::Relaxed)
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
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
367 fn increase_borrow_count(&self, _py: Python) {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
368 // 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
369 // 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
370 self.borrow_count.fetch_add(1, Ordering::Relaxed);
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
371 }
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 fn decrease_borrow_count(&self, _py: Python) {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
374 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
375 assert!(prev_count > 0);
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
376 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
377
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
378 fn current_generation(&self, _py: Python) -> usize {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
379 self.generation.load(Ordering::Relaxed)
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
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
382 fn increment_generation(&self, py: Python) {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
383 assert_eq!(self.current_borrow_count(py), 0);
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
384 // 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
385 // 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
386 self.generation.fetch_add(1, Ordering::Relaxed);
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
387 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
388 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
389
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
390 /// Helper to keep the borrow count updated while the shared object is
52610
c25d345f5aa5 rust-pyo3-sharedref: renamed PySharedRefCell to PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52609
diff changeset
391 /// immutably borrowed without using the `RwLock` interface.
52606
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
392 struct BorrowPyShared<'a> {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
393 py: Python<'a>,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
394 state: &'a PySharedState,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
395 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
396
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
397 impl<'a> BorrowPyShared<'a> {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
398 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
399 state.increase_borrow_count(py);
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
400 BorrowPyShared { py, state }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
401 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
402 }
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 impl<'a> Drop for BorrowPyShared<'a> {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
405 fn drop(&mut self) {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
406 self.state.decrease_borrow_count(self.py);
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
407 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
408 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
409
52610
c25d345f5aa5 rust-pyo3-sharedref: renamed PySharedRefCell to PyShareable
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52609
diff changeset
410 /// An immutable reference to [`PyShareable`] value, not bound to lifetime.
52606
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 /// 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
413 /// borrowed.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
414 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
415 /// # Safety
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 /// Even though [`UnsafePyLeaked`] tries to enforce the real lifetime of the
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
418 /// 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
419 /// 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
420 /// reference outlive the actual object lifetime.
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 /// TODO these two examples would not compile if [`UnsafePyLeaked::map()`]
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
423 /// would only accept [`Fn`] instead of [`FnOnce`].
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
424 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
425 /// ```ignore
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
426 /// let outer;
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
427 /// unsafe { leaked.map(py, |o| { outer = o }) }; // Bad
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
428 /// ```
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
429 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
430 /// ```ignore
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
431 /// let outer;
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
432 /// let mut leaked_iter = leaked.map(py, |o| o.iter());
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
433 /// {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
434 /// let mut iter = unsafe { leaked_iter.try_borrow_mut(py) };
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
435 /// let inner = iter.next(); // Good, in borrow scope
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
436 /// outer = inner; // Bad, &'static T may outlive
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 pub struct UnsafePyLeaked<T: ?Sized> {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
440 owner: PyObject,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
441 state: &'static PySharedState,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
442 /// Generation counter of data `T` captured when UnsafePyLeaked is
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
443 /// created.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
444 generation: usize,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
445 /// 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
446 /// state.generation == self.generation.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
447 data: T,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
448 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
449
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
450 // DO NOT implement Deref for UnsafePyLeaked<T>! Dereferencing UnsafePyLeaked
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
451 // without taking Python GIL wouldn't be safe. Also, the underling reference
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
452 // is invalid if generation != state.generation.
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<T: ?Sized> UnsafePyLeaked<T> {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
455 // 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
456 // 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
457 // 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
458
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
459 // try_borrow() and try_borrow_mut() are unsafe because self.data may
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
460 // have a function returning the inner &'static reference.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
461 // If T is &'static U, its lifetime can be easily coerced to &'a U, but
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
462 // how could we do that for Whatever<'static> in general?
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
463
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
464 /// Immutably borrows the wrapped value.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
465 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
466 /// 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
467 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
468 /// # Safety
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
469 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
470 /// 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
471 /// copy it out of the borrow scope.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
472 pub unsafe fn try_borrow<'a>(
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
473 &'a self,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
474 py: Python<'a>,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
475 ) -> PyResult<PyLeakedRef<'a, T>> {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
476 self.validate_generation(py)?;
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
477 Ok(PyLeakedRef {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
478 _borrow: BorrowPyShared::new(py, self.state),
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
479 data: &self.data,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
480 })
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
481 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
482
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
483 /// Mutably borrows the wrapped value.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
484 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
485 /// 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
486 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
487 /// Typically `T` is an iterator. If `T` is an immutable reference,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
488 /// `get_mut()` is useless since the inner value can't be mutated.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
489 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
490 /// # Safety
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
491 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
492 /// 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
493 /// copy it out of the borrow scope.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
494 pub unsafe fn try_borrow_mut<'a>(
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
495 &'a mut self,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
496 py: Python<'a>,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
497 ) -> PyResult<PyLeakedRefMut<'a, T>> {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
498 self.validate_generation(py)?;
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
499 Ok(PyLeakedRefMut {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
500 _borrow: BorrowPyShared::new(py, self.state),
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
501 data: &mut self.data,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
502 })
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
503 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
504
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
505 fn validate_generation(&self, py: Python) -> PyResult<()> {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
506 if self.state.current_generation(py) == self.generation {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
507 Ok(())
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
508 } else {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
509 Err(PyRuntimeError::new_err(
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
510 "Cannot access to leaked reference after mutation",
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
511 ))
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
512 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
513 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
514 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
515
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
516 impl<T> UnsafePyLeaked<T> {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
517 /// Converts the inner value by the given function.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
518 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
519 /// 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
520 /// iterator of that collection.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
521 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
522 /// # Panics
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
523 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
524 /// Panics if the underlying reference has been invalidated.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
525 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
526 /// This is typically called immediately after the `UnsafePyLeaked` is
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
527 /// 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
528 /// would occur.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
529 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
530 /// # Safety
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
531 ///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
532 /// 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
533 /// It's typically a static reference, but is valid only while the
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
534 /// corresponding `UnsafePyLeaked` is alive. Do not copy it out of the
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
535 /// function call.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
536 /// TODO would it be safe with `f: impl Fn(T) -> U` then?
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
537 pub unsafe fn map<U>(
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
538 self,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
539 py: Python,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
540 f: impl FnOnce(T) -> U,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
541 ) -> UnsafePyLeaked<U> {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
542 // 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
543 // is still intact.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
544 self.validate_generation(py)
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
545 .expect("map() over invalidated leaked reference");
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
546
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
547 // 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
548 // 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
549 // 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
550 // returned object back to Something<'static>.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
551 let new_data = f(self.data);
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
552 UnsafePyLeaked {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
553 owner: self.owner,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
554 state: self.state,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
555 generation: self.generation,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
556 data: new_data,
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 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
559 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
560
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
561 /// An immutably borrowed reference to a leaked value.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
562 pub struct PyLeakedRef<'a, T: 'a + ?Sized> {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
563 _borrow: BorrowPyShared<'a>,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
564 data: &'a T,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
565 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
566
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
567 impl<'a, T: ?Sized> Deref for PyLeakedRef<'a, T> {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
568 type Target = T;
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
569
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
570 fn deref(&self) -> &T {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
571 self.data
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
572 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
573 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
574
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
575 /// A mutably borrowed reference to a leaked value.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
576 pub struct PyLeakedRefMut<'a, T: 'a + ?Sized> {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
577 _borrow: BorrowPyShared<'a>,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
578 data: &'a mut T,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
579 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
580
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
581 impl<'a, T: ?Sized> Deref for PyLeakedRefMut<'a, T> {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
582 type Target = T;
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
583
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
584 fn deref(&self) -> &T {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
585 self.data
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
586 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
587 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
588
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
589 impl<'a, T: ?Sized> DerefMut for PyLeakedRefMut<'a, T> {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
590 fn deref_mut(&mut self) -> &mut T {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
591 self.data
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
592 }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
593 }