json_pretty_compact/
fmt.rs

1// MIT License
2//
3// Copyright (c) 2024 Robin Doer
4//
5// Permission is hereby granted, free of charge, to any person obtaining a copy
6// of this software and associated documentation files (the "Software"), to deal
7// in the Software without restriction, including without limitation the rights
8// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9// copies of the Software, and to permit persons to whom the Software is
10// furnished to do so, subject to the following conditions:
11//
12// The above copyright notice and this permission notice shall be included in all
13// copies or substantial portions of the Software.
14//
15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21// SOFTWARE.
22
23use serde_json::ser::{CharEscape, CompactFormatter, Formatter};
24use std::io;
25
26use crate::error::Error;
27use crate::options::Options;
28use crate::token::Token;
29
30fn write_to_vec<F: FnOnce(&mut Vec<u8>) -> io::Result<()>>(f: F) -> io::Result<Vec<u8>> {
31    let mut vec = vec![];
32
33    f(&mut vec).map(|()| vec)
34}
35
36macro_rules! write_func {
37    ($name:ident ( )) => {
38        fn $name<W: ?Sized + io::Write>(&mut self, writer: &mut W) -> io::Result<()> {
39            let vec = write_to_vec(|v| CompactFormatter.$name(v))?;
40
41            self.token.push(Token::Data(vec.into()));
42            self.format_json(writer)
43        }
44    };
45
46    ($name:ident ( $value:ty ) ) => {
47        fn $name<W: ?Sized + io::Write>(
48            &mut self,
49            writer: &mut W,
50            value: $value,
51        ) -> io::Result<()> {
52            let vec = write_to_vec(|v| CompactFormatter.$name(v, value))?;
53
54            self.token.push(Token::Data(vec.into()));
55            self.format_json(writer)
56        }
57    };
58}
59
60/// The formatter.
61///
62/// The `PrettyCompactFormatter` type implements a pretty [serde_json]
63/// formatter which tries to be as compact as possible. This can increase the
64/// readability of formatted JSON.
65///
66/// # Basic usage
67///
68/// * Use [`PrettyCompactFormatter::new()`] to create a formatter with a set of
69///   default rules.
70///
71///   Defaults are:
72///   - indentation: 2 characters
73///   - maximum line length: 120 characters
74///
75/// * Use [`PrettyCompactFormatter::no_rules()`] without any rules.
76///
77///   Without any further applied configuration it acts as a plain pretty
78///   formatter.
79///
80/// # Configuration
81///
82/// * Change the indentation with [`PrettyCompactFormatter::with_indent`].
83///
84/// ```
85/// use json_pretty_compact::PrettyCompactFormatter;
86///
87/// let formatter = PrettyCompactFormatter::new().with_indent(4);
88/// ```
89///
90/// * Change the maximum line length length with
91///   [`PrettyCompactFormatter::with_max_line_length`].
92///
93/// ```
94/// use json_pretty_compact::PrettyCompactFormatter;
95///
96/// let formatter = PrettyCompactFormatter::new().with_max_line_length(80);
97/// ```
98pub struct PrettyCompactFormatter {
99    options: Options,
100    token: Vec<Token>,
101    level: u32,
102}
103
104impl PrettyCompactFormatter {
105    /// Creates a `PrettyCompactFormatter` with a set of default rules.
106    pub fn new() -> PrettyCompactFormatter {
107        Self {
108            options: Options::default(),
109            token: vec![],
110            level: 0,
111        }
112    }
113
114    /// Creates a `PrettyCompactFormatter` without any rules applied.
115    pub fn no_rules() -> PrettyCompactFormatter {
116        Self {
117            options: Options::no_rules(),
118            ..Self::new()
119        }
120    }
121
122    /// Changes the indentation to the given value.
123    pub fn with_indent(mut self, indent: u32) -> Self {
124        self.options.set_indent(indent);
125        self
126    }
127
128    /// Changes the maximum line length to the given value.
129    pub fn with_max_line_length(mut self, len: u32) -> Self {
130        self.options.set_max_len(len);
131        self
132    }
133
134    fn format_json<W: ?Sized + io::Write>(&mut self, writer: &mut W) -> io::Result<()> {
135        if self.token.last().map_or(false, |t| t.is_end_array()) {
136            self.reduce_array()?;
137        } else if self.token.last().map_or(false, |t| t.is_end_object()) {
138            self.reduce_object()?;
139        }
140
141        if self.token.len() == 1 {
142            self.token[0].format(writer, &self.options, None)?;
143        }
144
145        Ok(())
146    }
147
148    fn reduce_array(&mut self) -> Result<(), Error> {
149        let (idx, level) = self
150            .find_last_token(|t| t.as_begin_array())
151            .ok_or(Error::NoArrayStart)?;
152
153        let mut array = self.token.drain(idx..).collect::<Vec<Token>>();
154
155        array.remove(0);
156        array.pop();
157
158        self.token.push(Token::Array(level, array));
159
160        Ok(())
161    }
162
163    fn reduce_object(&mut self) -> Result<(), Error> {
164        let (idx, level) = self
165            .find_last_token(|t| t.as_begin_object())
166            .ok_or(Error::NoObjectStart)?;
167
168        let mut object = self.token.drain(idx..).collect::<Vec<Token>>();
169
170        object.remove(0);
171        object.pop();
172
173        self.token.push(Token::Object(level, object));
174
175        Ok(())
176    }
177
178    fn find_last_token<P: FnMut(&Token) -> Option<u32>>(
179        &self,
180        mut predicate: P,
181    ) -> Option<(usize, u32)> {
182        self.token
183            .iter()
184            .enumerate()
185            .rev()
186            .find_map(|(idx, ev)| predicate(ev).map(|n| (idx, n)))
187    }
188}
189
190impl Default for PrettyCompactFormatter {
191    fn default() -> Self {
192        Self::new()
193    }
194}
195
196impl Formatter for PrettyCompactFormatter {
197    write_func!(write_null());
198    write_func!(write_bool(bool));
199    write_func!(write_i8(i8));
200    write_func!(write_i16(i16));
201    write_func!(write_i32(i32));
202    write_func!(write_i64(i64));
203    write_func!(write_i128(i128));
204    write_func!(write_u8(u8));
205    write_func!(write_u16(u16));
206    write_func!(write_u32(u32));
207    write_func!(write_u64(u64));
208    write_func!(write_u128(u128));
209    write_func!(write_f32(f32));
210    write_func!(write_f64(f64));
211    write_func!(write_number_str(&str));
212
213    fn begin_string<W: ?Sized + io::Write>(&mut self, _writer: &mut W) -> io::Result<()> {
214        self.token.push(Token::Data(b"\"".to_vec()));
215
216        Ok(())
217    }
218
219    fn end_string<W: ?Sized + io::Write>(&mut self, writer: &mut W) -> io::Result<()> {
220        let t = self.token.last_mut().ok_or(Error::EmptyTokenQueue)?;
221        let data = t.as_data_mut_err()?;
222
223        data.extend_from_slice(b"\"");
224
225        self.format_json(writer)
226    }
227
228    fn write_string_fragment<W: ?Sized + io::Write>(
229        &mut self,
230        _writer: &mut W,
231        fragment: &str,
232    ) -> io::Result<()> {
233        let t = self.token.last_mut().ok_or(Error::EmptyTokenQueue)?;
234        let data = t.as_data_mut_err()?;
235
236        data.extend_from_slice(fragment.as_bytes());
237
238        Ok(())
239    }
240
241    fn write_char_escape<W: ?Sized + io::Write>(
242        &mut self,
243        _writer: &mut W,
244        char_escape: CharEscape,
245    ) -> io::Result<()> {
246        let vec = write_to_vec(|v| CompactFormatter.write_char_escape(v, char_escape))?;
247
248        let t = self.token.last_mut().ok_or(Error::EmptyTokenQueue)?;
249        let data = t.as_data_mut_err()?;
250
251        data.extend_from_slice(&vec);
252
253        Ok(())
254    }
255
256    write_func!(write_byte_array(&[u8]));
257
258    fn begin_array<W: ?Sized + io::Write>(&mut self, _writer: &mut W) -> io::Result<()> {
259        self.token.push(Token::BeginArray(self.level));
260        self.level += 1;
261
262        Ok(())
263    }
264
265    fn end_array<W: ?Sized + io::Write>(&mut self, writer: &mut W) -> io::Result<()> {
266        self.token.push(Token::EndArray);
267        self.level -= 1;
268
269        self.format_json(writer)
270    }
271
272    fn begin_array_value<W: ?Sized + io::Write>(
273        &mut self,
274        _writer: &mut W,
275        _first: bool,
276    ) -> io::Result<()> {
277        Ok(())
278    }
279
280    fn end_array_value<W: ?Sized + io::Write>(&mut self, _writer: &mut W) -> io::Result<()> {
281        Ok(())
282    }
283
284    fn begin_object<W: ?Sized + io::Write>(&mut self, _writer: &mut W) -> io::Result<()> {
285        self.token.push(Token::BeginObject(self.level));
286        self.level += 1;
287
288        Ok(())
289    }
290
291    fn end_object<W: ?Sized + io::Write>(&mut self, writer: &mut W) -> io::Result<()> {
292        self.token.push(Token::EndObject);
293        self.level -= 1;
294
295        self.format_json(writer)
296    }
297
298    fn begin_object_key<W: ?Sized + io::Write>(
299        &mut self,
300        _writer: &mut W,
301        _first: bool,
302    ) -> io::Result<()> {
303        Ok(())
304    }
305
306    fn end_object_key<W: ?Sized + io::Write>(&mut self, _writer: &mut W) -> io::Result<()> {
307        Ok(())
308    }
309
310    fn begin_object_value<W: ?Sized + io::Write>(&mut self, _writer: &mut W) -> io::Result<()> {
311        Ok(())
312    }
313
314    fn end_object_value<W: ?Sized + io::Write>(&mut self, _writer: &mut W) -> io::Result<()> {
315        Ok(())
316    }
317
318    write_func!(write_raw_fragment(&str));
319}