rust/hg-cpython/src/ref_sharing.rs
author Yuya Nishihara <yuya@tcha.org>
Tue, 22 Oct 2019 16:04:34 +0900
changeset 44207 e960c30d7e50
parent 44206 9804badd5970
child 44235 6b7aef44274b
permissions -rw-r--r--
rust-cpython: mark all PyLeaked methods as unsafe Unfortunately, these methods can be abused to obtain the inner 'static reference. The simplest (pseudo-code) example is: let leaked: PyLeaked<&'static _> = shared.leak_immutable(); let static_ref: &'static _ = &*leaked.try_borrow(py)?; // PyLeakedRef::deref() tries to bound the lifetime to itself, but // the underlying data is a &'static reference, so the returned // reference can be &'static. This problem can be easily fixed by coercing the lifetime, but there are many other ways to achieve that, and there wouldn't be a generic solution: let leaked: PyLeaked<&'static [_]> = shared.leak_immutable(); let leaked_iter: PyLeaked<slice::Iter<'static, _>> = unsafe { leaked.map(|v| v.iter()) }; let static_slice: &'static [_] = leaked_iter.try_borrow(py)?.as_slice(); So basically I failed to design the safe borrowing interface. Maybe we'll instead have to add much more restricted interface on top of the unsafe PyLeaked methods? For instance, Iterator::next() could be implemented if its Item type is not &'a (where 'a may be cheated.) Anyway, this seems not an easy issue, so it's probably better to leave the current interface as unsafe, and get broader comments while upstreaming this feature.
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
43424
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
    25
use cpython::{exc, PyClone, PyErr, PyObject, PyResult, Python};
44206
9804badd5970 rust-cpython: make PySharedRef::try_borrow_mut() return BorrowMutError
Yuya Nishihara <yuya@tcha.org>
parents: 44205
diff changeset
    26
use std::cell::{BorrowMutError, 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
    27
use std::ops::{Deref, DerefMut};
44206
9804badd5970 rust-cpython: make PySharedRef::try_borrow_mut() return BorrowMutError
Yuya Nishihara <yuya@tcha.org>
parents: 44205
diff changeset
    28
use std::result;
43424
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
    29
use std::sync::atomic::{AtomicUsize, Ordering};
42752
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    30
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    31
/// Manages the shared state between Python and Rust
43424
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
    32
///
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
    33
/// `PySharedState` is owned by `PySharedRefCell`, and is shared across its
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
    34
/// derived references. The consistency of these references are guaranteed
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
    35
/// as follows:
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
    36
///
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
    37
/// - The immutability of `py_class!` object fields. Any mutation of
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
    38
///   `PySharedRefCell` is allowed only through its `borrow_mut()`.
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
    39
/// - The `py: Python<'_>` token, which makes sure that any data access is
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
    40
///   synchronized by the GIL.
43427
b7ab3a0a9e57 rust-cpython: leverage RefCell::borrow() to guarantee there's no mutable ref
Yuya Nishihara <yuya@tcha.org>
parents: 43426
diff changeset
    41
/// - The underlying `RefCell`, which prevents `PySharedRefCell` data from
b7ab3a0a9e57 rust-cpython: leverage RefCell::borrow() to guarantee there's no mutable ref
Yuya Nishihara <yuya@tcha.org>
parents: 43426
diff changeset
    42
///   being directly borrowed or leaked while it is mutably borrowed.
43425
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
    43
/// - The `borrow_count`, which is the number of references borrowed from
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
    44
///   `PyLeaked`. Just like `RefCell`, mutation is prohibited while `PyLeaked`
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
    45
///   is borrowed.
43424
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
    46
/// - The `generation` counter, which increments on `borrow_mut()`. `PyLeaked`
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
    47
///   reference is valid only if the `current_generation()` equals to the
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
    48
///   `generation` at the time of `leak_immutable()`.
43173
070a38737334 rust-cpython: move py_shared_state to PySharedRefCell object
Yuya Nishihara <yuya@tcha.org>
parents: 43082
diff changeset
    49
#[derive(Debug, Default)]
43288
434d7a3e92e3 rust-cpython: make inner functions and structs of ref_sharing private
Yuya Nishihara <yuya@tcha.org>
parents: 43287
diff changeset
    50
struct PySharedState {
43424
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
    51
    // The counter variable could be Cell<usize> since any operation on
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
    52
    // PySharedState is synchronized by the GIL, but being "atomic" makes
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
    53
    // PySharedState inherently Sync. The ordering requirement doesn't
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
    54
    // matter thanks to the GIL.
43425
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
    55
    borrow_count: AtomicUsize,
43424
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
    56
    generation: AtomicUsize,
42752
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    57
}
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    58
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    59
impl PySharedState {
43425
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
    60
    fn current_borrow_count(&self, _py: Python) -> usize {
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
    61
        self.borrow_count.load(Ordering::Relaxed)
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
    62
    }
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
    63
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
    64
    fn increase_borrow_count(&self, _py: Python) {
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
    65
        // Note that this wraps around if there are more than usize::MAX
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
    66
        // borrowed references, which shouldn't happen due to memory limit.
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
    67
        self.borrow_count.fetch_add(1, Ordering::Relaxed);
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
    68
    }
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
    69
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
    70
    fn decrease_borrow_count(&self, _py: Python) {
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
    71
        let prev_count = self.borrow_count.fetch_sub(1, Ordering::Relaxed);
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
    72
        assert!(prev_count > 0);
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
    73
    }
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
    74
43424
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
    75
    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
    76
        self.generation.load(Ordering::Relaxed)
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
    77
    }
44204
bafdaf4858d8 rust-cpython: inline PySharedState::try_borrow_mut()
Yuya Nishihara <yuya@tcha.org>
parents: 44203
diff changeset
    78
bafdaf4858d8 rust-cpython: inline PySharedState::try_borrow_mut()
Yuya Nishihara <yuya@tcha.org>
parents: 44203
diff changeset
    79
    fn increment_generation(&self, py: Python) {
bafdaf4858d8 rust-cpython: inline PySharedState::try_borrow_mut()
Yuya Nishihara <yuya@tcha.org>
parents: 44203
diff changeset
    80
        assert_eq!(self.current_borrow_count(py), 0);
bafdaf4858d8 rust-cpython: inline PySharedState::try_borrow_mut()
Yuya Nishihara <yuya@tcha.org>
parents: 44203
diff changeset
    81
        // Note that this wraps around to the same value if mutably
bafdaf4858d8 rust-cpython: inline PySharedState::try_borrow_mut()
Yuya Nishihara <yuya@tcha.org>
parents: 44203
diff changeset
    82
        // borrowed more than usize::MAX times, which wouldn't happen
bafdaf4858d8 rust-cpython: inline PySharedState::try_borrow_mut()
Yuya Nishihara <yuya@tcha.org>
parents: 44203
diff changeset
    83
        // in practice.
bafdaf4858d8 rust-cpython: inline PySharedState::try_borrow_mut()
Yuya Nishihara <yuya@tcha.org>
parents: 44203
diff changeset
    84
        self.generation.fetch_add(1, Ordering::Relaxed);
bafdaf4858d8 rust-cpython: inline PySharedState::try_borrow_mut()
Yuya Nishihara <yuya@tcha.org>
parents: 44203
diff changeset
    85
    }
42752
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    86
}
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    87
43425
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
    88
/// Helper to keep the borrow count updated while the shared object is
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
    89
/// immutably borrowed without using the `RefCell` interface.
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
    90
struct BorrowPyShared<'a> {
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
    91
    py: Python<'a>,
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
    92
    py_shared_state: &'a PySharedState,
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
    93
}
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
    94
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
    95
impl<'a> BorrowPyShared<'a> {
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
    96
    fn new(
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
    97
        py: Python<'a>,
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
    98
        py_shared_state: &'a PySharedState,
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
    99
    ) -> BorrowPyShared<'a> {
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
   100
        py_shared_state.increase_borrow_count(py);
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
   101
        BorrowPyShared {
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
   102
            py,
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
   103
            py_shared_state,
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
   104
        }
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
   105
    }
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
   106
}
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
   107
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
   108
impl Drop for BorrowPyShared<'_> {
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
   109
    fn drop(&mut self) {
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
   110
        self.py_shared_state.decrease_borrow_count(self.py);
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
   111
    }
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
   112
}
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
   113
42849
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42839
diff changeset
   114
/// `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
   115
///
43288
434d7a3e92e3 rust-cpython: make inner functions and structs of ref_sharing private
Yuya Nishihara <yuya@tcha.org>
parents: 43287
diff changeset
   116
/// 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
   117
/// 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
   118
#[derive(Debug)]
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42839
diff changeset
   119
pub struct PySharedRefCell<T> {
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42839
diff changeset
   120
    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
   121
    py_shared_state: PySharedState,
42849
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42839
diff changeset
   122
}
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42839
diff changeset
   123
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42839
diff changeset
   124
impl<T> PySharedRefCell<T> {
43173
070a38737334 rust-cpython: move py_shared_state to PySharedRefCell object
Yuya Nishihara <yuya@tcha.org>
parents: 43082
diff changeset
   125
    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
   126
        Self {
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42839
diff changeset
   127
            inner: RefCell::new(value),
43173
070a38737334 rust-cpython: move py_shared_state to PySharedRefCell object
Yuya Nishihara <yuya@tcha.org>
parents: 43082
diff changeset
   128
            py_shared_state: PySharedState::default(),
42849
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42839
diff changeset
   129
        }
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42839
diff changeset
   130
    }
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42839
diff changeset
   131
43288
434d7a3e92e3 rust-cpython: make inner functions and structs of ref_sharing private
Yuya Nishihara <yuya@tcha.org>
parents: 43287
diff changeset
   132
    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
   133
        // py_shared_state isn't involved since
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42839
diff changeset
   134
        // - inner.borrow() would fail if self is mutably borrowed,
44189
4a4c3b9fd91b rust-cpython: make sure PySharedRef::borrow_mut() never panics
Yuya Nishihara <yuya@tcha.org>
parents: 44188
diff changeset
   135
        // - and inner.try_borrow_mut() would fail while self is borrowed.
42849
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42839
diff changeset
   136
        self.inner.borrow()
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42839
diff changeset
   137
    }
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42839
diff changeset
   138
44189
4a4c3b9fd91b rust-cpython: make sure PySharedRef::borrow_mut() never panics
Yuya Nishihara <yuya@tcha.org>
parents: 44188
diff changeset
   139
    fn try_borrow_mut<'a>(
4a4c3b9fd91b rust-cpython: make sure PySharedRef::borrow_mut() never panics
Yuya Nishihara <yuya@tcha.org>
parents: 44188
diff changeset
   140
        &'a self,
4a4c3b9fd91b rust-cpython: make sure PySharedRef::borrow_mut() never panics
Yuya Nishihara <yuya@tcha.org>
parents: 44188
diff changeset
   141
        py: Python<'a>,
44206
9804badd5970 rust-cpython: make PySharedRef::try_borrow_mut() return BorrowMutError
Yuya Nishihara <yuya@tcha.org>
parents: 44205
diff changeset
   142
    ) -> result::Result<RefMut<'a, T>, BorrowMutError> {
44204
bafdaf4858d8 rust-cpython: inline PySharedState::try_borrow_mut()
Yuya Nishihara <yuya@tcha.org>
parents: 44203
diff changeset
   143
        if self.py_shared_state.current_borrow_count(py) > 0 {
44206
9804badd5970 rust-cpython: make PySharedRef::try_borrow_mut() return BorrowMutError
Yuya Nishihara <yuya@tcha.org>
parents: 44205
diff changeset
   144
            // propagate borrow-by-leaked state to inner to get BorrowMutError
9804badd5970 rust-cpython: make PySharedRef::try_borrow_mut() return BorrowMutError
Yuya Nishihara <yuya@tcha.org>
parents: 44205
diff changeset
   145
            let _dummy = self.inner.borrow();
9804badd5970 rust-cpython: make PySharedRef::try_borrow_mut() return BorrowMutError
Yuya Nishihara <yuya@tcha.org>
parents: 44205
diff changeset
   146
            self.inner.try_borrow_mut()?;
9804badd5970 rust-cpython: make PySharedRef::try_borrow_mut() return BorrowMutError
Yuya Nishihara <yuya@tcha.org>
parents: 44205
diff changeset
   147
            unreachable!("BorrowMutError must be returned");
44204
bafdaf4858d8 rust-cpython: inline PySharedState::try_borrow_mut()
Yuya Nishihara <yuya@tcha.org>
parents: 44203
diff changeset
   148
        }
44206
9804badd5970 rust-cpython: make PySharedRef::try_borrow_mut() return BorrowMutError
Yuya Nishihara <yuya@tcha.org>
parents: 44205
diff changeset
   149
        let inner_ref = self.inner.try_borrow_mut()?;
44204
bafdaf4858d8 rust-cpython: inline PySharedState::try_borrow_mut()
Yuya Nishihara <yuya@tcha.org>
parents: 44203
diff changeset
   150
        self.py_shared_state.increment_generation(py);
bafdaf4858d8 rust-cpython: inline PySharedState::try_borrow_mut()
Yuya Nishihara <yuya@tcha.org>
parents: 44203
diff changeset
   151
        Ok(inner_ref)
42849
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42839
diff changeset
   152
    }
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42839
diff changeset
   153
}
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42839
diff changeset
   154
43178
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   155
/// 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
   156
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
   157
    py: Python<'a>,
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   158
    owner: &'a PyObject,
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   159
    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
   160
}
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   161
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   162
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
   163
    /// # Safety
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   164
    ///
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   165
    /// 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
   166
    /// would get wrong.
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   167
    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
   168
        py: Python<'a>,
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   169
        owner: &'a PyObject,
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   170
        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
   171
    ) -> Self {
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   172
        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
   173
    }
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   174
43272
00222775d59b rust-refsharing: add missing lifetime parameter in ref_sharing
Rapha?l Gom?s <rgomes@octobus.net>
parents: 43180
diff changeset
   175
    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
   176
        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
   177
    }
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   178
44203
2a24ead003f0 rust-cpython: add panicking version of borrow_mut() and use it
Yuya Nishihara <yuya@tcha.org>
parents: 44189
diff changeset
   179
    /// Mutably borrows the wrapped value.
2a24ead003f0 rust-cpython: add panicking version of borrow_mut() and use it
Yuya Nishihara <yuya@tcha.org>
parents: 44189
diff changeset
   180
    ///
2a24ead003f0 rust-cpython: add panicking version of borrow_mut() and use it
Yuya Nishihara <yuya@tcha.org>
parents: 44189
diff changeset
   181
    /// # Panics
2a24ead003f0 rust-cpython: add panicking version of borrow_mut() and use it
Yuya Nishihara <yuya@tcha.org>
parents: 44189
diff changeset
   182
    ///
2a24ead003f0 rust-cpython: add panicking version of borrow_mut() and use it
Yuya Nishihara <yuya@tcha.org>
parents: 44189
diff changeset
   183
    /// Panics if the value is currently borrowed through `PySharedRef`
2a24ead003f0 rust-cpython: add panicking version of borrow_mut() and use it
Yuya Nishihara <yuya@tcha.org>
parents: 44189
diff changeset
   184
    /// or `PyLeaked`.
2a24ead003f0 rust-cpython: add panicking version of borrow_mut() and use it
Yuya Nishihara <yuya@tcha.org>
parents: 44189
diff changeset
   185
    pub fn borrow_mut(&self) -> RefMut<'a, T> {
2a24ead003f0 rust-cpython: add panicking version of borrow_mut() and use it
Yuya Nishihara <yuya@tcha.org>
parents: 44189
diff changeset
   186
        self.try_borrow_mut().expect("already borrowed")
2a24ead003f0 rust-cpython: add panicking version of borrow_mut() and use it
Yuya Nishihara <yuya@tcha.org>
parents: 44189
diff changeset
   187
    }
2a24ead003f0 rust-cpython: add panicking version of borrow_mut() and use it
Yuya Nishihara <yuya@tcha.org>
parents: 44189
diff changeset
   188
2a24ead003f0 rust-cpython: add panicking version of borrow_mut() and use it
Yuya Nishihara <yuya@tcha.org>
parents: 44189
diff changeset
   189
    /// Mutably borrows the wrapped value, returning an error if the value
2a24ead003f0 rust-cpython: add panicking version of borrow_mut() and use it
Yuya Nishihara <yuya@tcha.org>
parents: 44189
diff changeset
   190
    /// is currently borrowed.
44206
9804badd5970 rust-cpython: make PySharedRef::try_borrow_mut() return BorrowMutError
Yuya Nishihara <yuya@tcha.org>
parents: 44205
diff changeset
   191
    pub fn try_borrow_mut(
9804badd5970 rust-cpython: make PySharedRef::try_borrow_mut() return BorrowMutError
Yuya Nishihara <yuya@tcha.org>
parents: 44205
diff changeset
   192
        &self,
9804badd5970 rust-cpython: make PySharedRef::try_borrow_mut() return BorrowMutError
Yuya Nishihara <yuya@tcha.org>
parents: 44205
diff changeset
   193
    ) -> result::Result<RefMut<'a, T>, BorrowMutError> {
44189
4a4c3b9fd91b rust-cpython: make sure PySharedRef::borrow_mut() never panics
Yuya Nishihara <yuya@tcha.org>
parents: 44188
diff changeset
   194
        self.data.try_borrow_mut(self.py)
43178
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   195
    }
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   196
43285
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   197
    /// Returns a leaked reference.
43427
b7ab3a0a9e57 rust-cpython: leverage RefCell::borrow() to guarantee there's no mutable ref
Yuya Nishihara <yuya@tcha.org>
parents: 43426
diff changeset
   198
    ///
b7ab3a0a9e57 rust-cpython: leverage RefCell::borrow() to guarantee there's no mutable ref
Yuya Nishihara <yuya@tcha.org>
parents: 43426
diff changeset
   199
    /// # Panics
b7ab3a0a9e57 rust-cpython: leverage RefCell::borrow() to guarantee there's no mutable ref
Yuya Nishihara <yuya@tcha.org>
parents: 43426
diff changeset
   200
    ///
b7ab3a0a9e57 rust-cpython: leverage RefCell::borrow() to guarantee there's no mutable ref
Yuya Nishihara <yuya@tcha.org>
parents: 43426
diff changeset
   201
    /// Panics if this is mutably borrowed.
43430
8418b77132c1 rust-cpython: remove useless PyResult<> from leak_immutable()
Yuya Nishihara <yuya@tcha.org>
parents: 43429
diff changeset
   202
    pub fn leak_immutable(&self) -> PyLeaked<&'static T> {
43285
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   203
        let state = &self.data.py_shared_state;
43427
b7ab3a0a9e57 rust-cpython: leverage RefCell::borrow() to guarantee there's no mutable ref
Yuya Nishihara <yuya@tcha.org>
parents: 43426
diff changeset
   204
        // make sure self.data isn't mutably borrowed; otherwise the
b7ab3a0a9e57 rust-cpython: leverage RefCell::borrow() to guarantee there's no mutable ref
Yuya Nishihara <yuya@tcha.org>
parents: 43426
diff changeset
   205
        // generation number can't be trusted.
b7ab3a0a9e57 rust-cpython: leverage RefCell::borrow() to guarantee there's no mutable ref
Yuya Nishihara <yuya@tcha.org>
parents: 43426
diff changeset
   206
        let data_ref = self.borrow();
44205
f015d679f08c rust-cpython: inline PySharedState::leak_immutable() and PyLeaked::new()
Yuya Nishihara <yuya@tcha.org>
parents: 44204
diff changeset
   207
f015d679f08c rust-cpython: inline PySharedState::leak_immutable() and PyLeaked::new()
Yuya Nishihara <yuya@tcha.org>
parents: 44204
diff changeset
   208
        // &'static cast is safe because data_ptr and state_ptr are owned
f015d679f08c rust-cpython: inline PySharedState::leak_immutable() and PyLeaked::new()
Yuya Nishihara <yuya@tcha.org>
parents: 44204
diff changeset
   209
        // by self.owner, and we do have the GIL for thread safety.
f015d679f08c rust-cpython: inline PySharedState::leak_immutable() and PyLeaked::new()
Yuya Nishihara <yuya@tcha.org>
parents: 44204
diff changeset
   210
        let data_ptr: *const T = &*data_ref;
f015d679f08c rust-cpython: inline PySharedState::leak_immutable() and PyLeaked::new()
Yuya Nishihara <yuya@tcha.org>
parents: 44204
diff changeset
   211
        let state_ptr: *const PySharedState = state;
f015d679f08c rust-cpython: inline PySharedState::leak_immutable() and PyLeaked::new()
Yuya Nishihara <yuya@tcha.org>
parents: 44204
diff changeset
   212
        PyLeaked::<&'static T> {
f015d679f08c rust-cpython: inline PySharedState::leak_immutable() and PyLeaked::new()
Yuya Nishihara <yuya@tcha.org>
parents: 44204
diff changeset
   213
            inner: self.owner.clone_ref(self.py),
f015d679f08c rust-cpython: inline PySharedState::leak_immutable() and PyLeaked::new()
Yuya Nishihara <yuya@tcha.org>
parents: 44204
diff changeset
   214
            data: unsafe { &*data_ptr },
f015d679f08c rust-cpython: inline PySharedState::leak_immutable() and PyLeaked::new()
Yuya Nishihara <yuya@tcha.org>
parents: 44204
diff changeset
   215
            py_shared_state: unsafe { &*state_ptr },
f015d679f08c rust-cpython: inline PySharedState::leak_immutable() and PyLeaked::new()
Yuya Nishihara <yuya@tcha.org>
parents: 44204
diff changeset
   216
            generation: state.current_generation(self.py),
43285
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   217
        }
43178
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   218
    }
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   219
}
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   220
42752
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   221
/// 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
   222
/// data members with Python.
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   223
///
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   224
/// # Parameters
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   225
///
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   226
/// * `$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
   227
/// * `$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
   228
/// * `$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
   229
/// 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
   230
/// * `$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
   231
/// 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
   232
///
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   233
/// # Safety
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   234
///
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   235
/// `$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
   236
/// 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
   237
///
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   238
/// # Example
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   239
///
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   240
/// ```
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   241
/// struct MyStruct {
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   242
///     inner: Vec<u32>;
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   243
/// }
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   244
///
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   245
/// py_class!(pub class MyType |py| {
42849
8db8fa1de2ef rust-cpython: introduce restricted variant of RefCell
Yuya Nishihara <yuya@tcha.org>
parents: 42839
diff changeset
   246
///     data inner: PySharedRefCell<MyStruct>;
42752
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   247
/// });
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   248
///
43178
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   249
/// 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
   250
/// ```
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   251
macro_rules! py_shared_ref {
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
        $name: ident,
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   254
        $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
   255
        $data_member: ident,
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   256
        $shared_accessor: ident
42752
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   257
    ) => {
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   258
        impl $name {
43178
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   259
            /// 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
   260
            ///
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   261
            /// 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
   262
            /// 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
   263
            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
   264
                &'a self,
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   265
                py: Python<'a>,
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   266
            ) -> $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
   267
                use cpython::PythonObject;
1b2200bd06b6 rust-cpython: add safe wrapper representing shared data borrowed from PyObject
Yuya Nishihara <yuya@tcha.org>
parents: 43177
diff changeset
   268
                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
   269
                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
   270
                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
   271
                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
   272
            }
42752
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   273
        }
43177
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
   274
    };
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
   275
}
42752
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   276
43177
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
   277
/// 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
   278
///
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
   279
/// 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
   280
/// borrowed.
43422
b9f791090211 rust-cpython: rename PyLeakedRef to PyLeaked
Yuya Nishihara <yuya@tcha.org>
parents: 43289
diff changeset
   281
pub struct PyLeaked<T> {
43285
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   282
    inner: PyObject,
44188
1f9e6fbdd3e6 rust-cpython: remove useless wrappers from PyLeaked, just move by map()
Yuya Nishihara <yuya@tcha.org>
parents: 43430
diff changeset
   283
    data: T,
43177
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
   284
    py_shared_state: &'static PySharedState,
43424
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
   285
    /// 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
   286
    generation: usize,
43177
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
   287
}
42752
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   288
43422
b9f791090211 rust-cpython: rename PyLeakedRef to PyLeaked
Yuya Nishihara <yuya@tcha.org>
parents: 43289
diff changeset
   289
// 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
   290
// 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
   291
// 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
   292
43422
b9f791090211 rust-cpython: rename PyLeakedRef to PyLeaked
Yuya Nishihara <yuya@tcha.org>
parents: 43289
diff changeset
   293
impl<T> PyLeaked<T> {
43423
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43422
diff changeset
   294
    /// Immutably borrows the wrapped value.
43424
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
   295
    ///
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
   296
    /// Borrowing fails if the underlying reference has been invalidated.
44207
e960c30d7e50 rust-cpython: mark all PyLeaked methods as unsafe
Yuya Nishihara <yuya@tcha.org>
parents: 44206
diff changeset
   297
    ///
e960c30d7e50 rust-cpython: mark all PyLeaked methods as unsafe
Yuya Nishihara <yuya@tcha.org>
parents: 44206
diff changeset
   298
    /// # Safety
e960c30d7e50 rust-cpython: mark all PyLeaked methods as unsafe
Yuya Nishihara <yuya@tcha.org>
parents: 44206
diff changeset
   299
    ///
e960c30d7e50 rust-cpython: mark all PyLeaked methods as unsafe
Yuya Nishihara <yuya@tcha.org>
parents: 44206
diff changeset
   300
    /// The lifetime of the innermost object is cheated. Do not obtain and
e960c30d7e50 rust-cpython: mark all PyLeaked methods as unsafe
Yuya Nishihara <yuya@tcha.org>
parents: 44206
diff changeset
   301
    /// copy it out of the borrow scope. See the example of `try_borrow_mut()`
e960c30d7e50 rust-cpython: mark all PyLeaked methods as unsafe
Yuya Nishihara <yuya@tcha.org>
parents: 44206
diff changeset
   302
    /// for details.
e960c30d7e50 rust-cpython: mark all PyLeaked methods as unsafe
Yuya Nishihara <yuya@tcha.org>
parents: 44206
diff changeset
   303
    pub unsafe fn try_borrow<'a>(
43423
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43422
diff changeset
   304
        &'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
   305
        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
   306
    ) -> PyResult<PyLeakedRef<'a, T>> {
43424
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
   307
        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
   308
        Ok(PyLeakedRef {
43425
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
   309
            _borrow: BorrowPyShared::new(py, self.py_shared_state),
44188
1f9e6fbdd3e6 rust-cpython: remove useless wrappers from PyLeaked, just move by map()
Yuya Nishihara <yuya@tcha.org>
parents: 43430
diff changeset
   310
            data: &self.data,
43423
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43422
diff changeset
   311
        })
43285
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   312
    }
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   313
43423
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43422
diff changeset
   314
    /// Mutably borrows the wrapped value.
43285
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   315
    ///
43424
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
   316
    /// 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
   317
    ///
43285
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   318
    /// 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
   319
    /// `get_mut()` is useless since the inner value can't be mutated.
44207
e960c30d7e50 rust-cpython: mark all PyLeaked methods as unsafe
Yuya Nishihara <yuya@tcha.org>
parents: 44206
diff changeset
   320
    ///
e960c30d7e50 rust-cpython: mark all PyLeaked methods as unsafe
Yuya Nishihara <yuya@tcha.org>
parents: 44206
diff changeset
   321
    /// # Safety
e960c30d7e50 rust-cpython: mark all PyLeaked methods as unsafe
Yuya Nishihara <yuya@tcha.org>
parents: 44206
diff changeset
   322
    ///
e960c30d7e50 rust-cpython: mark all PyLeaked methods as unsafe
Yuya Nishihara <yuya@tcha.org>
parents: 44206
diff changeset
   323
    /// The lifetime of the innermost object is cheated. Do not obtain and
e960c30d7e50 rust-cpython: mark all PyLeaked methods as unsafe
Yuya Nishihara <yuya@tcha.org>
parents: 44206
diff changeset
   324
    /// copy it out of the borrow scope. For example, the following code
e960c30d7e50 rust-cpython: mark all PyLeaked methods as unsafe
Yuya Nishihara <yuya@tcha.org>
parents: 44206
diff changeset
   325
    /// is unsafe:
e960c30d7e50 rust-cpython: mark all PyLeaked methods as unsafe
Yuya Nishihara <yuya@tcha.org>
parents: 44206
diff changeset
   326
    ///
e960c30d7e50 rust-cpython: mark all PyLeaked methods as unsafe
Yuya Nishihara <yuya@tcha.org>
parents: 44206
diff changeset
   327
    /// ```compile_fail
e960c30d7e50 rust-cpython: mark all PyLeaked methods as unsafe
Yuya Nishihara <yuya@tcha.org>
parents: 44206
diff changeset
   328
    /// let slice;
e960c30d7e50 rust-cpython: mark all PyLeaked methods as unsafe
Yuya Nishihara <yuya@tcha.org>
parents: 44206
diff changeset
   329
    /// {
e960c30d7e50 rust-cpython: mark all PyLeaked methods as unsafe
Yuya Nishihara <yuya@tcha.org>
parents: 44206
diff changeset
   330
    ///     let iter = leaked.try_borrow_mut(py);
e960c30d7e50 rust-cpython: mark all PyLeaked methods as unsafe
Yuya Nishihara <yuya@tcha.org>
parents: 44206
diff changeset
   331
    ///     // slice can outlive since the iterator is of Iter<'static, T>
e960c30d7e50 rust-cpython: mark all PyLeaked methods as unsafe
Yuya Nishihara <yuya@tcha.org>
parents: 44206
diff changeset
   332
    ///     // type, but it shouldn't.
e960c30d7e50 rust-cpython: mark all PyLeaked methods as unsafe
Yuya Nishihara <yuya@tcha.org>
parents: 44206
diff changeset
   333
    ///     slice = iter.as_slice();
e960c30d7e50 rust-cpython: mark all PyLeaked methods as unsafe
Yuya Nishihara <yuya@tcha.org>
parents: 44206
diff changeset
   334
    /// }
e960c30d7e50 rust-cpython: mark all PyLeaked methods as unsafe
Yuya Nishihara <yuya@tcha.org>
parents: 44206
diff changeset
   335
    /// println!("{:?}", slice);
e960c30d7e50 rust-cpython: mark all PyLeaked methods as unsafe
Yuya Nishihara <yuya@tcha.org>
parents: 44206
diff changeset
   336
    /// ```
e960c30d7e50 rust-cpython: mark all PyLeaked methods as unsafe
Yuya Nishihara <yuya@tcha.org>
parents: 44206
diff changeset
   337
    pub unsafe fn try_borrow_mut<'a>(
43423
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43422
diff changeset
   338
        &'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
   339
        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
   340
    ) -> PyResult<PyLeakedRefMut<'a, T>> {
43424
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
   341
        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
   342
        Ok(PyLeakedRefMut {
43425
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
   343
            _borrow: BorrowPyShared::new(py, self.py_shared_state),
44188
1f9e6fbdd3e6 rust-cpython: remove useless wrappers from PyLeaked, just move by map()
Yuya Nishihara <yuya@tcha.org>
parents: 43430
diff changeset
   344
            data: &mut self.data,
43423
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43422
diff changeset
   345
        })
43285
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   346
    }
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   347
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   348
    /// 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
   349
    ///
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   350
    /// 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
   351
    /// iterator of that container.
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   352
    ///
43424
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
   353
    /// # Panics
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
   354
    ///
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
   355
    /// 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
   356
    ///
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
   357
    /// 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
   358
    /// 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
   359
    ///
43285
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   360
    /// # Safety
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   361
    ///
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   362
    /// 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
   363
    /// 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
   364
    /// 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
   365
    /// function call.
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   366
    pub unsafe fn map<U>(
44188
1f9e6fbdd3e6 rust-cpython: remove useless wrappers from PyLeaked, just move by map()
Yuya Nishihara <yuya@tcha.org>
parents: 43430
diff changeset
   367
        self,
43285
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   368
        py: Python,
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   369
        f: impl FnOnce(T) -> U,
43422
b9f791090211 rust-cpython: rename PyLeakedRef to PyLeaked
Yuya Nishihara <yuya@tcha.org>
parents: 43289
diff changeset
   370
    ) -> PyLeaked<U> {
43424
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
   371
        // 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
   372
        // is still intact.
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
   373
        self.validate_generation(py)
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
   374
            .expect("map() over invalidated leaked reference");
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
   375
43285
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   376
        // 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
   377
        // 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
   378
        // 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
   379
        // returned object back to Something<'static>.
44188
1f9e6fbdd3e6 rust-cpython: remove useless wrappers from PyLeaked, just move by map()
Yuya Nishihara <yuya@tcha.org>
parents: 43430
diff changeset
   380
        let new_data = f(self.data);
43422
b9f791090211 rust-cpython: rename PyLeakedRef to PyLeaked
Yuya Nishihara <yuya@tcha.org>
parents: 43289
diff changeset
   381
        PyLeaked {
44188
1f9e6fbdd3e6 rust-cpython: remove useless wrappers from PyLeaked, just move by map()
Yuya Nishihara <yuya@tcha.org>
parents: 43430
diff changeset
   382
            inner: self.inner,
1f9e6fbdd3e6 rust-cpython: remove useless wrappers from PyLeaked, just move by map()
Yuya Nishihara <yuya@tcha.org>
parents: 43430
diff changeset
   383
            data: new_data,
43285
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   384
            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
   385
            generation: self.generation,
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
   386
        }
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
   387
    }
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
   388
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
   389
    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
   390
        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
   391
            Ok(())
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
   392
        } else {
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
   393
            Err(PyErr::new::<exc::RuntimeError, _>(
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
   394
                py,
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
   395
                "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
   396
            ))
43285
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   397
        }
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   398
    }
43177
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
   399
}
42752
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   400
43423
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43422
diff changeset
   401
/// 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
   402
pub struct PyLeakedRef<'a, T> {
43425
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
   403
    _borrow: BorrowPyShared<'a>,
43423
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43422
diff changeset
   404
    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
   405
}
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43422
diff changeset
   406
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43422
diff changeset
   407
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
   408
    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
   409
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43422
diff changeset
   410
    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
   411
        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
   412
    }
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43422
diff changeset
   413
}
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43422
diff changeset
   414
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43422
diff changeset
   415
/// 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
   416
pub struct PyLeakedRefMut<'a, T> {
43425
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
   417
    _borrow: BorrowPyShared<'a>,
43423
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43422
diff changeset
   418
    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
   419
}
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43422
diff changeset
   420
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43422
diff changeset
   421
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
   422
    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
   423
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43422
diff changeset
   424
    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
   425
        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
   426
    }
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43422
diff changeset
   427
}
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43422
diff changeset
   428
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43422
diff changeset
   429
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
   430
    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
   431
        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
   432
    }
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43422
diff changeset
   433
}
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43422
diff changeset
   434
42752
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   435
/// 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
   436
///
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
   437
/// 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
   438
///     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
   439
///
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
   440
/// # Parameters
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
   441
///
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
   442
/// * `$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
   443
/// * `$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
   444
/// * `$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
   445
/// * `$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
   446
/// 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
   447
/// * `$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
   448
///
44207
e960c30d7e50 rust-cpython: mark all PyLeaked methods as unsafe
Yuya Nishihara <yuya@tcha.org>
parents: 44206
diff changeset
   449
/// # Safety
e960c30d7e50 rust-cpython: mark all PyLeaked methods as unsafe
Yuya Nishihara <yuya@tcha.org>
parents: 44206
diff changeset
   450
///
e960c30d7e50 rust-cpython: mark all PyLeaked methods as unsafe
Yuya Nishihara <yuya@tcha.org>
parents: 44206
diff changeset
   451
/// `$success_func` may take a reference, but it's lifetime may be cheated.
e960c30d7e50 rust-cpython: mark all PyLeaked methods as unsafe
Yuya Nishihara <yuya@tcha.org>
parents: 44206
diff changeset
   452
/// Do not copy it out of the function call.
e960c30d7e50 rust-cpython: mark all PyLeaked methods as unsafe
Yuya Nishihara <yuya@tcha.org>
parents: 44206
diff changeset
   453
///
42888
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
   454
/// # Example
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
   455
///
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
   456
/// ```
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
   457
/// struct MyStruct {
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
   458
///     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
   459
/// }
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
   460
///
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
   461
/// 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
   462
///     data inner: PySharedRefCell<MyStruct>;
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
   463
///
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
   464
///     def __iter__(&self) -> PyResult<MyTypeItemsIterator> {
43430
8418b77132c1 rust-cpython: remove useless PyResult<> from leak_immutable()
Yuya Nishihara <yuya@tcha.org>
parents: 43429
diff changeset
   465
///         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
   466
///         MyTypeItemsIterator::from_inner(
42888
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
   467
///             py,
43285
ffc1fbd7d1f5 rust-cpython: make PyLeakedRef operations relatively safe
Yuya Nishihara <yuya@tcha.org>
parents: 43284
diff changeset
   468
///             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
   469
///         )
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
   470
///     }
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
   471
/// });
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
   472
///
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
   473
/// impl MyType {
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
   474
///     fn translate_key_value(
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
   475
///         py: Python,
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
   476
///         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
   477
///     ) -> PyResult<Option<(PyBytes, PyBytes)>> {
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
   478
///         let (f, entry) = res;
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
   479
///         Ok(Some((
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
   480
///             PyBytes::new(py, f),
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
   481
///             PyBytes::new(py, entry),
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
   482
///         )))
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
   483
///     }
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
   484
/// }
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
   485
///
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
   486
/// 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
   487
///
42889
ea91a126c803 rust-cpython: rename py_shared_iterator_impl to py_shared_iterator
Yuya Nishihara <yuya@tcha.org>
parents: 42888
diff changeset
   488
/// py_shared_iterator!(
42888
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
   489
///     MyTypeItemsIterator,
43422
b9f791090211 rust-cpython: rename PyLeakedRef to PyLeaked
Yuya Nishihara <yuya@tcha.org>
parents: 43289
diff changeset
   490
///     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
   491
///     MyType::translate_key_value,
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
   492
///     Option<(PyBytes, PyBytes)>
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
   493
/// );
67853749961b rust-cpython: replace dyn Iterator<..> of mapping with concrete type
Yuya Nishihara <yuya@tcha.org>
parents: 42887
diff changeset
   494
/// ```
42889
ea91a126c803 rust-cpython: rename py_shared_iterator_impl to py_shared_iterator
Yuya Nishihara <yuya@tcha.org>
parents: 42888
diff changeset
   495
macro_rules! py_shared_iterator {
42752
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   496
    (
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   497
        $name: ident,
43177
5cb8867c9e2b rust-cpython: move $leaked struct out of macro
Yuya Nishihara <yuya@tcha.org>
parents: 43176
diff changeset
   498
        $leaked: ty,
42752
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   499
        $success_func: expr,
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   500
        $success_type: ty
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   501
    ) => {
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   502
        py_class!(pub class $name |py| {
43426
6f9f15a476a4 rust-cpython: remove useless Option<$leaked> from py_shared_iterator
Yuya Nishihara <yuya@tcha.org>
parents: 43425
diff changeset
   503
            data inner: RefCell<$leaked>;
42752
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   504
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   505
            def __next__(&self) -> PyResult<$success_type> {
43426
6f9f15a476a4 rust-cpython: remove useless Option<$leaked> from py_shared_iterator
Yuya Nishihara <yuya@tcha.org>
parents: 43425
diff changeset
   506
                let mut leaked = self.inner(py).borrow_mut();
44207
e960c30d7e50 rust-cpython: mark all PyLeaked methods as unsafe
Yuya Nishihara <yuya@tcha.org>
parents: 44206
diff changeset
   507
                let mut iter = unsafe { leaked.try_borrow_mut(py)? };
43426
6f9f15a476a4 rust-cpython: remove useless Option<$leaked> from py_shared_iterator
Yuya Nishihara <yuya@tcha.org>
parents: 43425
diff changeset
   508
                match iter.next() {
6f9f15a476a4 rust-cpython: remove useless Option<$leaked> from py_shared_iterator
Yuya Nishihara <yuya@tcha.org>
parents: 43425
diff changeset
   509
                    None => Ok(None),
44207
e960c30d7e50 rust-cpython: mark all PyLeaked methods as unsafe
Yuya Nishihara <yuya@tcha.org>
parents: 44206
diff changeset
   510
                    // res may be a reference of cheated 'static lifetime
43426
6f9f15a476a4 rust-cpython: remove useless Option<$leaked> from py_shared_iterator
Yuya Nishihara <yuya@tcha.org>
parents: 43425
diff changeset
   511
                    Some(res) => $success_func(py, res),
42752
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   512
                }
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   513
            }
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   514
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   515
            def __iter__(&self) -> PyResult<Self> {
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   516
                Ok(self.clone_ref(py))
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   517
            }
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   518
        });
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   519
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   520
        impl $name {
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   521
            pub fn from_inner(
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   522
                py: Python,
42890
74d67c645278 rust-cpython: remove Option<_> from interface of py_shared_iterator
Yuya Nishihara <yuya@tcha.org>
parents: 42889
diff changeset
   523
                leaked: $leaked,
42752
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   524
            ) -> PyResult<Self> {
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   525
                Self::create_instance(
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   526
                    py,
43426
6f9f15a476a4 rust-cpython: remove useless Option<$leaked> from py_shared_iterator
Yuya Nishihara <yuya@tcha.org>
parents: 43425
diff changeset
   527
                    RefCell::new(leaked),
42752
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   528
                )
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   529
            }
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   530
        }
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   531
    };
30320c7bf79f rust-cpython: add macro for sharing references
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   532
}
43289
8d432d3a2d7c rust-cpython: prepare for writing tests that require libpython
Yuya Nishihara <yuya@tcha.org>
parents: 43288
diff changeset
   533
8d432d3a2d7c rust-cpython: prepare for writing tests that require libpython
Yuya Nishihara <yuya@tcha.org>
parents: 43288
diff changeset
   534
#[cfg(test)]
8d432d3a2d7c rust-cpython: prepare for writing tests that require libpython
Yuya Nishihara <yuya@tcha.org>
parents: 43288
diff changeset
   535
#[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
   536
mod test {
8d432d3a2d7c rust-cpython: prepare for writing tests that require libpython
Yuya Nishihara <yuya@tcha.org>
parents: 43288
diff changeset
   537
    use super::*;
8d432d3a2d7c rust-cpython: prepare for writing tests that require libpython
Yuya Nishihara <yuya@tcha.org>
parents: 43288
diff changeset
   538
    use cpython::{GILGuard, Python};
8d432d3a2d7c rust-cpython: prepare for writing tests that require libpython
Yuya Nishihara <yuya@tcha.org>
parents: 43288
diff changeset
   539
8d432d3a2d7c rust-cpython: prepare for writing tests that require libpython
Yuya Nishihara <yuya@tcha.org>
parents: 43288
diff changeset
   540
    py_class!(class Owner |py| {
8d432d3a2d7c rust-cpython: prepare for writing tests that require libpython
Yuya Nishihara <yuya@tcha.org>
parents: 43288
diff changeset
   541
        data string: PySharedRefCell<String>;
8d432d3a2d7c rust-cpython: prepare for writing tests that require libpython
Yuya Nishihara <yuya@tcha.org>
parents: 43288
diff changeset
   542
    });
8d432d3a2d7c rust-cpython: prepare for writing tests that require libpython
Yuya Nishihara <yuya@tcha.org>
parents: 43288
diff changeset
   543
    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
   544
8d432d3a2d7c rust-cpython: prepare for writing tests that require libpython
Yuya Nishihara <yuya@tcha.org>
parents: 43288
diff changeset
   545
    fn prepare_env() -> (GILGuard, Owner) {
8d432d3a2d7c rust-cpython: prepare for writing tests that require libpython
Yuya Nishihara <yuya@tcha.org>
parents: 43288
diff changeset
   546
        let gil = Python::acquire_gil();
8d432d3a2d7c rust-cpython: prepare for writing tests that require libpython
Yuya Nishihara <yuya@tcha.org>
parents: 43288
diff changeset
   547
        let py = gil.python();
8d432d3a2d7c rust-cpython: prepare for writing tests that require libpython
Yuya Nishihara <yuya@tcha.org>
parents: 43288
diff changeset
   548
        let owner =
8d432d3a2d7c rust-cpython: prepare for writing tests that require libpython
Yuya Nishihara <yuya@tcha.org>
parents: 43288
diff changeset
   549
            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
   550
                .unwrap();
8d432d3a2d7c rust-cpython: prepare for writing tests that require libpython
Yuya Nishihara <yuya@tcha.org>
parents: 43288
diff changeset
   551
        (gil, owner)
8d432d3a2d7c rust-cpython: prepare for writing tests that require libpython
Yuya Nishihara <yuya@tcha.org>
parents: 43288
diff changeset
   552
    }
8d432d3a2d7c rust-cpython: prepare for writing tests that require libpython
Yuya Nishihara <yuya@tcha.org>
parents: 43288
diff changeset
   553
8d432d3a2d7c rust-cpython: prepare for writing tests that require libpython
Yuya Nishihara <yuya@tcha.org>
parents: 43288
diff changeset
   554
    #[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
   555
    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
   556
        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
   557
        let py = gil.python();
43430
8418b77132c1 rust-cpython: remove useless PyResult<> from leak_immutable()
Yuya Nishihara <yuya@tcha.org>
parents: 43429
diff changeset
   558
        let leaked = owner.string_shared(py).leak_immutable();
44207
e960c30d7e50 rust-cpython: mark all PyLeaked methods as unsafe
Yuya Nishihara <yuya@tcha.org>
parents: 44206
diff changeset
   559
        let leaked_ref = unsafe { leaked.try_borrow(py) }.unwrap();
43423
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43422
diff changeset
   560
        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
   561
    }
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43422
diff changeset
   562
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43422
diff changeset
   563
    #[test]
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43422
diff changeset
   564
    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
   565
        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
   566
        let py = gil.python();
43430
8418b77132c1 rust-cpython: remove useless PyResult<> from leak_immutable()
Yuya Nishihara <yuya@tcha.org>
parents: 43429
diff changeset
   567
        let leaked = owner.string_shared(py).leak_immutable();
43423
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43422
diff changeset
   568
        let mut leaked_iter = unsafe { leaked.map(py, |s| s.chars()) };
44207
e960c30d7e50 rust-cpython: mark all PyLeaked methods as unsafe
Yuya Nishihara <yuya@tcha.org>
parents: 44206
diff changeset
   569
        let mut leaked_ref =
e960c30d7e50 rust-cpython: mark all PyLeaked methods as unsafe
Yuya Nishihara <yuya@tcha.org>
parents: 44206
diff changeset
   570
            unsafe { leaked_iter.try_borrow_mut(py) }.unwrap();
43423
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43422
diff changeset
   571
        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
   572
        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
   573
        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
   574
        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
   575
    }
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43422
diff changeset
   576
945d4dba5e78 rust-cpython: add stub wrapper that'll prevent leaked data from being mutated
Yuya Nishihara <yuya@tcha.org>
parents: 43422
diff changeset
   577
    #[test]
43424
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
   578
    fn test_leaked_borrow_after_mut() {
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
   579
        let (gil, owner) = prepare_env();
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
   580
        let py = gil.python();
43430
8418b77132c1 rust-cpython: remove useless PyResult<> from leak_immutable()
Yuya Nishihara <yuya@tcha.org>
parents: 43429
diff changeset
   581
        let leaked = owner.string_shared(py).leak_immutable();
44203
2a24ead003f0 rust-cpython: add panicking version of borrow_mut() and use it
Yuya Nishihara <yuya@tcha.org>
parents: 44189
diff changeset
   582
        owner.string_shared(py).borrow_mut().clear();
44207
e960c30d7e50 rust-cpython: mark all PyLeaked methods as unsafe
Yuya Nishihara <yuya@tcha.org>
parents: 44206
diff changeset
   583
        assert!(unsafe { leaked.try_borrow(py) }.is_err());
43424
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
   584
    }
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
   585
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
   586
    #[test]
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
   587
    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
   588
        let (gil, owner) = prepare_env();
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
   589
        let py = gil.python();
43430
8418b77132c1 rust-cpython: remove useless PyResult<> from leak_immutable()
Yuya Nishihara <yuya@tcha.org>
parents: 43429
diff changeset
   590
        let leaked = owner.string_shared(py).leak_immutable();
43424
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
   591
        let mut leaked_iter = unsafe { leaked.map(py, |s| s.chars()) };
44203
2a24ead003f0 rust-cpython: add panicking version of borrow_mut() and use it
Yuya Nishihara <yuya@tcha.org>
parents: 44189
diff changeset
   592
        owner.string_shared(py).borrow_mut().clear();
44207
e960c30d7e50 rust-cpython: mark all PyLeaked methods as unsafe
Yuya Nishihara <yuya@tcha.org>
parents: 44206
diff changeset
   593
        assert!(unsafe { leaked_iter.try_borrow_mut(py) }.is_err());
43424
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
   594
    }
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
   595
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
   596
    #[test]
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
   597
    #[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
   598
    fn test_leaked_map_after_mut() {
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
   599
        let (gil, owner) = prepare_env();
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
   600
        let py = gil.python();
43430
8418b77132c1 rust-cpython: remove useless PyResult<> from leak_immutable()
Yuya Nishihara <yuya@tcha.org>
parents: 43429
diff changeset
   601
        let leaked = owner.string_shared(py).leak_immutable();
44203
2a24ead003f0 rust-cpython: add panicking version of borrow_mut() and use it
Yuya Nishihara <yuya@tcha.org>
parents: 44189
diff changeset
   602
        owner.string_shared(py).borrow_mut().clear();
43424
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
   603
        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
   604
    }
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
   605
0836efe4967b rust-cpython: add generation counter to leaked reference
Yuya Nishihara <yuya@tcha.org>
parents: 43423
diff changeset
   606
    #[test]
44203
2a24ead003f0 rust-cpython: add panicking version of borrow_mut() and use it
Yuya Nishihara <yuya@tcha.org>
parents: 44189
diff changeset
   607
    fn test_try_borrow_mut_while_leaked_ref() {
43289
8d432d3a2d7c rust-cpython: prepare for writing tests that require libpython
Yuya Nishihara <yuya@tcha.org>
parents: 43288
diff changeset
   608
        let (gil, owner) = prepare_env();
8d432d3a2d7c rust-cpython: prepare for writing tests that require libpython
Yuya Nishihara <yuya@tcha.org>
parents: 43288
diff changeset
   609
        let py = gil.python();
44203
2a24ead003f0 rust-cpython: add panicking version of borrow_mut() and use it
Yuya Nishihara <yuya@tcha.org>
parents: 44189
diff changeset
   610
        assert!(owner.string_shared(py).try_borrow_mut().is_ok());
43430
8418b77132c1 rust-cpython: remove useless PyResult<> from leak_immutable()
Yuya Nishihara <yuya@tcha.org>
parents: 43429
diff changeset
   611
        let leaked = owner.string_shared(py).leak_immutable();
43425
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
   612
        {
44207
e960c30d7e50 rust-cpython: mark all PyLeaked methods as unsafe
Yuya Nishihara <yuya@tcha.org>
parents: 44206
diff changeset
   613
            let _leaked_ref = unsafe { leaked.try_borrow(py) }.unwrap();
44203
2a24ead003f0 rust-cpython: add panicking version of borrow_mut() and use it
Yuya Nishihara <yuya@tcha.org>
parents: 44189
diff changeset
   614
            assert!(owner.string_shared(py).try_borrow_mut().is_err());
43425
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
   615
            {
44207
e960c30d7e50 rust-cpython: mark all PyLeaked methods as unsafe
Yuya Nishihara <yuya@tcha.org>
parents: 44206
diff changeset
   616
                let _leaked_ref2 = unsafe { leaked.try_borrow(py) }.unwrap();
44203
2a24ead003f0 rust-cpython: add panicking version of borrow_mut() and use it
Yuya Nishihara <yuya@tcha.org>
parents: 44189
diff changeset
   617
                assert!(owner.string_shared(py).try_borrow_mut().is_err());
43425
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
   618
            }
44203
2a24ead003f0 rust-cpython: add panicking version of borrow_mut() and use it
Yuya Nishihara <yuya@tcha.org>
parents: 44189
diff changeset
   619
            assert!(owner.string_shared(py).try_borrow_mut().is_err());
43425
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
   620
        }
44203
2a24ead003f0 rust-cpython: add panicking version of borrow_mut() and use it
Yuya Nishihara <yuya@tcha.org>
parents: 44189
diff changeset
   621
        assert!(owner.string_shared(py).try_borrow_mut().is_ok());
43425
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
   622
    }
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
   623
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
   624
    #[test]
44203
2a24ead003f0 rust-cpython: add panicking version of borrow_mut() and use it
Yuya Nishihara <yuya@tcha.org>
parents: 44189
diff changeset
   625
    fn test_try_borrow_mut_while_leaked_ref_mut() {
43425
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
   626
        let (gil, owner) = prepare_env();
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
   627
        let py = gil.python();
44203
2a24ead003f0 rust-cpython: add panicking version of borrow_mut() and use it
Yuya Nishihara <yuya@tcha.org>
parents: 44189
diff changeset
   628
        assert!(owner.string_shared(py).try_borrow_mut().is_ok());
43430
8418b77132c1 rust-cpython: remove useless PyResult<> from leak_immutable()
Yuya Nishihara <yuya@tcha.org>
parents: 43429
diff changeset
   629
        let leaked = owner.string_shared(py).leak_immutable();
43425
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
   630
        let mut leaked_iter = unsafe { leaked.map(py, |s| s.chars()) };
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
   631
        {
44207
e960c30d7e50 rust-cpython: mark all PyLeaked methods as unsafe
Yuya Nishihara <yuya@tcha.org>
parents: 44206
diff changeset
   632
            let _leaked_ref =
e960c30d7e50 rust-cpython: mark all PyLeaked methods as unsafe
Yuya Nishihara <yuya@tcha.org>
parents: 44206
diff changeset
   633
                unsafe { leaked_iter.try_borrow_mut(py) }.unwrap();
44203
2a24ead003f0 rust-cpython: add panicking version of borrow_mut() and use it
Yuya Nishihara <yuya@tcha.org>
parents: 44189
diff changeset
   634
            assert!(owner.string_shared(py).try_borrow_mut().is_err());
43425
ed50f2c31a4c rust-cpython: allow mutation unless leaked reference is borrowed
Yuya Nishihara <yuya@tcha.org>
parents: 43424
diff changeset
   635
        }
44203
2a24ead003f0 rust-cpython: add panicking version of borrow_mut() and use it
Yuya Nishihara <yuya@tcha.org>
parents: 44189
diff changeset
   636
        assert!(owner.string_shared(py).try_borrow_mut().is_ok());
43289
8d432d3a2d7c rust-cpython: prepare for writing tests that require libpython
Yuya Nishihara <yuya@tcha.org>
parents: 43288
diff changeset
   637
    }
43427
b7ab3a0a9e57 rust-cpython: leverage RefCell::borrow() to guarantee there's no mutable ref
Yuya Nishihara <yuya@tcha.org>
parents: 43426
diff changeset
   638
b7ab3a0a9e57 rust-cpython: leverage RefCell::borrow() to guarantee there's no mutable ref
Yuya Nishihara <yuya@tcha.org>
parents: 43426
diff changeset
   639
    #[test]
b7ab3a0a9e57 rust-cpython: leverage RefCell::borrow() to guarantee there's no mutable ref
Yuya Nishihara <yuya@tcha.org>
parents: 43426
diff changeset
   640
    #[should_panic(expected = "mutably borrowed")]
b7ab3a0a9e57 rust-cpython: leverage RefCell::borrow() to guarantee there's no mutable ref
Yuya Nishihara <yuya@tcha.org>
parents: 43426
diff changeset
   641
    fn test_leak_while_borrow_mut() {
b7ab3a0a9e57 rust-cpython: leverage RefCell::borrow() to guarantee there's no mutable ref
Yuya Nishihara <yuya@tcha.org>
parents: 43426
diff changeset
   642
        let (gil, owner) = prepare_env();
b7ab3a0a9e57 rust-cpython: leverage RefCell::borrow() to guarantee there's no mutable ref
Yuya Nishihara <yuya@tcha.org>
parents: 43426
diff changeset
   643
        let py = gil.python();
b7ab3a0a9e57 rust-cpython: leverage RefCell::borrow() to guarantee there's no mutable ref
Yuya Nishihara <yuya@tcha.org>
parents: 43426
diff changeset
   644
        let _mut_ref = owner.string_shared(py).borrow_mut();
43430
8418b77132c1 rust-cpython: remove useless PyResult<> from leak_immutable()
Yuya Nishihara <yuya@tcha.org>
parents: 43429
diff changeset
   645
        owner.string_shared(py).leak_immutable();
43427
b7ab3a0a9e57 rust-cpython: leverage RefCell::borrow() to guarantee there's no mutable ref
Yuya Nishihara <yuya@tcha.org>
parents: 43426
diff changeset
   646
    }
44189
4a4c3b9fd91b rust-cpython: make sure PySharedRef::borrow_mut() never panics
Yuya Nishihara <yuya@tcha.org>
parents: 44188
diff changeset
   647
4a4c3b9fd91b rust-cpython: make sure PySharedRef::borrow_mut() never panics
Yuya Nishihara <yuya@tcha.org>
parents: 44188
diff changeset
   648
    #[test]
44203
2a24ead003f0 rust-cpython: add panicking version of borrow_mut() and use it
Yuya Nishihara <yuya@tcha.org>
parents: 44189
diff changeset
   649
    fn test_try_borrow_mut_while_borrow() {
2a24ead003f0 rust-cpython: add panicking version of borrow_mut() and use it
Yuya Nishihara <yuya@tcha.org>
parents: 44189
diff changeset
   650
        let (gil, owner) = prepare_env();
2a24ead003f0 rust-cpython: add panicking version of borrow_mut() and use it
Yuya Nishihara <yuya@tcha.org>
parents: 44189
diff changeset
   651
        let py = gil.python();
2a24ead003f0 rust-cpython: add panicking version of borrow_mut() and use it
Yuya Nishihara <yuya@tcha.org>
parents: 44189
diff changeset
   652
        let _ref = owner.string_shared(py).borrow();
2a24ead003f0 rust-cpython: add panicking version of borrow_mut() and use it
Yuya Nishihara <yuya@tcha.org>
parents: 44189
diff changeset
   653
        assert!(owner.string_shared(py).try_borrow_mut().is_err());
2a24ead003f0 rust-cpython: add panicking version of borrow_mut() and use it
Yuya Nishihara <yuya@tcha.org>
parents: 44189
diff changeset
   654
    }
2a24ead003f0 rust-cpython: add panicking version of borrow_mut() and use it
Yuya Nishihara <yuya@tcha.org>
parents: 44189
diff changeset
   655
2a24ead003f0 rust-cpython: add panicking version of borrow_mut() and use it
Yuya Nishihara <yuya@tcha.org>
parents: 44189
diff changeset
   656
    #[test]
2a24ead003f0 rust-cpython: add panicking version of borrow_mut() and use it
Yuya Nishihara <yuya@tcha.org>
parents: 44189
diff changeset
   657
    #[should_panic(expected = "already borrowed")]
44189
4a4c3b9fd91b rust-cpython: make sure PySharedRef::borrow_mut() never panics
Yuya Nishihara <yuya@tcha.org>
parents: 44188
diff changeset
   658
    fn test_borrow_mut_while_borrow() {
4a4c3b9fd91b rust-cpython: make sure PySharedRef::borrow_mut() never panics
Yuya Nishihara <yuya@tcha.org>
parents: 44188
diff changeset
   659
        let (gil, owner) = prepare_env();
4a4c3b9fd91b rust-cpython: make sure PySharedRef::borrow_mut() never panics
Yuya Nishihara <yuya@tcha.org>
parents: 44188
diff changeset
   660
        let py = gil.python();
4a4c3b9fd91b rust-cpython: make sure PySharedRef::borrow_mut() never panics
Yuya Nishihara <yuya@tcha.org>
parents: 44188
diff changeset
   661
        let _ref = owner.string_shared(py).borrow();
44203
2a24ead003f0 rust-cpython: add panicking version of borrow_mut() and use it
Yuya Nishihara <yuya@tcha.org>
parents: 44189
diff changeset
   662
        owner.string_shared(py).borrow_mut();
44189
4a4c3b9fd91b rust-cpython: make sure PySharedRef::borrow_mut() never panics
Yuya Nishihara <yuya@tcha.org>
parents: 44188
diff changeset
   663
    }
43289
8d432d3a2d7c rust-cpython: prepare for writing tests that require libpython
Yuya Nishihara <yuya@tcha.org>
parents: 43288
diff changeset
   664
}