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