1use core::fmt;
2use printer::JsonPrinter;
3use sizes::JsonSizesVisitor;
4
5use crate::visitor::JsonVisit;
6
7mod printer;
8pub(crate) mod sizes;
9
10#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
11pub enum Indent {
12 Spaces(u8),
13 Tabs(u8),
14}
15
16impl Indent {
17 pub fn by(self, n: usize) -> IndentBy {
18 IndentBy(self, n)
19 }
20}
21
22impl fmt::Display for Indent {
23 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
24 match self {
25 Self::Spaces(n) => {
26 for _ in 0..*n {
27 f.write_str(" ")?
28 }
29 }
30 Self::Tabs(n) => {
31 for _ in 0..*n {
32 f.write_str("\t")?
33 }
34 }
35 }
36
37 Ok(())
38 }
39}
40
41pub struct IndentBy(Indent, usize);
42
43impl fmt::Display for IndentBy {
44 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
45 for _ in 0..self.1 {
46 self.0.fmt(f)?
47 }
48
49 Ok(())
50 }
51}
52
53pub struct Spaces(pub usize);
54
55impl fmt::Display for Spaces {
56 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
57 for _ in 0..self.0 {
58 f.write_str(" ")?
59 }
60
61 Ok(())
62 }
63}
64
65#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
66pub enum Padding {
67 Spaces(u8),
68 NewLine,
69}
70
71impl fmt::Display for Padding {
72 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
73 match self {
74 Self::Spaces(n) => {
75 for _ in 0..*n {
76 f.write_str(" ")?
77 }
78 }
79 Self::NewLine => f.write_str("\n")?,
80 }
81
82 Ok(())
83 }
84}
85
86#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
87pub enum Limit {
88 Always,
90
91 Item(usize),
93
94 Width(usize),
97
98 ItemOrWidth(usize, usize),
102}
103
104#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
106#[non_exhaustive]
107pub struct JsonPrintOptions {
108 pub indent: Indent,
110
111 pub array_begin: usize,
113
114 pub array_end: usize,
116
117 pub array_empty: usize,
119
120 pub array_before_comma: usize,
122
123 pub array_after_comma: usize,
125
126 pub array_limit: Option<Limit>,
128
129 pub object_begin: usize,
131
132 pub object_end: usize,
134
135 pub object_empty: usize,
137
138 pub object_before_comma: usize,
140
141 pub object_after_comma: usize,
143
144 pub object_before_colon: usize,
146
147 pub object_after_colon: usize,
149
150 pub object_limit: Option<Limit>,
152}
153
154impl JsonPrintOptions {
155 pub const PRETTY: Self = Self {
157 indent: Indent::Spaces(2),
158 array_begin: 1,
159 array_end: 1,
160 array_empty: 0,
161 array_before_comma: 0,
162 array_after_comma: 1,
163 array_limit: Some(Limit::ItemOrWidth(1, 16)),
164 object_begin: 1,
165 object_end: 1,
166 object_empty: 0,
167 object_before_comma: 0,
168 object_after_comma: 1,
169 object_before_colon: 0,
170 object_after_colon: 1,
171 object_limit: Some(Limit::ItemOrWidth(1, 16)),
172 };
173
174 pub const COMPACT: Self = Self {
178 indent: Indent::Spaces(0),
179 array_begin: 0,
180 array_end: 0,
181 array_empty: 0,
182 array_before_comma: 0,
183 array_after_comma: 0,
184 array_limit: None,
185 object_begin: 0,
186 object_end: 0,
187 object_empty: 0,
188 object_before_comma: 0,
189 object_after_comma: 0,
190 object_before_colon: 0,
191 object_after_colon: 0,
192 object_limit: None,
193 };
194
195 pub const INLINE: Self = Self {
199 indent: Indent::Spaces(0),
200 array_begin: 1,
201 array_end: 1,
202 array_empty: 0,
203 array_before_comma: 0,
204 array_after_comma: 1,
205 array_limit: None,
206 object_begin: 1,
207 object_end: 1,
208 object_empty: 0,
209 object_before_comma: 0,
210 object_after_comma: 1,
211 object_before_colon: 0,
212 object_after_colon: 1,
213 object_limit: None,
214 };
215}
216
217pub trait JsonPrint {
219 #[inline(always)]
221 fn pretty_print(&self) -> Printed<'_, 'static, Self> {
222 self.print_with(&JsonPrintOptions::PRETTY)
223 }
224
225 #[inline(always)]
227 fn compact_print(&self) -> Printed<'_, 'static, Self> {
228 self.print_with(&JsonPrintOptions::COMPACT)
229 }
230
231 #[inline(always)]
233 fn inline_print(&self) -> Printed<'_, 'static, Self> {
234 self.print_with(&JsonPrintOptions::INLINE)
235 }
236
237 #[inline(always)]
239 fn print_with<'o>(&self, options: &'o JsonPrintOptions) -> Printed<'_, 'o, Self> {
240 Printed(self, options, 0)
241 }
242
243 fn fmt_with(
244 &self,
245 f: &mut fmt::Formatter,
246 options: &JsonPrintOptions,
247 indent: usize,
248 ) -> fmt::Result;
249}
250
251impl<T: JsonVisit> JsonPrint for T {
252 fn fmt_with(
253 &self,
254 f: &mut fmt::Formatter,
255 options: &JsonPrintOptions,
256 indent: usize,
257 ) -> fmt::Result {
258 let mut sizes = Vec::new();
259 self.visit(JsonSizesVisitor::new(options, &mut sizes));
260 let mut offset = 0;
261 self.visit(JsonPrinter::new(options, &sizes, &mut offset, indent, f))
262 }
263}
264
265pub struct Printed<'t, 'o, T: ?Sized>(&'t T, &'o JsonPrintOptions, usize);
267
268impl<T: JsonPrint> fmt::Display for Printed<'_, '_, T> {
269 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
270 self.0.fmt_with(f, self.1, self.2)
271 }
272}