From 261c0c5f567b32d28988e226b86403ac91cb1204 Mon Sep 17 00:00:00 2001 From: David Hewitt <1939362+davidhewitt@users.noreply.github.com> Date: Wed, 1 Jun 2022 09:07:00 +0100 Subject: [PATCH] macros: simpler expansion for `intern!` --- src/once_cell.rs | 36 +++++++++++++++++------------- tests/test_compile_error.rs | 1 + tests/ui/invalid_intern_arg.rs | 6 +++++ tests/ui/invalid_intern_arg.stderr | 8 +++++++ 4 files changed, 35 insertions(+), 16 deletions(-) create mode 100644 tests/ui/invalid_intern_arg.rs create mode 100644 tests/ui/invalid_intern_arg.stderr diff --git a/src/once_cell.rs b/src/once_cell.rs index c41d8d3aba5..e0627e6ff1e 100644 --- a/src/once_cell.rs +++ b/src/once_cell.rs @@ -1,5 +1,5 @@ //! A write-once cell mediated by the Python GIL. -use crate::Python; +use crate::{types::PyString, Py, Python}; use std::cell::UnsafeCell; /// A write-once cell similar to [`once_cell::OnceCell`](https://docs.rs/once_cell/1.4.0/once_cell/). @@ -151,24 +151,28 @@ impl GILOnceCell { #[macro_export] macro_rules! intern { ($py: expr, $text: expr) => {{ - fn isolate_from_dyn_env(py: $crate::Python<'_>) -> &$crate::types::PyString { - static INTERNED: $crate::once_cell::GILOnceCell<$crate::Py<$crate::types::PyString>> = - $crate::once_cell::GILOnceCell::new(); - - INTERNED - .get_or_init(py, || { - $crate::conversion::IntoPy::into_py( - $crate::types::PyString::intern(py, $text), - py, - ) - }) - .as_ref(py) - } - - isolate_from_dyn_env($py) + static INTERNED: $crate::once_cell::Interned = $crate::once_cell::Interned::new($text); + INTERNED.get($py) }}; } +/// Implementation detail for `intern!` macro. +#[doc(hidden)] +pub struct Interned(&'static str, GILOnceCell>); + +impl Interned { + pub const fn new(value: &'static str) -> Self { + Interned(value, GILOnceCell::new()) + } + + #[inline] + pub fn get<'py>(&'py self, py: Python<'py>) -> &'py PyString { + self.1 + .get_or_init(py, || PyString::intern(py, self.0).into()) + .as_ref(py) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/tests/test_compile_error.rs b/tests/test_compile_error.rs index 989928c2775..f85c925a673 100644 --- a/tests/test_compile_error.rs +++ b/tests/test_compile_error.rs @@ -94,6 +94,7 @@ fn _test_compile_errors() { #[rustversion::since(1.60)] fn tests_rust_1_60(t: &trybuild::TestCases) { + t.compile_fail("tests/ui/invalid_intern_arg.rs"); t.compile_fail("tests/ui/invalid_immutable_pyclass_borrow.rs"); t.compile_fail("tests/ui/invalid_pymethod_receiver.rs"); t.compile_fail("tests/ui/missing_intopy.rs"); diff --git a/tests/ui/invalid_intern_arg.rs b/tests/ui/invalid_intern_arg.rs new file mode 100644 index 00000000000..fa9e1e59f0c --- /dev/null +++ b/tests/ui/invalid_intern_arg.rs @@ -0,0 +1,6 @@ +use pyo3::Python; + +fn main() { + let foo = if true { "foo" } else { "bar" }; + Python::with_gil(|py| py.import(pyo3::intern!(py, foo)).unwrap()); +} diff --git a/tests/ui/invalid_intern_arg.stderr b/tests/ui/invalid_intern_arg.stderr new file mode 100644 index 00000000000..bb84d00e15b --- /dev/null +++ b/tests/ui/invalid_intern_arg.stderr @@ -0,0 +1,8 @@ +error[E0435]: attempt to use a non-constant value in a constant + --> tests/ui/invalid_intern_arg.rs:5:55 + | +5 | Python::with_gil(|py| py.import(pyo3::intern!(py, foo)).unwrap()); + | ------------------^^^- + | | | + | | non-constant value + | help: consider using `let` instead of `static`: `let INTERNED`