macros: simpler expansion for intern!

This commit is contained in:
David Hewitt 2022-06-01 09:07:00 +01:00
parent 2769963536
commit 261c0c5f56
4 changed files with 35 additions and 16 deletions

View file

@ -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<T> GILOnceCell<T> {
#[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<Py<PyString>>);
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::*;

View file

@ -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");

View file

@ -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());
}

View file

@ -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`