##// END OF EJS Templates
rust-cpython: make PySharedRef::try_borrow_mut() return BorrowMutError...
Yuya Nishihara -
r44667:b556400b default draft
parent child Browse files
Show More
@@ -1,44 +1,42 b''
1 1 // ancestors.rs
2 2 //
3 3 // Copyright 2018 Georges Racinet <gracinet@anybox.fr>
4 4 //
5 5 // This software may be used and distributed according to the terms of the
6 6 // GNU General Public License version 2 or any later version.
7 7
8 8 //! Bindings for Rust errors
9 9 //!
10 10 //! [`GraphError`] exposes `hg::GraphError` as a subclass of `ValueError`
11 11 //! but some variants of `hg::GraphError` can be converted directly to other
12 12 //! existing Python exceptions if appropriate.
13 13 //!
14 14 //! [`GraphError`]: struct.GraphError.html
15 15 use cpython::{
16 16 exc::{RuntimeError, ValueError},
17 17 py_exception, PyErr, Python,
18 18 };
19 19 use hg;
20 20
21 21 py_exception!(rustext, GraphError, ValueError);
22 22
23 23 impl GraphError {
24 24 pub fn pynew(py: Python, inner: hg::GraphError) -> PyErr {
25 25 match inner {
26 26 hg::GraphError::ParentOutOfRange(r) => {
27 27 GraphError::new(py, ("ParentOutOfRange", r))
28 28 }
29 29 hg::GraphError::WorkingDirectoryUnsupported => {
30 30 match py
31 31 .import("mercurial.error")
32 32 .and_then(|m| m.get(py, "WdirUnsupported"))
33 33 {
34 34 Err(e) => e,
35 35 Ok(cls) => PyErr::from_instance(py, cls),
36 36 }
37 37 }
38 38 }
39 39 }
40 40 }
41 41
42 42 py_exception!(rustext, HgPathPyError, RuntimeError);
43
44 py_exception!(shared_ref, AlreadyBorrowed, RuntimeError);
@@ -1,634 +1,633 b''
1 1 // ref_sharing.rs
2 2 //
3 3 // Copyright 2019 Raphaël Gomès <rgomes@octobus.net>
4 4 //
5 5 // Permission is hereby granted, free of charge, to any person obtaining a copy
6 6 // of this software and associated documentation files (the "Software"), to
7 7 // deal in the Software without restriction, including without limitation the
8 8 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9 9 // sell copies of the Software, and to permit persons to whom the Software is
10 10 // furnished to do so, subject to the following conditions:
11 11 //
12 12 // The above copyright notice and this permission notice shall be included in
13 13 // all copies or substantial portions of the Software.
14 14 //
15 15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 20 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 21 // IN THE SOFTWARE.
22 22
23 23 //! Macros for use in the `hg-cpython` bridge library.
24 24
25 use crate::exceptions::AlreadyBorrowed;
26 25 use cpython::{exc, PyClone, PyErr, PyObject, PyResult, Python};
27 use std::cell::{Ref, RefCell, RefMut};
26 use std::cell::{BorrowMutError, Ref, RefCell, RefMut};
28 27 use std::ops::{Deref, DerefMut};
28 use std::result;
29 29 use std::sync::atomic::{AtomicUsize, Ordering};
30 30
31 31 /// Manages the shared state between Python and Rust
32 32 ///
33 33 /// `PySharedState` is owned by `PySharedRefCell`, and is shared across its
34 34 /// derived references. The consistency of these references are guaranteed
35 35 /// as follows:
36 36 ///
37 37 /// - The immutability of `py_class!` object fields. Any mutation of
38 38 /// `PySharedRefCell` is allowed only through its `borrow_mut()`.
39 39 /// - The `py: Python<'_>` token, which makes sure that any data access is
40 40 /// synchronized by the GIL.
41 41 /// - The underlying `RefCell`, which prevents `PySharedRefCell` data from
42 42 /// being directly borrowed or leaked while it is mutably borrowed.
43 43 /// - The `borrow_count`, which is the number of references borrowed from
44 44 /// `PyLeaked`. Just like `RefCell`, mutation is prohibited while `PyLeaked`
45 45 /// is borrowed.
46 46 /// - The `generation` counter, which increments on `borrow_mut()`. `PyLeaked`
47 47 /// reference is valid only if the `current_generation()` equals to the
48 48 /// `generation` at the time of `leak_immutable()`.
49 49 #[derive(Debug, Default)]
50 50 struct PySharedState {
51 51 // The counter variable could be Cell<usize> since any operation on
52 52 // PySharedState is synchronized by the GIL, but being "atomic" makes
53 53 // PySharedState inherently Sync. The ordering requirement doesn't
54 54 // matter thanks to the GIL.
55 55 borrow_count: AtomicUsize,
56 56 generation: AtomicUsize,
57 57 }
58 58
59 59 impl PySharedState {
60 60 fn current_borrow_count(&self, _py: Python) -> usize {
61 61 self.borrow_count.load(Ordering::Relaxed)
62 62 }
63 63
64 64 fn increase_borrow_count(&self, _py: Python) {
65 65 // Note that this wraps around if there are more than usize::MAX
66 66 // borrowed references, which shouldn't happen due to memory limit.
67 67 self.borrow_count.fetch_add(1, Ordering::Relaxed);
68 68 }
69 69
70 70 fn decrease_borrow_count(&self, _py: Python) {
71 71 let prev_count = self.borrow_count.fetch_sub(1, Ordering::Relaxed);
72 72 assert!(prev_count > 0);
73 73 }
74 74
75 75 fn current_generation(&self, _py: Python) -> usize {
76 76 self.generation.load(Ordering::Relaxed)
77 77 }
78 78
79 79 fn increment_generation(&self, py: Python) {
80 80 assert_eq!(self.current_borrow_count(py), 0);
81 81 // Note that this wraps around to the same value if mutably
82 82 // borrowed more than usize::MAX times, which wouldn't happen
83 83 // in practice.
84 84 self.generation.fetch_add(1, Ordering::Relaxed);
85 85 }
86 86 }
87 87
88 88 /// Helper to keep the borrow count updated while the shared object is
89 89 /// immutably borrowed without using the `RefCell` interface.
90 90 struct BorrowPyShared<'a> {
91 91 py: Python<'a>,
92 92 py_shared_state: &'a PySharedState,
93 93 }
94 94
95 95 impl<'a> BorrowPyShared<'a> {
96 96 fn new(
97 97 py: Python<'a>,
98 98 py_shared_state: &'a PySharedState,
99 99 ) -> BorrowPyShared<'a> {
100 100 py_shared_state.increase_borrow_count(py);
101 101 BorrowPyShared {
102 102 py,
103 103 py_shared_state,
104 104 }
105 105 }
106 106 }
107 107
108 108 impl Drop for BorrowPyShared<'_> {
109 109 fn drop(&mut self) {
110 110 self.py_shared_state.decrease_borrow_count(self.py);
111 111 }
112 112 }
113 113
114 114 /// `RefCell` wrapper to be safely used in conjunction with `PySharedState`.
115 115 ///
116 116 /// This object can be stored in a `py_class!` object as a data field. Any
117 117 /// operation is allowed through the `PySharedRef` interface.
118 118 #[derive(Debug)]
119 119 pub struct PySharedRefCell<T> {
120 120 inner: RefCell<T>,
121 121 py_shared_state: PySharedState,
122 122 }
123 123
124 124 impl<T> PySharedRefCell<T> {
125 125 pub fn new(value: T) -> PySharedRefCell<T> {
126 126 Self {
127 127 inner: RefCell::new(value),
128 128 py_shared_state: PySharedState::default(),
129 129 }
130 130 }
131 131
132 132 fn borrow<'a>(&'a self, _py: Python<'a>) -> Ref<'a, T> {
133 133 // py_shared_state isn't involved since
134 134 // - inner.borrow() would fail if self is mutably borrowed,
135 135 // - and inner.try_borrow_mut() would fail while self is borrowed.
136 136 self.inner.borrow()
137 137 }
138 138
139 139 fn try_borrow_mut<'a>(
140 140 &'a self,
141 141 py: Python<'a>,
142 ) -> PyResult<RefMut<'a, T>> {
142 ) -> result::Result<RefMut<'a, T>, BorrowMutError> {
143 143 if self.py_shared_state.current_borrow_count(py) > 0 {
144 return Err(AlreadyBorrowed::new(
145 py,
146 "Cannot borrow mutably while immutably borrowed",
147 ));
144 // propagate borrow-by-leaked state to inner to get BorrowMutError
145 let _dummy = self.inner.borrow();
146 self.inner.try_borrow_mut()?;
147 unreachable!("BorrowMutError must be returned");
148 148 }
149 let inner_ref = self
150 .inner
151 .try_borrow_mut()
152 .map_err(|e| AlreadyBorrowed::new(py, e.to_string()))?;
149 let inner_ref = self.inner.try_borrow_mut()?;
153 150 self.py_shared_state.increment_generation(py);
154 151 Ok(inner_ref)
155 152 }
156 153 }
157 154
158 155 /// Sharable data member of type `T` borrowed from the `PyObject`.
159 156 pub struct PySharedRef<'a, T> {
160 157 py: Python<'a>,
161 158 owner: &'a PyObject,
162 159 data: &'a PySharedRefCell<T>,
163 160 }
164 161
165 162 impl<'a, T> PySharedRef<'a, T> {
166 163 /// # Safety
167 164 ///
168 165 /// The `data` must be owned by the `owner`. Otherwise, the leak count
169 166 /// would get wrong.
170 167 pub unsafe fn new(
171 168 py: Python<'a>,
172 169 owner: &'a PyObject,
173 170 data: &'a PySharedRefCell<T>,
174 171 ) -> Self {
175 172 Self { py, owner, data }
176 173 }
177 174
178 175 pub fn borrow(&self) -> Ref<'a, T> {
179 176 self.data.borrow(self.py)
180 177 }
181 178
182 179 /// Mutably borrows the wrapped value.
183 180 ///
184 181 /// # Panics
185 182 ///
186 183 /// Panics if the value is currently borrowed through `PySharedRef`
187 184 /// or `PyLeaked`.
188 185 pub fn borrow_mut(&self) -> RefMut<'a, T> {
189 186 self.try_borrow_mut().expect("already borrowed")
190 187 }
191 188
192 189 /// Mutably borrows the wrapped value, returning an error if the value
193 190 /// is currently borrowed.
194 pub fn try_borrow_mut(&self) -> PyResult<RefMut<'a, T>> {
191 pub fn try_borrow_mut(
192 &self,
193 ) -> result::Result<RefMut<'a, T>, BorrowMutError> {
195 194 self.data.try_borrow_mut(self.py)
196 195 }
197 196
198 197 /// Returns a leaked reference.
199 198 ///
200 199 /// # Panics
201 200 ///
202 201 /// Panics if this is mutably borrowed.
203 202 pub fn leak_immutable(&self) -> PyLeaked<&'static T> {
204 203 let state = &self.data.py_shared_state;
205 204 // make sure self.data isn't mutably borrowed; otherwise the
206 205 // generation number can't be trusted.
207 206 let data_ref = self.borrow();
208 207
209 208 // &'static cast is safe because data_ptr and state_ptr are owned
210 209 // by self.owner, and we do have the GIL for thread safety.
211 210 let data_ptr: *const T = &*data_ref;
212 211 let state_ptr: *const PySharedState = state;
213 212 PyLeaked::<&'static T> {
214 213 inner: self.owner.clone_ref(self.py),
215 214 data: unsafe { &*data_ptr },
216 215 py_shared_state: unsafe { &*state_ptr },
217 216 generation: state.current_generation(self.py),
218 217 }
219 218 }
220 219 }
221 220
222 221 /// Allows a `py_class!` generated struct to share references to one of its
223 222 /// data members with Python.
224 223 ///
225 224 /// # Parameters
226 225 ///
227 226 /// * `$name` is the same identifier used in for `py_class!` macro call.
228 227 /// * `$inner_struct` is the identifier of the underlying Rust struct
229 228 /// * `$data_member` is the identifier of the data member of `$inner_struct`
230 229 /// that will be shared.
231 230 /// * `$shared_accessor` is the function name to be generated, which allows
232 231 /// safe access to the data member.
233 232 ///
234 233 /// # Safety
235 234 ///
236 235 /// `$data_member` must persist while the `$name` object is alive. In other
237 236 /// words, it must be an accessor to a data field of the Python object.
238 237 ///
239 238 /// # Example
240 239 ///
241 240 /// ```
242 241 /// struct MyStruct {
243 242 /// inner: Vec<u32>;
244 243 /// }
245 244 ///
246 245 /// py_class!(pub class MyType |py| {
247 246 /// data inner: PySharedRefCell<MyStruct>;
248 247 /// });
249 248 ///
250 249 /// py_shared_ref!(MyType, MyStruct, inner, inner_shared);
251 250 /// ```
252 251 macro_rules! py_shared_ref {
253 252 (
254 253 $name: ident,
255 254 $inner_struct: ident,
256 255 $data_member: ident,
257 256 $shared_accessor: ident
258 257 ) => {
259 258 impl $name {
260 259 /// Returns a safe reference to the shared `$data_member`.
261 260 ///
262 261 /// This function guarantees that `PySharedRef` is created with
263 262 /// the valid `self` and `self.$data_member(py)` pair.
264 263 fn $shared_accessor<'a>(
265 264 &'a self,
266 265 py: Python<'a>,
267 266 ) -> $crate::ref_sharing::PySharedRef<'a, $inner_struct> {
268 267 use cpython::PythonObject;
269 268 use $crate::ref_sharing::PySharedRef;
270 269 let owner = self.as_object();
271 270 let data = self.$data_member(py);
272 271 unsafe { PySharedRef::new(py, owner, data) }
273 272 }
274 273 }
275 274 };
276 275 }
277 276
278 277 /// Manage immutable references to `PyObject` leaked into Python iterators.
279 278 ///
280 279 /// This reference will be invalidated once the original value is mutably
281 280 /// borrowed.
282 281 pub struct PyLeaked<T> {
283 282 inner: PyObject,
284 283 data: T,
285 284 py_shared_state: &'static PySharedState,
286 285 /// Generation counter of data `T` captured when PyLeaked is created.
287 286 generation: usize,
288 287 }
289 288
290 289 // DO NOT implement Deref for PyLeaked<T>! Dereferencing PyLeaked
291 290 // without taking Python GIL wouldn't be safe. Also, the underling reference
292 291 // is invalid if generation != py_shared_state.generation.
293 292
294 293 impl<T> PyLeaked<T> {
295 294 /// Immutably borrows the wrapped value.
296 295 ///
297 296 /// Borrowing fails if the underlying reference has been invalidated.
298 297 pub fn try_borrow<'a>(
299 298 &'a self,
300 299 py: Python<'a>,
301 300 ) -> PyResult<PyLeakedRef<'a, T>> {
302 301 self.validate_generation(py)?;
303 302 Ok(PyLeakedRef {
304 303 _borrow: BorrowPyShared::new(py, self.py_shared_state),
305 304 data: &self.data,
306 305 })
307 306 }
308 307
309 308 /// Mutably borrows the wrapped value.
310 309 ///
311 310 /// Borrowing fails if the underlying reference has been invalidated.
312 311 ///
313 312 /// Typically `T` is an iterator. If `T` is an immutable reference,
314 313 /// `get_mut()` is useless since the inner value can't be mutated.
315 314 pub fn try_borrow_mut<'a>(
316 315 &'a mut self,
317 316 py: Python<'a>,
318 317 ) -> PyResult<PyLeakedRefMut<'a, T>> {
319 318 self.validate_generation(py)?;
320 319 Ok(PyLeakedRefMut {
321 320 _borrow: BorrowPyShared::new(py, self.py_shared_state),
322 321 data: &mut self.data,
323 322 })
324 323 }
325 324
326 325 /// Converts the inner value by the given function.
327 326 ///
328 327 /// Typically `T` is a static reference to a container, and `U` is an
329 328 /// iterator of that container.
330 329 ///
331 330 /// # Panics
332 331 ///
333 332 /// Panics if the underlying reference has been invalidated.
334 333 ///
335 334 /// This is typically called immediately after the `PyLeaked` is obtained.
336 335 /// In which case, the reference must be valid and no panic would occur.
337 336 ///
338 337 /// # Safety
339 338 ///
340 339 /// The lifetime of the object passed in to the function `f` is cheated.
341 340 /// It's typically a static reference, but is valid only while the
342 341 /// corresponding `PyLeaked` is alive. Do not copy it out of the
343 342 /// function call.
344 343 pub unsafe fn map<U>(
345 344 self,
346 345 py: Python,
347 346 f: impl FnOnce(T) -> U,
348 347 ) -> PyLeaked<U> {
349 348 // Needs to test the generation value to make sure self.data reference
350 349 // is still intact.
351 350 self.validate_generation(py)
352 351 .expect("map() over invalidated leaked reference");
353 352
354 353 // f() could make the self.data outlive. That's why map() is unsafe.
355 354 // In order to make this function safe, maybe we'll need a way to
356 355 // temporarily restrict the lifetime of self.data and translate the
357 356 // returned object back to Something<'static>.
358 357 let new_data = f(self.data);
359 358 PyLeaked {
360 359 inner: self.inner,
361 360 data: new_data,
362 361 py_shared_state: self.py_shared_state,
363 362 generation: self.generation,
364 363 }
365 364 }
366 365
367 366 fn validate_generation(&self, py: Python) -> PyResult<()> {
368 367 if self.py_shared_state.current_generation(py) == self.generation {
369 368 Ok(())
370 369 } else {
371 370 Err(PyErr::new::<exc::RuntimeError, _>(
372 371 py,
373 372 "Cannot access to leaked reference after mutation",
374 373 ))
375 374 }
376 375 }
377 376 }
378 377
379 378 /// Immutably borrowed reference to a leaked value.
380 379 pub struct PyLeakedRef<'a, T> {
381 380 _borrow: BorrowPyShared<'a>,
382 381 data: &'a T,
383 382 }
384 383
385 384 impl<T> Deref for PyLeakedRef<'_, T> {
386 385 type Target = T;
387 386
388 387 fn deref(&self) -> &T {
389 388 self.data
390 389 }
391 390 }
392 391
393 392 /// Mutably borrowed reference to a leaked value.
394 393 pub struct PyLeakedRefMut<'a, T> {
395 394 _borrow: BorrowPyShared<'a>,
396 395 data: &'a mut T,
397 396 }
398 397
399 398 impl<T> Deref for PyLeakedRefMut<'_, T> {
400 399 type Target = T;
401 400
402 401 fn deref(&self) -> &T {
403 402 self.data
404 403 }
405 404 }
406 405
407 406 impl<T> DerefMut for PyLeakedRefMut<'_, T> {
408 407 fn deref_mut(&mut self) -> &mut T {
409 408 self.data
410 409 }
411 410 }
412 411
413 412 /// Defines a `py_class!` that acts as a Python iterator over a Rust iterator.
414 413 ///
415 414 /// TODO: this is a bit awkward to use, and a better (more complicated)
416 415 /// procedural macro would simplify the interface a lot.
417 416 ///
418 417 /// # Parameters
419 418 ///
420 419 /// * `$name` is the identifier to give to the resulting Rust struct.
421 420 /// * `$leaked` corresponds to `$leaked` in the matching `py_shared_ref!` call.
422 421 /// * `$iterator_type` is the type of the Rust iterator.
423 422 /// * `$success_func` is a function for processing the Rust `(key, value)`
424 423 /// tuple on iteration success, turning it into something Python understands.
425 424 /// * `$success_func` is the return type of `$success_func`
426 425 ///
427 426 /// # Example
428 427 ///
429 428 /// ```
430 429 /// struct MyStruct {
431 430 /// inner: HashMap<Vec<u8>, Vec<u8>>;
432 431 /// }
433 432 ///
434 433 /// py_class!(pub class MyType |py| {
435 434 /// data inner: PySharedRefCell<MyStruct>;
436 435 ///
437 436 /// def __iter__(&self) -> PyResult<MyTypeItemsIterator> {
438 437 /// let leaked_ref = self.inner_shared(py).leak_immutable();
439 438 /// MyTypeItemsIterator::from_inner(
440 439 /// py,
441 440 /// unsafe { leaked_ref.map(py, |o| o.iter()) },
442 441 /// )
443 442 /// }
444 443 /// });
445 444 ///
446 445 /// impl MyType {
447 446 /// fn translate_key_value(
448 447 /// py: Python,
449 448 /// res: (&Vec<u8>, &Vec<u8>),
450 449 /// ) -> PyResult<Option<(PyBytes, PyBytes)>> {
451 450 /// let (f, entry) = res;
452 451 /// Ok(Some((
453 452 /// PyBytes::new(py, f),
454 453 /// PyBytes::new(py, entry),
455 454 /// )))
456 455 /// }
457 456 /// }
458 457 ///
459 458 /// py_shared_ref!(MyType, MyStruct, inner, MyTypeLeakedRef);
460 459 ///
461 460 /// py_shared_iterator!(
462 461 /// MyTypeItemsIterator,
463 462 /// PyLeaked<HashMap<'static, Vec<u8>, Vec<u8>>>,
464 463 /// MyType::translate_key_value,
465 464 /// Option<(PyBytes, PyBytes)>
466 465 /// );
467 466 /// ```
468 467 macro_rules! py_shared_iterator {
469 468 (
470 469 $name: ident,
471 470 $leaked: ty,
472 471 $success_func: expr,
473 472 $success_type: ty
474 473 ) => {
475 474 py_class!(pub class $name |py| {
476 475 data inner: RefCell<$leaked>;
477 476
478 477 def __next__(&self) -> PyResult<$success_type> {
479 478 let mut leaked = self.inner(py).borrow_mut();
480 479 let mut iter = leaked.try_borrow_mut(py)?;
481 480 match iter.next() {
482 481 None => Ok(None),
483 482 Some(res) => $success_func(py, res),
484 483 }
485 484 }
486 485
487 486 def __iter__(&self) -> PyResult<Self> {
488 487 Ok(self.clone_ref(py))
489 488 }
490 489 });
491 490
492 491 impl $name {
493 492 pub fn from_inner(
494 493 py: Python,
495 494 leaked: $leaked,
496 495 ) -> PyResult<Self> {
497 496 Self::create_instance(
498 497 py,
499 498 RefCell::new(leaked),
500 499 )
501 500 }
502 501 }
503 502 };
504 503 }
505 504
506 505 #[cfg(test)]
507 506 #[cfg(any(feature = "python27-bin", feature = "python3-bin"))]
508 507 mod test {
509 508 use super::*;
510 509 use cpython::{GILGuard, Python};
511 510
512 511 py_class!(class Owner |py| {
513 512 data string: PySharedRefCell<String>;
514 513 });
515 514 py_shared_ref!(Owner, String, string, string_shared);
516 515
517 516 fn prepare_env() -> (GILGuard, Owner) {
518 517 let gil = Python::acquire_gil();
519 518 let py = gil.python();
520 519 let owner =
521 520 Owner::create_instance(py, PySharedRefCell::new("new".to_owned()))
522 521 .unwrap();
523 522 (gil, owner)
524 523 }
525 524
526 525 #[test]
527 526 fn test_leaked_borrow() {
528 527 let (gil, owner) = prepare_env();
529 528 let py = gil.python();
530 529 let leaked = owner.string_shared(py).leak_immutable();
531 530 let leaked_ref = leaked.try_borrow(py).unwrap();
532 531 assert_eq!(*leaked_ref, "new");
533 532 }
534 533
535 534 #[test]
536 535 fn test_leaked_borrow_mut() {
537 536 let (gil, owner) = prepare_env();
538 537 let py = gil.python();
539 538 let leaked = owner.string_shared(py).leak_immutable();
540 539 let mut leaked_iter = unsafe { leaked.map(py, |s| s.chars()) };
541 540 let mut leaked_ref = leaked_iter.try_borrow_mut(py).unwrap();
542 541 assert_eq!(leaked_ref.next(), Some('n'));
543 542 assert_eq!(leaked_ref.next(), Some('e'));
544 543 assert_eq!(leaked_ref.next(), Some('w'));
545 544 assert_eq!(leaked_ref.next(), None);
546 545 }
547 546
548 547 #[test]
549 548 fn test_leaked_borrow_after_mut() {
550 549 let (gil, owner) = prepare_env();
551 550 let py = gil.python();
552 551 let leaked = owner.string_shared(py).leak_immutable();
553 552 owner.string_shared(py).borrow_mut().clear();
554 553 assert!(leaked.try_borrow(py).is_err());
555 554 }
556 555
557 556 #[test]
558 557 fn test_leaked_borrow_mut_after_mut() {
559 558 let (gil, owner) = prepare_env();
560 559 let py = gil.python();
561 560 let leaked = owner.string_shared(py).leak_immutable();
562 561 let mut leaked_iter = unsafe { leaked.map(py, |s| s.chars()) };
563 562 owner.string_shared(py).borrow_mut().clear();
564 563 assert!(leaked_iter.try_borrow_mut(py).is_err());
565 564 }
566 565
567 566 #[test]
568 567 #[should_panic(expected = "map() over invalidated leaked reference")]
569 568 fn test_leaked_map_after_mut() {
570 569 let (gil, owner) = prepare_env();
571 570 let py = gil.python();
572 571 let leaked = owner.string_shared(py).leak_immutable();
573 572 owner.string_shared(py).borrow_mut().clear();
574 573 let _leaked_iter = unsafe { leaked.map(py, |s| s.chars()) };
575 574 }
576 575
577 576 #[test]
578 577 fn test_try_borrow_mut_while_leaked_ref() {
579 578 let (gil, owner) = prepare_env();
580 579 let py = gil.python();
581 580 assert!(owner.string_shared(py).try_borrow_mut().is_ok());
582 581 let leaked = owner.string_shared(py).leak_immutable();
583 582 {
584 583 let _leaked_ref = leaked.try_borrow(py).unwrap();
585 584 assert!(owner.string_shared(py).try_borrow_mut().is_err());
586 585 {
587 586 let _leaked_ref2 = leaked.try_borrow(py).unwrap();
588 587 assert!(owner.string_shared(py).try_borrow_mut().is_err());
589 588 }
590 589 assert!(owner.string_shared(py).try_borrow_mut().is_err());
591 590 }
592 591 assert!(owner.string_shared(py).try_borrow_mut().is_ok());
593 592 }
594 593
595 594 #[test]
596 595 fn test_try_borrow_mut_while_leaked_ref_mut() {
597 596 let (gil, owner) = prepare_env();
598 597 let py = gil.python();
599 598 assert!(owner.string_shared(py).try_borrow_mut().is_ok());
600 599 let leaked = owner.string_shared(py).leak_immutable();
601 600 let mut leaked_iter = unsafe { leaked.map(py, |s| s.chars()) };
602 601 {
603 602 let _leaked_ref = leaked_iter.try_borrow_mut(py).unwrap();
604 603 assert!(owner.string_shared(py).try_borrow_mut().is_err());
605 604 }
606 605 assert!(owner.string_shared(py).try_borrow_mut().is_ok());
607 606 }
608 607
609 608 #[test]
610 609 #[should_panic(expected = "mutably borrowed")]
611 610 fn test_leak_while_borrow_mut() {
612 611 let (gil, owner) = prepare_env();
613 612 let py = gil.python();
614 613 let _mut_ref = owner.string_shared(py).borrow_mut();
615 614 owner.string_shared(py).leak_immutable();
616 615 }
617 616
618 617 #[test]
619 618 fn test_try_borrow_mut_while_borrow() {
620 619 let (gil, owner) = prepare_env();
621 620 let py = gil.python();
622 621 let _ref = owner.string_shared(py).borrow();
623 622 assert!(owner.string_shared(py).try_borrow_mut().is_err());
624 623 }
625 624
626 625 #[test]
627 626 #[should_panic(expected = "already borrowed")]
628 627 fn test_borrow_mut_while_borrow() {
629 628 let (gil, owner) = prepare_env();
630 629 let py = gil.python();
631 630 let _ref = owner.string_shared(py).borrow();
632 631 owner.string_shared(py).borrow_mut();
633 632 }
634 633 }
General Comments 0
You need to be logged in to leave comments. Login now