dgrunwald / rust-cpython

Rust <-> Python bindings
MIT License
1.81k stars 136 forks source link

Cheaper and safe caching for py_capsule! and py_capsule_fn! #268

Open SimonSapin opened 3 years ago

SimonSapin commented 3 years ago

The py_capsule! and py_capsule_fn! macros generate retrieve functions that cache their results for subsequent calls.

Prior to this commit, caching is done with a generated unsafe static mut item whose access is made thread-safe by a std::sync::Once on the side. However this synchronization is unnecessary since retreive takes a Python<'_> parameter that indicates that the GIL is held.

This changes the cache to use safe static item instead, with GILProtected for synchronization-free thread-safety and OnceCell for interior mutability. As a bonus, this removes the need for cache-related unsafe code in generated retrieve functions.

This adds a dependency to the once_cell crate, which can be removed when OnceCell becomes stable in the standard library: https://github.com/rust-lang/rust/issues/74465

Alternatively OnceCell could be replaced with UnsafeCell plus some unsafe code, effectively inlining the core of the logic of OnceCell.

Fixes https://github.com/dgrunwald/rust-cpython/issues/263

SimonSapin commented 3 years ago

@markbt, any thought on this?