feat(tvix/eval): implement 'builtins.filter'

This is a little ugly because the plain Iterator::filter method can
not be used (it does not support fallible primitives), so we need to
resort to an `Iterator::filter_map` and deal with the wrapping in
Options everywhere.

This prevents use of `?` which introduces the need for some matching,
but it's not *too* bad.

Change-Id: Ie2c3c0c9756c4c627176f64fb4e0054e717c26d1
Reviewed-on: https://cl.tvl.fyi/c/depot/+/6765
Tested-by: BuildkiteCI
Reviewed-by: sterni <sternenseemann@systemli.org>
This commit is contained in:
Vincent Ambo 2022-09-23 03:14:34 +03:00 committed by tazjin
parent 1015f2f8e7
commit f816813d41
4 changed files with 44 additions and 1 deletions

View file

@ -132,6 +132,35 @@ fn pure_builtins() -> Vec<Builtin> {
}
}
}),
Builtin::new("filter", &[true, true], |args, vm| {
let list: NixList = args[1].to_list()?;
list.into_iter()
.filter_map(|elem| {
vm.push(elem.clone());
let result = match vm.call_value(&args[0]) {
Err(err) => return Some(Err(err)),
Ok(result) => result,
};
// Must be assigned to a local to avoid a borrowcheck
// failure related to the ForceResult destructor.
let result = match result.force(vm) {
Err(err) => Some(Err(vm.error(err))),
Ok(value) => match value.as_bool() {
Ok(true) => Some(Ok(elem)),
Ok(false) => None,
Err(err) => Some(Err(vm.error(err))),
},
};
result
})
.collect::<Result<Vec<Value>, _>>()
.map(|list| Value::List(NixList::from(list)))
.map_err(Into::into)
}),
Builtin::new("getAttr", &[true, true], |args, _| {
let k = args[0].to_str()?;
let xs = args[1].to_attrs()?;