feat: EvalState.weak_ref()

(cherry picked from commit d7a72c82ebfbfbb1b58fa15044b63648b2109260)
This commit is contained in:
Robert Hensing 2024-06-27 16:01:40 +02:00
parent e0dead151e
commit 01c9d0b2d3
2 changed files with 57 additions and 2 deletions

View file

@ -4,14 +4,14 @@ use anyhow::{bail, Result};
use lazy_static::lazy_static;
use nix_c_raw as raw;
use nix_store::path::StorePath;
use nix_store::store::Store;
use nix_store::store::{Store, StoreWeak};
use nix_util::context::Context;
use nix_util::string_return::{callback_get_result_string, callback_get_result_string_data};
use nix_util::{check_call, check_call_opt_key, result_string_init};
use std::ffi::{c_char, CString};
use std::os::raw::c_uint;
use std::ptr::{null, null_mut, NonNull};
use std::sync::Arc;
use std::sync::{Arc, Weak};
lazy_static! {
static ref INIT: Result<()> = {
@ -38,6 +38,26 @@ pub struct RealisedString {
pub paths: Vec<StorePath>,
}
/// A [Weak] reference to an [EvalState]
pub struct EvalStateWeak {
inner: Weak<EvalStateRef>,
store: StoreWeak,
}
impl EvalStateWeak {
/// Upgrade the weak reference to a proper [EvalState].
///
/// If no normal reference to the [EvalState] is around anymore elsewhere, this fails by returning `None`.
pub fn upgrade(&self) -> Option<EvalState> {
self.inner.upgrade().and_then(|eval_state| {
self.store.upgrade().map(|store| EvalState {
eval_state: eval_state,
store: store,
context: Context::new(),
})
})
}
}
struct EvalStateRef {
eval_state: NonNull<raw::EvalState>,
}
@ -106,6 +126,13 @@ impl EvalState {
pub fn store(&self) -> &Store {
&self.store
}
pub fn weak_ref(&self) -> EvalStateWeak {
EvalStateWeak {
inner: Arc::downgrade(&self.eval_state),
store: self.store.weak_ref(),
}
}
/// Parses and evaluates a Nix expression `expr`.
///
/// Expressions can contain relative paths such as `./.` that are resolved relative to the given `path`.
@ -481,6 +508,32 @@ mod tests {
.unwrap();
}
#[test]
fn weak_ref() {
gc_registering_current_thread(|| {
let store = Store::open("auto", HashMap::new()).unwrap();
let es = EvalState::new(store, []).unwrap();
let weak = es.weak_ref();
let _es = weak.upgrade().unwrap();
})
.unwrap();
}
#[test]
fn weak_ref_gone() {
gc_registering_current_thread(|| {
let weak = {
let store = Store::open("auto", HashMap::new()).unwrap();
let es = EvalState::new(store, []).unwrap();
es.weak_ref()
};
assert!(weak.upgrade().is_none());
assert!(weak.store.upgrade().is_none());
assert!(weak.inner.upgrade().is_none());
})
.unwrap();
}
#[test]
fn eval_state_lookup_path() {
let import_expression = "import <test_file0> + import <test_file1>";

View file

@ -39,6 +39,8 @@ pub struct StoreWeak {
}
impl StoreWeak {
/// Upgrade the weak reference to a proper [Store].
///
/// If no normal reference to the [Store] is around anymore elsewhere, this fails by returning `None`.
pub fn upgrade(&self) -> Option<Store> {
self.inner.upgrade().map(|inner| Store {
inner,