1use super::string::JSONString;
4use super::JSONValue;
5use std::collections::HashMap;
6use std::hash::BuildHasher;
7use std::hash::Hash;
8use std::io;
9
10fn write_object_entry<W, K, V>(w: &mut W, key: &K, value: &V) -> io::Result<()>
12where
13 W: io::Write,
14 K: JSONString,
15 V: JSONValue,
16{
17 key.write_json(w)?;
18 w.write_all(b":")?;
19 value.write_json(w)
20}
21
22fn write_object<'a, W, K, V, I>(w: &mut W, iter: &mut I) -> io::Result<()>
24where
25 W: io::Write,
26 K: JSONString,
27 V: JSONValue,
28 V: 'a,
29 K: 'a,
30 I: Iterator<Item = (&'a K, &'a V)>,
31{
32 w.write_all(b"{")?;
33 if let Some((key, value)) = iter.next() {
34 write_object_entry(w, key, value)?;
35 for (key, value) in iter {
36 w.write_all(b",")?;
37 write_object_entry(w, key, value)?;
38 }
39 }
40 w.write_all(b"}")
41}
42
43pub struct ToJSONObject<K, V, I>(pub I)
59where
60 K: JSONString,
61 V: JSONValue,
62 for<'a> &'a I: IntoIterator<Item = &'a (K, V)>;
63
64impl<K, V, I> JSONValue for ToJSONObject<K, V, I>
65where
66 K: JSONString,
67 V: JSONValue,
68 for<'a> &'a I: IntoIterator<Item = &'a (K, V)>,
69{
70 fn write_json<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
71 let mut iter = (&self.0).into_iter().map(|(k, v)| (k, v)); write_object(w, &mut iter)
73 }
74}
75
76impl<K: JSONString + Eq + Hash, V: JSONValue, S: BuildHasher> JSONValue for HashMap<K, V, S> {
78 fn write_json<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
79 write_object(w, &mut self.iter())
80 }
81}
82
83pub trait JSONObject: JSONValue {
84 fn write_json_ending<W: io::Write>(&self, f: &mut W, first: bool) -> io::Result<()>;
85 #[inline]
86 fn write_json_full<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
87 self.write_json_ending(w, true)
88 }
89}
90
91pub struct JSONObjectEntry<K: JSONString, V: JSONValue, U: JSONObject> {
95 pub key: K,
96 pub value: V,
97 pub next: U,
98}
99
100impl<K: JSONString, V: JSONValue, U: JSONObject> JSONObject for JSONObjectEntry<K, V, U> {
101 #[inline(always)]
102 fn write_json_ending<W: io::Write>(&self, w: &mut W, first: bool) -> io::Result<()> {
103 w.write_all(if first { b"{" } else { b"," })?;
104 self.key.write_json(w)?;
105 w.write_all(b":")?;
106 self.value.write_json(w)?;
107 self.next.write_json_ending(w, false)
108 }
109}
110
111impl<K: JSONString, V: JSONValue, U: JSONObject> JSONValue for JSONObjectEntry<K, V, U> {
112 #[inline(always)]
113 fn write_json<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
114 self.write_json_full(w)
115 }
116}
117
118pub struct JSONObjectEnd;
122
123impl JSONObject for JSONObjectEnd {
124 #[inline(always)]
125 fn write_json_ending<W: io::Write>(&self, w: &mut W, first: bool) -> io::Result<()> {
126 w.write_all(if first { b"{}" } else { b"}" })
127 }
128}
129
130impl JSONValue for JSONObjectEnd {
131 fn write_json<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
132 self.write_json_full(w)
133 }
134}
135
136#[macro_export]
137#[doc(hidden)]
138macro_rules! inlined_json_object {
139 (key : $key:ident, value : $value:expr, next : $next:expr) => {{
140 use $crate::object::JSONObject;
141 use $crate::JSONValue;
142
143 struct InlinedJSONObjectEntry<V: JSONValue, U: JSONObject> {
144 value: V,
145 next: U,
146 }
147
148 impl<V: JSONValue, U: JSONObject> JSONObject for InlinedJSONObjectEntry<V, U> {
149 #[inline(always)]
150 fn write_json_ending<W: ::std::io::Write>(
151 &self,
152 w: &mut W,
153 first: bool,
154 ) -> ::std::io::Result<()> {
155 w.write_all(
156 if first {
157 concat!("{\"", stringify!($key), "\":")
158 } else {
159 concat!(",\"", stringify!($key), "\":")
160 }
161 .as_bytes(),
162 )?;
163 self.value.write_json(w)?;
164 self.next.write_json_ending(w, false)
165 }
166 }
167
168 impl<V: JSONValue, U: JSONObject> JSONValue for InlinedJSONObjectEntry<V, U> {
169 fn write_json<W: ::std::io::Write>(&self, w: &mut W) -> ::std::io::Result<()> {
170 self.write_json_full(w)
171 }
172 }
173
174 InlinedJSONObjectEntry {
175 value: $value,
176 next: $next,
177 }
178 }};
179}
180
181#[macro_export]
244macro_rules! json_object {
245 () => { $crate::object::JSONObjectEnd{} };
246 ($key:ident : null, $($rest:tt)*) => { json_object!($key : (), $($rest)*) };
248 ($key:ident : true, $($rest:tt)*) => { json_object!($key : $crate::base_types::JSONtrue, $($rest)*) };
249 ($key:ident : false, $($rest:tt)*) => { json_object!($key : $crate::base_types::JSONfalse, $($rest)*) };
250 ($key:ident : $value:expr, $($rest:tt)*) => {
252 inlined_json_object!{
253 key: $key,
254 value: $value,
255 next: json_object!($($rest)*)
256 }
257 };
258 ([$key:expr] : $value:expr, $($rest:tt)*) => {
260 $crate::object::JSONObjectEntry {
261 key: $key,
262 value: $value,
263 next: json_object!($($rest)*)
264 }
265 };
266 ($key:ident, $($rest:tt)*) => { json_object!($key : $key, $($rest)*) };
268 ($key:ident : $value:ident) => { json_object!($key:$value,) };
270 ($key:ident : $value:expr) => { json_object!($key:$value,) };
271 ([$key:expr] : $value:expr) => { json_object!([$key]:$value,) };
272 ($key:ident) => { json_object!($key,) };
273}
274
275#[cfg(test)]
276mod tests {
277 use super::*;
279
280 #[test]
281 fn test_empty() {
282 assert_eq!("{}", JSONObjectEnd.to_json_string());
283 assert_eq!("{}", json_object!().to_json_string());
284 }
285
286 #[test]
287 fn test_single_pair() {
288 assert_eq!(
289 r#"{"x":{}}"#,
290 json_object!(x: json_object!()).to_json_string()
291 );
292 assert_eq!(
294 r#"{"x":{}}"#,
295 json_object!(x: json_object!(),).to_json_string()
296 );
297 }
298
299 #[test]
300 fn test_two_pairs() {
301 assert_eq!(
302 r#"{"x":{},"y":{}}"#,
303 json_object! {
304 x : json_object!(),
305 y : json_object!()
306 }
307 .to_json_string()
308 );
309 }
310
311 #[test]
312 fn test_nested() {
313 assert_eq!(
314 r#"{"x":{"y":{}}}"#,
315 json_object! {
316 x : json_object! {
317 y : json_object!()
318 }
319 }
320 .to_json_string()
321 );
322 }
323
324 #[test]
325 fn test_dynamic_keys() {
326 let x = "x";
327 let y = String::from("y");
328 assert_eq!(
329 r#"{"x":{"y":{}}}"#,
330 json_object! {
331 [x] : json_object! {
332 [y] : json_object!()
333 }
334 }
335 .to_json_string()
336 );
337 }
338
339 #[test]
340 fn test_hashmap() {
341 let mut map = HashMap::new();
342 map.insert("x", 1);
343 map.insert("y", 2);
344 let expected = vec![r#"{"x":1,"y":2}"#, r#"{"y":2,"x":1}"#];
346 assert!(expected.contains(&&map.to_json_string()[..]));
347 }
348
349 #[test]
350 fn test_zero_size() {
351 use std::mem::size_of_val;
352 let json_obj = json_object! {
356 null: null,
357 nested: json_object! {
358 also_null: (),
359 bool : true,
360 deeper: json_object! {
361 other_bool: false
362 }
363 }
364 };
365 assert_eq!(0, size_of_val(&json_obj));
366 }
367}