Skip to content

Commit d43cacf

Browse files
committed
feat: add serialization configuration for sorting map keys
1 parent 3de10b9 commit d43cacf

File tree

6 files changed

+499
-75
lines changed

6 files changed

+499
-75
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ license = "Apache-2.0"
1010
name = "sonic-rs"
1111
readme = "README.md"
1212
repository = "https://github.com/cloudwego/sonic-rs"
13-
version = "0.5.5"
13+
version = "0.5.6"
1414

1515
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
1616

src/config.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,8 @@ pub(crate) struct DeserializeCfg {
33
pub use_rawnumber: bool,
44
pub utf8_lossy: bool,
55
}
6+
7+
#[derive(Debug, Clone, Copy, Default)]
8+
pub(crate) struct SerializeCfg {
9+
pub sort_map_keys: bool,
10+
}

src/format.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use crate::{serde::tri, util::string::format_string, writer::WriteExt};
88

99
/// This trait abstracts away serializing the JSON control characters, which allows the user to
1010
/// optionally pretty print the JSON output.
11-
pub trait Formatter {
11+
pub trait Formatter: Clone {
1212
/// Writes a `null` value to the specified writer.
1313
#[inline]
1414
fn write_null<W>(&mut self, writer: &mut W) -> io::Result<()>

src/serde/mod.rs

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ mod test {
3030

3131
use bytes::Bytes;
3232
use faststr::FastStr;
33-
use serde::{de::IgnoredAny, Deserialize, Serialize};
33+
use serde::{de::IgnoredAny, ser::SerializeMap, Deserialize, Serialize};
3434

3535
use super::*;
3636
use crate::{Result, Value};
@@ -50,6 +50,84 @@ mod test {
5050
};
5151
}
5252

53+
struct UnorderedMap<'a> {
54+
entries: &'a [(&'a str, u8)],
55+
}
56+
57+
impl Serialize for UnorderedMap<'_> {
58+
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
59+
where
60+
S: serde::Serializer,
61+
{
62+
let mut map = serializer.serialize_map(Some(self.entries.len()))?;
63+
for (key, value) in self.entries {
64+
map.serialize_entry(key, value)?;
65+
}
66+
map.end()
67+
}
68+
}
69+
70+
#[test]
71+
fn test_serializer_sort_map_keys_toggle() {
72+
let entries = [("b", 1u8), ("a", 2u8), ("c", 3u8)];
73+
let unordered = UnorderedMap { entries: &entries };
74+
75+
let mut ser = Serializer::new(Vec::new());
76+
unordered.serialize(&mut ser).unwrap();
77+
let output = String::from_utf8(ser.into_inner()).unwrap();
78+
let expected_default = r#"{"b":1,"a":2,"c":3}"#;
79+
assert_eq!(output, expected_default);
80+
81+
let mut ser = Serializer::new(Vec::new()).sort_map_keys();
82+
unordered.serialize(&mut ser).unwrap();
83+
let output = String::from_utf8(ser.into_inner()).unwrap();
84+
assert_eq!(output, r#"{"a":2,"b":1,"c":3}"#);
85+
}
86+
87+
#[test]
88+
fn test_value_to_string_sort_behavior() {
89+
let value: Value = crate::json!({"b": 1, "a": 2, "c": 3});
90+
91+
let json = to_string(&value).unwrap();
92+
let expected_sorted = r#"{"a":2,"b":1,"c":3}"#;
93+
94+
if cfg!(feature = "sort_keys") {
95+
assert_eq!(json, expected_sorted);
96+
} else {
97+
let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
98+
assert_eq!(parsed, serde_json::json!({"b": 1, "a": 2, "c": 3}));
99+
}
100+
101+
let mut ser = Serializer::new(Vec::new()).sort_map_keys();
102+
value.serialize(&mut ser).unwrap();
103+
let sorted_json = String::from_utf8(ser.into_inner()).unwrap();
104+
assert_eq!(sorted_json, expected_sorted);
105+
}
106+
107+
#[test]
108+
fn test_value_serializer_sort_map_keys() {
109+
let value: Value = crate::json!({"delta": 4, "beta": 2, "alpha": 1});
110+
111+
let mut ser = Serializer::new(Vec::new());
112+
value.serialize(&mut ser).unwrap();
113+
let default_json = String::from_utf8(ser.into_inner()).unwrap();
114+
115+
if cfg!(feature = "sort_keys") {
116+
assert_eq!(default_json, r#"{"alpha":1,"beta":2,"delta":4}"#);
117+
} else {
118+
let parsed: serde_json::Value = serde_json::from_str(&default_json).unwrap();
119+
assert_eq!(
120+
parsed,
121+
serde_json::json!({"delta": 4, "beta": 2, "alpha": 1})
122+
);
123+
}
124+
125+
let mut ser = Serializer::new(Vec::new()).sort_map_keys();
126+
value.serialize(&mut ser).unwrap();
127+
let sorted = String::from_utf8(ser.into_inner()).unwrap();
128+
assert_eq!(sorted, r#"{"alpha":1,"beta":2,"delta":4}"#);
129+
}
130+
53131
#[derive(Debug, Deserialize, Serialize, PartialEq)]
54132
struct Foo {
55133
name: FastStr,

0 commit comments

Comments
 (0)