Skip to content

Commit a16846d

Browse files
committed
less unsafe
1 parent f49d3fa commit a16846d

File tree

1 file changed

+18
-12
lines changed

1 file changed

+18
-12
lines changed

src/random.rs

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,9 @@ impl<'py> PyBitGeneratorMethods<'py> for Bound<'py, PyBitGenerator> {
118118
};
119119
Ok(PyBitGeneratorGuard {
120120
raw_bitgen: non_null,
121-
_capsule: capsule,
122-
lock,
121+
_capsule: capsule.unbind(),
122+
lock: lock.unbind(),
123+
py: self.py(),
123124
})
124125
}
125126
}
@@ -134,8 +135,14 @@ impl<'py> TryFrom<&Bound<'py, PyBitGenerator>> for PyBitGeneratorGuard<'py> {
134135
/// [`PyBitGenerator`] lock allowing to access its methods without holding the GIL.
135136
pub struct PyBitGeneratorGuard<'py> {
136137
raw_bitgen: NonNull<npy_bitgen>,
137-
_capsule: Bound<'py, PyCapsule>,
138-
lock: Bound<'py, PyAny>,
138+
/// This field makes sure the `raw_bitgen` inside the capsule doesn’t get deallocated.
139+
_capsule: Py<PyCapsule>,
140+
/// This lock makes sure no other threads try to use the BitGenerator while we do.
141+
lock: Py<PyAny>,
142+
/// This should be an unsafe field (https://github.com/rust-lang/rust/issues/132922)
143+
///
144+
/// SAFETY: only use this in `Drop::drop` (when we are sure the GIL is held).
145+
py: Python<'py>,
139146
}
140147

141148
// SAFETY: we can’t have public APIs that access the Python objects,
@@ -145,18 +152,17 @@ unsafe impl Send for PyBitGeneratorGuard<'_> {}
145152
impl Drop for PyBitGeneratorGuard<'_> {
146153
fn drop(&mut self) {
147154
// ignore errors. This includes when `try_drop` was called manually
148-
let _ = self.lock.call_method0("release");
155+
let _ = self.lock.bind(self.py).call_method0("release");
149156
}
150157
}
151158

152159
// SAFETY: We hold the `BitGenerator.lock`,
153160
// so nothing apart from us is allowed to change its state.
154-
impl PyBitGeneratorGuard<'_> {
161+
impl<'py> PyBitGeneratorGuard<'py> {
155162
/// Drop the lock manually before `Drop::drop` tries to do it (used for testing).
156-
/// SAFETY: Can’t be used inside of a `Python::allow_threads` block.
157163
#[allow(dead_code)]
158-
unsafe fn try_drop(self) -> PyResult<()> {
159-
self.lock.call_method0("release")?;
164+
fn try_drop(self, py: Python<'py>) -> PyResult<()> {
165+
self.lock.bind(py).call_method0("release")?;
160166
Ok(())
161167
}
162168

@@ -223,7 +229,7 @@ mod tests {
223229
py.allow_threads(|| {
224230
let _ = bitgen.next_raw();
225231
});
226-
assert!(unsafe { bitgen.try_drop() }.is_ok());
232+
assert!(bitgen.try_drop(py).is_ok());
227233
Ok(())
228234
})
229235
}
@@ -240,7 +246,7 @@ mod tests {
240246
assert!(bitgen.random_ratio(1, 1));
241247
assert!(!bitgen.random_ratio(0, 1));
242248
});
243-
assert!(unsafe { bitgen.try_drop() }.is_ok());
249+
assert!(bitgen.try_drop(py).is_ok());
244250
Ok(())
245251
})
246252
}
@@ -251,7 +257,7 @@ mod tests {
251257
let generator = get_bit_generator(py)?;
252258
let bitgen = generator.lock()?;
253259
assert!(generator.lock().is_err());
254-
assert!(unsafe { bitgen.try_drop() }.is_ok());
260+
assert!(bitgen.try_drop(py).is_ok());
255261
Ok(())
256262
})
257263
}

0 commit comments

Comments
 (0)