Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ appveyor = { repository = "dgrunwald/rust-cpython" }
[dependencies]
libc = "0.2"
num-traits = "0.2"

# TODO: use `std::lazy::OnceCell` instead and when it’s stable
# and this crate requires a minimum Rust version that has it stable:
# https://github.com/rust-lang/rust/issues/74465
once_cell = "1.8"

paste = "1"
serde = { version = "1", features = ["derive"], optional = true }

Expand All @@ -43,7 +49,7 @@ rustversion = "1.0"
serde_bytes = { version = "0.11" }
serde_cbor = { version = "0.11" }

# These features are both optional, but you must pick one to
# These features are both optional, but you must pick one to
# indicate which python ffi you are trying to bind to.
[dependencies.python27-sys]
optional = true
Expand Down Expand Up @@ -83,7 +89,7 @@ py-link-mode-default = [ "python3-sys/link-mode-default" ]
py-link-mode-unresolved-static = [ "python3-sys/link-mode-unresolved-static" ]

# Optional features to support explicitly specifying python minor version.
# If you don't care which minor version, just specify python3-sys as a
# If you don't care which minor version, just specify python3-sys as a
# feature.
python-3-9 = ["python3-sys/python-3-9"]
python-3-8 = ["python3-sys/python-3-8"]
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ pub mod _detail {
handle_callback, py_fn_impl, AbortOnDrop, PyObjectCallbackConverter,
PythonObjectCallbackConverter,
};
pub use once_cell::unsync::OnceCell;
pub use paste;
}

Expand Down
38 changes: 17 additions & 21 deletions src/objects/capsule.rs
Original file line number Diff line number Diff line change
Expand Up @@ -347,28 +347,27 @@ macro_rules! py_capsule {
(from $($capsmod:ident).+ import $capsname:ident as $rustmod:ident for $ruststruct: ident ) => (
mod $rustmod {
use super::*;
use std::sync::Once;
use $crate::_detail::OnceCell;
use $crate::GILProtected;
use $crate::PyClone;

static mut CAPS_DATA: Option<$crate::PyResult<&$ruststruct>> = None;

static INIT: Once = Once::new();
static CAPS_DATA: GILProtected<OnceCell<$crate::PyResult<&$ruststruct>>> =
GILProtected::new(OnceCell::new());

pub type RawPyObject = $crate::_detail::ffi::PyObject;

pub unsafe fn retrieve<'a>(py: $crate::Python) -> $crate::PyResult<&'a $ruststruct> {
INIT.call_once(|| {
let ref_to_result = CAPS_DATA.get(py).get_or_init(|| {
let caps_name =
std::ffi::CStr::from_bytes_with_nul_unchecked(
concat!($( stringify!($capsmod), "."),*,
stringify!($capsname),
"\0").as_bytes());
CAPS_DATA = Some($crate::PyCapsule::import_data(py, caps_name));
$crate::PyCapsule::import_data(py, caps_name)
});
match CAPS_DATA {
Some(Ok(d)) => Ok(d),
Some(Err(ref e)) => Err(e.clone_ref(py)),
_ => panic!("Uninitialized"), // can't happen
match ref_to_result {
&Ok(ref x) => Ok(x),
&Err(ref e) => Err(e.clone_ref(py))
}
}
}
Expand Down Expand Up @@ -397,7 +396,7 @@ macro_rules! py_capsule {
/// ```ignore
/// mod $rustmod {
/// pub type CapsuleFn = unsafe extern "C" (args) -> ret_type ;
/// pub unsafe fn retrieve<'a>(py: Python) -> PyResult<CapsuleFn) { ... }
/// pub unsafe fn retrieve<'a>(py: Python) -> PyResult<CapsuleFn> { ... }
/// }
/// ```
/// - a `RawPyObject` type suitable for signatures that involve Python C objects;
Expand Down Expand Up @@ -482,15 +481,15 @@ macro_rules! py_capsule_fn {
(from $($capsmod:ident).+ import $capsname:ident as $rustmod:ident signature $( $sig: tt)* ) => (
mod $rustmod {
use super::*;
use std::sync::Once;
use $crate::_detail::OnceCell;
use $crate::GILProtected;
use $crate::PyClone;

pub type CapsuleFn = unsafe extern "C" fn $( $sig )*;
pub type RawPyObject = $crate::_detail::ffi::PyObject;

static mut CAPS_FN: Option<$crate::PyResult<CapsuleFn>> = None;

static INIT: Once = Once::new();
static CAPS_FN: GILProtected<OnceCell<$crate::PyResult<CapsuleFn>>> =
GILProtected::new(OnceCell::new());

fn import(py: $crate::Python) -> $crate::PyResult<CapsuleFn> {
unsafe {
Expand All @@ -504,12 +503,9 @@ macro_rules! py_capsule_fn {
}

pub fn retrieve(py: $crate::Python) -> $crate::PyResult<CapsuleFn> {
unsafe {
INIT.call_once(|| { CAPS_FN = Some(import(py)) });
match CAPS_FN.as_ref().unwrap() {
&Ok(f) => Ok(f),
&Err(ref e) => Err(e.clone_ref(py)),
}
match CAPS_FN.get(py).get_or_init(|| import(py)) {
&Ok(f) => Ok(f),
&Err(ref e) => Err(e.clone_ref(py)),
}
}
}
Expand Down