1use alloc::{string::String, collections::BTreeMap};
2#[cfg(feature = "std")]
3use std::collections::HashMap;
4
5use crate::{Read, Stack, JsonError, Value, JsonDeserialize, JsonStructure, JsonSerialize};
6
7type YieldedField<'read, T, R, S> = Result<(String, T), JsonError<'read, R, S>>;
8fn deserialize_map<'read, 'parent, T: JsonDeserialize, R: Read<'read>, S: Stack>(
9 value: Value<'read, 'parent, R, S>,
10) -> Result<impl Iterator<Item = YieldedField<'read, T, R, S>>, JsonError<'read, R, S>> {
11 let mut iter = value.fields()?;
12 Ok(core::iter::from_fn(move || {
13 let mut field = match iter.next()? {
14 Ok(value) => value,
15 Err(e) => return Some(Err(e)),
16 };
17 let key = match field.key().collect::<Result<String, _>>() {
18 Ok(key) => key,
19 Err(e) => return Some(Err(e)),
20 };
21 let value = field.value();
22 match T::deserialize(value) {
23 Ok(value) => Some(Ok((key, value))),
24 Err(e) => Some(Err(e)),
25 }
26 }))
27}
28
29fn serialize_field<'serializing>(
30 (key, value): (&'serializing str, &'serializing (impl 'serializing + JsonSerialize)),
31) -> impl Iterator<Item = char> {
32 key.serialize().chain(core::iter::once(':')).chain(value.serialize())
33}
34
35#[rustfmt::skip]
36fn serialize_map<'serializing>(
37 mut iter: impl Iterator<Item = (&'serializing str, &'serializing (impl 'serializing + JsonSerialize))>,
38) -> impl Iterator<Item = char> {
39 let fields = iter.next().map(|first_field| {
40 let first_field = serialize_field(first_field);
41 let next_fields =
42 iter.flat_map(|next_field| core::iter::once(',').chain(serialize_field(next_field)));
43 first_field.chain(next_fields)
44 });
45 core::iter::once('{').chain(fields.into_iter().flatten()).chain(core::iter::once('}'))
46}
47
48impl<T: JsonDeserialize> JsonDeserialize for BTreeMap<String, T> {
49 fn deserialize<'read, 'parent, R: Read<'read>, S: Stack>(
50 value: Value<'read, 'parent, R, S>,
51 ) -> Result<Self, JsonError<'read, R, S>> {
52 deserialize_map::<T, _, _>(value)?.collect()
53 }
54}
55impl<K: AsRef<str>, T: 'static + JsonSerialize> JsonSerialize for BTreeMap<K, T> {
56 fn serialize(&self) -> impl Iterator<Item = char> {
57 serialize_map(self.iter().map(|(key, value)| (key.as_ref(), value)))
58 }
59}
60impl<T: JsonDeserialize> JsonStructure for BTreeMap<String, T> {}
61
62#[cfg(feature = "std")]
63impl<T: JsonDeserialize> JsonDeserialize for HashMap<String, T> {
64 fn deserialize<'read, 'parent, R: Read<'read>, S: Stack>(
65 value: Value<'read, 'parent, R, S>,
66 ) -> Result<Self, JsonError<'read, R, S>> {
67 deserialize_map::<T, _, _>(value)?.collect()
68 }
69}
70#[cfg(feature = "std")]
71impl<K: AsRef<str>, T: 'static + JsonSerialize> JsonSerialize for HashMap<K, T> {
72 fn serialize(&self) -> impl Iterator<Item = char> {
73 serialize_map(self.iter().map(|(key, value)| (key.as_ref(), value)))
74 }
75}
76#[cfg(feature = "std")]
77impl<T: JsonDeserialize> JsonStructure for HashMap<String, T> {}
78
79#[cfg(feature = "alloc")]
80#[test]
81fn btree_map() {
82 assert_eq!(BTreeMap::<String, u16>::new().serialize().collect::<String>().as_str(), "{}");
83 let test_map = |map: BTreeMap<String, u16>| {
84 assert_eq!(
85 BTreeMap::<String, u16>::deserialize_structure::<_, crate::ConstStack<32>>(
86 map.serialize().collect::<String>().as_bytes()
87 )
88 .unwrap(),
89 map
90 );
91 };
92 test_map(BTreeMap::from([("key1".to_string(), 1)]));
93 test_map(BTreeMap::from([("key1".to_string(), 1), ("key2".to_string(), 2)]));
94}
95
96#[cfg(feature = "std")]
97#[test]
98fn hash_map() {
99 assert_eq!(HashMap::<String, u16>::new().serialize().collect::<String>().as_str(), "{}");
100 let test_map = |map: HashMap<String, u16>| {
101 assert_eq!(
102 HashMap::<String, u16>::deserialize_structure::<_, crate::ConstStack<32>>(
103 map.serialize().collect::<String>().as_bytes()
104 )
105 .unwrap(),
106 map
107 );
108 };
109 test_map(HashMap::from([("key1".to_string(), 1)]));
110 test_map(HashMap::from([("key1".to_string(), 1), ("key2".to_string(), 2)]));
111}