1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
use std::marker::PhantomData;
use serde::{de::Visitor, Deserialize};
pub struct OrderedMap<K, V> {
items: Vec<(K, V)>,
}
impl<K, V> Default for OrderedMap<K, V> {
fn default() -> Self {
Self { items: Default::default() }
}
}
impl<'de, K: Deserialize<'de>, V: Deserialize<'de>> Deserialize<'de>
for OrderedMap<K, V>
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
deserializer.deserialize_map(OrderedMapVisitor(PhantomData))
}
}
struct OrderedMapVisitor<K, V>(PhantomData<(K, V)>);
impl<'de, K: Deserialize<'de>, V: Deserialize<'de>> Visitor<'de>
for OrderedMapVisitor<K, V>
{
type Value = OrderedMap<K, V>;
fn expecting(
&self,
formatter: &mut std::fmt::Formatter,
) -> std::fmt::Result {
formatter.write_str("a map of key-value pairs")
}
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where
A: serde::de::MapAccess<'de>,
{
let mut items = Vec::with_capacity(map.size_hint().unwrap_or(0));
while let Some(entry) = map.next_entry()? {
items.push(entry)
}
Ok(OrderedMap { items })
}
}
impl<K, V> IntoIterator for OrderedMap<K, V> {
type Item = (K, V);
type IntoIter = std::vec::IntoIter<(K, V)>;
fn into_iter(self) -> Self::IntoIter {
self.items.into_iter()
}
}
#[cfg(test)]
mod tests {
use quote::quote;
use serde::Deserialize;
use crate::{from_tokenstream, Result};
use super::OrderedMap;
#[derive(Deserialize)]
#[serde(transparent)]
struct Value(pub String);
#[test]
fn test_ordered_map() -> Result<()> {
let data = from_tokenstream::<OrderedMap<Value, Value>>("e! {
"key" = "value1",
"key" = "value2"
})?;
let mut kv = data.into_iter().map(|(k, v)| (k.0, v.0));
assert_eq!(kv.next(), Some(("key".to_string(), "value1".to_string())));
assert_eq!(kv.next(), Some(("key".to_string(), "value2".to_string())));
assert_eq!(kv.next(), None);
Ok(())
}
}