2
2
//!
3
3
//! Using the patterns described in [“Extending `numpy.random`”][ext],
4
4
//! you can generate random numbers without holding the GIL,
5
- //! by [acquiring][`PyBitGeneratorMethods::lock`] a [ lock][`PyBitGeneratorLock `] for the [`PyBitGenerator`]:
5
+ //! by [acquiring][`PyBitGeneratorMethods::lock`] a lock [guard ][`PyBitGeneratorGuard `] for the [`PyBitGenerator`]:
6
6
//!
7
7
//! ```rust
8
8
//! use pyo3::prelude::*;
16
16
//! let random_number = bitgen.next_u64();
17
17
//! ```
18
18
//!
19
- //! With the [`rand`] crate installed, you can also use the [`rand::Rng`] APIs from the [`PyBitGeneratorLock `]:
19
+ //! With the [`rand`] crate installed, you can also use the [`rand::Rng`] APIs from the [`PyBitGeneratorGuard `]:
20
20
//!
21
21
//! ```rust
22
22
//! use rand::Rng as _;
@@ -76,11 +76,11 @@ unsafe impl PyTypeInfo for PyBitGenerator {
76
76
/// Methods for [`PyBitGenerator`].
77
77
pub trait PyBitGeneratorMethods {
78
78
/// Acquire a lock on the BitGenerator to allow calling its methods in.
79
- fn lock ( & self ) -> PyResult < PyBitGeneratorLock > ;
79
+ fn lock ( & self ) -> PyResult < PyBitGeneratorGuard > ;
80
80
}
81
81
82
82
impl < ' py > PyBitGeneratorMethods for Bound < ' py , PyBitGenerator > {
83
- fn lock ( & self ) -> PyResult < PyBitGeneratorLock > {
83
+ fn lock ( & self ) -> PyResult < PyBitGeneratorGuard > {
84
84
let capsule = self . getattr ( "capsule" ) ?. downcast_into :: < PyCapsule > ( ) ?;
85
85
let lock = self . getattr ( "lock" ) ?;
86
86
if lock. getattr ( "locked" ) ?. call0 ( ) ?. extract ( ) ? {
@@ -97,28 +97,29 @@ impl<'py> PyBitGeneratorMethods for Bound<'py, PyBitGenerator> {
97
97
return Err ( PyRuntimeError :: new_err ( "Invalid BitGenerator capsule" ) ) ;
98
98
}
99
99
} ;
100
- Ok ( PyBitGeneratorLock {
100
+ Ok ( PyBitGeneratorGuard {
101
101
raw_bitgen : non_null,
102
102
lock : lock. unbind ( ) ,
103
103
} )
104
104
}
105
105
}
106
106
107
- impl < ' py > TryFrom < & Bound < ' py , PyBitGenerator > > for PyBitGeneratorLock {
107
+ impl < ' py > TryFrom < & Bound < ' py , PyBitGenerator > > for PyBitGeneratorGuard {
108
108
type Error = PyErr ;
109
109
fn try_from ( value : & Bound < ' py , PyBitGenerator > ) -> Result < Self , Self :: Error > {
110
110
value. lock ( )
111
111
}
112
112
}
113
113
114
114
/// [`PyBitGenerator`] lock allowing to access its methods without holding the GIL.
115
- pub struct PyBitGeneratorLock {
115
+ pub struct PyBitGeneratorGuard {
116
116
raw_bitgen : NonNull < npy_bitgen > ,
117
117
lock : Py < PyAny > ,
118
118
}
119
119
120
- // SAFETY for all methods: We hold the BitGenerator lock, so nothing is allowed to change its state
121
- impl PyBitGeneratorLock {
120
+ // SAFETY: We hold the `BitGenerator.lock`,
121
+ // so nothing apart from us is allowed to change its state.
122
+ impl PyBitGeneratorGuard {
122
123
/// Returns the next random unsigned 64 bit integer.
123
124
pub fn next_uint64 ( & mut self ) -> u64 {
124
125
unsafe {
@@ -149,7 +150,7 @@ impl PyBitGeneratorLock {
149
150
}
150
151
}
151
152
152
- impl Drop for PyBitGeneratorLock {
153
+ impl Drop for PyBitGeneratorGuard {
153
154
fn drop ( & mut self ) {
154
155
let r = Python :: with_gil ( |py| -> PyResult < ( ) > {
155
156
self . lock . bind ( py) . getattr ( "release" ) ?. call0 ( ) ?;
@@ -162,7 +163,7 @@ impl Drop for PyBitGeneratorLock {
162
163
}
163
164
164
165
#[ cfg( feature = "rand" ) ]
165
- impl rand:: RngCore for PyBitGeneratorLock {
166
+ impl rand:: RngCore for PyBitGeneratorGuard {
166
167
fn next_u32 ( & mut self ) -> u32 {
167
168
self . next_uint32 ( )
168
169
}
@@ -207,14 +208,19 @@ mod tests {
207
208
Ok ( ( ) )
208
209
}
209
210
210
- /// Test that dropping the lock works while holding the GIL
211
+ /// Test that releasing the lock works while holding the GIL
211
212
#[ test]
212
213
fn unlock_with_held_gil ( ) -> PyResult < ( ) > {
213
214
Python :: with_gil ( |py| {
214
215
let generator = get_bit_generator ( py) ?;
215
216
let mut bitgen = generator. lock ( ) ?;
216
217
let _ = bitgen. next_raw ( ) ;
217
218
std:: mem:: drop ( bitgen) ;
219
+ assert ! ( !generator
220
+ . getattr( "lock" ) ?
221
+ . getattr( "locked" ) ?
222
+ . call0( ) ?
223
+ . extract( ) ?) ;
218
224
Ok ( ( ) )
219
225
} )
220
226
}
0 commit comments