Skip to content

Commit baf94de

Browse files
committed
Merge pull request #48 from dtolnay/serde
Serde support
2 parents 53bf10a + 1e00af9 commit baf94de

File tree

5 files changed

+144
-4
lines changed

5 files changed

+144
-4
lines changed

.travis.yml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@ sudo: false
33
matrix:
44
include:
55
- rust: beta
6+
env: FEATURES="serde_impl"
67
- rust: nightly
7-
env: FEATURES="--features nightly"
8+
env: FEATURES="serde_impl nightly"
89
script:
9-
- cargo build $FEATURES
10-
- cargo test $FEATURES
11-
- cargo doc --no-deps $FEATURES
10+
- cargo build --features "$FEATURES"
11+
- cargo test --features "$FEATURES"
12+
- cargo doc --no-deps --features "$FEATURES"
1213
after_success: |
1314
[ $TRAVIS_RUST_VERSION = nightly ] &&
1415
[ $TRAVIS_BRANCH = master ] &&

Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,8 @@ readme = "README.md"
1717

1818
[features]
1919
nightly = []
20+
serde_impl = ["serde", "serde_json"]
21+
22+
[dependencies]
23+
serde = { version = "^0.7", optional = true }
24+
serde_json = { version = "^0.7", optional = true }

src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@
3131
#![cfg_attr(feature = "nightly", feature(hashmap_public_hasher))]
3232
#![cfg_attr(all(feature = "nightly", test), feature(test))]
3333

34+
// Optional Serde support
35+
#[cfg(feature = "serde_impl")]
36+
mod serde;
37+
3438
use std::borrow::Borrow;
3539
use std::cmp::Ordering;
3640
use std::collections::hash_map::{self, HashMap};

src/serde.rs

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
//! An optional implementation of serialization/deserialization. Reference
2+
//! implementations used:
3+
//!
4+
//! - [Serialize][1].
5+
//! - [Deserialize][2].
6+
//!
7+
//! [1]: https://github.com/serde-rs/serde/blob/97856462467db2e90cf368e407c7ebcc726a01a9/serde/src/ser/impls.rs#L601-L611
8+
//! [2]: https://github.com/serde-rs/serde/blob/97856462467db2e90cf368e407c7ebcc726a01a9/serde/src/de/impls.rs#L694-L746
9+
10+
extern crate serde;
11+
12+
use std::marker::PhantomData;
13+
use std::hash::{BuildHasher, Hash};
14+
15+
use super::LinkedHashMap;
16+
17+
use self::serde::{Serialize, Serializer, Deserialize, Deserializer};
18+
use self::serde::ser::impls::MapIteratorVisitor;
19+
use self::serde::de::{Visitor, MapVisitor, Error};
20+
21+
impl<K, V, S> Serialize for LinkedHashMap<K, V, S>
22+
where K: Serialize + Eq + Hash,
23+
V: Serialize,
24+
S: BuildHasher
25+
{
26+
#[inline]
27+
fn serialize<T>(&self, serializer: &mut T) -> Result<(), T::Error>
28+
where T: Serializer,
29+
{
30+
serializer.serialize_map(MapIteratorVisitor::new(self.iter(), Some(self.len())))
31+
}
32+
}
33+
34+
/// `serde::de::Visitor` for a linked hash map.
35+
pub struct LinkedHashMapVisitor<K, V> {
36+
marker: PhantomData<LinkedHashMap<K, V>>,
37+
}
38+
39+
impl<K, V> LinkedHashMapVisitor<K, V> {
40+
/// Creates a new visitor for a linked hash map.
41+
pub fn new() -> Self {
42+
LinkedHashMapVisitor {
43+
marker: PhantomData,
44+
}
45+
}
46+
}
47+
48+
impl<K, V> Visitor for LinkedHashMapVisitor<K, V>
49+
where K: Deserialize + Eq + Hash,
50+
V: Deserialize,
51+
{
52+
type Value = LinkedHashMap<K, V>;
53+
54+
#[inline]
55+
fn visit_unit<E>(&mut self) -> Result<Self::Value, E>
56+
where E: Error,
57+
{
58+
Ok(LinkedHashMap::new())
59+
}
60+
61+
#[inline]
62+
fn visit_map<Visitor>(&mut self, mut visitor: Visitor) -> Result<Self::Value, Visitor::Error>
63+
where Visitor: MapVisitor,
64+
{
65+
let mut values = LinkedHashMap::with_capacity(visitor.size_hint().0);
66+
67+
while let Some((key, value)) = try!(visitor.visit()) {
68+
values.insert(key, value);
69+
}
70+
71+
try!(visitor.end());
72+
73+
Ok(values)
74+
}
75+
}
76+
77+
impl<K, V> Deserialize for LinkedHashMap<K, V>
78+
where K: Deserialize + Eq + Hash,
79+
V: Deserialize,
80+
{
81+
fn deserialize<D>(deserializer: &mut D) -> Result<LinkedHashMap<K, V>, D::Error>
82+
where D: Deserializer,
83+
{
84+
deserializer.deserialize_map(LinkedHashMapVisitor::new())
85+
}
86+
}

tests/serde.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#![cfg(feature = "serde_impl")]
2+
3+
extern crate linked_hash_map;
4+
extern crate serde;
5+
extern crate serde_json;
6+
7+
use linked_hash_map::LinkedHashMap;
8+
9+
#[test]
10+
fn test_ser_empty() {
11+
let map = LinkedHashMap::<String, u32>::new();
12+
let j = serde_json::to_string(&map).unwrap();
13+
let expected = "{}";
14+
assert_eq!(j, expected);
15+
}
16+
17+
#[test]
18+
fn test_ser() {
19+
let mut map = LinkedHashMap::new();
20+
map.insert("b", 20);
21+
map.insert("a", 10);
22+
map.insert("c", 30);
23+
24+
let j = serde_json::to_string(&map).unwrap();
25+
let expected = r#"{"b":20,"a":10,"c":30}"#;
26+
assert_eq!(j, expected);
27+
}
28+
29+
#[test]
30+
fn test_de_empty() {
31+
let j = "{}";
32+
let map: LinkedHashMap<String, u32> = serde_json::from_str(j).unwrap();
33+
assert_eq!(map.len(), 0);
34+
}
35+
36+
#[test]
37+
fn test_de() {
38+
let j = r#"{"b":20,"a":10,"c":30}"#;
39+
let map: LinkedHashMap<String, u32> = serde_json::from_str(j).unwrap();
40+
let items: Vec<_> = map.iter().map(|(k, v)| (k.clone(), *v)).collect();
41+
assert_eq!(items, [("b".to_owned(), 20),
42+
("a".to_owned(), 10),
43+
("c".to_owned(), 30)]);
44+
}

0 commit comments

Comments
 (0)