Skip to content

Commit bcbc2c8

Browse files
committed
feat(preserve_order): integrate IndexMap support across Value types and deserializers
1 parent 901692f commit bcbc2c8

File tree

8 files changed

+118
-20
lines changed

8 files changed

+118
-20
lines changed

src/serde/value/borrowed/de.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,17 +176,32 @@ impl<'de> SeqAccess<'de> for ArrayRef<'de> {
176176
}
177177
}
178178

179+
#[cfg(not(feature = "preserve_order"))]
179180
struct ObjectAccess<'de, const N: usize = 32> {
180181
i: halfbrown::IntoIter<Cow<'de, str>, Value<'de>, N>,
181182
v: Option<Value<'de>>,
182183
}
183184

185+
#[cfg(feature = "preserve_order")]
186+
struct ObjectAccess<'de> {
187+
i: indexmap::map::IntoIter<Cow<'de, str>, Value<'de>>,
188+
v: Option<Value<'de>>,
189+
}
190+
191+
#[cfg(not(feature = "preserve_order"))]
184192
impl<'de, const N: usize> ObjectAccess<'de, N> {
185193
fn new(i: halfbrown::IntoIter<Cow<'de, str>, Value<'de>, N>) -> Self {
186194
Self { i, v: None }
187195
}
188196
}
189197

198+
#[cfg(feature = "preserve_order")]
199+
impl<'de> ObjectAccess<'de> {
200+
fn new(i: indexmap::map::IntoIter<Cow<'de, str>, Value<'de>>) -> Self {
201+
Self { i, v: None }
202+
}
203+
}
204+
190205
// `MapAccess` is provided to the `Visitor` to give it the ability to iterate
191206
// through entries of the map.
192207
impl<'de> MapAccess<'de> for ObjectAccess<'de> {
@@ -216,16 +231,32 @@ impl<'de> MapAccess<'de> for ObjectAccess<'de> {
216231
}
217232
}
218233

234+
#[cfg(not(feature = "preserve_order"))]
219235
struct ObjectRefAccess<'de> {
220236
i: halfbrown::Iter<'de, Cow<'de, str>, Value<'de>>,
221237
v: Option<&'de Value<'de>>,
222238
}
239+
240+
#[cfg(feature = "preserve_order")]
241+
struct ObjectRefAccess<'de> {
242+
i: indexmap::map::Iter<'de, Cow<'de, str>, Value<'de>>,
243+
v: Option<&'de Value<'de>>,
244+
}
245+
246+
#[cfg(not(feature = "preserve_order"))]
223247
impl<'de> ObjectRefAccess<'de> {
224248
fn new(i: halfbrown::Iter<'de, Cow<'de, str>, Value<'de>>) -> Self {
225249
Self { i, v: None }
226250
}
227251
}
228252

253+
#[cfg(feature = "preserve_order")]
254+
impl<'de> ObjectRefAccess<'de> {
255+
fn new(i: indexmap::map::Iter<'de, Cow<'de, str>, Value<'de>>) -> Self {
256+
Self { i, v: None }
257+
}
258+
}
259+
229260
// `MapAccess` is provided to the `Visitor` to give it the ability to iterate
230261
// through entries of the map.
231262
impl<'de> MapAccess<'de> for ObjectRefAccess<'de> {

src/serde/value/owned/de.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,16 +164,32 @@ impl<'de> SeqAccess<'de> for ArrayRef<'de> {
164164
}
165165
}
166166

167+
#[cfg(not(feature = "preserve_order"))]
167168
struct ObjectAccess<const N: usize = 32> {
168169
i: halfbrown::IntoIter<String, Value, N>,
169170
v: Option<Value>,
170171
}
171172

173+
#[cfg(feature = "preserve_order")]
174+
struct ObjectAccess {
175+
i: indexmap::map::IntoIter<String, Value>,
176+
v: Option<Value>,
177+
}
178+
179+
#[cfg(not(feature = "preserve_order"))]
172180
impl<const N: usize> ObjectAccess<N> {
173181
fn new(i: halfbrown::IntoIter<String, Value, N>) -> Self {
174182
Self { i, v: None }
175183
}
176184
}
185+
186+
#[cfg(feature = "preserve_order")]
187+
impl ObjectAccess {
188+
fn new(i: indexmap::map::IntoIter<String, Value>) -> Self {
189+
Self { i, v: None }
190+
}
191+
}
192+
177193
// `MapAccess` is provided to the `Visitor` to give it the ability to iterate
178194
// through entries of the map.
179195
impl<'de> MapAccess<'de> for ObjectAccess {
@@ -203,17 +219,32 @@ impl<'de> MapAccess<'de> for ObjectAccess {
203219
}
204220
}
205221

222+
#[cfg(not(feature = "preserve_order"))]
206223
struct ObjectRefAccess<'de> {
207224
i: halfbrown::Iter<'de, String, Value>,
208225
v: Option<&'de Value>,
209226
}
210227

228+
#[cfg(feature = "preserve_order")]
229+
struct ObjectRefAccess<'de> {
230+
i: indexmap::map::Iter<'de, String, Value>,
231+
v: Option<&'de Value>,
232+
}
233+
234+
#[cfg(not(feature = "preserve_order"))]
211235
impl<'de> ObjectRefAccess<'de> {
212236
fn new(i: halfbrown::Iter<'de, String, Value>) -> Self {
213237
Self { i, v: None }
214238
}
215239
}
216240

241+
#[cfg(feature = "preserve_order")]
242+
impl<'de> ObjectRefAccess<'de> {
243+
fn new(i: indexmap::map::Iter<'de, String, Value>) -> Self {
244+
Self { i, v: None }
245+
}
246+
}
247+
217248
// `MapAccess` is provided to the `Visitor` to give it the ability to iterate
218249
// through entries of the map.
219250
impl<'de> MapAccess<'de> for ObjectRefAccess<'de> {

src/value.rs

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,10 @@ pub use self::owned::{
6868
to_value_with_buffers as to_owned_value_with_buffers,
6969
};
7070
use crate::{Buffers, Deserializer, Result};
71+
#[cfg(not(feature = "preserve_order"))]
7172
use halfbrown::HashMap;
73+
#[cfg(feature = "preserve_order")]
74+
use indexmap::IndexMap;
7275
use std::hash::Hash;
7376
use std::marker::PhantomData;
7477
use tape::Node;
@@ -78,8 +81,18 @@ pub use value_trait::*;
7881
#[cfg(feature = "known-key")]
7982
pub type ObjectHasher = crate::known_key::NotSoRandomState;
8083
/// Hasher used for objects
81-
#[cfg(not(feature = "known-key"))]
84+
#[cfg(all(not(feature = "known-key"), not(feature = "preserve_order")))]
8285
pub type ObjectHasher = halfbrown::DefaultHashBuilder;
86+
/// Hasher used for objects
87+
#[cfg(all(not(feature = "known-key"), feature = "preserve_order"))]
88+
pub type ObjectHasher = std::hash::RandomState;
89+
90+
/// Hashmap used for objects
91+
#[cfg(not(feature = "preserve_order"))]
92+
type ObjectMap<K, V> = HashMap<K, V, ObjectHasher>;
93+
/// Hashmap used for objects
94+
#[cfg(feature = "preserve_order")]
95+
type ObjectMap<K, V> = IndexMap<K, V, ObjectHasher>;
8396

8497
/// Parses a slice of bytes into a Value dom.
8598
///
@@ -92,7 +105,7 @@ pub type ObjectHasher = halfbrown::DefaultHashBuilder;
92105
/// Will return `Err` if `s` is invalid JSON.
93106
pub fn deserialize<'de, Value, Key>(s: &'de mut [u8]) -> Result<Value>
94107
where
95-
Value: ValueBuilder<'de> + From<Vec<Value>> + From<HashMap<Key, Value, ObjectHasher>> + 'de,
108+
Value: ValueBuilder<'de> + From<Vec<Value>> + From<ObjectMap<Key, Value>> + 'de,
96109
Key: Hash + Eq + From<&'de str>,
97110
{
98111
match Deserializer::from_slice(s) {
@@ -117,7 +130,7 @@ pub fn deserialize_with_buffers<'de, Value, Key>(
117130
buffers: &mut Buffers,
118131
) -> Result<Value>
119132
where
120-
Value: ValueBuilder<'de> + From<Vec<Value>> + From<HashMap<Key, Value, ObjectHasher>> + 'de,
133+
Value: ValueBuilder<'de> + From<Vec<Value>> + From<ObjectMap<Key, Value>> + 'de,
121134
Key: Hash + Eq + From<&'de str>,
122135
{
123136
match Deserializer::from_slice_with_buffers(s, buffers) {
@@ -128,7 +141,7 @@ where
128141

129142
struct ValueDeserializer<'de, Value, Key>
130143
where
131-
Value: ValueBuilder<'de> + From<Vec<Value>> + From<HashMap<Key, Value, ObjectHasher>> + 'de,
144+
Value: ValueBuilder<'de> + From<Vec<Value>> + From<ObjectMap<Key, Value>> + 'de,
132145
Key: Hash + Eq + From<&'de str>,
133146
{
134147
de: Deserializer<'de>,
@@ -140,7 +153,7 @@ where
140153
Value: ValueBuilder<'de>
141154
+ From<&'de str>
142155
+ From<Vec<Value>>
143-
+ From<HashMap<Key, Value, ObjectHasher>>
156+
+ From<ObjectMap<Key, Value>>
144157
+ 'de,
145158
Key: Hash + Eq + From<&'de str>,
146159
{
@@ -179,8 +192,8 @@ where
179192

180193
#[cfg_attr(not(feature = "no-inline"), inline)]
181194
fn parse_map(&mut self, len: usize) -> Value {
182-
let mut res: HashMap<Key, Value, ObjectHasher> =
183-
HashMap::with_capacity_and_hasher(len, ObjectHasher::default());
195+
let mut res: ObjectMap<Key, Value> =
196+
ObjectMap::with_capacity_and_hasher(len, ObjectHasher::default());
184197

185198
// Since we checked if it's empty we know that we at least have one
186199
// element so we eat this

src/value/borrowed.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ use std::ops::{Index, IndexMut};
3838
/// Representation of a JSON object
3939
#[cfg(not(feature = "preserve_order"))]
4040
pub type Object<'value> = HashMap<Cow<'value, str>, Value<'value>, ObjectHasher>;
41+
/// Representation of a JSON object
4142
#[cfg(feature = "preserve_order")]
4243
pub type Object<'value> = IndexMap<Cow<'value, str>, Value<'value>, ObjectHasher>;
4344

src/value/borrowed/from.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use super::{Object, Value};
2-
use crate::OwnedValue;
3-
use crate::StaticNode;
2+
use crate::{ObjectHasher, OwnedValue, StaticNode};
43
use crate::cow::Cow;
54

65
impl From<OwnedValue> for Value<'_> {
@@ -202,11 +201,13 @@ impl<'value, K: Into<Cow<'value, str>>, V: Into<Value<'value>>> FromIterator<(K,
202201
{
203202
#[cfg_attr(not(feature = "no-inline"), inline)]
204203
fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
205-
Value::Object(Box::new(
206-
iter.into_iter()
207-
.map(|(k, v)| (Into::into(k), Into::into(v)))
208-
.collect(),
209-
))
204+
let iter = iter.into_iter();
205+
let (lower, _) = iter.size_hint();
206+
let mut map = Object::with_capacity_and_hasher(lower, ObjectHasher::default());
207+
for (k, v) in iter {
208+
map.insert(k.into(), v.into());
209+
}
210+
Value::Object(Box::new(map))
210211
}
211212
}
212213

src/value/lazy/object.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,22 +18,34 @@ pub enum Iter<'borrow, 'tape, 'input> {
1818
/// Tape variant
1919
Tape(tape::object::Iter<'tape, 'input>),
2020
/// Value variant
21+
#[cfg(not(feature = "preserve_order"))]
2122
Value(halfbrown::Iter<'borrow, crate::cow::Cow<'input, str>, borrowed::Value<'input>>),
23+
/// Value variant
24+
#[cfg(feature = "preserve_order")]
25+
Value(indexmap::map::Iter<'borrow, crate::cow::Cow<'input, str>, borrowed::Value<'input>>),
2226
}
2327

2428
/// Iterator over the keys of an object
2529
pub enum Keys<'borrow, 'tape, 'input> {
2630
/// Tape variant
2731
Tape(tape::object::Keys<'tape, 'input>),
2832
/// Value variant
33+
#[cfg(not(feature = "preserve_order"))]
2934
Value(halfbrown::Keys<'borrow, crate::cow::Cow<'input, str>, borrowed::Value<'input>>),
35+
/// Value variant
36+
#[cfg(feature = "preserve_order")]
37+
Value(indexmap::map::Keys<'borrow, crate::cow::Cow<'input, str>, borrowed::Value<'input>>),
3038
}
3139
/// Iterator over the values of an object
3240
pub enum Values<'borrow, 'tape, 'input> {
3341
/// Tape variant
3442
Tape(tape::object::Values<'tape, 'input>),
3543
/// Value variant
44+
#[cfg(not(feature = "preserve_order"))]
3645
Value(halfbrown::Values<'borrow, crate::cow::Cow<'input, str>, borrowed::Value<'input>>),
46+
/// Value variant
47+
#[cfg(feature = "preserve_order")]
48+
Value(indexmap::map::Values<'borrow, crate::cow::Cow<'input, str>, borrowed::Value<'input>>),
3749
}
3850

3951
//value_trait::Object for

src/value/owned.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,19 @@ mod serialize;
2626
use super::ObjectHasher;
2727
use crate::{Buffers, prelude::*};
2828
use crate::{Deserializer, Node, Result};
29+
#[cfg(not(feature = "preserve_order"))]
2930
use halfbrown::HashMap;
31+
#[cfg(feature = "preserve_order")]
32+
use indexmap::IndexMap;
3033
use std::fmt;
3134
use std::ops::{Index, IndexMut};
3235

3336
/// Representation of a JSON object
37+
#[cfg(not(feature = "preserve_order"))]
3438
pub type Object = HashMap<String, Value, ObjectHasher>;
39+
/// Representation of a JSON object
40+
#[cfg(feature = "preserve_order")]
41+
pub type Object = IndexMap<String, Value, ObjectHasher>;
3542

3643
/// Parses a slice of bytes into a Value dom.
3744
///

src/value/owned/from.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use super::{Object, Value};
2-
use crate::{BorrowedValue, StaticNode};
2+
use crate::{BorrowedValue, ObjectHasher, StaticNode};
33

44
impl From<crate::BorrowedValue<'_>> for Value {
55
#[cfg_attr(not(feature = "no-inline"), inline)]
@@ -199,11 +199,13 @@ impl<V: Into<Value>> FromIterator<V> for Value {
199199
impl<K: ToString, V: Into<Value>> FromIterator<(K, V)> for Value {
200200
#[cfg_attr(not(feature = "no-inline"), inline)]
201201
fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
202-
Self::Object(Box::new(
203-
iter.into_iter()
204-
.map(|(k, v)| (k.to_string(), Into::into(v)))
205-
.collect(),
206-
))
202+
let iter = iter.into_iter();
203+
let (lower, _) = iter.size_hint();
204+
let mut map = Object::with_capacity_and_hasher(lower, ObjectHasher::default());
205+
for (k, v) in iter {
206+
map.insert(k.to_string(), v.into());
207+
}
208+
Self::Object(Box::new(map))
207209
}
208210
}
209211

0 commit comments

Comments
 (0)