From c1a06c100e1e0a2a4587e629ca132782fca536dc Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 17 Oct 2024 19:13:23 +0200 Subject: [PATCH] Add methods on Map and Value to destroy preserved ordering --- src/map.rs | 22 ++++++++++++++++++++++ src/value/mod.rs | 26 ++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/src/map.rs b/src/map.rs index 90da86fed..7ff325b9d 100644 --- a/src/map.rs +++ b/src/map.rs @@ -348,6 +348,28 @@ impl Map { { self.map.retain(f); } + + /// Sorts this map's entries in-place using `str`'s usual ordering. + /// + /// If serde_json's "preserve_order" feature is not enabled, this method + /// does no work because all JSON maps are always kept in a sorted state. + /// + /// If serde_json's "preserve_order" feature is enabled, this method + /// destroys the original source order or insertion order of this map in + /// favor of an alphanumerical order that matches how a BTreeMap with the + /// same contents would be ordered. This takes **O(n log n + c)** time where + /// _n_ is the length of the map and _c_ is the capacity. + /// + /// Other maps nested within the values of this map are not sorted. If you + /// need the entire data structure to be sorted at all levels, you must also + /// call `map.`[`values_mut`]`().for_each(`[`Value::sort_all_objects`]`)`. + /// + /// [`values_mut`]: Map::values_mut + #[inline] + pub fn sort_keys(&mut self) { + #[cfg(feature = "preserve_order")] + self.map.sort_unstable_keys(); + } } #[allow(clippy::derivable_impls)] // clippy bug: https://github.com/rust-lang/rust-clippy/issues/7655 diff --git a/src/value/mod.rs b/src/value/mod.rs index 026f10dcb..6b40f9a52 100644 --- a/src/value/mod.rs +++ b/src/value/mod.rs @@ -861,6 +861,32 @@ impl Value { pub fn take(&mut self) -> Value { mem::replace(self, Value::Null) } + + /// Reorders the entries of all `Value::Object` nested within this JSON + /// value according to `str`'s usual ordering. + /// + /// If serde_json's "preserve_order" feature is not enabled, this method + /// does no work because all JSON maps are always kept in a sorted state. + /// + /// If serde_json's "preserve_order" feature is enabled, this method + /// destroys the original source order or insertion order of the JSON + /// objects in favor of an alphanumerical order that matches how a BTreeMap + /// with the same contents would be ordered. + pub fn sort_all_objects(&mut self) { + #[cfg(feature = "preserve_order")] + { + match self { + Value::Object(map) => { + map.sort_keys(); + map.values_mut().for_each(Value::sort_all_objects); + } + Value::Array(list) => { + list.iter_mut().for_each(Value::sort_all_objects); + } + _ => {} + } + } + } } /// The default value is `Value::Null`.