feat(nix/eval): Implement builtins.groupBy
Change-Id: I3e0aa017a7100cbeb86d2e5747471b36affcc102 Reviewed-on: https://cl.tvl.fyi/c/depot/+/7038 Autosubmit: grfn <grfn@gws.fyi> Reviewed-by: tazjin <tazjin@tvl.su> Tested-by: BuildkiteCI
This commit is contained in:
parent
dfa4c4847c
commit
e2f0967d3f
3 changed files with 34 additions and 0 deletions
|
@ -323,6 +323,17 @@ fn pure_builtins() -> Vec<Builtin> {
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
Builtin::new("groupBy", &[true, true], |args: Vec<Value>, vm: &mut VM| {
|
||||||
|
let mut res: BTreeMap<NixString, Value> = BTreeMap::new();
|
||||||
|
for val in args[1].to_list()? {
|
||||||
|
let key = vm.call_with(&args[0], [val.clone()])?.force(vm)?.to_str()?;
|
||||||
|
res.entry(key)
|
||||||
|
.or_insert_with(|| Value::List(NixList::new()))
|
||||||
|
.as_list_mut()?
|
||||||
|
.push(val);
|
||||||
|
}
|
||||||
|
Ok(Value::attrs(NixAttrs::from_map(res)))
|
||||||
|
}),
|
||||||
Builtin::new("hasAttr", &[true, true], |args: Vec<Value>, _: &mut VM| {
|
Builtin::new("hasAttr", &[true, true], |args: Vec<Value>, _: &mut VM| {
|
||||||
let k = args[0].to_str()?;
|
let k = args[0].to_str()?;
|
||||||
let xs = args[1].to_attrs()?;
|
let xs = args[1].to_attrs()?;
|
||||||
|
|
|
@ -49,6 +49,14 @@ mod arbitrary {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NixList {
|
impl NixList {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self(vec![])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push(&mut self, val: Value) {
|
||||||
|
self.0.push(val)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn concat(&self, other: &Self) -> Self {
|
pub fn concat(&self, other: &Self) -> Self {
|
||||||
let mut ret = self.clone();
|
let mut ret = self.clone();
|
||||||
ret.0.extend_from_slice(&other.0);
|
ret.0.extend_from_slice(&other.0);
|
||||||
|
|
|
@ -79,6 +79,19 @@ macro_rules! gen_cast {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generate an `as_*_mut/to_*_mut` accessor method that returns either the
|
||||||
|
/// expected type, or a type error.
|
||||||
|
macro_rules! gen_cast_mut {
|
||||||
|
( $name:ident, $type:ty, $expected:expr, $variant:ident) => {
|
||||||
|
pub fn $name(&mut self) -> Result<&mut $type, ErrorKind> {
|
||||||
|
match self {
|
||||||
|
Value::$variant(x) => Ok(x),
|
||||||
|
other => Err(type_error($expected, &other)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/// Generate an `is_*` type-checking method.
|
/// Generate an `is_*` type-checking method.
|
||||||
macro_rules! gen_is {
|
macro_rules! gen_is {
|
||||||
( $name:ident, $variant:pat ) => {
|
( $name:ident, $variant:pat ) => {
|
||||||
|
@ -284,6 +297,8 @@ impl Value {
|
||||||
gen_cast!(to_list, NixList, "list", Value::List(l), l.clone());
|
gen_cast!(to_list, NixList, "list", Value::List(l), l.clone());
|
||||||
gen_cast!(to_closure, Closure, "lambda", Value::Closure(c), c.clone());
|
gen_cast!(to_closure, Closure, "lambda", Value::Closure(c), c.clone());
|
||||||
|
|
||||||
|
gen_cast_mut!(as_list_mut, NixList, "list", List);
|
||||||
|
|
||||||
gen_is!(is_path, Value::Path(_));
|
gen_is!(is_path, Value::Path(_));
|
||||||
gen_is!(is_number, Value::Integer(_) | Value::Float(_));
|
gen_is!(is_number, Value::Integer(_) | Value::Float(_));
|
||||||
gen_is!(is_bool, Value::Bool(_));
|
gen_is!(is_bool, Value::Bool(_));
|
||||||
|
|
Loading…
Reference in a new issue