simd_json/value/borrowed/
serialize.rs

1// This is mostly taken from json-rust's codegen
2// as it seems to perform well and it makes snense 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                    stry!(self.write(b"["));
113                    self.indent();
114
115                    stry!(self.new_line());
116                    stry!(self.write_json(item));
117
118                    for item in iter {
119                        stry!(self.write(b","));
120                        stry!(self.new_line());
121                        stry!(self.write_json(item));
122                    }
123                    self.dedent();
124                    stry!(self.new_line());
125                    self.write(b"]")
126                }
127            }
128            Value::Object(ref object) => self.write_object(object),
129        }
130    }
131}
132
133trait FastGenerator: BaseGenerator {
134    type T: Write;
135
136    #[cfg_attr(not(feature = "no-inline"), inline)]
137    fn write_object(&mut self, object: &Object) -> io::Result<()> {
138        if object.is_empty() {
139            self.write(b"{}")
140        } else {
141            let mut iter = object.iter();
142            stry!(self.write(b"{\""));
143
144            // We know this exists since it's not empty
145            let Some((key, value)) = iter.next() else {
146                // We check against size
147                unreachable!("object is not empty but has no next");
148            };
149            stry!(self.write_simple_str_content(key));
150            stry!(self.write(b"\":"));
151            stry!(self.write_json(value));
152
153            for (key, value) in iter {
154                stry!(self.write(b",\""));
155                stry!(self.write_simple_str_content(key));
156                stry!(self.write(b"\":"));
157                stry!(self.write_json(value));
158            }
159            self.write(b"}")
160        }
161    }
162
163    #[cfg_attr(not(feature = "no-inline"), inline)]
164    fn write_json(&mut self, json: &Value) -> io::Result<()> {
165        match *json {
166            Value::Static(StaticNode::Null) => self.write(b"null"),
167            Value::Static(StaticNode::I64(number)) => self.write_int(number),
168            #[cfg(feature = "128bit")]
169            Value::Static(StaticNode::I128(number)) => self.write_int(number),
170            Value::Static(StaticNode::U64(number)) => self.write_int(number),
171            #[cfg(feature = "128bit")]
172            Value::Static(StaticNode::U128(number)) => self.write_int(number),
173            #[allow(clippy::useless_conversion)] // .into() required by ordered-float
174            Value::Static(StaticNode::F64(number)) => self.write_float(number.into()),
175            Value::Static(StaticNode::Bool(true)) => self.write(b"true"),
176            Value::Static(StaticNode::Bool(false)) => self.write(b"false"),
177            Value::String(ref string) => self.write_string(string),
178            Value::Array(ref array) => {
179                if array.is_empty() {
180                    self.write(b"[]")
181                } else {
182                    let mut iter = <[Value]>::iter(array);
183                    // We know we have one item
184                    let Some(item) = iter.next() else {
185                        // We check against size
186                        unreachable!("array is not empty but has no next");
187                    };
188
189                    stry!(self.write(b"["));
190                    stry!(self.write_json(item));
191
192                    for item in iter {
193                        stry!(self.write(b","));
194                        stry!(self.write_json(item));
195                    }
196                    self.write(b"]")
197                }
198            }
199            Value::Object(ref object) => self.write_object(object),
200        }
201    }
202}
203
204impl FastGenerator for DumpGenerator {
205    type T = Vec<u8>;
206}
207
208impl Generator for PrettyGenerator {
209    type T = Vec<u8>;
210}
211
212impl<W> FastGenerator for WriterGenerator<'_, W>
213where
214    W: Write,
215{
216    type T = W;
217}
218
219impl<W> Generator for PrettyWriterGenerator<'_, W>
220where
221    W: Write,
222{
223    type T = W;
224}
225
226#[cfg(test)]
227mod test {
228    use super::Value;
229    use crate::prelude::*;
230
231    #[test]
232    fn null() {
233        assert_eq!(Value::Static(StaticNode::Null).encode(), "null");
234    }
235    #[test]
236    fn bool_true() {
237        assert_eq!(Value::Static(StaticNode::Bool(true)).encode(), "true");
238    }
239    #[test]
240    fn bool_false() {
241        assert_eq!(Value::Static(StaticNode::Bool(false)).encode(), "false");
242    }
243
244    #[test]
245    fn obj() {
246        let mut o = Value::object();
247        o.insert("k", ()).expect("insert");
248        assert_eq!(o.encode(), r#"{"k":null}"#);
249    }
250
251    fn assert_str(from: &str, to: &str) {
252        assert_eq!(Value::String(from.into()).encode(), to);
253    }
254    #[test]
255    fn string() {
256        assert_str("this is a test", r#""this is a test""#);
257        assert_str(r#"this is a test ""#, r#""this is a test \"""#);
258        assert_str(r#"this is a test """#, r#""this is a test \"\"""#);
259        assert_str(
260            "this is a test a long test that should span the 32 byte boundary",
261            r#""this is a test a long test that should span the 32 byte boundary""#,
262        );
263        assert_str(
264            r#"this is a test a "long" test that should span the 32 byte boundary"#,
265            r#""this is a test a \"long\" test that should span the 32 byte boundary""#,
266        );
267
268        assert_str(
269            r#"this is a test a \"long\" test that should span the 32 byte boundary"#,
270            r#""this is a test a \\\"long\\\" test that should span the 32 byte boundary""#,
271        );
272    }
273}