1use crate::JsonValue;
2use std::collections::HashMap;
3use std::fmt;
4use std::io::{self, Write};
5
6#[derive(Debug)]
9pub struct JsonGenerateError {
10 msg: String,
11}
12
13impl JsonGenerateError {
14 pub fn message(&self) -> &str {
15 self.msg.as_str()
16 }
17}
18
19impl fmt::Display for JsonGenerateError {
20 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21 write!(f, "Generate error: {}", &self.msg)
22 }
23}
24
25impl std::error::Error for JsonGenerateError {}
26
27pub type JsonGenerateResult = Result<String, JsonGenerateError>;
29
30pub struct JsonGenerator<'indent, W: Write> {
46 out: W,
47 indent: Option<&'indent str>,
48}
49
50impl<'indent, W: Write> JsonGenerator<'indent, W> {
51 pub fn new(out: W) -> Self {
54 Self { out, indent: None }
55 }
56
57 pub fn indent(mut self, indent: &'indent str) -> Self {
74 self.indent = Some(indent);
75 self
76 }
77
78 fn quote(&mut self, s: &str) -> io::Result<()> {
79 const B: u8 = b'b'; const T: u8 = b't'; const N: u8 = b'n'; const F: u8 = b'f'; const R: u8 = b'r'; const Q: u8 = b'"'; const S: u8 = b'\\'; const U: u8 = 1; #[rustfmt::skip]
89 const ESCAPE_TABLE: [u8; 256] = [
90 U, U, U, U, U, U, U, U, B, T, N, U, F, R, U, U, U, U, U, U, U, U, U, U, U, U, U, U, U, U, U, U, 0, 0, Q, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, S, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ];
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
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
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
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
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
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
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
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
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 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
294pub 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
313pub 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}