Mercurial > public > mercurial-scm > hg-stable
annotate rust/pyo3-sharedref/src/lib.rs @ 52633:d85514a88706
rust-pyo3-sharedref: reworked constructors
We had previously duplicated the `new` associated function on
`PySharedRef` with a method on `PySharedRefCell`: in `rust-cpython`,
the former was hidden by the accessor defined by the `py_class!` macro,
which we did not port yet.
On `PySharedRefCell` itself, replacing the `new` associated function
by the `From` trait carries all the needed semantics, and has the
advantage of less repetititons of the type name, which will help
with further refactorings and renamings.
author | Georges Racinet <georges.racinet@cloudcrane.io> |
---|---|
date | Sun, 15 Dec 2024 14:42:53 +0100 |
parents | be765f6797cc |
children | d1e304025b90 |
rev | line source |
---|---|
52631
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
1 // Copyright (c) 2019 Raphaël Gomès <rgomes@octobus.net>, |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
2 // Yuya Nishihara <yuya@tcha.org> |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
3 // 2024 Georges Racinet <georges.racinet@cloudcrane.io> |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
4 // |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
5 // Permission is hereby granted, free of charge, to any person obtaining a copy |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
6 // of this software and associated documentation files (the "Software"), to |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
7 // deal in the Software without restriction, including without limitation the |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
8 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
9 // sell copies of the Software, and to permit persons to whom the Software is |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
10 // furnished to do so, subject to the following conditions: |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
11 // |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
12 // The above copyright notice and this permission notice shall be included in |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
13 // all copies or substantial portions of the Software. |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
14 // |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
20 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
21 // IN THE SOFTWARE. |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
22 |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
23 //! Utility to share Rust reference across Python objects. |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
24 |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
25 use pyo3::exceptions::PyRuntimeError; |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
26 use pyo3::prelude::*; |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
27 |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
28 use std::ops::{Deref, DerefMut}; |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
29 use std::sync::atomic::{AtomicUsize, Ordering}; |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
30 use std::sync::{ |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
31 RwLock, RwLockReadGuard, RwLockWriteGuard, TryLockError, TryLockResult, |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
32 }; |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
33 |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
34 /// A mutable memory location shareable immutably across Python objects. |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
35 /// |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
36 /// This data structure is meant to be used as a field in a Python class |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
37 /// definition. |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
38 /// It provides interior mutability in a way that allows it to be immutably |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
39 /// referenced by other Python objects defined in Rust than its owner, in |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
40 /// a more general form than references to the whole data. |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
41 /// These immutable references are stored in the referencing Python objects as |
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. |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
50 /// The [`PySharedRef::leak_immutable()`] and [`UnsafePyLeaked::map()`] methods |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
51 /// provide a way around this issue. |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
52 /// |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
53 /// [`PySharedRefCell`] is [`Sync`]. It works internally with locks and |
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 /// |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
56 /// [`PySharedRefCell`] is merely a data struct to be stored in its |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
57 /// owner Python object. |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
58 /// Any further operation will be performed through [`PySharedRef`], which is |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
59 /// a lifetime-bound reference to the [`PySharedRefCell`]. |
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 { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
77 /// rust_set: PySharedRefCell<HashSet<i32>>, |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
78 /// } |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
79 /// |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
80 /// #[pymethods] |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
81 /// impl Set { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
82 /// #[new] |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
83 /// fn new(values: &Bound<'_, PyTuple>) -> PyResult<Self> { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
84 /// let as_vec = values.extract::<Vec<i32>>()?; |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
85 /// let s: HashSet<_> = as_vec.iter().copied().collect(); |
52633
d85514a88706
rust-pyo3-sharedref: reworked constructors
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
52631
diff
changeset
|
86 /// Ok(Self { rust_set: s.into() }) |
52631
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
87 /// } |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
88 /// |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
89 /// fn __iter__(slf: &Bound<'_, Self>) -> SetIterator { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
90 /// SetIterator::new(slf) |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
91 /// } |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
92 /// |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
93 /// fn add(slf: &Bound<'_, Self>, i: i32) -> PyResult<()> { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
94 /// let rust_set = &slf.borrow().rust_set; |
52633
d85514a88706
rust-pyo3-sharedref: reworked constructors
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
52631
diff
changeset
|
95 /// let shared_ref = unsafe { rust_set.borrow_with_owner(slf) }; |
52631
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
96 /// let mut set_ref = shared_ref.borrow_mut(); |
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; |
52633
d85514a88706
rust-pyo3-sharedref: reworked constructors
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
52631
diff
changeset
|
113 /// let shared_ref = unsafe { rust_set.borrow_with_owner(s) }; |
52631
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. |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
170 #[derive(Debug)] |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
171 pub struct PySharedRefCell<T: ?Sized> { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
172 state: PySharedState, |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
173 data: RwLock<T>, |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
174 } |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
175 |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
176 impl<T> PySharedRefCell<T> { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
177 /// 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
|
178 /// on the owner Python object. |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
179 /// |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
180 /// # Safety |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
181 /// |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
182 /// 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
|
183 /// `leak_immutable()` on the shared ref would create an invalid reference. |
52633
d85514a88706
rust-pyo3-sharedref: reworked constructors
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
52631
diff
changeset
|
184 pub unsafe fn borrow_with_owner<'py>( |
52631
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
185 &'py self, |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
186 owner: &'py Bound<'py, PyAny>, |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
187 ) -> PySharedRef<'py, T> { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
188 PySharedRef { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
189 owner, |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
190 state: &self.state, |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
191 data: &self.data, |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
192 } |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
193 } |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
194 } |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
195 |
52633
d85514a88706
rust-pyo3-sharedref: reworked constructors
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
52631
diff
changeset
|
196 impl<T> From<T> for PySharedRefCell<T> { |
d85514a88706
rust-pyo3-sharedref: reworked constructors
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
52631
diff
changeset
|
197 fn from(value: T) -> Self { |
d85514a88706
rust-pyo3-sharedref: reworked constructors
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
52631
diff
changeset
|
198 Self { |
d85514a88706
rust-pyo3-sharedref: reworked constructors
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
52631
diff
changeset
|
199 state: PySharedState::new(), |
d85514a88706
rust-pyo3-sharedref: reworked constructors
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
52631
diff
changeset
|
200 data: value.into(), |
d85514a88706
rust-pyo3-sharedref: reworked constructors
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
52631
diff
changeset
|
201 } |
d85514a88706
rust-pyo3-sharedref: reworked constructors
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
52631
diff
changeset
|
202 } |
d85514a88706
rust-pyo3-sharedref: reworked constructors
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
52631
diff
changeset
|
203 } |
d85514a88706
rust-pyo3-sharedref: reworked constructors
Georges Racinet <georges.racinet@cloudcrane.io>
parents:
52631
diff
changeset
|
204 |
52631
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
205 /// Errors that can happen in `leak_immutable()` |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
206 #[derive(Debug, PartialEq, Eq)] |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
207 pub enum TryLeakError { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
208 /// 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
|
209 InnerLockPoisoned, |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
210 /// 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
|
211 InnerLockWouldBlock, |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
212 } |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
213 |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
214 impl<T> From<TryLockError<T>> for TryLeakError { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
215 fn from(e: TryLockError<T>) -> Self { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
216 match e { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
217 TryLockError::Poisoned(_) => Self::InnerLockPoisoned, |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
218 TryLockError::WouldBlock => Self::InnerLockWouldBlock, |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
219 } |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
220 } |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
221 } |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
222 |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
223 /// A reference to [`PySharedRefCell`] owned by a Python object. |
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 /// This is a lifetime-bound reference to the [`PySharedRefCell`] data field. |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
226 pub struct PySharedRef<'py, T: 'py + ?Sized> { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
227 owner: &'py Bound<'py, PyAny>, |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
228 state: &'py PySharedState, |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
229 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
|
230 } |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
231 |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
232 impl<'py, T: ?Sized> PySharedRef<'py, T> { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
233 /// Immutably borrows the wrapped value. |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
234 /// |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
235 /// # Panics |
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 /// Panics if the value is currently mutably borrowed. |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
238 pub fn borrow(&self) -> RwLockReadGuard<'py, T> { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
239 self.try_borrow().expect("already mutably borrowed") |
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 |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
242 /// 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
|
243 /// is currently mutably borrowed. |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
244 pub fn try_borrow(&self) -> TryLockResult<RwLockReadGuard<'py, T>> { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
245 // state isn't involved since |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
246 // - data.try_borrow() would fail if self is mutably borrowed, |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
247 // - and data.try_borrow_mut() would fail while self is borrowed. |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
248 self.data.try_read() |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
249 } |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
250 |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
251 /// Mutably borrows the wrapped value. |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
252 /// |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
253 /// Any existing leaked references will be invalidated. |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
254 /// |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
255 /// # Panics |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
256 /// |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
257 /// Panics if the value is currently borrowed. |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
258 pub fn borrow_mut(&self) -> RwLockWriteGuard<'py, T> { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
259 self.try_borrow_mut().expect("already borrowed") |
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 |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
262 /// 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
|
263 /// is currently borrowed. |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
264 pub fn try_borrow_mut(&self) -> TryLockResult<RwLockWriteGuard<'py, T>> { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
265 // the value may be immutably borrowed through UnsafePyLeaked |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
266 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
|
267 // 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
|
268 let _dummy = self.data.read(); |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
269 let _unused = self.data.try_write()?; |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
270 unreachable!("BorrowMutError should have been returned"); |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
271 } |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
272 |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
273 let data_ref = self.data.try_write()?; |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
274 self.state.increment_generation(self.py()); |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
275 Ok(data_ref) |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
276 } |
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 /// 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
|
279 /// |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
280 /// # Panics |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
281 /// |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
282 /// Panics if the value is currently mutably borrowed. |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
283 pub fn leak_immutable(&self) -> UnsafePyLeaked<&'static T> { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
284 self.try_leak_immutable().expect("already mutably borrowed") |
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 |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
287 /// 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
|
288 /// 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
|
289 pub fn try_leak_immutable( |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
290 &self, |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
291 ) -> Result<UnsafePyLeaked<&'static T>, TryLeakError> { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
292 // 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
|
293 // generation number wouldn't be trusted. |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
294 let data_ref = self.try_borrow()?; |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
295 |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
296 // keep reference to the owner so the data and state are alive, |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
297 // but the data pointer can be invalidated by borrow_mut(). |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
298 // the state wouldn't since it is immutable. |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
299 let state_ptr: *const PySharedState = self.state; |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
300 let data_ptr: *const T = &*data_ref; |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
301 Ok(UnsafePyLeaked::<&'static T> { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
302 owner: self.owner.clone().unbind(), |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
303 state: unsafe { &*state_ptr }, |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
304 generation: self.state.current_generation(self.py()), |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
305 data: unsafe { &*data_ptr }, |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
306 }) |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
307 } |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
308 |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
309 /// Retrieve the GIL handle |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
310 fn py(&self) -> Python<'py> { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
311 // 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
|
312 // 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
|
313 // of `Bound` does it for us. |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
314 self.owner.py() |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
315 } |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
316 } |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
317 |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
318 /// The shared state between Python and Rust |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
319 /// |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
320 /// `PySharedState` is owned by `PySharedRefCell`, and is shared across its |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
321 /// 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
|
322 /// as follows: |
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 immutability of `PycCass` object fields. Any mutation of |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
325 /// [`PySharedRefCell`] is allowed only through its `borrow_mut()`. |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
326 /// - 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
|
327 /// synchronized by the GIL. |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
328 /// - The underlying `RefCell`, which prevents `PySharedRefCell` value from |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
329 /// being directly borrowed or leaked while it is mutably borrowed. |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
330 /// - 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
|
331 /// `UnsafePyLeaked`. Just like `RefCell`, mutation is prohibited while |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
332 /// `UnsafePyLeaked` is borrowed. |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
333 /// - The `generation` counter, which increments on `borrow_mut()`. |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
334 /// `UnsafePyLeaked` reference is valid only if the `current_generation()` |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
335 /// equals to the `generation` at the time of `leak_immutable()`. |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
336 #[derive(Debug)] |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
337 struct PySharedState { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
338 // 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
|
339 // 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
|
340 // PySharedState inherently Sync. The ordering requirement doesn't |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
341 // 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
|
342 // everywhere. |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
343 /// 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
|
344 borrow_count: AtomicUsize, |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
345 /// The mutation counter of the underlying value. |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
346 generation: AtomicUsize, |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
347 } |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
348 |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
349 impl PySharedState { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
350 const fn new() -> PySharedState { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
351 PySharedState { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
352 borrow_count: AtomicUsize::new(0), |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
353 generation: AtomicUsize::new(0), |
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 } |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
356 |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
357 fn current_borrow_count(&self, _py: Python) -> usize { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
358 self.borrow_count.load(Ordering::Relaxed) |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
359 } |
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 fn increase_borrow_count(&self, _py: Python) { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
362 // 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
|
363 // 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
|
364 self.borrow_count.fetch_add(1, 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 decrease_borrow_count(&self, _py: Python) { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
368 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
|
369 assert!(prev_count > 0); |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
370 } |
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 fn current_generation(&self, _py: Python) -> usize { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
373 self.generation.load(Ordering::Relaxed) |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
374 } |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
375 |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
376 fn increment_generation(&self, py: Python) { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
377 assert_eq!(self.current_borrow_count(py), 0); |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
378 // 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
|
379 // 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
|
380 self.generation.fetch_add(1, Ordering::Relaxed); |
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 } |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
383 |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
384 /// Helper to keep the borrow count updated while the shared object is |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
385 /// immutably borrowed without using the `RefCell` interface. |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
386 struct BorrowPyShared<'a> { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
387 py: Python<'a>, |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
388 state: &'a PySharedState, |
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 |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
391 impl<'a> BorrowPyShared<'a> { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
392 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
|
393 state.increase_borrow_count(py); |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
394 BorrowPyShared { py, state } |
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 |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
398 impl<'a> Drop for BorrowPyShared<'a> { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
399 fn drop(&mut self) { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
400 self.state.decrease_borrow_count(self.py); |
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 /// An immutable reference to [`PySharedRefCell`] value, not bound to lifetime. |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
405 /// |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
406 /// 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
|
407 /// borrowed. |
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 /// # Safety |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
410 /// |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
411 /// 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
|
412 /// 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
|
413 /// 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
|
414 /// reference outlive the actual object lifetime. |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
415 /// |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
416 /// 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
|
417 /// would only accept [`Fn`] instead of [`FnOnce`]. |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
418 /// |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
419 /// ```ignore |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
420 /// let outer; |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
421 /// unsafe { leaked.map(py, |o| { outer = o }) }; // Bad |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
422 /// ``` |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
423 /// |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
424 /// ```ignore |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
425 /// let outer; |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
426 /// 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
|
427 /// { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
428 /// 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
|
429 /// let inner = iter.next(); // Good, in borrow scope |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
430 /// outer = inner; // Bad, &'static T may outlive |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
431 /// } |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
432 /// ``` |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
433 pub struct UnsafePyLeaked<T: ?Sized> { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
434 owner: PyObject, |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
435 state: &'static PySharedState, |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
436 /// 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
|
437 /// created. |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
438 generation: usize, |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
439 /// 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
|
440 /// state.generation == self.generation. |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
441 data: T, |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
442 } |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
443 |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
444 // 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
|
445 // 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
|
446 // is invalid if generation != state.generation. |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
447 |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
448 impl<T: ?Sized> UnsafePyLeaked<T> { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
449 // 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
|
450 // 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
|
451 // 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
|
452 |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
453 // 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
|
454 // have a function returning the inner &'static reference. |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
455 // 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
|
456 // 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
|
457 |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
458 /// Immutably borrows the wrapped value. |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
459 /// |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
460 /// 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
|
461 /// |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
462 /// # Safety |
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 /// 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
|
465 /// copy it out of the borrow scope. |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
466 pub unsafe fn try_borrow<'a>( |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
467 &'a self, |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
468 py: Python<'a>, |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
469 ) -> PyResult<PyLeakedRef<'a, T>> { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
470 self.validate_generation(py)?; |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
471 Ok(PyLeakedRef { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
472 _borrow: BorrowPyShared::new(py, self.state), |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
473 data: &self.data, |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
474 }) |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
475 } |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
476 |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
477 /// Mutably borrows the wrapped value. |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
478 /// |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
479 /// 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
|
480 /// |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
481 /// 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
|
482 /// `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
|
483 /// |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
484 /// # Safety |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
485 /// |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
486 /// 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
|
487 /// copy it out of the borrow scope. |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
488 pub unsafe fn try_borrow_mut<'a>( |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
489 &'a mut self, |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
490 py: Python<'a>, |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
491 ) -> PyResult<PyLeakedRefMut<'a, T>> { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
492 self.validate_generation(py)?; |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
493 Ok(PyLeakedRefMut { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
494 _borrow: BorrowPyShared::new(py, self.state), |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
495 data: &mut self.data, |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
496 }) |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
497 } |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
498 |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
499 fn validate_generation(&self, py: Python) -> PyResult<()> { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
500 if self.state.current_generation(py) == self.generation { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
501 Ok(()) |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
502 } else { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
503 Err(PyRuntimeError::new_err( |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
504 "Cannot access to leaked reference after mutation", |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
505 )) |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
506 } |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
507 } |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
508 } |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
509 |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
510 impl<T> UnsafePyLeaked<T> { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
511 /// Converts the inner value by the given function. |
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 /// 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
|
514 /// iterator of that collection. |
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 /// # Panics |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
517 /// |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
518 /// Panics if the underlying reference has been invalidated. |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
519 /// |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
520 /// 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
|
521 /// 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
|
522 /// would occur. |
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 /// # Safety |
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 /// 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
|
527 /// 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
|
528 /// 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
|
529 /// function call. |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
530 /// 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
|
531 pub unsafe fn map<U>( |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
532 self, |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
533 py: Python, |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
534 f: impl FnOnce(T) -> U, |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
535 ) -> UnsafePyLeaked<U> { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
536 // 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
|
537 // is still intact. |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
538 self.validate_generation(py) |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
539 .expect("map() over invalidated leaked reference"); |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
540 |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
541 // 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
|
542 // 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
|
543 // 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
|
544 // returned object back to Something<'static>. |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
545 let new_data = f(self.data); |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
546 UnsafePyLeaked { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
547 owner: self.owner, |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
548 state: self.state, |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
549 generation: self.generation, |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
550 data: new_data, |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
551 } |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
552 } |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
553 } |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
554 |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
555 /// An immutably borrowed reference to a leaked value. |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
556 pub struct PyLeakedRef<'a, T: 'a + ?Sized> { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
557 _borrow: BorrowPyShared<'a>, |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
558 data: &'a T, |
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 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
|
562 type Target = T; |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
563 |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
564 fn deref(&self) -> &T { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
565 self.data |
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 } |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
568 |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
569 /// A mutably borrowed reference to a leaked value. |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
570 pub struct PyLeakedRefMut<'a, T: 'a + ?Sized> { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
571 _borrow: BorrowPyShared<'a>, |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
572 data: &'a mut T, |
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 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
|
576 type Target = T; |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
577 |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
578 fn deref(&self) -> &T { |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
579 self.data |
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 } |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
582 |
be765f6797cc
rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff
changeset
|
583 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
|
584 fn deref_mut(&mut self) -> &mut 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 } |