1use alloc::borrow::{Cow, ToOwned};
2use alloc::boxed::Box;
3use alloc::collections::BTreeMap;
4use alloc::string::String;
5use core::ops::Deref;
6
7use crate::cowstr::CowStr;
8use crate::{DecodeError, DecodeErrorPath, DecodeErrorType, ESExpr, ESExprCodec, ESExprConstructor, ESExprDictCodec, ESExprEncodedEq, ESExprTag, ESExprTagSet};
9
10impl<K: Ord, A: ESExprEncodedEq> ESExprEncodedEq for BTreeMap<K, A> {
11 fn is_encoded_eq(&self, other: &Self) -> bool {
12 self.len() == other.len() &&
13 self.iter()
14 .zip(other.iter())
15 .all(|((k1, v1), (k2, v2))|
16 k1 == k2 && v1.is_encoded_eq(v2)
17 )
18 }
19}
20
21impl<'a, A: ESExprCodec<'a>> ESExprCodec<'a> for BTreeMap<String, A> {
22 const TAGS: ESExprTagSet = ESExprTagSet::Tags(&[ESExprTag::Constructor(CowStr::Static("dict"))]);
23
24 fn encode_esexpr(&'a self) -> ESExpr<'a> {
25 ESExpr::constructor(
26 "dict",
27 [],
28 self.iter()
29 .map(|(k, v)| (CowStr::Borrowed(k), v.encode_esexpr()))
30 .collect::<BTreeMap<_, _>>(),
31 )
32 }
33
34 fn decode_esexpr(expr: ESExpr<'a>) -> Result<Self, DecodeError> {
35 match expr {
36 ESExpr::Constructor(ESExprConstructor { name, args, kwargs }) if name == "dict" => {
37 if !args.is_empty() {
38 return Err(DecodeError::new(
39 DecodeErrorType::OutOfRange("Dict must not have positional arguments".to_owned()),
40 DecodeErrorPath::Constructor(name.deref().to_owned()),
41 ));
42 }
43
44 let mut dict = BTreeMap::default();
45
46 for (k, v) in kwargs {
47 dict.insert(k.into_string(), A::decode_esexpr(v)?);
48 }
49
50 Ok(dict)
51 },
52 _ => Err(DecodeError::new(
53 DecodeErrorType::UnexpectedExpr {
54 expected_tags: <Self as ESExprCodec>::TAGS,
55 actual_tag: expr.tag().into_owned(),
56 },
57 DecodeErrorPath::Current,
58 )),
59 }
60 }
61}
62
63impl<'a, A: ESExprCodec<'a>> ESExprCodec<'a> for BTreeMap<Cow<'a, str>, A> {
64 const TAGS: ESExprTagSet = ESExprTagSet::Tags(&[ESExprTag::Constructor(CowStr::Static("dict"))]);
65
66 fn encode_esexpr(&'a self) -> ESExpr<'a> {
67 let mut kwargs = BTreeMap::new();
68
69 for (k, v) in self {
70 kwargs.insert(CowStr::Borrowed(k.as_ref()), v.encode_esexpr());
71 }
72
73 ESExpr::constructor(
74 "dict",
75 [],
76 self.iter()
77 .map(|(k, v)| (CowStr::Borrowed(k.as_ref()), v.encode_esexpr()))
78 .collect::<BTreeMap<_, _>>(),
79 )
80 }
81
82 fn decode_esexpr(expr: ESExpr<'a>) -> Result<Self, DecodeError> {
83 match expr {
84 ESExpr::Constructor(ESExprConstructor { name, args, kwargs }) if name == "dict" => {
85 if !args.is_empty() {
86 return Err(DecodeError::new(
87 DecodeErrorType::OutOfRange("Dict must not have positional arguments".to_owned()),
88 DecodeErrorPath::Constructor(name.deref().to_owned()),
89 ));
90 }
91
92 let mut dict = BTreeMap::default();
93
94 for (k, v) in kwargs {
95 dict.insert(Cow::from(k), A::decode_esexpr(v)?);
96 }
97
98 Ok(dict)
99 },
100 _ => Err(DecodeError::new(
101 DecodeErrorType::UnexpectedExpr {
102 expected_tags: <Self as ESExprCodec>::TAGS,
103 actual_tag: expr.tag().into_owned(),
104 },
105 DecodeErrorPath::Current,
106 )),
107 }
108 }
109}
110
111impl<'a, A: ESExprCodec<'a>> ESExprCodec<'a> for BTreeMap<CowStr<'a>, A> {
112 const TAGS: ESExprTagSet = ESExprTagSet::Tags(&[ESExprTag::Constructor(CowStr::Static("dict"))]);
113
114 fn encode_esexpr(&'a self) -> ESExpr<'a> {
115 ESExpr::constructor(
116 "dict",
117 [],
118 self.iter()
119 .map(|(k, v)| (CowStr::Borrowed(k.as_ref()), v.encode_esexpr()))
120 .collect::<BTreeMap<_, _>>(),
121 )
122 }
123
124 fn decode_esexpr(expr: ESExpr<'a>) -> Result<Self, DecodeError> {
125 match expr {
126 ESExpr::Constructor(ESExprConstructor { name, args, kwargs }) if name == "dict" => {
127 if !args.is_empty() {
128 return Err(DecodeError::new(
129 DecodeErrorType::OutOfRange("Dict must not have positional arguments".to_owned()),
130 DecodeErrorPath::Constructor(name.deref().to_owned()),
131 ));
132 }
133
134 let mut dict = BTreeMap::default();
135
136 for (k, v) in kwargs {
137 dict.insert(k, A::decode_esexpr(v)?);
138 }
139
140 Ok(dict)
141 },
142 _ => Err(DecodeError::new(
143 DecodeErrorType::UnexpectedExpr {
144 expected_tags: <Self as ESExprCodec>::TAGS,
145 actual_tag: expr.tag().into_owned(),
146 },
147 DecodeErrorPath::Current,
148 )),
149 }
150 }
151}
152
153impl<'a, A: ESExprCodec<'a>> ESExprDictCodec<'a> for BTreeMap<Cow<'a, str>, A> {
154 type Element = A;
155
156 fn encode_dict_element(&'a self, kwargs: &mut BTreeMap<CowStr<'a>, ESExpr<'a>>) {
157 for (k, v) in self {
158 kwargs.insert(CowStr::Borrowed(k.as_ref()), v.encode_esexpr());
159 }
160 }
161
162 fn decode_dict_element(
163 kwargs: &mut BTreeMap<CowStr<'a>, ESExpr<'a>>,
164 constructor_name: &str,
165 ) -> Result<Self, DecodeError> {
166 core::mem::take(kwargs)
167 .into_iter()
168 .map(|(k, v)| {
169 let value = A::decode_esexpr(v).map_err(|mut e| {
170 e.error_path_with(|old_path| {
171 DecodeErrorPath::Keyword(constructor_name.to_owned(), k.deref().to_owned(), Box::new(old_path))
172 });
173 e
174 })?;
175
176 Ok((Cow::from(k), value))
177 })
178 .collect()
179 }
180}
181
182impl<'a, A: ESExprCodec<'a>> ESExprDictCodec<'a> for BTreeMap<String, A> {
183 type Element = A;
184
185
186 fn encode_dict_element(&'a self, kwargs: &mut BTreeMap<CowStr<'a>, ESExpr<'a>>) {
187 for (k, v) in self {
188 kwargs.insert(CowStr::Borrowed(k.as_ref()), v.encode_esexpr());
189 }
190 }
191
192 fn decode_dict_element(
193 kwargs: &mut BTreeMap<CowStr<'a>, ESExpr<'a>>,
194 constructor_name: &str,
195 ) -> Result<Self, DecodeError> {
196 core::mem::take(kwargs)
197 .into_iter()
198 .map(|(k, v)| {
199 let value = A::decode_esexpr(v).map_err(|mut e| {
200 e.error_path_with(|old_path| {
201 DecodeErrorPath::Keyword(constructor_name.to_owned(), k.deref().to_owned(), Box::new(old_path))
202 });
203 e
204 })?;
205
206 Ok((k.into_string(), value))
207 })
208 .collect()
209 }
210}