From ba45a444c6610e78fe7401ee870117d38d29a914 Mon Sep 17 00:00:00 2001 From: Adam Reichold Date: Sun, 3 Apr 2022 12:27:34 +0200 Subject: [PATCH] Add intern! macro which can be used to amortize the cost of creating Python objects by storing them inside a GILOnceCell. --- CHANGELOG.md | 1 + src/lib.rs | 1 + src/once_cell.rs | 27 +++++++++++++++++++++++++++ 3 files changed, 29 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index db19eba9431..453363f21be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Allow dependent crates to access config values from `pyo3-build-config` via cargo link dep env vars. [#2092](https://github.com/PyO3/pyo3/pull/2092) - Added methods on `InterpreterConfig` to run Python scripts using the configured executable. [#2092](https://github.com/PyO3/pyo3/pull/2092) - Added FFI definitions for `PyType_FromModuleAndSpec`, `PyType_GetModule`, `PyType_GetModuleState` and `PyModule_AddType`. [#2250](https://github.com/PyO3/pyo3/pull/2250) +- Add `intern!` macro which can be used to amortize the cost of creating Python objects by storing them inside a `GILOnceCell`. [#2269](https://github.com/PyO3/pyo3/pull/2269) ### Changed diff --git a/src/lib.rs b/src/lib.rs index ce2a1e24905..6da166235c7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -375,6 +375,7 @@ pub mod impl_; mod instance; pub mod marker; pub mod marshal; +#[macro_use] pub mod once_cell; pub mod panic; pub mod prelude; diff --git a/src/once_cell.rs b/src/once_cell.rs index 739864c5ab0..7cf941d37f3 100644 --- a/src/once_cell.rs +++ b/src/once_cell.rs @@ -101,3 +101,30 @@ impl GILOnceCell { Ok(()) } } + +/// Will convert the given value into a Python object and intern that within a [`GILOnceCell`] +/// +/// # Example +/// +/// ``` +/// use pyo3::intern; +/// # use pyo3::{types::PyDict, Python}; +/// +/// # Python::with_gil(|py| { +/// let dict = PyDict::new(py); +/// dict.set_item(intern!(py, "foo"), 42).unwrap(); +/// # }); +/// ``` +#[macro_export] +macro_rules! intern { + ($py: expr, $value: expr) => {{ + static INTERNED: $crate::once_cell::GILOnceCell<$crate::PyObject> = + $crate::once_cell::GILOnceCell::new(); + + INTERNED + .get_or_init($py, || { + $crate::conversion::ToPyObject::to_object($value, $py) + }) + .as_ref($py) + }}; +}