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