Skip to content

Commit 823b8e7

Browse files
committed
New Native Types and lighter GILPool
1 parent e40f022 commit 823b8e7

25 files changed

+113
-300
lines changed

src/conversion.rs

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
//! Conversions between various states of Rust and Python types and their wrappers.
44
use crate::err::{self, PyDowncastError, PyResult};
55
use crate::object::PyObject;
6-
use crate::type_object::{PyDowncastImpl, PyTypeInfo};
6+
use crate::type_object::PyTypeInfo;
77
use crate::types::PyTuple;
88
use crate::{ffi, gil, Py, PyAny, PyCell, PyClass, PyNativeType, PyRef, PyRefMut, Python};
99
use std::ptr::NonNull;
@@ -311,7 +311,7 @@ where
311311
/// If `T` implements `PyTryFrom`, we can convert `&PyAny` to `&T`.
312312
///
313313
/// This trait is similar to `std::convert::TryFrom`
314-
pub trait PyTryFrom<'v>: Sized + PyDowncastImpl {
314+
pub trait PyTryFrom<'v>: Sized + PyNativeType {
315315
/// Cast from a concrete Python object type to PyObject.
316316
fn try_from<V: Into<&'v PyAny>>(value: V) -> Result<&'v Self, PyDowncastError>;
317317

@@ -348,7 +348,7 @@ where
348348

349349
impl<'v, T> PyTryFrom<'v> for T
350350
where
351-
T: PyDowncastImpl + PyTypeInfo + PyNativeType,
351+
T: PyTypeInfo + PyNativeType,
352352
{
353353
fn try_from<V: Into<&'v PyAny>>(value: V) -> Result<&'v Self, PyDowncastError> {
354354
let value = value.into();
@@ -460,28 +460,14 @@ where
460460
T: 'p + crate::PyNativeType,
461461
{
462462
unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<&'p Self> {
463-
NonNull::new(ptr).map(|p| Self::unchecked_downcast(gil::register_owned(py, p)))
463+
gil::register_owned(py, NonNull::new(ptr)?);
464+
Some(&*(ptr as *mut Self))
464465
}
465466
unsafe fn from_borrowed_ptr_or_opt(
466-
py: Python<'p>,
467-
ptr: *mut ffi::PyObject,
468-
) -> Option<&'p Self> {
469-
NonNull::new(ptr).map(|p| Self::unchecked_downcast(gil::register_borrowed(py, p)))
470-
}
471-
}
472-
473-
unsafe impl<'p, T> FromPyPointer<'p> for PyCell<T>
474-
where
475-
T: PyClass,
476-
{
477-
unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<&'p Self> {
478-
NonNull::new(ptr).map(|p| &*(gil::register_owned(py, p).as_ptr() as *const PyCell<T>))
479-
}
480-
unsafe fn from_borrowed_ptr_or_opt(
481-
py: Python<'p>,
467+
_py: Python<'p>,
482468
ptr: *mut ffi::PyObject,
483469
) -> Option<&'p Self> {
484-
NonNull::new(ptr).map(|p| &*(gil::register_borrowed(py, p).as_ptr() as *const PyCell<T>))
470+
NonNull::new(ptr as *mut Self).map(|p| &*p.as_ptr())
485471
}
486472
}
487473

src/gil.rs

Lines changed: 12 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
//! Interaction with python's global interpreter lock
44
5-
use crate::{ffi, internal_tricks::Unsendable, PyAny, Python};
5+
use crate::{ffi, internal_tricks::Unsendable, Python};
66
use std::cell::{Cell, UnsafeCell};
77
use std::{any, mem::ManuallyDrop, ptr::NonNull, sync};
88

@@ -144,8 +144,7 @@ impl Drop for GILGuard {
144144

145145
/// Implementation of release pool
146146
struct ReleasePoolImpl {
147-
owned: ArrayList<NonNull<ffi::PyObject>>,
148-
borrowed: ArrayList<NonNull<ffi::PyObject>>,
147+
owned: Vec<NonNull<ffi::PyObject>>,
149148
pointers: *mut Vec<NonNull<ffi::PyObject>>,
150149
obj: Vec<Box<dyn any::Any>>,
151150
p: parking_lot::Mutex<*mut Vec<NonNull<ffi::PyObject>>>,
@@ -154,8 +153,7 @@ struct ReleasePoolImpl {
154153
impl ReleasePoolImpl {
155154
fn new() -> Self {
156155
Self {
157-
owned: ArrayList::new(),
158-
borrowed: ArrayList::new(),
156+
owned: Vec::with_capacity(256),
159157
pointers: Box::into_raw(Box::new(Vec::with_capacity(256))),
160158
obj: Vec::with_capacity(8),
161159
p: parking_lot::Mutex::new(Box::into_raw(Box::new(Vec::with_capacity(256)))),
@@ -180,14 +178,12 @@ impl ReleasePoolImpl {
180178
vec.set_len(0);
181179
}
182180

183-
pub unsafe fn drain(&mut self, _py: Python, owned: usize, borrowed: usize) {
181+
pub unsafe fn drain(&mut self, _py: Python, owned: usize) {
184182
// Release owned objects(call decref)
185-
while owned < self.owned.len() {
186-
let last = self.owned.pop_back().unwrap();
187-
ffi::Py_DECREF(last.as_ptr());
183+
for i in owned..self.owned.len() {
184+
ffi::Py_DECREF(self.owned[i].as_ptr());
188185
}
189-
// Release borrowed objects(don't call decref)
190-
self.borrowed.truncate(borrowed);
186+
self.owned.truncate(owned);
191187
self.release_pointers();
192188
self.obj.clear();
193189
}
@@ -219,7 +215,6 @@ unsafe impl Sync for ReleasePool {}
219215
#[doc(hidden)]
220216
pub struct GILPool {
221217
owned: usize,
222-
borrowed: usize,
223218
// Stable solution for impl !Send
224219
no_send: Unsendable,
225220
}
@@ -235,7 +230,6 @@ impl GILPool {
235230
pool.release_pointers();
236231
GILPool {
237232
owned: pool.owned.len(),
238-
borrowed: pool.borrowed.len(),
239233
no_send: Unsendable::default(),
240234
}
241235
}
@@ -248,7 +242,7 @@ impl Drop for GILPool {
248242
fn drop(&mut self) {
249243
unsafe {
250244
let pool = POOL.get_or_init();
251-
pool.drain(self.python(), self.owned, self.borrowed);
245+
pool.drain(self.python(), self.owned);
252246
}
253247
decrement_gil_count();
254248
}
@@ -275,14 +269,9 @@ pub unsafe fn register_pointer(obj: NonNull<ffi::PyObject>) {
275269
}
276270
}
277271

278-
pub unsafe fn register_owned(_py: Python, obj: NonNull<ffi::PyObject>) -> &PyAny {
272+
pub unsafe fn register_owned(_py: Python, obj: NonNull<ffi::PyObject>) {
279273
let pool = POOL.get_or_init();
280-
&*(pool.owned.push_back(obj) as *const _ as *const PyAny)
281-
}
282-
283-
pub unsafe fn register_borrowed(_py: Python, obj: NonNull<ffi::PyObject>) -> &PyAny {
284-
let pool = POOL.get_or_init();
285-
&*(pool.borrowed.push_back(obj) as *const _ as *const PyAny)
274+
pool.owned.push(obj);
286275
}
287276

288277
/// Increment pyo3's internal GIL count - to be called whenever GILPool or GILGuard is created.
@@ -304,70 +293,10 @@ fn decrement_gil_count() {
304293
})
305294
}
306295

307-
use self::array_list::ArrayList;
308-
309-
mod array_list {
310-
use std::collections::LinkedList;
311-
const BLOCK_SIZE: usize = 256;
312-
313-
/// A container type for Release Pool
314-
/// See #271 for why this is crated
315-
pub(super) struct ArrayList<T> {
316-
inner: LinkedList<[Option<T>; BLOCK_SIZE]>,
317-
length: usize,
318-
}
319-
320-
impl<T: Copy> ArrayList<T> {
321-
pub fn new() -> Self {
322-
ArrayList {
323-
inner: LinkedList::new(),
324-
length: 0,
325-
}
326-
}
327-
pub fn push_back(&mut self, item: T) -> &T {
328-
let next_idx = self.next_idx();
329-
if next_idx == 0 {
330-
self.inner.push_back([None; BLOCK_SIZE]);
331-
}
332-
self.inner.back_mut().unwrap()[next_idx] = Some(item);
333-
self.length += 1;
334-
self.inner.back().unwrap()[next_idx].as_ref().unwrap()
335-
}
336-
pub fn pop_back(&mut self) -> Option<T> {
337-
self.length -= 1;
338-
let current_idx = self.next_idx();
339-
if current_idx == 0 {
340-
let last_list = self.inner.pop_back()?;
341-
return last_list[0];
342-
}
343-
self.inner.back().and_then(|arr| arr[current_idx])
344-
}
345-
pub fn len(&self) -> usize {
346-
self.length
347-
}
348-
pub fn truncate(&mut self, new_len: usize) {
349-
if self.length <= new_len {
350-
return;
351-
}
352-
while self.inner.len() > (new_len + BLOCK_SIZE - 1) / BLOCK_SIZE {
353-
self.inner.pop_back();
354-
}
355-
self.length = new_len;
356-
}
357-
fn next_idx(&self) -> usize {
358-
self.length % BLOCK_SIZE
359-
}
360-
}
361-
}
362-
363296
#[cfg(test)]
364297
mod test {
365-
use super::{GILPool, NonNull, GIL_COUNT, POOL};
366-
use crate::object::PyObject;
367-
use crate::AsPyPointer;
368-
use crate::Python;
369-
use crate::ToPyObject;
370-
use crate::{ffi, gil};
298+
use super::{GILPool, GIL_COUNT, POOL};
299+
use crate::{ffi, gil, AsPyPointer, PyObject, Python, ToPyObject};
371300

372301
fn get_object() -> PyObject {
373302
// Convenience function for getting a single unique object
@@ -442,66 +371,6 @@ mod test {
442371
}
443372
}
444373

445-
#[test]
446-
fn test_borrowed() {
447-
unsafe {
448-
let p = POOL.get_or_init();
449-
450-
let obj = get_object();
451-
let obj_ptr = obj.as_ptr();
452-
{
453-
let gil = Python::acquire_gil();
454-
let py = gil.python();
455-
assert_eq!(p.borrowed.len(), 0);
456-
457-
gil::register_borrowed(py, NonNull::new(obj_ptr).unwrap());
458-
459-
assert_eq!(p.borrowed.len(), 1);
460-
assert_eq!(ffi::Py_REFCNT(obj_ptr), 1);
461-
}
462-
{
463-
let _gil = Python::acquire_gil();
464-
assert_eq!(p.borrowed.len(), 0);
465-
assert_eq!(ffi::Py_REFCNT(obj_ptr), 1);
466-
}
467-
}
468-
}
469-
470-
#[test]
471-
fn test_borrowed_nested() {
472-
unsafe {
473-
let p = POOL.get_or_init();
474-
475-
let obj = get_object();
476-
let obj_ptr = obj.as_ptr();
477-
{
478-
let gil = Python::acquire_gil();
479-
let py = gil.python();
480-
assert_eq!(p.borrowed.len(), 0);
481-
482-
gil::register_borrowed(py, NonNull::new(obj_ptr).unwrap());
483-
484-
assert_eq!(p.borrowed.len(), 1);
485-
assert_eq!(ffi::Py_REFCNT(obj_ptr), 1);
486-
487-
{
488-
let _pool = GILPool::new();
489-
assert_eq!(p.borrowed.len(), 1);
490-
gil::register_borrowed(py, NonNull::new(obj_ptr).unwrap());
491-
assert_eq!(p.borrowed.len(), 2);
492-
}
493-
494-
assert_eq!(p.borrowed.len(), 1);
495-
assert_eq!(ffi::Py_REFCNT(obj_ptr), 1);
496-
}
497-
{
498-
let _gil = Python::acquire_gil();
499-
assert_eq!(p.borrowed.len(), 0);
500-
assert_eq!(ffi::Py_REFCNT(obj_ptr), 1);
501-
}
502-
}
503-
}
504-
505374
#[test]
506375
fn test_pyobject_drop_with_gil_decreases_refcnt() {
507376
let gil = Python::acquire_gil();

src/instance.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::err::{PyErr, PyResult};
33
use crate::gil;
44
use crate::object::PyObject;
55
use crate::objectprotocol::ObjectProtocol;
6-
use crate::type_object::{PyBorrowFlagLayout, PyDowncastImpl};
6+
use crate::type_object::PyBorrowFlagLayout;
77
use crate::{
88
ffi, AsPyPointer, FromPyObject, IntoPy, IntoPyPointer, PyAny, PyCell, PyClass,
99
PyClassInitializer, PyRef, PyRefMut, PyTypeInfo, Python, ToPyObject,
@@ -21,6 +21,15 @@ pub unsafe trait PyNativeType: Sized {
2121
fn py(&self) -> Python {
2222
unsafe { Python::assume_gil_acquired() }
2323
}
24+
/// Cast `&PyAny` to `&Self` without no type checking.
25+
///
26+
/// # Safety
27+
///
28+
/// Unless obj is not an instance of a type corresponding to Self,
29+
/// this method causes undefined behavior.
30+
unsafe fn unchecked_downcast(obj: &PyAny) -> &Self {
31+
&*(obj.as_ptr() as *const Self)
32+
}
2433
}
2534

2635
/// A Python object of known type.
@@ -176,8 +185,8 @@ where
176185
{
177186
type Target = T::AsRefTarget;
178187
fn as_ref<'p>(&'p self, _py: Python<'p>) -> &'p Self::Target {
179-
let any = self as *const Py<T> as *const PyAny;
180-
unsafe { PyDowncastImpl::unchecked_downcast(&*any) }
188+
let any = self.as_ptr() as *const PyAny;
189+
unsafe { PyNativeType::unchecked_downcast(&*any) }
181190
}
182191
}
183192

src/object.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ impl PyObject {
3232
PyObject(ptr)
3333
}
3434

35+
#[cfg(test)]
3536
pub(crate) unsafe fn into_nonnull(self) -> NonNull<ffi::PyObject> {
3637
let res = self.0;
3738
std::mem::forget(self); // Avoid Drop
@@ -268,7 +269,7 @@ impl PyObject {
268269
impl AsPyRef for PyObject {
269270
type Target = PyAny;
270271
fn as_ref<'p>(&'p self, _py: Python<'p>) -> &'p PyAny {
271-
unsafe { &*(self as *const _ as *const PyAny) }
272+
unsafe { &*(self.as_ptr() as *const PyAny) }
272273
}
273274
}
274275

src/pycell.rs

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
use crate::conversion::{AsPyPointer, FromPyPointer, ToPyObject};
33
use crate::pyclass_init::PyClassInitializer;
44
use crate::pyclass_slots::{PyClassDict, PyClassWeakRef};
5-
use crate::type_object::{PyBorrowFlagLayout, PyDowncastImpl, PyLayout, PySizedLayout, PyTypeInfo};
6-
use crate::{ffi, FromPy, PyAny, PyClass, PyErr, PyNativeType, PyObject, PyResult, Python};
5+
use crate::type_object::{PyBorrowFlagLayout, PyLayout, PySizedLayout, PyTypeInfo};
6+
use crate::{ffi, FromPy, PyClass, PyErr, PyNativeType, PyObject, PyResult, Python};
77
use std::cell::{Cell, UnsafeCell};
88
use std::fmt;
99
use std::mem::ManuallyDrop;
@@ -159,6 +159,8 @@ pub struct PyCell<T: PyClass> {
159159
weakref: T::WeakRef,
160160
}
161161

162+
unsafe impl<T: PyClass> PyNativeType for PyCell<T> {}
163+
162164
impl<T: PyClass> PyCell<T> {
163165
/// Make new `PyCell` on the Python heap and returns the reference of it.
164166
///
@@ -360,13 +362,6 @@ unsafe impl<T: PyClass> PyLayout<T> for PyCell<T> {
360362
}
361363
}
362364

363-
unsafe impl<T: PyClass> PyDowncastImpl for PyCell<T> {
364-
unsafe fn unchecked_downcast(obj: &PyAny) -> &Self {
365-
&*(obj.as_ptr() as *const Self)
366-
}
367-
private_impl! {}
368-
}
369-
370365
impl<T: PyClass> AsPyPointer for PyCell<T> {
371366
fn as_ptr(&self) -> *mut ffi::PyObject {
372367
self.inner.as_ptr()

0 commit comments

Comments
 (0)