Mercurial > public > mercurial-scm > hg
changeset 52776:6fa23eed335b
rust-pyo3: PyFnCache
This is a translitteration of the `PyFnCache` from `hg-cpython/src/revlog.rs`.
To match the Python code organization, we put it its own top-level Rust module.
Our immediate use case is for the `revlog` module, but we believe it
will eventually be useful elsewhere.
author | Georges Racinet <georges.racinet@cloudcrane.io> |
---|---|
date | Tue, 24 Dec 2024 18:16:38 +0100 |
parents | 264047bf4b9b |
children | 32008b1e7104 |
files | rust/hg-pyo3/src/lib.rs rust/hg-pyo3/src/store.rs |
diffstat | 2 files changed, 78 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/rust/hg-pyo3/src/lib.rs Tue Dec 24 18:02:11 2024 +0100 +++ b/rust/hg-pyo3/src/lib.rs Tue Dec 24 18:16:38 2024 +0100 @@ -6,6 +6,7 @@ mod exceptions; mod revision; mod revlog; +mod store; mod util; #[pymodule]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rust/hg-pyo3/src/store.rs Tue Dec 24 18:16:38 2024 +0100 @@ -0,0 +1,77 @@ +// store.rs +// +// Copyright 2020-2024 Raphaël Gomès <raphael.gomes@octobus.net> +// 2024 Georges Racinet <georges.racinet@cloudcrane.io> +// +// This software may be used and distributed according to the terms of the +// GNU General Public License version 2 or any later version. +#![allow(unused)] // for now +use pyo3::prelude::*; +use pyo3::types::PyBytes; + +use std::sync::atomic::{AtomicBool, Ordering}; + +use hg::{fncache::FnCache, utils::files::get_bytes_from_path}; + +pub struct PyFnCache { + fncache: PyObject, +} + +impl PyFnCache { + pub fn new(fncache: PyObject) -> Self { + Self { fncache } + } +} + +impl Clone for PyFnCache { + fn clone(&self) -> Self { + Python::with_gil(|py| Self { + fncache: self.fncache.clone_ref(py), + }) + } +} + +/// Cache whether the fncache is loaded to avoid Python round-trip every time. +/// Once the fncache is loaded, it stays loaded unless we're in a very +/// long-running process, none of which we actually support for now. +static FN_CACHE_IS_LOADED: AtomicBool = AtomicBool::new(false); + +// TODO perhaps a bit of magic with `Bound<'_, PyFnCache>` would spare us +// the GIL reacquisitions +impl FnCache for PyFnCache { + fn is_loaded(&self) -> bool { + if FN_CACHE_IS_LOADED.load(Ordering::Relaxed) { + return true; + } + Python::with_gil(|py| { + // TODO raise in case of error? + let is_loaded = self + .fncache + .getattr(py, "is_loaded") + .ok() + .map(|o| { + o.extract::<bool>(py).expect( + "is_loaded returned something other than a bool", + ) + }) + .unwrap_or(false); + if is_loaded { + FN_CACHE_IS_LOADED.store(true, Ordering::Relaxed); + } + is_loaded + }) + } + fn add(&self, path: &std::path::Path) { + Python::with_gil(|py| { + // TODO raise in case of error? + self.fncache + .call_method( + py, + "add", + (PyBytes::new(py, &get_bytes_from_path(path)),), + None, + ) + .ok(); + }) + } +}