diff --git a/Cargo.toml b/Cargo.toml index 82af904..f65a6c0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,9 +10,13 @@ readme = "README.md" keywords = ["serde"] license = "MIT" +[features] +preserve_order = ["indexmap"] + [dependencies] serde = "^1.0.0" ordered-float = "^1.0.1" +indexmap = { version = "1.0.2", optional = true, features = ["serde-1"] } [dev-dependencies] serde_derive = "^1.0.0" diff --git a/src/de.rs b/src/de.rs index bfd7bee..681b200 100644 --- a/src/de.rs +++ b/src/de.rs @@ -1,9 +1,8 @@ use serde::de; -use std::collections::BTreeMap; use std::error::Error; use std::fmt; -use Value; +use {Value, MapImpl}; #[derive(Debug)] pub enum Unexpected { @@ -274,7 +273,7 @@ impl<'de> de::Visitor<'de> for ValueVisitor { } fn visit_map>(self, mut visitor: V) -> Result { - let mut values = BTreeMap::new(); + let mut values = MapImpl::new(); while let Some((key, value)) = try!(visitor.next_entry()) { values.insert(key, value); } diff --git a/src/lib.rs b/src/lib.rs index 586c2ad..be0da01 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,12 +3,19 @@ #[macro_use] extern crate serde; extern crate ordered_float; +#[cfg(feature = "preserve_order")] +extern crate indexmap; #[cfg(test)] #[macro_use] extern crate serde_derive; -use std::collections::BTreeMap; +#[cfg(feature = "preserve_order")] +pub(crate) use indexmap::IndexMap as MapImpl; + +#[cfg(not(feature = "preserve_order"))] +pub(crate) use std::collections::BTreeMap as MapImpl; + use std::cmp::Ordering; use std::hash::{Hash, Hasher}; use serde::Deserialize; @@ -44,7 +51,7 @@ pub enum Value { Option(Option>), Newtype(Box), Seq(Vec), - Map(BTreeMap), + Map(MapImpl), Bytes(Vec), } @@ -72,7 +79,17 @@ impl Hash for Value { Value::Option(ref v) => v.hash(hasher), Value::Newtype(ref v) => v.hash(hasher), Value::Seq(ref v) => v.hash(hasher), - Value::Map(ref v) => v.hash(hasher), + Value::Map(ref v) => { + #[cfg(feature = "preserve_order")] { + for (key, value) in v.iter() { + key.hash(hasher); + value.hash(hasher); + } + } + #[cfg(not(feature = "preserve_order"))] { + v.hash(hasher) + } + } Value::Bytes(ref v) => v.hash(hasher), } } @@ -125,7 +142,14 @@ impl Ord for Value { (&Value::Option(ref v0), &Value::Option(ref v1)) => v0.cmp(v1), (&Value::Newtype(ref v0), &Value::Newtype(ref v1)) => v0.cmp(v1), (&Value::Seq(ref v0), &Value::Seq(ref v1)) => v0.cmp(v1), - (&Value::Map(ref v0), &Value::Map(ref v1)) => v0.cmp(v1), + (&Value::Map(ref v0), &Value::Map(ref v1)) => { + #[cfg(feature = "preserve_order")] { + v0.iter().cmp(v1.iter()) + } + #[cfg(not(feature = "preserve_order"))] { + v0.cmp(v1) + } + }, (&Value::Bytes(ref v0), &Value::Bytes(ref v1)) => v0.cmp(v1), (ref v0, ref v1) => v0.discriminant().cmp(&v1.discriminant()), } diff --git a/src/ser.rs b/src/ser.rs index bde1594..7b8e44a 100644 --- a/src/ser.rs +++ b/src/ser.rs @@ -1,9 +1,8 @@ use serde::ser; -use std::collections::BTreeMap; use std::error::Error; use std::fmt; -use Value; +use {Value, MapImpl}; #[derive(Debug)] pub enum SerializerError { @@ -224,7 +223,7 @@ impl ser::Serializer for Serializer { self, _len: Option ) -> Result { - Ok(SerializeMap { map: BTreeMap::new(), key: None }) + Ok(SerializeMap { map: MapImpl::new(), key: None }) } fn serialize_struct( @@ -232,7 +231,7 @@ impl ser::Serializer for Serializer { _name: &'static str, _len: usize ) -> Result { - Ok(SerializeStruct(BTreeMap::new())) + Ok(SerializeStruct(MapImpl::new())) } fn serialize_struct_variant( @@ -242,7 +241,7 @@ impl ser::Serializer for Serializer { _variant: &'static str, _len: usize ) -> Result { - Ok(SerializeStructVariant(BTreeMap::new())) + Ok(SerializeStructVariant(MapImpl::new())) } } @@ -339,7 +338,7 @@ impl ser::SerializeTupleVariant for SerializeTupleVariant { } struct SerializeMap { - map: BTreeMap, + map: MapImpl, key: Option, } @@ -373,7 +372,7 @@ impl ser::SerializeMap for SerializeMap { } } -struct SerializeStruct(BTreeMap); +struct SerializeStruct(MapImpl); impl ser::SerializeStruct for SerializeStruct { type Ok = Value; @@ -398,7 +397,7 @@ impl ser::SerializeStruct for SerializeStruct { } } -struct SerializeStructVariant(BTreeMap); +struct SerializeStructVariant(MapImpl); impl ser::SerializeStructVariant for SerializeStructVariant { type Ok = Value;