From 52778c37e9aa4b90c007dbfb3403b8fb766a77cd Mon Sep 17 00:00:00 2001 From: Robert Hensing Date: Tue, 9 Apr 2024 13:14:53 +0200 Subject: [PATCH] feat: EvalState.call (cherry picked from commit f3aa6e523c0c5214533d0005d8c3f85a0579b1de) --- rust/nix-expr/src/eval_state.rs | 76 +++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/rust/nix-expr/src/eval_state.rs b/rust/nix-expr/src/eval_state.rs index 1559727..006eaa6 100644 --- a/rust/nix-expr/src/eval_state.rs +++ b/rust/nix-expr/src/eval_state.rs @@ -192,6 +192,23 @@ impl EvalState { Ok(RealisedString { s, paths }) } + /// Eagerly apply a function to an argument. + pub fn call(&self, f: Value, a: Value) -> Result { + let v = unsafe { + let value = self.new_value_uninitialized(); + raw::value_call( + self.context.ptr(), + self.raw_ptr(), + f.raw_ptr(), + a.raw_ptr(), + value.raw_ptr(), + ); + value + }; + self.context.check_err()?; + Ok(v) + } + fn new_value_uninitialized(&self) -> Value { let value = unsafe { raw::alloc_value(self.context.ptr(), self.raw_ptr()) }; Value::new(value) @@ -490,4 +507,63 @@ mod tests { }) .unwrap(); } + + #[test] + fn eval_state_call() { + gc_registering_current_thread(|| { + let store = Store::open("auto").unwrap(); + let es = EvalState::new(store).unwrap(); + let f = es.eval_from_string("x: x + 1", "").unwrap(); + let a = es.eval_from_string("2", "").unwrap(); + let v = es.call(f, a).unwrap(); + es.force(&v).unwrap(); + let t = es.value_type(&v).unwrap(); + assert!(t == ValueType::Int); + let i = es.require_int(&v).unwrap(); + assert!(i == 3); + }) + .unwrap(); + } + + #[test] + fn eval_state_call_fail_body() { + gc_registering_current_thread(|| { + let store = Store::open("auto").unwrap(); + let es = EvalState::new(store).unwrap(); + let f = es.eval_from_string("x: x + 1", "").unwrap(); + let a = es.eval_from_string("true", "").unwrap(); + let r = es.call(f, a); + match r { + Ok(_) => panic!("expected an error"), + Err(e) => { + if !e.to_string().contains("cannot coerce") { + eprintln!("{}", e); + assert!(false); + } + } + } + }) + .unwrap(); + } + + #[test] + fn eval_state_call_fail_args() { + gc_registering_current_thread(|| { + let store = Store::open("auto").unwrap(); + let es = EvalState::new(store).unwrap(); + let f = es.eval_from_string("{x}: x + 1", "").unwrap(); + let a = es.eval_from_string("{}", "").unwrap(); + let r = es.call(f, a); + match r { + Ok(_) => panic!("expected an error"), + Err(e) => { + if !e.to_string().contains("called without required argument") { + eprintln!("{}", e); + assert!(false); + } + } + } + }) + .unwrap(); + } }