rust/pyo3-sharedref/src/lib.rs
author Georges Racinet <georges.racinet@cloudcrane.io>
Sun, 15 Dec 2024 13:58:31 +0100
changeset 52609 d1e304025b90
parent 52608 d85514a88706
child 52610 c25d345f5aa5
permissions -rw-r--r--
rust-pyo3-sharedref: replaced borrow/borrow_mut with RwLock namings The "borrow" word had way too many uses in this context. Originally, it came from the rust-cpython version, which is based on `RefCell`. Before this change, we had untracktable stacks of borrows (first the `Bound`, then the `PySharedRefCell`). In any case, the change to `RwLock` is far from being neutral, and we may need in a future without GIL to also expose blocking methods, to account for in-Rust possible concurrency. Using `read()` and `write()` right now matches our PyO3 habits anyway, where all non-Sync objects have to be wrapped in a RwLock.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
52606
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
     1
// Copyright (c) 2019 Raphaël Gomès <rgomes@octobus.net>,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
     2
//                    Yuya Nishihara <yuya@tcha.org>
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
     3
//               2024 Georges Racinet <georges.racinet@cloudcrane.io>
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
     4
//
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
     5
// Permission is hereby granted, free of charge, to any person obtaining a copy
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
     6
// of this software and associated documentation files (the "Software"), to
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
     7
// deal in the Software without restriction, including without limitation the
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
     8
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
     9
// sell copies of the Software, and to permit persons to whom the Software is
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    10
// furnished to do so, subject to the following conditions:
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    11
//
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    12
// The above copyright notice and this permission notice shall be included in
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    13
// all copies or substantial portions of the Software.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    14
//
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    15
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    16
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    17
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    18
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    19
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    20
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    21
// IN THE SOFTWARE.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    22
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    23
//! Utility to share Rust reference across Python objects.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    24
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    25
use pyo3::exceptions::PyRuntimeError;
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    26
use pyo3::prelude::*;
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    27
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    28
use std::ops::{Deref, DerefMut};
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    29
use std::sync::atomic::{AtomicUsize, Ordering};
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    30
use std::sync::{
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    31
    RwLock, RwLockReadGuard, RwLockWriteGuard, TryLockError, TryLockResult,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    32
};
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    33
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    34
/// A mutable memory location shareable immutably across Python objects.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    35
///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    36
/// This data structure is meant to be used as a field in a Python class
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    37
/// definition.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    38
/// It provides interior mutability in a way that allows it to be immutably
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    39
/// referenced by other Python objects defined in Rust than its owner, in
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    40
/// a more general form than references to the whole data.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    41
/// These immutable references are stored in the referencing Python objects as
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    42
/// [`UnsafePyLeaked`] fields.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    43
///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    44
/// The primary use case is to implement a Python iterator over a Rust
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    45
/// iterator: since a Python object cannot hold a lifetime-bound object,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    46
/// `Iter<'a, T>` cannot be a data field of the Python iterator object.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    47
/// While `&'a T` can be replaced with [`std::sync::Arc`], this is typically
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    48
/// not suited for more complex objects that are created from such references
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    49
/// and re-expose the lifetime on their types, such as iterators.
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();
52608
d85514a88706 rust-pyo3-sharedref: reworked constructors
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52606
diff changeset
    86
///         Ok(Self { rust_set: s.into() })
52606
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    87
///     }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    88
///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    89
///     fn __iter__(slf: &Bound<'_, Self>) -> SetIterator {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    90
///         SetIterator::new(slf)
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    91
///     }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    92
///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    93
///     fn add(slf: &Bound<'_, Self>, i: i32) -> PyResult<()> {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    94
///         let rust_set = &slf.borrow().rust_set;
52608
d85514a88706 rust-pyo3-sharedref: reworked constructors
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52606
diff changeset
    95
///         let shared_ref = unsafe { rust_set.borrow_with_owner(slf) };
52609
d1e304025b90 rust-pyo3-sharedref: replaced borrow/borrow_mut with RwLock namings
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52608
diff changeset
    96
///         let mut set_ref = shared_ref.write();
52606
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    97
///         set_ref.insert(i);
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    98
///         Ok(())
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
    99
///     }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   100
/// }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   101
///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   102
/// #[pyclass]
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   103
/// struct SetIterator {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   104
///     rust_iter: UnsafePyLeaked<IterHashSet<'static, i32>>,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   105
/// }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   106
///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   107
/// #[pymethods]
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   108
/// impl SetIterator {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   109
///     #[new]
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   110
///     fn new(s: &Bound<'_, Set>) -> Self {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   111
///         let py = s.py();
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   112
///         let rust_set = &s.borrow().rust_set;
52608
d85514a88706 rust-pyo3-sharedref: reworked constructors
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52606
diff changeset
   113
///         let shared_ref = unsafe { rust_set.borrow_with_owner(s) };
52606
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   114
///         let leaked_set = shared_ref.leak_immutable();
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   115
///         let iter = unsafe { leaked_set.map(py, |o| o.iter()) };
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   116
///         Self {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   117
///             rust_iter: iter.into(),
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   118
///         }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   119
///     }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   120
///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   121
///     fn __iter__(slf: PyRef<'_, Self>) -> PyRef<'_, Self> {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   122
///         slf
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   123
///     }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   124
///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   125
///     fn __next__(mut slf: PyRefMut<'_, Self>) -> PyResult<Option<i32>> {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   126
///         let py = slf.py();
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   127
///         let leaked = &mut slf.rust_iter;
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   128
///         let mut inner = unsafe { leaked.try_borrow_mut(py) }?;
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   129
///         Ok(inner.next().copied())
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   130
///     }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   131
/// }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   132
///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   133
/// /// a shortcut similar  to `[pyo3::py_run!]`, allowing inspection of PyErr
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   134
/// fn py_run(statement: &CStr, locals: &Bound<'_, PyDict>) -> PyResult<()> {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   135
///     locals.py().run(statement, None, Some(locals))
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   136
/// }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   137
///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   138
/// # pyo3::prepare_freethreaded_python();
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   139
/// Python::with_gil(|py| {
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   140
///     let tuple = PyTuple::new(py, vec![2, 1, 2])?;
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   141
///     let set = Bound::new(py, Set::new(&tuple)?)?;
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   142
///     let iter = Bound::new(py, Set::__iter__(&set))?;
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   143
///     let locals = PyDict::new(py);
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   144
///     locals.set_item("rust_set", set).unwrap();
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   145
///     locals.set_item("rust_iter", iter).unwrap();
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   146
///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   147
///     /// iterating on our Rust set just works
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   148
///     py_run(
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   149
///         c_str!("assert sorted(i for i in rust_iter) == [1, 2]"),
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   150
///         &locals,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   151
///     )?;
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   152
///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   153
///     /// however, if any mutation occurs on the Rust set, the iterator
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   154
///     /// becomes invalid. Attempts to use it raise `RuntimeError`.
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   155
///     py_run(c_str!("rust_set.add(3)"), &locals)?;
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   156
///     let err = py_run(c_str!("next(rust_iter)"), &locals).unwrap_err();
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   157
///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   158
///     let exc_repr = format!("{:?}", err.value(py));
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   159
///     assert_eq!(
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   160
///         exc_repr,
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   161
///         "RuntimeError('Cannot access to leaked reference after mutation')"
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   162
///     );
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   163
/// # Ok::<(), PyErr>(())
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   164
/// })
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   165
/// # .expect("This example should not return an error");
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   166
/// ```
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   167
///
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   168
/// The borrow rules are enforced dynamically in a similar manner to the
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   169
/// Python iterator.
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.
52608
d85514a88706 rust-pyo3-sharedref: reworked constructors
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52606
diff changeset
   184
    pub unsafe fn borrow_with_owner<'py>(
52606
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
52608
d85514a88706 rust-pyo3-sharedref: reworked constructors
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52606
diff changeset
   196
impl<T> From<T> for PySharedRefCell<T> {
d85514a88706 rust-pyo3-sharedref: reworked constructors
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52606
diff changeset
   197
    fn from(value: T) -> Self {
d85514a88706 rust-pyo3-sharedref: reworked constructors
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52606
diff changeset
   198
        Self {
d85514a88706 rust-pyo3-sharedref: reworked constructors
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52606
diff changeset
   199
            state: PySharedState::new(),
d85514a88706 rust-pyo3-sharedref: reworked constructors
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52606
diff changeset
   200
            data: value.into(),
d85514a88706 rust-pyo3-sharedref: reworked constructors
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52606
diff changeset
   201
        }
d85514a88706 rust-pyo3-sharedref: reworked constructors
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52606
diff changeset
   202
    }
d85514a88706 rust-pyo3-sharedref: reworked constructors
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52606
diff changeset
   203
}
d85514a88706 rust-pyo3-sharedref: reworked constructors
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52606
diff changeset
   204
52606
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> {
52609
d1e304025b90 rust-pyo3-sharedref: replaced borrow/borrow_mut with RwLock namings
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52608
diff changeset
   233
    /// Take the lock on the wrapped value for read-only operations.
52606
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   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
    ///
52609
d1e304025b90 rust-pyo3-sharedref: replaced borrow/borrow_mut with RwLock namings
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52608
diff changeset
   237
    /// Panics if the lock is currently held for write operations.
d1e304025b90 rust-pyo3-sharedref: replaced borrow/borrow_mut with RwLock namings
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52608
diff changeset
   238
    pub fn read(&self) -> RwLockReadGuard<'py, T> {
d1e304025b90 rust-pyo3-sharedref: replaced borrow/borrow_mut with RwLock namings
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52608
diff changeset
   239
        self.try_read().expect("already mutably borrowed")
52606
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   240
    }
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   241
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.
52609
d1e304025b90 rust-pyo3-sharedref: replaced borrow/borrow_mut with RwLock namings
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52608
diff changeset
   244
    pub fn try_read(&self) -> TryLockResult<RwLockReadGuard<'py, T>> {
52606
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   245
        // state isn't involved since
52609
d1e304025b90 rust-pyo3-sharedref: replaced borrow/borrow_mut with RwLock namings
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52608
diff changeset
   246
        // - data.try_read() would fail if self is mutably borrowed,
d1e304025b90 rust-pyo3-sharedref: replaced borrow/borrow_mut with RwLock namings
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52608
diff changeset
   247
        // - and data.try_write() would fail while self is borrowed.
52606
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   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
52609
d1e304025b90 rust-pyo3-sharedref: replaced borrow/borrow_mut with RwLock namings
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52608
diff changeset
   251
    /// Take the lock on the wrapped value for write operations.
52606
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   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
    ///
52609
d1e304025b90 rust-pyo3-sharedref: replaced borrow/borrow_mut with RwLock namings
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52608
diff changeset
   257
    /// Panics if the lock is currently held.
d1e304025b90 rust-pyo3-sharedref: replaced borrow/borrow_mut with RwLock namings
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52608
diff changeset
   258
    pub fn write(&self) -> RwLockWriteGuard<'py, T> {
d1e304025b90 rust-pyo3-sharedref: replaced borrow/borrow_mut with RwLock namings
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52608
diff changeset
   259
        self.try_write().expect("already borrowed")
52606
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.
52609
d1e304025b90 rust-pyo3-sharedref: replaced borrow/borrow_mut with RwLock namings
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52608
diff changeset
   264
    pub fn try_write(&self) -> TryLockResult<RwLockWriteGuard<'py, T>> {
52606
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   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.
52609
d1e304025b90 rust-pyo3-sharedref: replaced borrow/borrow_mut with RwLock namings
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52608
diff changeset
   294
        let data_ref = self.try_read()?;
52606
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,
52609
d1e304025b90 rust-pyo3-sharedref: replaced borrow/borrow_mut with RwLock namings
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52608
diff changeset
   297
        // but the data pointer can be invalidated by write().
52606
be765f6797cc rust-pyo3: initial port of PySharedRef
Georges Racinet <georges.racinet@octobus.net>
parents:
diff changeset
   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
52609
d1e304025b90 rust-pyo3-sharedref: replaced borrow/borrow_mut with RwLock namings
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52608
diff changeset
   325
///   [`PySharedRefCell`] is allowed only through its `write()`.
52606
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.
52609
d1e304025b90 rust-pyo3-sharedref: replaced borrow/borrow_mut with RwLock namings
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52608
diff changeset
   333
/// - The `generation` counter, which increments on `write()`. `UnsafePyLeaked`
d1e304025b90 rust-pyo3-sharedref: replaced borrow/borrow_mut with RwLock namings
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52608
diff changeset
   334
///   reference is valid only if the `current_generation()` equals to the
d1e304025b90 rust-pyo3-sharedref: replaced borrow/borrow_mut with RwLock namings
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 52608
diff changeset
   335
///   `generation` at the time of `leak_immutable()`.
52606
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
}