diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3a337db9..80360a74 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,9 +33,13 @@ jobs: matrix: rust-version: [stable] runs-on: [ubuntu, macos] + python-version: ["3.13"] include: - rust-version: ${{ needs.resolve.outputs.MSRV }} runs-on: ubuntu + - rust-version: stable + runs-on: ubuntu + python-version: "3.13t" - rust-version: nightly runs-on: ubuntu @@ -49,9 +53,9 @@ jobs: - uses: actions/checkout@v4 - name: set up python - uses: actions/setup-python@v5 + uses: quansight-labs/setup-python@v5 with: - python-version: "3.13" + python-version: ${{ matrix.python-version }} - uses: dtolnay/rust-toolchain@master with: @@ -78,10 +82,15 @@ jobs: token: ${{ secrets.CODECOV_TOKEN }} test-python: - name: test jiter-python + name: test jiter-python ${{ matrix.python-version }} runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: ["3.13", "3.13t"] + env: RUNS_ON: ubuntu-latest @@ -89,16 +98,16 @@ jobs: - uses: actions/checkout@v4 - name: set up python - uses: actions/setup-python@v5 + uses: quansight-labs/setup-python@v5 with: - python-version: "3.13" + python-version: ${{ matrix.python-version }} - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 - uses: taiki-e/install-action@cargo-llvm-cov - name: Install python dependencies - run: make python-install + run: pip install -r crates/jiter-python/tests/requirements.txt - name: Build jiter-python run: | diff --git a/crates/jiter-python/src/lib.rs b/crates/jiter-python/src/lib.rs index 8488982d..9f080e91 100644 --- a/crates/jiter-python/src/lib.rs +++ b/crates/jiter-python/src/lib.rs @@ -58,13 +58,13 @@ mod jiter_python { } #[pyfunction] - pub fn cache_clear(py: Python<'_>) { - jiter::cache_clear(py); + pub fn cache_clear() { + jiter::cache_clear(); } #[pyfunction] - pub fn cache_usage(py: Python<'_>) -> usize { - jiter::cache_usage(py) + pub fn cache_usage() -> usize { + jiter::cache_usage() } #[pymodule_init] diff --git a/crates/jiter/src/py_string_cache.rs b/crates/jiter/src/py_string_cache.rs index 874d8811..58728238 100644 --- a/crates/jiter/src/py_string_cache.rs +++ b/crates/jiter/src/py_string_cache.rs @@ -1,9 +1,8 @@ -use std::cell::RefCell; +use std::sync::{Mutex, OnceLock}; use ahash::random_state::RandomState; use pyo3::exceptions::{PyTypeError, PyValueError}; use pyo3::prelude::*; -use pyo3::sync::{GILOnceCell, GILProtected}; use pyo3::types::{PyBool, PyString}; #[derive(Debug, Clone, Copy)] @@ -86,28 +85,34 @@ impl StringMaybeCache for StringNoCache { } } -static STRING_CACHE: GILOnceCell>> = GILOnceCell::new(); +static STRING_CACHE: OnceLock> = OnceLock::new(); -macro_rules! get_string_cache { - ($py:ident) => { - STRING_CACHE - .get_or_init($py, || GILProtected::new(RefCell::new(PyStringCache::default()))) - .get($py) - }; +#[inline] +fn get_string_cache() -> &'static Mutex { + STRING_CACHE.get_or_init(|| Mutex::new(PyStringCache::default())) } -pub fn cache_usage(py: Python) -> usize { - get_string_cache!(py).borrow().usage() +pub fn cache_usage() -> usize { + get_string_cache() + .lock() + .expect("no code panics with mutex locked") + .usage() } -pub fn cache_clear(py: Python) { - get_string_cache!(py).borrow_mut().clear(); +pub fn cache_clear() { + get_string_cache() + .lock() + .expect("no code panics with mutex locked") + .clear(); } pub fn cached_py_string<'py>(py: Python<'py>, s: &str, ascii_only: bool) -> Bound<'py, PyString> { // from tests, 0 and 1 character strings are faster not cached if (2..64).contains(&s.len()) { - get_string_cache!(py).borrow_mut().get_or_insert(py, s, ascii_only) + get_string_cache() + .lock() + .expect("no code panics with mutex locked") + .get_or_insert(py, s, ascii_only) } else { pystring_fast_new(py, s, ascii_only) }