From ddadd45c8e14e8f134f968d8433fca3f2efc9677 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 27 Oct 2023 10:47:59 -0500 Subject: [PATCH] feat: Add Array::sort_by `Array::sort_by_key` can't really use a borrowed key because it will be shuffling things around. As an alternative, we can just provide the `cmp` to use. Fixes #639 --- crates/toml_edit/src/array.rs | 30 ++++++++++++++++++++++++ crates/toml_edit/tests/testsuite/edit.rs | 7 ++++++ 2 files changed, 37 insertions(+) diff --git a/crates/toml_edit/src/array.rs b/crates/toml_edit/src/array.rs index bd9ac514..97033de5 100644 --- a/crates/toml_edit/src/array.rs +++ b/crates/toml_edit/src/array.rs @@ -317,6 +317,36 @@ impl Array { .retain(|item| item.as_value().map(&mut keep).unwrap_or(false)); } + /// Sorts the slice with a comparator function. + /// + /// This sort is stable (i.e., does not reorder equal elements) and *O*(*n* \* log(*n*)) worst-case. + /// + /// The comparator function must define a total ordering for the elements in the slice. If + /// the ordering is not total, the order of the elements is unspecified. An order is a + /// total order if it is (for all `a`, `b` and `c`): + /// + /// * total and antisymmetric: exactly one of `a < b`, `a == b` or `a > b` is true, and + /// * transitive, `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`. + /// + /// For example, while [`f64`] doesn't implement [`Ord`] because `NaN != NaN`, we can use + /// `partial_cmp` as our sort function when we know the slice doesn't contain a `NaN`. + #[inline] + pub fn sort_by(&mut self, mut compare: F) + where + F: FnMut(&Value, &Value) -> std::cmp::Ordering, + { + self.values.sort_by(move |lhs, rhs| { + let lhs = lhs.as_value(); + let rhs = rhs.as_value(); + match (lhs, rhs) { + (None, None) => std::cmp::Ordering::Equal, + (Some(_), None) => std::cmp::Ordering::Greater, + (None, Some(_)) => std::cmp::Ordering::Less, + (Some(lhs), Some(rhs)) => compare(lhs, rhs), + } + }) + } + /// Sorts the array with a key extraction function. /// /// This sort is stable (i.e., does not reorder equal elements) and *O*(*m* \* *n* \* log(*n*)) diff --git a/crates/toml_edit/tests/testsuite/edit.rs b/crates/toml_edit/tests/testsuite/edit.rs index 28f73c1a..94c20d41 100644 --- a/crates/toml_edit/tests/testsuite/edit.rs +++ b/crates/toml_edit/tests/testsuite/edit.rs @@ -853,3 +853,10 @@ src.git = "https://github.com/nixos/nixpkgs" "#, ); } + +#[test] +fn sorting_with_references() { + let values = vec!["foo", "qux", "bar"]; + let mut array = toml_edit::Array::from_iter(values); + array.sort_by(|lhs, rhs| lhs.as_str().cmp(&rhs.as_str())); +}