Skip to content

Commit 1a4174e

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

6 files changed

Lines changed: 522 additions & 76 deletions

File tree

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: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,17 @@ pub(crate) struct DeserializeCfg {
33
pub use_rawnumber: bool,
44
pub utf8_lossy: bool,
55
}
6+
7+
#[derive(Debug, Clone, Copy)]
8+
pub(crate) struct SerializeCfg {
9+
pub sort_map_keys: bool,
10+
}
11+
12+
impl Default for SerializeCfg {
13+
#[inline]
14+
fn default() -> Self {
15+
Self {
16+
sort_map_keys: cfg!(feature = "sort_keys"),
17+
}
18+
}
19+
}

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: 92 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,10 @@ 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::*;
36-
use crate::{Result, Value};
36+
use crate::{config::SerializeCfg, Result, Value};
3737

3838
macro_rules! hashmap {
3939
() => {
@@ -50,6 +50,96 @@ 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_serialize_cfg_default_matches_feature() {
72+
assert_eq!(
73+
SerializeCfg::default().sort_map_keys,
74+
cfg!(feature = "sort_keys")
75+
);
76+
}
77+
78+
#[test]
79+
fn test_serializer_sort_map_keys_toggle() {
80+
let entries = [("b", 1u8), ("a", 2u8), ("c", 3u8)];
81+
let unordered = UnorderedMap { entries: &entries };
82+
83+
let mut ser = Serializer::new(Vec::new());
84+
unordered.serialize(&mut ser).unwrap();
85+
let output = String::from_utf8(ser.into_inner()).unwrap();
86+
let expected_default = if cfg!(feature = "sort_keys") {
87+
r#"{"a":2,"b":1,"c":3}"#
88+
} else {
89+
r#"{"b":1,"a":2,"c":3}"#
90+
};
91+
assert_eq!(output, expected_default);
92+
93+
let mut ser = Serializer::new(Vec::new()).sort_map_keys();
94+
unordered.serialize(&mut ser).unwrap();
95+
let output = String::from_utf8(ser.into_inner()).unwrap();
96+
assert_eq!(output, r#"{"a":2,"b":1,"c":3}"#);
97+
}
98+
99+
#[test]
100+
fn test_value_to_string_sort_behavior() {
101+
let value: Value = crate::json!({"b": 1, "a": 2, "c": 3});
102+
103+
let json = to_string(&value).unwrap();
104+
let expected_sorted = r#"{"a":2,"b":1,"c":3}"#;
105+
106+
if cfg!(feature = "sort_keys") {
107+
assert_eq!(json, expected_sorted);
108+
} else {
109+
let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
110+
assert_eq!(parsed, serde_json::json!({"b": 1, "a": 2, "c": 3}));
111+
}
112+
113+
let mut ser = Serializer::new(Vec::new()).sort_map_keys();
114+
value.serialize(&mut ser).unwrap();
115+
let sorted_json = String::from_utf8(ser.into_inner()).unwrap();
116+
assert_eq!(sorted_json, expected_sorted);
117+
}
118+
119+
#[test]
120+
fn test_value_serializer_sort_map_keys() {
121+
let value: Value = crate::json!({"delta": 4, "beta": 2, "alpha": 1});
122+
123+
let mut ser = Serializer::new(Vec::new());
124+
value.serialize(&mut ser).unwrap();
125+
let default_json = String::from_utf8(ser.into_inner()).unwrap();
126+
127+
if cfg!(feature = "sort_keys") {
128+
assert_eq!(default_json, r#"{"alpha":1,"beta":2,"delta":4}"#);
129+
} else {
130+
let parsed: serde_json::Value = serde_json::from_str(&default_json).unwrap();
131+
assert_eq!(
132+
parsed,
133+
serde_json::json!({"delta": 4, "beta": 2, "alpha": 1})
134+
);
135+
}
136+
137+
let mut ser = Serializer::new(Vec::new()).sort_map_keys();
138+
value.serialize(&mut ser).unwrap();
139+
let sorted = String::from_utf8(ser.into_inner()).unwrap();
140+
assert_eq!(sorted, r#"{"alpha":1,"beta":2,"delta":4}"#);
141+
}
142+
53143
#[derive(Debug, Deserialize, Serialize, PartialEq)]
54144
struct Foo {
55145
name: FastStr,

0 commit comments

Comments
 (0)