feat: Add EvalState::call_multi
(cherry picked from commit e1866f0c61011ffb57b607abe871340aca294f19)
This commit is contained in:
parent
8a437b71a0
commit
dc01d3731f
1 changed files with 82 additions and 0 deletions
|
|
@ -433,6 +433,24 @@ impl EvalState {
|
|||
Ok(value)
|
||||
}
|
||||
|
||||
/// Eagerly apply a function with multiple curried arguments.
|
||||
#[doc(alias = "nix_value_call_multi")]
|
||||
pub fn call_multi(&mut self, f: &Value, args: &[Value]) -> Result<Value> {
|
||||
let value = self.new_value_uninitialized()?;
|
||||
let mut args_ptrs = args.iter().map(|a| a.raw_ptr()).collect::<Vec<_>>();
|
||||
unsafe {
|
||||
check_call!(raw::value_call_multi(
|
||||
&mut self.context,
|
||||
self.eval_state.as_ptr(),
|
||||
f.raw_ptr(),
|
||||
args_ptrs.len(),
|
||||
args_ptrs.as_mut_ptr(),
|
||||
value.raw_ptr()
|
||||
))
|
||||
}?;
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
/// Apply a function to an argument, but don't evaluate the result just yet.
|
||||
///
|
||||
/// For an eager version, see [`call`][`EvalState::call`].
|
||||
|
|
@ -1166,6 +1184,24 @@ mod tests {
|
|||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn eval_state_call_multi() {
|
||||
gc_registering_current_thread(|| {
|
||||
let store = Store::open("auto", HashMap::new()).unwrap();
|
||||
let mut es = EvalState::new(store, []).unwrap();
|
||||
// This is a function that takes two arguments.
|
||||
let f = es.eval_from_string("x: y: x - y", "<test>").unwrap();
|
||||
let a = es.eval_from_string("2", "<test>").unwrap();
|
||||
let b = es.eval_from_string("3", "<test>").unwrap();
|
||||
let v = es.call_multi(&f, &[a, b]).unwrap();
|
||||
let t = es.value_type_unforced(&v);
|
||||
assert!(t == Some(ValueType::Int));
|
||||
let i = es.require_int(&v).unwrap();
|
||||
assert!(i == -1);
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn eval_state_apply() {
|
||||
gc_registering_current_thread(|| {
|
||||
|
|
@ -1206,6 +1242,29 @@ mod tests {
|
|||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn eval_state_call_multi_fail_body() {
|
||||
gc_registering_current_thread(|| {
|
||||
let store = Store::open("auto", HashMap::new()).unwrap();
|
||||
let mut es = EvalState::new(store, []).unwrap();
|
||||
// This is a function that takes two arguments.
|
||||
let f = es.eval_from_string("x: y: x - y", "<test>").unwrap();
|
||||
let a = es.eval_from_string("2", "<test>").unwrap();
|
||||
let b = es.eval_from_string("true", "<test>").unwrap();
|
||||
let r = es.call_multi(&f, &[a, b]);
|
||||
match r {
|
||||
Ok(_) => panic!("expected an error"),
|
||||
Err(e) => {
|
||||
if !e.to_string().contains("expected an integer but found") {
|
||||
eprintln!("{}", e);
|
||||
assert!(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn eval_state_apply_fail_body() {
|
||||
gc_registering_current_thread(|| {
|
||||
|
|
@ -1252,6 +1311,29 @@ mod tests {
|
|||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn eval_state_call_multi_fail_args() {
|
||||
gc_registering_current_thread(|| {
|
||||
let store = Store::open("auto", HashMap::new()).unwrap();
|
||||
let mut es = EvalState::new(store, []).unwrap();
|
||||
// This is a function that takes two arguments.
|
||||
let f = es.eval_from_string("{x}: {y}: x - y", "<test>").unwrap();
|
||||
let a = es.eval_from_string("{x = 2;}", "<test>").unwrap();
|
||||
let b = es.eval_from_string("{}", "<test>").unwrap();
|
||||
let r = es.call_multi(&f, &[a, b]);
|
||||
match r {
|
||||
Ok(_) => panic!("expected an error"),
|
||||
Err(e) => {
|
||||
if !e.to_string().contains("called without required argument") {
|
||||
eprintln!("{}", e);
|
||||
assert!(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
/// This tests the behavior of `new_value_apply`, which is lazy, unlike `call`.
|
||||
#[test]
|
||||
fn eval_state_apply_fail_args_lazy() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue