Skip to content

Commit

Permalink
macros: simpler expansion for intern!
Browse files Browse the repository at this point in the history
  • Loading branch information
davidhewitt committed Jun 2, 2022
1 parent 2769963 commit ede6439
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 16 deletions.
36 changes: 20 additions & 16 deletions src/once_cell.rs
Original file line number Diff line number Diff line change
@@ -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/).
Expand Down Expand Up @@ -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::*;
Expand Down
1 change: 1 addition & 0 deletions tests/test_compile_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ fn test_compile_errors() {
fn _test_compile_errors() {
let t = trybuild::TestCases::new();

t.compile_fail("tests/ui/invalid_intern_arg.rs");
t.compile_fail("tests/ui/invalid_macro_args.rs");
t.compile_fail("tests/ui/invalid_need_module_arg_position.rs");
t.compile_fail("tests/ui/invalid_property_args.rs");
Expand Down
6 changes: 6 additions & 0 deletions tests/ui/invalid_intern_arg.rs
Original file line number Diff line number Diff line change
@@ -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());
}
8 changes: 8 additions & 0 deletions tests/ui/invalid_intern_arg.stderr
Original file line number Diff line number Diff line change
@@ -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`

0 comments on commit ede6439

Please sign in to comment.