• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::JsonValue;
2 use std::collections::HashMap;
3 use std::fmt;
4 use std::io::{self, Write};
5 
6 /// Serialization error. This error only happens when some write error happens on writing the serialized byte sequence
7 /// to the given `io::Write` object.
8 #[derive(Debug)]
9 pub struct JsonGenerateError {
10     msg: String,
11 }
12 
13 impl JsonGenerateError {
message(&self) -> &str14     pub fn message(&self) -> &str {
15         self.msg.as_str()
16     }
17 }
18 
19 impl fmt::Display for JsonGenerateError {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result20     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21         write!(f, "Generate error: {}", &self.msg)
22     }
23 }
24 
25 impl std::error::Error for JsonGenerateError {}
26 
27 /// Convenient type alias for serialization results.
28 pub type JsonGenerateResult = Result<String, JsonGenerateError>;
29 
30 /// JSON serializer for `JsonValue`.
31 ///
32 /// Basically you don't need to use this struct directly since `JsonValue::stringify` or `JsonValue::format` methods are
33 /// using this internally.
34 ///
35 /// ```
36 /// use tinyjson::{JsonGenerator, JsonValue};
37 ///
38 /// let v = JsonValue::from("hello, world".to_string());
39 /// let mut buf = vec![];
40 /// let mut gen = JsonGenerator::new(&mut buf);
41 /// gen.generate(&v).unwrap();
42 ///
43 /// assert_eq!(String::from_utf8(buf).unwrap(), "\"hello, world\"");
44 /// ```
45 pub struct JsonGenerator<'indent, W: Write> {
46     out: W,
47     indent: Option<&'indent str>,
48 }
49 
50 impl<'indent, W: Write> JsonGenerator<'indent, W> {
51     /// Create a new `JsonGenerator` object. The serialized byte sequence will be written to the given `io::Write`
52     /// object.
new(out: W) -> Self53     pub fn new(out: W) -> Self {
54         Self { out, indent: None }
55     }
56 
57     /// Set indent string. This will be used by [`JsonGenerator::generate`].
58     /// ```
59     /// use tinyjson::{JsonGenerator, JsonValue};
60     ///
61     /// let v = JsonValue::from(vec![1.0.into(), 2.0.into(), 3.0.into()]);
62     /// let mut buf = vec![];
63     /// let mut gen = JsonGenerator::new(&mut buf).indent("        ");
64     /// gen.generate(&v).unwrap();
65     ///
66     /// assert_eq!(String::from_utf8(buf).unwrap(),
67     /// "[
68     ///         1,
69     ///         2,
70     ///         3
71     /// ]");
72     /// ```
indent(mut self, indent: &'indent str) -> Self73     pub fn indent(mut self, indent: &'indent str) -> Self {
74         self.indent = Some(indent);
75         self
76     }
77 
quote(&mut self, s: &str) -> io::Result<()>78     fn quote(&mut self, s: &str) -> io::Result<()> {
79         const B: u8 = b'b'; // \x08
80         const T: u8 = b't'; // \x09
81         const N: u8 = b'n'; // \x0a
82         const F: u8 = b'f'; // \x0c
83         const R: u8 = b'r'; // \x0d
84         const Q: u8 = b'"'; // \x22
85         const S: u8 = b'\\'; // \x5c
86         const U: u8 = 1; // non-printable
87 
88         #[rustfmt::skip]
89         const ESCAPE_TABLE: [u8; 256] = [
90          // 0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
91             U, U, U, U, U, U, U, U, B, T, N, U, F, R, U, U, // 0
92             U, U, U, U, U, U, U, U, U, U, U, U, U, U, U, U, // 1
93             0, 0, Q, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2
94             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3
95             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4
96             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, S, 0, 0, 0, // 5
97             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6
98             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7
99             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8
100             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9
101             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A
102             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B
103             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C
104             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D
105             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E
106             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // F
107         ];
108 
109         self.out.write_all(b"\"")?;
110         let mut start = 0;
111         for (i, c) in s.char_indices() {
112             let u = c as usize;
113             if u < 256 {
114                 let esc = ESCAPE_TABLE[u];
115                 if esc == 0 {
116                     continue;
117                 }
118                 if start != i {
119                     self.out.write_all(s[start..i].as_bytes())?;
120                 }
121                 if esc == U {
122                     write!(self.out, "\\u{:04x}", u)?;
123                 } else {
124                     self.out.write_all(&[b'\\', esc])?;
125                 }
126                 start = i + 1;
127             }
128         }
129         if start != s.len() {
130             self.out.write_all(s[start..].as_bytes())?;
131         }
132         self.out.write_all(b"\"")
133     }
134 
number(&mut self, f: f64) -> io::Result<()>135     fn number(&mut self, f: f64) -> io::Result<()> {
136         if f.is_infinite() {
137             Err(io::Error::new(
138                 io::ErrorKind::Other,
139                 "JSON cannot represent inf",
140             ))
141         } else if f.is_nan() {
142             Err(io::Error::new(
143                 io::ErrorKind::Other,
144                 "JSON cannot represent NaN",
145             ))
146         } else {
147             write!(self.out, "{}", f)
148         }
149     }
150 
encode_array(&mut self, array: &[JsonValue]) -> io::Result<()>151     fn encode_array(&mut self, array: &[JsonValue]) -> io::Result<()> {
152         self.out.write_all(b"[")?;
153         let mut first = true;
154         for elem in array.iter() {
155             if first {
156                 first = false;
157             } else {
158                 self.out.write_all(b",")?;
159             }
160             self.encode(elem)?;
161         }
162         self.out.write_all(b"]")
163     }
164 
encode_object(&mut self, m: &HashMap<String, JsonValue>) -> io::Result<()>165     fn encode_object(&mut self, m: &HashMap<String, JsonValue>) -> io::Result<()> {
166         self.out.write_all(b"{")?;
167         let mut first = true;
168         for (k, v) in m {
169             if first {
170                 first = false;
171             } else {
172                 self.out.write_all(b",")?;
173             }
174             self.quote(k)?;
175             self.out.write_all(b":")?;
176             self.encode(v)?;
177         }
178         self.out.write_all(b"}")
179     }
180 
encode(&mut self, value: &JsonValue) -> io::Result<()>181     fn encode(&mut self, value: &JsonValue) -> io::Result<()> {
182         match value {
183             JsonValue::Number(n) => self.number(*n),
184             JsonValue::Boolean(b) => write!(self.out, "{}", *b),
185             JsonValue::String(s) => self.quote(s),
186             JsonValue::Null => self.out.write_all(b"null"),
187             JsonValue::Array(a) => self.encode_array(a),
188             JsonValue::Object(o) => self.encode_object(o),
189         }
190     }
191 
write_indent(&mut self, indent: &str, level: usize) -> io::Result<()>192     fn write_indent(&mut self, indent: &str, level: usize) -> io::Result<()> {
193         for _ in 0..level {
194             self.out.write_all(indent.as_bytes())?;
195         }
196         Ok(())
197     }
198 
format_array(&mut self, array: &[JsonValue], indent: &str, level: usize) -> io::Result<()>199     fn format_array(&mut self, array: &[JsonValue], indent: &str, level: usize) -> io::Result<()> {
200         if array.is_empty() {
201             return self.out.write_all(b"[]");
202         }
203 
204         self.out.write_all(b"[\n")?;
205         let mut first = true;
206         for elem in array.iter() {
207             if first {
208                 first = false;
209             } else {
210                 self.out.write_all(b",\n")?;
211             }
212             self.write_indent(indent, level + 1)?;
213             self.format(elem, indent, level + 1)?;
214         }
215         self.out.write_all(b"\n")?;
216         self.write_indent(indent, level)?;
217         self.out.write_all(b"]")
218     }
219 
format_object( &mut self, m: &HashMap<String, JsonValue>, indent: &str, level: usize, ) -> io::Result<()>220     fn format_object(
221         &mut self,
222         m: &HashMap<String, JsonValue>,
223         indent: &str,
224         level: usize,
225     ) -> io::Result<()> {
226         if m.is_empty() {
227             return self.out.write_all(b"{}");
228         }
229 
230         self.out.write_all(b"{\n")?;
231         let mut first = true;
232         for (k, v) in m {
233             if first {
234                 first = false;
235             } else {
236                 self.out.write_all(b",\n")?;
237             }
238             self.write_indent(indent, level + 1)?;
239             self.quote(k)?;
240             self.out.write_all(b": ")?;
241             self.format(v, indent, level + 1)?;
242         }
243         self.out.write_all(b"\n")?;
244         self.write_indent(indent, level)?;
245         self.out.write_all(b"}")
246     }
247 
format(&mut self, value: &JsonValue, indent: &str, level: usize) -> io::Result<()>248     fn format(&mut self, value: &JsonValue, indent: &str, level: usize) -> io::Result<()> {
249         match value {
250             JsonValue::Number(n) => self.number(*n),
251             JsonValue::Boolean(b) => write!(self.out, "{}", *b),
252             JsonValue::String(s) => self.quote(s),
253             JsonValue::Null => self.out.write_all(b"null"),
254             JsonValue::Array(a) => self.format_array(a, indent, level),
255             JsonValue::Object(o) => self.format_object(o, indent, level),
256         }
257     }
258 
259     /// Serialize the `JsonValue` into UTF-8 byte sequence. The result will be written to the `io::Write` object passed
260     /// at [`JsonGenerator::new`].
261     /// This method serializes the value without indentation by default. But after setting an indent string via
262     /// [`JsonGenerator::indent`], this method will use the indent for elements of array and object.
263     ///
264     /// ```
265     /// use tinyjson::{JsonGenerator, JsonValue};
266     ///
267     /// let v = JsonValue::from(vec![1.0.into(), 2.0.into(), 3.0.into()]);
268     ///
269     /// let mut buf = vec![];
270     /// let mut gen = JsonGenerator::new(&mut buf);
271     /// gen.generate(&v).unwrap();
272     /// assert_eq!(String::from_utf8(buf).unwrap(), "[1,2,3]");
273     ///
274     /// let mut buf = vec![];
275     /// let mut gen = JsonGenerator::new(&mut buf).indent("  "); // with 2-spaces indent
276     /// gen.generate(&v).unwrap();
277     ///
278     /// assert_eq!(String::from_utf8(buf).unwrap(),
279     /// "[
280     ///   1,
281     ///   2,
282     ///   3
283     /// ]");
284     /// ```
generate(&mut self, value: &JsonValue) -> io::Result<()>285     pub fn generate(&mut self, value: &JsonValue) -> io::Result<()> {
286         if let Some(indent) = &self.indent {
287             self.format(value, indent, 0)
288         } else {
289             self.encode(value)
290         }
291     }
292 }
293 
294 /// Serialize the given `JsonValue` value to `String` without indentation. This method is almost identical to
295 /// `JsonValue::stringify` but exists for a historical reason.
296 ///
297 /// ```
298 /// use tinyjson::JsonValue;
299 ///
300 /// let v = JsonValue::from(vec![1.0.into(), 2.0.into(), 3.0.into()]);
301 /// let s = tinyjson::stringify(&v).unwrap();
302 /// assert_eq!(s, "[1,2,3]");
303 /// ```
stringify(value: &JsonValue) -> JsonGenerateResult304 pub fn stringify(value: &JsonValue) -> JsonGenerateResult {
305     let mut to = Vec::new();
306     let mut gen = JsonGenerator::new(&mut to);
307     gen.generate(value).map_err(|err| JsonGenerateError {
308         msg: format!("{}", err),
309     })?;
310     Ok(String::from_utf8(to).unwrap())
311 }
312 
313 /// Serialize the given `JsonValue` value to `String` with 2-spaces indentation. This method is almost identical to
314 /// `JsonValue::format` but exists for a historical reason.
315 ///
316 /// ```
317 /// use tinyjson::JsonValue;
318 ///
319 /// let v = JsonValue::from(vec![1.0.into(), 2.0.into(), 3.0.into()]);
320 /// let s = tinyjson::format(&v).unwrap();
321 /// assert_eq!(s, "[\n  1,\n  2,\n  3\n]");
322 /// ```
format(value: &JsonValue) -> JsonGenerateResult323 pub fn format(value: &JsonValue) -> JsonGenerateResult {
324     let mut to = Vec::new();
325     let mut gen = JsonGenerator::new(&mut to).indent("  ");
326     gen.generate(value).map_err(|err| JsonGenerateError {
327         msg: format!("{}", err),
328     })?;
329     Ok(String::from_utf8(to).unwrap())
330 }
331