refactor(eval): add keys_sorted() to NixAttrs

builtins.toXML relies on attr keys being sorted, which is an
implementation detail.
Cppnix creates sorted xml, and tests expect it too, so changed that
iter call site.
builtins.attrNames and attrValues should also returns sorted lists, so
changed that too.

Change-Id: Ic706afc6855d5d28932ade7482449c965b0ae94f
Reviewed-on: https://cl.snix.dev/c/snix/+/30307
Reviewed-by: Florian Klink <flokli@flokli.de>
Tested-by: besadii
This commit is contained in:
Starnick4444 2025-04-11 11:22:08 +02:00 committed by Bence Nemes
parent ff72278529
commit 851cfc7278
3 changed files with 11 additions and 5 deletions

View file

@ -150,7 +150,7 @@ mod pure_builtins {
let xs = set.to_attrs()?; let xs = set.to_attrs()?;
let mut output = Vec::with_capacity(xs.len()); let mut output = Vec::with_capacity(xs.len());
for (key, _val) in xs.iter() { for (key, _val) in xs.iter_sorted() {
output.push(Value::from(key.clone())); output.push(Value::from(key.clone()));
} }
@ -162,7 +162,7 @@ mod pure_builtins {
let xs = set.to_attrs()?; let xs = set.to_attrs()?;
let mut output = Vec::with_capacity(xs.len()); let mut output = Vec::with_capacity(xs.len());
for (_key, val) in xs.iter() { for (_key, val) in xs.iter_sorted() {
output.push(val.clone()); output.push(val.clone());
} }
@ -789,13 +789,13 @@ mod pure_builtins {
if left_set.is_empty() { if left_set.is_empty() {
return Ok(Value::attrs(NixAttrs::empty())); return Ok(Value::attrs(NixAttrs::empty()));
} }
let mut left_keys = left_set.keys(); let mut left_keys = left_set.keys_sorted();
let right_set = y.to_attrs()?; let right_set = y.to_attrs()?;
if right_set.is_empty() { if right_set.is_empty() {
return Ok(Value::attrs(NixAttrs::empty())); return Ok(Value::attrs(NixAttrs::empty()));
} }
let mut right_keys = right_set.keys(); let mut right_keys = right_set.keys_sorted();
let mut out: BTreeMap<NixString, Value> = BTreeMap::new(); let mut out: BTreeMap<NixString, Value> = BTreeMap::new();

View file

@ -67,7 +67,7 @@ fn value_variant_to_xml<W: Write>(w: &mut XmlEmitter<W>, value: &Value) -> Resul
Value::Attrs(attrs) => { Value::Attrs(attrs) => {
w.write_open_tag("attrs", &[])?; w.write_open_tag("attrs", &[])?;
for elem in attrs.iter() { for elem in attrs.iter_sorted() {
w.write_open_tag("attr", &[("name", &elem.0.to_str_lossy())])?; w.write_open_tag("attr", &[("name", &elem.0.to_str_lossy())])?;
value_variant_to_xml(w, elem.1)?; value_variant_to_xml(w, elem.1)?;
w.write_closing_tag("attr")?; w.write_closing_tag("attr")?;

View file

@ -318,6 +318,12 @@ impl NixAttrs {
}) })
} }
/// Same as [Self::keys], but marks call sites which rely on the
/// iteration being lexicographic.
pub fn keys_sorted(&self) -> Keys {
self.keys()
}
/// Implement construction logic of an attribute set, to encapsulate /// Implement construction logic of an attribute set, to encapsulate
/// logic about attribute set optimisations inside of this module. /// logic about attribute set optimisations inside of this module.
pub fn construct( pub fn construct(