rust/hg-cpython/src/ref_sharing.rs
author Yuya Nishihara <yuya@tcha.org>
Sat, 12 Oct 2019 20:48:30 +0900
changeset 43478 6f9f15a476a4
parent 43477 ed50f2c31a4c
child 43479 b7ab3a0a9e57
permissions -rw-r--r--
rust-cpython: remove useless Option<$leaked> from py_shared_iterator We no longer need to carefully drop the iterator when it's consumed. Mutation is allowed even if the iterator exists. There's a minor behavior change: next(iter) may return/raise something other than StopIteration if it's called after the iterator has been fully consumed, and if the Rust object isn't a FusedIterator.
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: 42943
diff changeset
     1
// ref_sharing.rs
42768
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: 42943
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: 42943
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: 42943
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: 42943
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: 42943
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: 42943
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: 42943
diff changeset
    11
//
fdfe5cfb3723 rust-cpython: change license of ref_sharing.rs to MIT
Yuya Nishihara <yuya@tcha.org>
parents: 42943
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: 42943
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: 42943
diff changeset
    14
//
fdfe5cfb3723 rust-cpython: change license of ref_sharing.rs to MIT
Yuya Nishihara <yuya@tcha.org>
parents: 42943
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: 42943
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: 42943
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: 42943
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: 42943
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: 42943
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: 42943
diff changeset
    21
// IN THE SOFTWARE.
42768
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;
43476
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
    26
use cpython::{exc, PyClone, PyErr, PyObject, PyResult, Python};
42855
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
diff changeset
    27
use std::cell::{Cell, Ref, RefCell, RefMut};
43475
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43474
diff changeset
    28
use std::ops::{Deref, DerefMut};
43476
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
    29
use std::sync::atomic::{AtomicUsize, Ordering};
42768
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
43476
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
    32
///
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
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: 43475
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: 43475
diff changeset
    35
/// as follows:
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
    36
///
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
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: 43475
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: 43475
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: 43475
diff changeset
    40
///   synchronized by the GIL.
43477
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
    41
/// - 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: 43476
diff changeset
    42
///   `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: 43476
diff changeset
    43
///   is borrowed.
43476
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
    44
/// - The `generation` counter, which increments on `borrow_mut()`. `PyLeaked`
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
    45
///   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: 43475
diff changeset
    46
///   `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
    47
#[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
    48
struct PySharedState {
42768
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    49
    mutably_borrowed: Cell<bool>,
43476
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
    50
    // 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: 43475
diff changeset
    51
    // 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: 43475
diff changeset
    52
    // PySharedState inherently Sync. The ordering requirement doesn't
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
    53
    // matter thanks to the GIL.
43477
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
    54
    borrow_count: AtomicUsize,
43476
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
    55
    generation: AtomicUsize,
42768
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    56
}
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    57
43175
a1908eb08342 rust-cpython: mark PySharedState as Sync so &'PySharedState can be Send
Yuya Nishihara <yuya@tcha.org>
parents: 43174
diff changeset
    58
// &PySharedState can be Send because any access to inner cells is
a1908eb08342 rust-cpython: mark PySharedState as Sync so &'PySharedState can be Send
Yuya Nishihara <yuya@tcha.org>
parents: 43174
diff changeset
    59
// synchronized by the GIL.
a1908eb08342 rust-cpython: mark PySharedState as Sync so &'PySharedState can be Send
Yuya Nishihara <yuya@tcha.org>
parents: 43174
diff changeset
    60
unsafe impl Sync for PySharedState {}
a1908eb08342 rust-cpython: mark PySharedState as Sync so &'PySharedState can be Send
Yuya Nishihara <yuya@tcha.org>
parents: 43174
diff changeset
    61
42768
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    62
impl PySharedState {
43288
434d7a3e92e3 rust-cpython: make inner functions and structs of ref_sharing private
Yuya Nishihara <yuya@tcha.org>
parents: 43287
diff changeset
    63
    fn borrow_mut<'a, T>(
42768
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    64
        &'a self,
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    65
        py: Python<'a>,
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    66
        pyrefmut: RefMut<'a, T>,
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    67
    ) -> PyResult<PyRefMut<'a, T>> {
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    68
        if self.mutably_borrowed.get() {
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    69
            return Err(AlreadyBorrowed::new(
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    70
                py,
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    71
                "Cannot borrow mutably while there exists another \
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    72
                 mutable reference in a Python object",
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    73
            ));
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    74
        }
43477
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
    75
        match self.current_borrow_count(py) {
42768
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    76
            0 => {
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    77
                self.mutably_borrowed.replace(true);
43476
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
    78
                // 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: 43475
diff changeset
    79
                // 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: 43475
diff changeset
    80
                // in practice.
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
    81
                self.generation.fetch_add(1, Ordering::Relaxed);
42768
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    82
                Ok(PyRefMut::new(py, pyrefmut, self))
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    83
            }
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    84
            _ => Err(AlreadyBorrowed::new(
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    85
                py,
43477
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
    86
                "Cannot borrow mutably while immutably borrowed",
42768
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    87
            )),
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    88
        }
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    89
    }
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    90
43176
aaec70a5f9a8 rust-cpython: store leaked reference to PySharedState in $leaked struct
Yuya Nishihara <yuya@tcha.org>
parents: 43175
diff changeset
    91
    /// 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
    92
    /// artificial static lifetime.
42768
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    93
    /// We need to be protected by the GIL for thread-safety.
42857
64e28b891796 rust-cpython: mark unsafe functions as such
Yuya Nishihara <yuya@tcha.org>
parents: 42856
diff changeset
    94
    ///
64e28b891796 rust-cpython: mark unsafe functions as such
Yuya Nishihara <yuya@tcha.org>
parents: 42856
diff changeset
    95
    /// # Safety
64e28b891796 rust-cpython: mark unsafe functions as such
Yuya Nishihara <yuya@tcha.org>
parents: 42856
diff changeset
    96
    ///
64e28b891796 rust-cpython: mark unsafe functions as such
Yuya Nishihara <yuya@tcha.org>
parents: 42856
diff changeset
    97
    /// 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: 42856
diff changeset
    98
    /// 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
    99
    unsafe fn leak_immutable<T>(
42768
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   100
        &self,
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   101
        py: Python,
42855
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
diff changeset
   102
        data: &PySharedRefCell<T>,
43176
aaec70a5f9a8 rust-cpython: store leaked reference to PySharedState in $leaked struct
Yuya Nishihara <yuya@tcha.org>
parents: 43175
diff changeset
   103
    ) -> PyResult<(&'static T, &'static PySharedState)> {
42768
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   104
        if self.mutably_borrowed.get() {
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   105
            return Err(AlreadyBorrowed::new(
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   106
                py,
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   107
                "Cannot borrow immutably while there is a \
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   108
                 mutable reference in Python objects",
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   109
            ));
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   110
        }
43176
aaec70a5f9a8 rust-cpython: store leaked reference to PySharedState in $leaked struct
Yuya Nishihara <yuya@tcha.org>
parents: 43175
diff changeset
   111
        // TODO: it's weird that self is data.py_shared_state. Maybe we
aaec70a5f9a8 rust-cpython: store leaked reference to PySharedState in $leaked struct
Yuya Nishihara <yuya@tcha.org>
parents: 43175
diff changeset
   112
        // can move stuff to PySharedRefCell?
42768
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   113
        let ptr = data.as_ptr();
43176
aaec70a5f9a8 rust-cpython: store leaked reference to PySharedState in $leaked struct
Yuya Nishihara <yuya@tcha.org>
parents: 43175
diff changeset
   114
        let state_ptr: *const PySharedState = &data.py_shared_state;
aaec70a5f9a8 rust-cpython: store leaked reference to PySharedState in $leaked struct
Yuya Nishihara <yuya@tcha.org>
parents: 43175
diff changeset
   115
        Ok((&*ptr, &*state_ptr))
42768
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
43477
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   118
    fn current_borrow_count(&self, _py: Python) -> usize {
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   119
        self.borrow_count.load(Ordering::Relaxed)
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   120
    }
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   121
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   122
    fn increase_borrow_count(&self, _py: Python) {
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   123
        // 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: 43476
diff changeset
   124
        // 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: 43476
diff changeset
   125
        self.borrow_count.fetch_add(1, Ordering::Relaxed);
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   126
    }
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   127
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   128
    fn decrease_borrow_count(&self, _py: Python) {
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   129
        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: 43476
diff changeset
   130
        assert!(prev_count > 0);
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   131
    }
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   132
42857
64e28b891796 rust-cpython: mark unsafe functions as such
Yuya Nishihara <yuya@tcha.org>
parents: 42856
diff changeset
   133
    /// # Safety
64e28b891796 rust-cpython: mark unsafe functions as such
Yuya Nishihara <yuya@tcha.org>
parents: 42856
diff changeset
   134
    ///
43288
434d7a3e92e3 rust-cpython: make inner functions and structs of ref_sharing private
Yuya Nishihara <yuya@tcha.org>
parents: 43287
diff changeset
   135
    /// It's up to you to make sure the reference is about to be deleted
434d7a3e92e3 rust-cpython: make inner functions and structs of ref_sharing private
Yuya Nishihara <yuya@tcha.org>
parents: 43287
diff changeset
   136
    /// when updating the leak count.
43477
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   137
    fn decrease_leak_count(&self, py: Python, mutable: bool) {
42768
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   138
        if mutable {
43477
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   139
            assert_eq!(self.current_borrow_count(py), 0);
42943
06080afd0565 rust-cpython: add sanity check to PySharedState::decrease_leak_count()
Yuya Nishihara <yuya@tcha.org>
parents: 42897
diff changeset
   140
            assert!(self.mutably_borrowed.get());
42768
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   141
            self.mutably_borrowed.replace(false);
42943
06080afd0565 rust-cpython: add sanity check to PySharedState::decrease_leak_count()
Yuya Nishihara <yuya@tcha.org>
parents: 42897
diff changeset
   142
        } else {
43477
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   143
            unimplemented!();
42768
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   144
        }
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   145
    }
43476
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   146
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   147
    fn current_generation(&self, _py: Python) -> usize {
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   148
        self.generation.load(Ordering::Relaxed)
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   149
    }
42768
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   150
}
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   151
43477
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   152
/// 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: 43476
diff changeset
   153
/// immutably borrowed without using the `RefCell` interface.
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   154
struct BorrowPyShared<'a> {
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   155
    py: Python<'a>,
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   156
    py_shared_state: &'a PySharedState,
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   157
}
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   158
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   159
impl<'a> BorrowPyShared<'a> {
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   160
    fn new(
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   161
        py: Python<'a>,
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   162
        py_shared_state: &'a PySharedState,
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   163
    ) -> BorrowPyShared<'a> {
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   164
        py_shared_state.increase_borrow_count(py);
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   165
        BorrowPyShared {
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   166
            py,
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   167
            py_shared_state,
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   168
        }
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   169
    }
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   170
}
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   171
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   172
impl Drop for BorrowPyShared<'_> {
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   173
    fn drop(&mut self) {
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   174
        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: 43476
diff changeset
   175
    }
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   176
}
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   177
42855
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
diff changeset
   178
/// `RefCell` wrapper to be safely used in conjunction with `PySharedState`.
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
diff changeset
   179
///
43288
434d7a3e92e3 rust-cpython: make inner functions and structs of ref_sharing private
Yuya Nishihara <yuya@tcha.org>
parents: 43287
diff changeset
   180
/// 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
   181
/// operation is allowed through the `PySharedRef` interface.
42855
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
diff changeset
   182
#[derive(Debug)]
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
diff changeset
   183
pub struct PySharedRefCell<T> {
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
diff changeset
   184
    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
   185
    py_shared_state: PySharedState,
42855
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
diff changeset
   186
}
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
diff changeset
   187
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
diff changeset
   188
impl<T> PySharedRefCell<T> {
43173
070a38737334 rust-cpython: move py_shared_state to PySharedRefCell object
Yuya Nishihara <yuya@tcha.org>
parents: 43082
diff changeset
   189
    pub fn new(value: T) -> PySharedRefCell<T> {
42855
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
diff changeset
   190
        Self {
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
diff changeset
   191
            inner: RefCell::new(value),
43173
070a38737334 rust-cpython: move py_shared_state to PySharedRefCell object
Yuya Nishihara <yuya@tcha.org>
parents: 43082
diff changeset
   192
            py_shared_state: PySharedState::default(),
42855
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
diff changeset
   193
        }
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
diff changeset
   194
    }
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
diff changeset
   195
43288
434d7a3e92e3 rust-cpython: make inner functions and structs of ref_sharing private
Yuya Nishihara <yuya@tcha.org>
parents: 43287
diff changeset
   196
    fn borrow<'a>(&'a self, _py: Python<'a>) -> Ref<'a, T> {
42855
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
diff changeset
   197
        // py_shared_state isn't involved since
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
diff changeset
   198
        // - inner.borrow() would fail if self is mutably borrowed,
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
diff changeset
   199
        // - and inner.borrow_mut() would fail while self is borrowed.
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
diff changeset
   200
        self.inner.borrow()
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
diff changeset
   201
    }
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
diff changeset
   202
43288
434d7a3e92e3 rust-cpython: make inner functions and structs of ref_sharing private
Yuya Nishihara <yuya@tcha.org>
parents: 43287
diff changeset
   203
    fn as_ptr(&self) -> *mut T {
42855
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
diff changeset
   204
        self.inner.as_ptr()
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
diff changeset
   205
    }
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
diff changeset
   206
43174
1c675c5fe5fe rust-cpython: move borrow_mut() to PySharedRefCell
Yuya Nishihara <yuya@tcha.org>
parents: 43173
diff changeset
   207
    // 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
   208
    // 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
   209
    // 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
   210
    // 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
   211
    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
   212
        self.py_shared_state.borrow_mut(py, self.inner.borrow_mut())
42855
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
diff changeset
   213
    }
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
diff changeset
   214
}
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
diff changeset
   215
43178
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   216
/// 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
   217
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
   218
    py: Python<'a>,
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   219
    owner: &'a PyObject,
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   220
    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
   221
}
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   222
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   223
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
   224
    /// # Safety
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   225
    ///
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   226
    /// 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
   227
    /// would get wrong.
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   228
    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
   229
        py: Python<'a>,
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   230
        owner: &'a PyObject,
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   231
        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
   232
    ) -> Self {
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   233
        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
   234
    }
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   235
43272
00222775d59b rust-refsharing: add missing lifetime parameter in ref_sharing
Raphaël Gomès <rgomes@octobus.net>
parents: 43180
diff changeset
   236
    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
   237
        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
   238
    }
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   239
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   240
    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
   241
        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
   242
    }
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   243
43285
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   244
    /// Returns a leaked reference.
43474
b9f791090211 rust-cpython: rename PyLeakedRef to PyLeaked
Yuya Nishihara <yuya@tcha.org>
parents: 43289
diff changeset
   245
    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
   246
        let state = &self.data.py_shared_state;
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   247
        unsafe {
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   248
            let (static_ref, static_state_ref) =
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   249
                state.leak_immutable(self.py, self.data)?;
43474
b9f791090211 rust-cpython: rename PyLeakedRef to PyLeaked
Yuya Nishihara <yuya@tcha.org>
parents: 43289
diff changeset
   250
            Ok(PyLeaked::new(
43285
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   251
                self.py,
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   252
                self.owner,
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   253
                static_ref,
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   254
                static_state_ref,
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   255
            ))
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   256
        }
43178
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   257
    }
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   258
}
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   259
42768
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   260
/// 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
   261
pub struct PyRefMut<'a, T> {
43287
0df8312463ae rust-cpython: keep Python<'a> token in PyRefMut
Yuya Nishihara <yuya@tcha.org>
parents: 43286
diff changeset
   262
    py: Python<'a>,
42768
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   263
    inner: RefMut<'a, T>,
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   264
    py_shared_state: &'a PySharedState,
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
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   267
impl<'a, T> PyRefMut<'a, T> {
42857
64e28b891796 rust-cpython: mark unsafe functions as such
Yuya Nishihara <yuya@tcha.org>
parents: 42856
diff changeset
   268
    // Must be constructed by PySharedState after checking its leak_count.
64e28b891796 rust-cpython: mark unsafe functions as such
Yuya Nishihara <yuya@tcha.org>
parents: 42856
diff changeset
   269
    // Otherwise, drop() would incorrectly update the state.
42768
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   270
    fn new(
43287
0df8312463ae rust-cpython: keep Python<'a> token in PyRefMut
Yuya Nishihara <yuya@tcha.org>
parents: 43286
diff changeset
   271
        py: Python<'a>,
42768
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   272
        inner: RefMut<'a, T>,
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   273
        py_shared_state: &'a PySharedState,
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   274
    ) -> Self {
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   275
        Self {
43287
0df8312463ae rust-cpython: keep Python<'a> token in PyRefMut
Yuya Nishihara <yuya@tcha.org>
parents: 43286
diff changeset
   276
            py,
42768
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   277
            inner,
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   278
            py_shared_state,
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
}
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   282
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   283
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
   284
    type Target = RefMut<'a, T>;
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   285
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   286
    fn deref(&self) -> &Self::Target {
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   287
        &self.inner
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   288
    }
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   289
}
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   290
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
   291
    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
   292
        &mut self.inner
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   293
    }
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   294
}
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   295
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   296
impl<'a, T> Drop for PyRefMut<'a, T> {
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   297
    fn drop(&mut self) {
43288
434d7a3e92e3 rust-cpython: make inner functions and structs of ref_sharing private
Yuya Nishihara <yuya@tcha.org>
parents: 43287
diff changeset
   298
        self.py_shared_state.decrease_leak_count(self.py, true);
42768
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   299
    }
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   300
}
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   301
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   302
/// 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
   303
/// data members with Python.
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   304
///
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   305
/// # Parameters
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   306
///
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   307
/// * `$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
   308
/// * `$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
   309
/// * `$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
   310
/// 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
   311
/// * `$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
   312
/// 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
   313
///
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   314
/// # Safety
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   315
///
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   316
/// `$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
   317
/// words, it must be an accessor to a data field of the Python object.
42768
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   318
///
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   319
/// # Example
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   320
///
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   321
/// ```
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   322
/// struct MyStruct {
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   323
///     inner: Vec<u32>;
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   324
/// }
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   325
///
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   326
/// py_class!(pub class MyType |py| {
42855
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42849
diff changeset
   327
///     data inner: PySharedRefCell<MyStruct>;
42768
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   328
/// });
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   329
///
43178
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   330
/// py_shared_ref!(MyType, MyStruct, inner, inner_shared);
42768
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   331
/// ```
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   332
macro_rules! py_shared_ref {
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   333
    (
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   334
        $name: ident,
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   335
        $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
   336
        $data_member: ident,
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   337
        $shared_accessor: ident
42768
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   338
    ) => {
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   339
        impl $name {
43178
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   340
            /// 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
   341
            ///
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   342
            /// 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
   343
            /// 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
   344
            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
   345
                &'a self,
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   346
                py: Python<'a>,
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   347
            ) -> $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
   348
                use cpython::PythonObject;
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   349
                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
   350
                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
   351
                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
   352
                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
   353
            }
42768
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   354
        }
43177
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
   355
    };
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
   356
}
42768
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   357
43177
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
   358
/// Manage immutable references to `PyObject` leaked into Python iterators.
43476
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   359
///
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   360
/// 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: 43475
diff changeset
   361
/// borrowed.
43474
b9f791090211 rust-cpython: rename PyLeakedRef to PyLeaked
Yuya Nishihara <yuya@tcha.org>
parents: 43289
diff changeset
   362
pub struct PyLeaked<T> {
43285
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   363
    inner: PyObject,
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   364
    data: Option<T>,
43177
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
   365
    py_shared_state: &'static PySharedState,
43476
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   366
    /// 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: 43475
diff changeset
   367
    generation: usize,
43177
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
   368
}
42768
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   369
43474
b9f791090211 rust-cpython: rename PyLeakedRef to PyLeaked
Yuya Nishihara <yuya@tcha.org>
parents: 43289
diff changeset
   370
// DO NOT implement Deref for PyLeaked<T>! Dereferencing PyLeaked
43476
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   371
// 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: 43475
diff changeset
   372
// 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
   373
43474
b9f791090211 rust-cpython: rename PyLeakedRef to PyLeaked
Yuya Nishihara <yuya@tcha.org>
parents: 43289
diff changeset
   374
impl<T> PyLeaked<T> {
43177
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
   375
    /// # Safety
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
   376
    ///
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
   377
    /// 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
   378
    fn new(
43177
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
   379
        py: Python,
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
   380
        inner: &PyObject,
43284
ce6dd1cee4c8 rust-cpython: put leaked reference in PyLeakedRef
Yuya Nishihara <yuya@tcha.org>
parents: 43272
diff changeset
   381
        data: T,
43177
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
   382
        py_shared_state: &'static PySharedState,
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
   383
    ) -> Self {
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
   384
        Self {
43285
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   385
            inner: inner.clone_ref(py),
43284
ce6dd1cee4c8 rust-cpython: put leaked reference in PyLeakedRef
Yuya Nishihara <yuya@tcha.org>
parents: 43272
diff changeset
   386
            data: Some(data),
43177
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
   387
            py_shared_state,
43476
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   388
            generation: py_shared_state.current_generation(py),
42768
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   389
        }
43177
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
   390
    }
43285
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   391
43475
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43474
diff changeset
   392
    /// Immutably borrows the wrapped value.
43476
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   393
    ///
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   394
    /// Borrowing fails if the underlying reference has been invalidated.
43475
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43474
diff changeset
   395
    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: 43474
diff changeset
   396
        &'a self,
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43474
diff changeset
   397
        py: Python<'a>,
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43474
diff changeset
   398
    ) -> PyResult<PyLeakedRef<'a, T>> {
43476
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   399
        self.validate_generation(py)?;
43475
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43474
diff changeset
   400
        Ok(PyLeakedRef {
43477
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   401
            _borrow: BorrowPyShared::new(py, self.py_shared_state),
43475
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43474
diff changeset
   402
            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: 43474
diff changeset
   403
        })
43285
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   404
    }
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   405
43475
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43474
diff changeset
   406
    /// Mutably borrows the wrapped value.
43285
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   407
    ///
43476
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   408
    /// Borrowing fails if the underlying reference has been invalidated.
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   409
    ///
43285
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   410
    /// 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
   411
    /// `get_mut()` is useless since the inner value can't be mutated.
43475
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43474
diff changeset
   412
    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: 43474
diff changeset
   413
        &'a mut self,
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43474
diff changeset
   414
        py: Python<'a>,
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43474
diff changeset
   415
    ) -> PyResult<PyLeakedRefMut<'a, T>> {
43476
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   416
        self.validate_generation(py)?;
43475
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43474
diff changeset
   417
        Ok(PyLeakedRefMut {
43477
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   418
            _borrow: BorrowPyShared::new(py, self.py_shared_state),
43475
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43474
diff changeset
   419
            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: 43474
diff changeset
   420
        })
43285
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   421
    }
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   422
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   423
    /// 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
   424
    ///
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   425
    /// 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
   426
    /// iterator of that container.
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   427
    ///
43476
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   428
    /// # Panics
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   429
    ///
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   430
    /// Panics if the underlying reference has been invalidated.
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   431
    ///
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   432
    /// 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: 43475
diff changeset
   433
    /// 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: 43475
diff changeset
   434
    ///
43285
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   435
    /// # Safety
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   436
    ///
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   437
    /// 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
   438
    /// It's typically a static reference, but is valid only while the
43474
b9f791090211 rust-cpython: rename PyLeakedRef to PyLeaked
Yuya Nishihara <yuya@tcha.org>
parents: 43289
diff changeset
   439
    /// 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
   440
    /// function call.
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   441
    pub unsafe fn map<U>(
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   442
        mut self,
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   443
        py: Python,
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   444
        f: impl FnOnce(T) -> U,
43474
b9f791090211 rust-cpython: rename PyLeakedRef to PyLeaked
Yuya Nishihara <yuya@tcha.org>
parents: 43289
diff changeset
   445
    ) -> PyLeaked<U> {
43476
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   446
        // 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: 43475
diff changeset
   447
        // is still intact.
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   448
        self.validate_generation(py)
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   449
            .expect("map() over invalidated leaked reference");
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   450
43285
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   451
        // 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
   452
        // 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
   453
        // 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
   454
        // returned object back to Something<'static>.
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   455
        let new_data = f(self.data.take().unwrap());
43474
b9f791090211 rust-cpython: rename PyLeakedRef to PyLeaked
Yuya Nishihara <yuya@tcha.org>
parents: 43289
diff changeset
   456
        PyLeaked {
43285
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   457
            inner: self.inner.clone_ref(py),
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   458
            data: Some(new_data),
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   459
            py_shared_state: self.py_shared_state,
43476
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   460
            generation: self.generation,
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   461
        }
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   462
    }
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   463
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   464
    fn validate_generation(&self, py: Python) -> PyResult<()> {
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   465
        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: 43475
diff changeset
   466
            Ok(())
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   467
        } else {
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   468
            Err(PyErr::new::<exc::RuntimeError, _>(
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   469
                py,
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   470
                "Cannot access to leaked reference after mutation",
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   471
            ))
43285
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   472
        }
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   473
    }
43177
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
   474
}
42768
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   475
43475
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43474
diff changeset
   476
/// 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: 43474
diff changeset
   477
pub struct PyLeakedRef<'a, T> {
43477
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   478
    _borrow: BorrowPyShared<'a>,
43475
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43474
diff changeset
   479
    data: &'a T,
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43474
diff changeset
   480
}
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43474
diff changeset
   481
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43474
diff changeset
   482
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: 43474
diff changeset
   483
    type Target = T;
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43474
diff changeset
   484
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43474
diff changeset
   485
    fn deref(&self) -> &T {
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43474
diff changeset
   486
        self.data
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43474
diff changeset
   487
    }
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43474
diff changeset
   488
}
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43474
diff changeset
   489
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43474
diff changeset
   490
/// 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: 43474
diff changeset
   491
pub struct PyLeakedRefMut<'a, T> {
43477
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   492
    _borrow: BorrowPyShared<'a>,
43475
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43474
diff changeset
   493
    data: &'a mut T,
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43474
diff changeset
   494
}
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43474
diff changeset
   495
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43474
diff changeset
   496
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: 43474
diff changeset
   497
    type Target = T;
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43474
diff changeset
   498
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43474
diff changeset
   499
    fn deref(&self) -> &T {
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43474
diff changeset
   500
        self.data
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43474
diff changeset
   501
    }
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43474
diff changeset
   502
}
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43474
diff changeset
   503
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43474
diff changeset
   504
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: 43474
diff changeset
   505
    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: 43474
diff changeset
   506
        self.data
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43474
diff changeset
   507
    }
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43474
diff changeset
   508
}
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43474
diff changeset
   509
42768
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   510
/// Defines a `py_class!` that acts as a Python iterator over a Rust iterator.
42894
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
   511
///
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
   512
/// 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: 42893
diff changeset
   513
///     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: 42893
diff changeset
   514
///
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
   515
/// # Parameters
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
   516
///
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
   517
/// * `$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: 42893
diff changeset
   518
/// * `$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: 42893
diff changeset
   519
/// * `$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: 42893
diff changeset
   520
/// * `$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: 42893
diff changeset
   521
/// 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: 42893
diff changeset
   522
/// * `$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: 42893
diff changeset
   523
///
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
   524
/// # Example
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
   525
///
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
   526
/// ```
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
   527
/// struct MyStruct {
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
   528
///     inner: HashMap<Vec<u8>, Vec<u8>>;
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
   529
/// }
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
   530
///
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
   531
/// py_class!(pub class MyType |py| {
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
   532
///     data inner: PySharedRefCell<MyStruct>;
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
   533
///
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
   534
///     def __iter__(&self) -> PyResult<MyTypeItemsIterator> {
43285
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   535
///         let leaked_ref = self.inner_shared(py).leak_immutable()?;
42897
5ccc08d02280 rust-cpython: leverage py_shared_iterator::from_inner() where appropriate
Yuya Nishihara <yuya@tcha.org>
parents: 42896
diff changeset
   536
///         MyTypeItemsIterator::from_inner(
42894
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
   537
///             py,
43285
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   538
///             unsafe { leaked_ref.map(py, |o| o.iter()) },
42894
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
   539
///         )
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
   540
///     }
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
   541
/// });
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
   542
///
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
   543
/// impl MyType {
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
   544
///     fn translate_key_value(
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
   545
///         py: Python,
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
   546
///         res: (&Vec<u8>, &Vec<u8>),
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
   547
///     ) -> PyResult<Option<(PyBytes, PyBytes)>> {
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
   548
///         let (f, entry) = res;
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
   549
///         Ok(Some((
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
   550
///             PyBytes::new(py, f),
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
   551
///             PyBytes::new(py, entry),
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
   552
///         )))
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
   553
///     }
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
   554
/// }
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
   555
///
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
   556
/// py_shared_ref!(MyType, MyStruct, inner, MyTypeLeakedRef);
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
   557
///
42895
ea91a126c803 rust-cpython: rename py_shared_iterator_impl to py_shared_iterator
Yuya Nishihara <yuya@tcha.org>
parents: 42894
diff changeset
   558
/// py_shared_iterator!(
42894
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
   559
///     MyTypeItemsIterator,
43474
b9f791090211 rust-cpython: rename PyLeakedRef to PyLeaked
Yuya Nishihara <yuya@tcha.org>
parents: 43289
diff changeset
   560
///     PyLeaked<HashMap<'static, Vec<u8>, Vec<u8>>>,
42894
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
   561
///     MyType::translate_key_value,
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
   562
///     Option<(PyBytes, PyBytes)>
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
   563
/// );
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42893
diff changeset
   564
/// ```
42895
ea91a126c803 rust-cpython: rename py_shared_iterator_impl to py_shared_iterator
Yuya Nishihara <yuya@tcha.org>
parents: 42894
diff changeset
   565
macro_rules! py_shared_iterator {
42768
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   566
    (
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   567
        $name: ident,
43177
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
   568
        $leaked: ty,
42768
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   569
        $success_func: expr,
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   570
        $success_type: ty
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   571
    ) => {
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   572
        py_class!(pub class $name |py| {
43478
6f9f15a476a4 rust-cpython: remove useless Option<$leaked> from py_shared_iterator
Yuya Nishihara <yuya@tcha.org>
parents: 43477
diff changeset
   573
            data inner: RefCell<$leaked>;
42768
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   574
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   575
            def __next__(&self) -> PyResult<$success_type> {
43478
6f9f15a476a4 rust-cpython: remove useless Option<$leaked> from py_shared_iterator
Yuya Nishihara <yuya@tcha.org>
parents: 43477
diff changeset
   576
                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: 43477
diff changeset
   577
                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: 43477
diff changeset
   578
                match iter.next() {
6f9f15a476a4 rust-cpython: remove useless Option<$leaked> from py_shared_iterator
Yuya Nishihara <yuya@tcha.org>
parents: 43477
diff changeset
   579
                    None => Ok(None),
6f9f15a476a4 rust-cpython: remove useless Option<$leaked> from py_shared_iterator
Yuya Nishihara <yuya@tcha.org>
parents: 43477
diff changeset
   580
                    Some(res) => $success_func(py, res),
42768
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   581
                }
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   582
            }
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   583
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   584
            def __iter__(&self) -> PyResult<Self> {
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   585
                Ok(self.clone_ref(py))
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   586
            }
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   587
        });
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   588
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   589
        impl $name {
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   590
            pub fn from_inner(
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   591
                py: Python,
42896
74d67c645278 rust-cpython: remove Option<_> from interface of py_shared_iterator
Yuya Nishihara <yuya@tcha.org>
parents: 42895
diff changeset
   592
                leaked: $leaked,
42768
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   593
            ) -> PyResult<Self> {
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   594
                Self::create_instance(
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   595
                    py,
43478
6f9f15a476a4 rust-cpython: remove useless Option<$leaked> from py_shared_iterator
Yuya Nishihara <yuya@tcha.org>
parents: 43477
diff changeset
   596
                    RefCell::new(leaked),
42768
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   597
                )
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   598
            }
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   599
        }
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   600
    };
30320c7bf79f rust-cpython: add macro for sharing references
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   601
}
43289
8d432d3a2d7c rust-cpython: prepare for writing tests that require libpython
Yuya Nishihara <yuya@tcha.org>
parents: 43288
diff changeset
   602
8d432d3a2d7c rust-cpython: prepare for writing tests that require libpython
Yuya Nishihara <yuya@tcha.org>
parents: 43288
diff changeset
   603
#[cfg(test)]
8d432d3a2d7c rust-cpython: prepare for writing tests that require libpython
Yuya Nishihara <yuya@tcha.org>
parents: 43288
diff changeset
   604
#[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
   605
mod test {
8d432d3a2d7c rust-cpython: prepare for writing tests that require libpython
Yuya Nishihara <yuya@tcha.org>
parents: 43288
diff changeset
   606
    use super::*;
8d432d3a2d7c rust-cpython: prepare for writing tests that require libpython
Yuya Nishihara <yuya@tcha.org>
parents: 43288
diff changeset
   607
    use cpython::{GILGuard, Python};
8d432d3a2d7c rust-cpython: prepare for writing tests that require libpython
Yuya Nishihara <yuya@tcha.org>
parents: 43288
diff changeset
   608
8d432d3a2d7c rust-cpython: prepare for writing tests that require libpython
Yuya Nishihara <yuya@tcha.org>
parents: 43288
diff changeset
   609
    py_class!(class Owner |py| {
8d432d3a2d7c rust-cpython: prepare for writing tests that require libpython
Yuya Nishihara <yuya@tcha.org>
parents: 43288
diff changeset
   610
        data string: PySharedRefCell<String>;
8d432d3a2d7c rust-cpython: prepare for writing tests that require libpython
Yuya Nishihara <yuya@tcha.org>
parents: 43288
diff changeset
   611
    });
8d432d3a2d7c rust-cpython: prepare for writing tests that require libpython
Yuya Nishihara <yuya@tcha.org>
parents: 43288
diff changeset
   612
    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
   613
8d432d3a2d7c rust-cpython: prepare for writing tests that require libpython
Yuya Nishihara <yuya@tcha.org>
parents: 43288
diff changeset
   614
    fn prepare_env() -> (GILGuard, Owner) {
8d432d3a2d7c rust-cpython: prepare for writing tests that require libpython
Yuya Nishihara <yuya@tcha.org>
parents: 43288
diff changeset
   615
        let gil = Python::acquire_gil();
8d432d3a2d7c rust-cpython: prepare for writing tests that require libpython
Yuya Nishihara <yuya@tcha.org>
parents: 43288
diff changeset
   616
        let py = gil.python();
8d432d3a2d7c rust-cpython: prepare for writing tests that require libpython
Yuya Nishihara <yuya@tcha.org>
parents: 43288
diff changeset
   617
        let owner =
8d432d3a2d7c rust-cpython: prepare for writing tests that require libpython
Yuya Nishihara <yuya@tcha.org>
parents: 43288
diff changeset
   618
            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
   619
                .unwrap();
8d432d3a2d7c rust-cpython: prepare for writing tests that require libpython
Yuya Nishihara <yuya@tcha.org>
parents: 43288
diff changeset
   620
        (gil, owner)
8d432d3a2d7c rust-cpython: prepare for writing tests that require libpython
Yuya Nishihara <yuya@tcha.org>
parents: 43288
diff changeset
   621
    }
8d432d3a2d7c rust-cpython: prepare for writing tests that require libpython
Yuya Nishihara <yuya@tcha.org>
parents: 43288
diff changeset
   622
8d432d3a2d7c rust-cpython: prepare for writing tests that require libpython
Yuya Nishihara <yuya@tcha.org>
parents: 43288
diff changeset
   623
    #[test]
43475
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43474
diff changeset
   624
    fn test_leaked_borrow() {
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43474
diff changeset
   625
        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: 43474
diff changeset
   626
        let py = gil.python();
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43474
diff changeset
   627
        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: 43474
diff changeset
   628
        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: 43474
diff changeset
   629
        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: 43474
diff changeset
   630
    }
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43474
diff changeset
   631
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43474
diff changeset
   632
    #[test]
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43474
diff changeset
   633
    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: 43474
diff changeset
   634
        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: 43474
diff changeset
   635
        let py = gil.python();
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43474
diff changeset
   636
        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: 43474
diff changeset
   637
        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: 43474
diff changeset
   638
        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: 43474
diff changeset
   639
        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: 43474
diff changeset
   640
        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: 43474
diff changeset
   641
        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: 43474
diff changeset
   642
        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: 43474
diff changeset
   643
    }
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43474
diff changeset
   644
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43474
diff changeset
   645
    #[test]
43476
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   646
    fn test_leaked_borrow_after_mut() {
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   647
        let (gil, owner) = prepare_env();
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   648
        let py = gil.python();
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   649
        let leaked = owner.string_shared(py).leak_immutable().unwrap();
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   650
        owner.string_shared(py).borrow_mut().unwrap().clear();
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   651
        assert!(leaked.try_borrow(py).is_err());
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   652
    }
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   653
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   654
    #[test]
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   655
    fn test_leaked_borrow_mut_after_mut() {
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   656
        let (gil, owner) = prepare_env();
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   657
        let py = gil.python();
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   658
        let leaked = owner.string_shared(py).leak_immutable().unwrap();
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   659
        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: 43475
diff changeset
   660
        owner.string_shared(py).borrow_mut().unwrap().clear();
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   661
        assert!(leaked_iter.try_borrow_mut(py).is_err());
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   662
    }
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   663
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   664
    #[test]
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   665
    #[should_panic(expected = "map() over invalidated leaked reference")]
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   666
    fn test_leaked_map_after_mut() {
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   667
        let (gil, owner) = prepare_env();
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   668
        let py = gil.python();
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   669
        let leaked = owner.string_shared(py).leak_immutable().unwrap();
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   670
        owner.string_shared(py).borrow_mut().unwrap().clear();
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   671
        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: 43475
diff changeset
   672
    }
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   673
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43475
diff changeset
   674
    #[test]
43477
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   675
    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
   676
        let (gil, owner) = prepare_env();
8d432d3a2d7c rust-cpython: prepare for writing tests that require libpython
Yuya Nishihara <yuya@tcha.org>
parents: 43288
diff changeset
   677
        let py = gil.python();
8d432d3a2d7c rust-cpython: prepare for writing tests that require libpython
Yuya Nishihara <yuya@tcha.org>
parents: 43288
diff changeset
   678
        assert!(owner.string_shared(py).borrow_mut().is_ok());
43477
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   679
        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: 43476
diff changeset
   680
        {
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   681
            let _leaked_ref = leaked.try_borrow(py).unwrap();
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   682
            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: 43476
diff changeset
   683
            {
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   684
                let _leaked_ref2 = leaked.try_borrow(py).unwrap();
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   685
                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: 43476
diff changeset
   686
            }
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   687
            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: 43476
diff changeset
   688
        }
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   689
        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: 43476
diff changeset
   690
    }
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   691
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   692
    #[test]
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   693
    fn test_borrow_mut_while_leaked_ref_mut() {
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   694
        let (gil, owner) = prepare_env();
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   695
        let py = gil.python();
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   696
        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: 43476
diff changeset
   697
        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: 43476
diff changeset
   698
        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: 43476
diff changeset
   699
        {
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   700
            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: 43476
diff changeset
   701
            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: 43476
diff changeset
   702
        }
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43476
diff changeset
   703
        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
   704
    }
8d432d3a2d7c rust-cpython: prepare for writing tests that require libpython
Yuya Nishihara <yuya@tcha.org>
parents: 43288
diff changeset
   705
}