Skip to main content

serde_single_key_map/
lib.rs

1//! Unwrap a single key map with serde.
2//! ## Installation
3//!
4//! Add it to your `Cargo.toml`:
5//!
6//! ```toml
7//! [dependencies]
8//! serde-single-key-map = "0.1"
9//! ```
10//!
11//! ## Usage
12//!
13//! ```rust,ignore
14//! #[derive(Debug, Deserialize)]
15//! struct Project {
16//!     name: String,
17//!     #[serde(deserialize_with = "serde_single_key_map::deserialize")]
18//!     items: Vec<Item>,
19//! }
20//!
21//! #[derive(Debug, Deserialize)]
22//! struct Item {
23//!     name: String,
24//!     source: String,
25//! }
26//!
27//! fn main() {
28//!     let s = r#"{
29//!         "name": "test",
30//!         "items": {
31//!             "item": [
32//!             {
33//!                 "name": "name",
34//!                 "source": "name.rs"
35//!             }
36//!             ]
37//!         }
38//!         }"#;
39//!     let project: Project = serde_json::from_str(s).expect("deserialize failed");
40//!     assert_eq!(project.name, "test");
41//!     assert_eq!(project.items.len(), 1);
42//!     let item = &project.items[0];
43//!     assert_eq!(item.name, "name");
44//!     assert_eq!(item.source, "name.rs");
45//! }
46//! ```
47//!
48use std::fmt;
49use std::marker::PhantomData;
50
51use serde::de::{self, Deserializer, DeserializeOwned};
52
53pub fn deserialize<'de, V, D>(d: D) -> Result<V, D::Error>
54where
55    D: Deserializer<'de>,
56    V: DeserializeOwned,
57{
58    struct SingleKeyMapVisitor<V: DeserializeOwned>(PhantomData<V>);
59
60    impl<'de, V> de::Visitor<'de> for SingleKeyMapVisitor<V>
61    where
62        V: DeserializeOwned,
63    {
64        type Value = V;
65
66        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
67            formatter.write_str("a map")
68        }
69
70        #[inline]
71        fn visit_map<T>(self, mut visitor: T) -> Result<V, T::Error>
72        where
73            T: de::MapAccess<'de>,
74        {
75            let item: Option<(String, V)> = visitor.next_entry()?;
76            if let Some((_, value)) = item {
77               return Ok(value);
78            }
79            Err(de::Error::custom("No single key value in map"))
80        }
81    }
82    d.deserialize_map(SingleKeyMapVisitor(PhantomData))
83}
84
85#[cfg(test)]
86mod tests {
87    use serde::Deserialize;
88
89    #[derive(Debug, Deserialize)]
90    struct Project {
91        name: String,
92        #[serde(deserialize_with = "crate::deserialize")]
93        items: Vec<Item>,
94    }
95
96    #[derive(Debug, Deserialize)]
97    struct Item {
98        name: String,
99        source: String,
100    }
101
102    #[test]
103    fn test_deserialize() {
104        let s = r#"{
105            "name": "test",
106            "items": {
107              "item": [
108                {
109                  "name": "name",
110                  "source": "name.rs"
111                }
112              ]
113            }
114          }"#;
115        let project: Project = serde_json::from_str(s).expect("deserialize failed");
116        assert_eq!(project.name, "test");
117        assert_eq!(project.items.len(), 1);
118        let item = &project.items[0];
119        assert_eq!(item.name, "name");
120        assert_eq!(item.source, "name.rs");
121    }
122
123    #[test]
124    #[should_panic]
125    fn test_deserialize_with_multiple_keys() {
126        let s = r#"{
127            "name": "test",
128            "items": {
129              "item": [
130                {
131                  "name": "name",
132                  "source": "name.rs"
133                }
134              ],
135              "extra": "test"
136            }
137          }"#;
138        let _project: Project = serde_json::from_str(s).expect("deserialize failed");
139    }
140
141    #[test]
142    #[should_panic]
143    fn test_deserialize_with_empty_map() {
144        let s = r#"{
145            "name": "test",
146            "items": {}
147          }"#;
148        let _project: Project = serde_json::from_str(s).expect("deserialize failed");
149    }
150}