simd_json/value/owned/
serialize.rs

1// This is mostly taken from json-rust's codegen
2// as it seems to perform well and it makes sense to see
3// if we can adopt the approach
4//
5// https://github.com/maciejhirsz/json-rust/blob/master/src/codegen.rs
6
7use super::{Object, Value};
8use crate::prelude::*;
9use std::io;
10use std::io::Write;
11use value_trait::generator::{
12    DumpGenerator, PrettyGenerator, PrettyWriterGenerator, WriterGenerator,
13};
14
15//use util::print_dec;
16
17impl Writable for Value {
18    #[cfg_attr(not(feature = "no-inline"), inline)]
19    fn encode(&self) -> String {
20        let mut g = DumpGenerator::new();
21        let _r = g.write_json(self);
22        g.consume()
23    }
24
25    #[cfg_attr(not(feature = "no-inline"), inline)]
26    fn encode_pp(&self) -> String {
27        let mut g = PrettyGenerator::new(2);
28        let _r = g.write_json(self);
29        g.consume()
30    }
31
32    #[cfg_attr(not(feature = "no-inline"), inline)]
33    fn write<'writer, W>(&self, w: &mut W) -> io::Result<()>
34    where
35        W: 'writer + Write,
36    {
37        let mut g = WriterGenerator::new(w);
38        g.write_json(self)
39    }
40
41    #[cfg_attr(not(feature = "no-inline"), inline)]
42    fn write_pp<'writer, W>(&self, w: &mut W) -> io::Result<()>
43    where
44        W: 'writer + Write,
45    {
46        let mut g = PrettyWriterGenerator::new(w, 2);
47        g.write_json(self)
48    }
49}
50
51trait Generator: BaseGenerator {
52    type T: Write;
53
54    #[cfg_attr(not(feature = "no-inline"), inline)]
55    fn write_object(&mut self, object: &Object) -> io::Result<()> {
56        if object.is_empty() {
57            self.write(b"{}")
58        } else {
59            let mut iter = object.iter();
60            stry!(self.write(b"{"));
61
62            // We know this exists since it's not empty
63            let Some((key, value)) = iter.next() else {
64                // We check against size
65                unreachable!("object is not empty but has no next");
66            };
67            self.indent();
68            stry!(self.new_line());
69            stry!(self.write_simple_string(key));
70            stry!(self.write_min(b": ", b':'));
71            stry!(self.write_json(value));
72
73            for (key, value) in iter {
74                stry!(self.write(b","));
75                stry!(self.new_line());
76                stry!(self.write_simple_string(key));
77                stry!(self.write_min(b": ", b':'));
78                stry!(self.write_json(value));
79            }
80            self.dedent();
81            stry!(self.new_line());
82            self.write(b"}")
83        }
84    }
85
86    #[cfg_attr(not(feature = "no-inline"), inline)]
87    fn write_json(&mut self, json: &Value) -> io::Result<()> {
88        match *json {
89            Value::Static(StaticNode::Null) => self.write(b"null"),
90            Value::Static(StaticNode::I64(number)) => self.write_int(number),
91            #[cfg(feature = "128bit")]
92            Value::Static(StaticNode::I128(number)) => self.write_int(number),
93            Value::Static(StaticNode::U64(number)) => self.write_int(number),
94            #[cfg(feature = "128bit")]
95            Value::Static(StaticNode::U128(number)) => self.write_int(number),
96            #[allow(clippy::useless_conversion)] // .into() required by ordered-float
97            Value::Static(StaticNode::F64(number)) => self.write_float(number.into()),
98            Value::Static(StaticNode::Bool(true)) => self.write(b"true"),
99            Value::Static(StaticNode::Bool(false)) => self.write(b"false"),
100            Value::String(ref string) => self.write_string(string),
101            Value::Array(ref array) => {
102                if array.is_empty() {
103                    self.write(b"[]")
104                } else {
105                    let mut iter = <[Value]>::iter(array);
106                    // We know we have one item
107
108                    let Some(item) = iter.next() else {
109                        // We check against size
110                        unreachable!("array is not empty but has no next");
111                    };
112
113                    stry!(self.write(b"["));
114
115                    self.indent();
116                    stry!(self.new_line());
117                    stry!(self.write_json(item));
118
119                    for item in iter {
120                        stry!(self.write(b","));
121                        stry!(self.new_line());
122                        stry!(self.write_json(item));
123                    }
124
125                    self.dedent();
126                    stry!(self.new_line());
127                    self.write(b"]")
128                }
129            }
130            Value::Object(ref object) => self.write_object(object),
131        }
132    }
133}
134
135trait FastGenerator: BaseGenerator {
136    type T: Write;
137
138    #[cfg_attr(not(feature = "no-inline"), inline)]
139    fn write_object(&mut self, object: &Object) -> io::Result<()> {
140        if object.is_empty() {
141            self.write(b"{}")
142        } else {
143            let mut iter = object.iter();
144            stry!(self.write(b"{\""));
145
146            // We know this exists since it's not empty
147            let Some((key, value)) = iter.next() else {
148                // We check against size
149                unreachable!("object is not empty but has no next");
150            };
151            stry!(self.write_simple_str_content(key));
152            stry!(self.write(b"\":"));
153            stry!(self.write_json(value));
154
155            for (key, value) in iter {
156                stry!(self.write(b",\""));
157                stry!(self.write_simple_str_content(key));
158                stry!(self.write(b"\":"));
159                stry!(self.write_json(value));
160            }
161            self.write(b"}")
162        }
163    }
164
165    #[cfg_attr(not(feature = "no-inline"), inline)]
166    fn write_json(&mut self, json: &Value) -> io::Result<()> {
167        match *json {
168            Value::Static(StaticNode::Null) => self.write(b"null"),
169            Value::Static(StaticNode::I64(number)) => self.write_int(number),
170            #[cfg(feature = "128bit")]
171            Value::Static(StaticNode::I128(number)) => self.write_int(number),
172            Value::Static(StaticNode::U64(number)) => self.write_int(number),
173            #[cfg(feature = "128bit")]
174            Value::Static(StaticNode::U128(number)) => self.write_int(number),
175            #[allow(clippy::useless_conversion)] // .into() required by ordered-float
176            Value::Static(StaticNode::F64(number)) => self.write_float(number.into()),
177            Value::Static(StaticNode::Bool(true)) => self.write(b"true"),
178            Value::Static(StaticNode::Bool(false)) => self.write(b"false"),
179            Value::String(ref string) => self.write_string(string),
180            Value::Array(ref array) => {
181                if array.is_empty() {
182                    self.write(b"[]")
183                } else {
184                    let mut iter = <[Value]>::iter(array);
185                    // We know we have one item
186                    let Some(item) = iter.next() else {
187                        // We check against size
188                        unreachable!("array is not empty but has no next");
189                    };
190
191                    stry!(self.write(b"["));
192                    stry!(self.write_json(item));
193
194                    for item in iter {
195                        stry!(self.write(b","));
196                        stry!(self.write_json(item));
197                    }
198                    self.write(b"]")
199                }
200            }
201            Value::Object(ref object) => self.write_object(object),
202        }
203    }
204}
205
206impl FastGenerator for DumpGenerator {
207    type T = Vec<u8>;
208}
209
210impl Generator for PrettyGenerator {
211    type T = Vec<u8>;
212}
213
214impl<W> FastGenerator for WriterGenerator<'_, W>
215where
216    W: Write,
217{
218    type T = W;
219}
220
221impl<W> Generator for PrettyWriterGenerator<'_, W>
222where
223    W: Write,
224{
225    type T = W;
226}
227
228#[cfg(test)]
229mod test {
230    use super::Value;
231    use crate::prelude::*;
232
233    #[test]
234    fn null() {
235        assert_eq!(Value::Static(StaticNode::Null).encode(), "null");
236    }
237    #[test]
238    fn bool_true() {
239        assert_eq!(Value::Static(StaticNode::Bool(true)).encode(), "true");
240    }
241    #[test]
242    fn bool_false() {
243        assert_eq!(Value::Static(StaticNode::Bool(false)).encode(), "false");
244    }
245
246    #[test]
247    fn obj() {
248        let mut o = Value::object();
249        o.insert("k", ()).expect("insert");
250        assert_eq!(o.encode(), r#"{"k":null}"#);
251    }
252    fn assert_str(from: &str, to: &str) {
253        assert_eq!(Value::String(from.into()).encode(), to);
254    }
255
256    #[test]
257    fn string() {
258        assert_str("this is a test", r#""this is a test""#);
259        assert_str(r#"this is a test ""#, r#""this is a test \"""#);
260        assert_str(r#"this is a test """#, r#""this is a test \"\"""#);
261        assert_str(
262            "this is a test a long test that should span the 32 byte boundary",
263            r#""this is a test a long test that should span the 32 byte boundary""#,
264        );
265        assert_str(
266            r#"this is a test a "long" test that should span the 32 byte boundary"#,
267            r#""this is a test a \"long\" test that should span the 32 byte boundary""#,
268        );
269
270        assert_str(
271            r#"this is a test a \"long\" test that should span the 32 byte boundary"#,
272            r#""this is a test a \\\"long\\\" test that should span the 32 byte boundary""#,
273        );
274    }
275}