1use crate::{Tag, Val};
8use alloc::string::String;
9use core::fmt::{self, Formatter};
10use std::io::{self, Write};
11
12#[macro_export]
19macro_rules! write_byte {
20 ($w:ident, $c:expr, $f:expr) => {{
21 match $c {
22 0x08 => write!($w, "\\b"),
24 0x0c => write!($w, "\\f"),
25 c @ (b'\t' | b'\n' | b'\r' | b'\\' | b'"') => {
26 write!($w, "{}", char::from(c).escape_default())
27 }
28 0x00..=0x1F | 0x7F..=0xFF => $f,
29 c => write!($w, "{}", char::from(c)),
30 }
31 }};
32}
33
34#[macro_export]
38macro_rules! write_utf8 {
39 ($w:ident, $s:ident, $f:expr) => {{
40 write!($w, "\"")?;
41 let is_special = |c| matches!(c, 0x00..=0x1F | b'\\' | b'"' | 0x7F);
42 for s in $s.split_inclusive(|c| is_special(*c)) {
43 match s.split_last() {
44 Some((last, init)) if is_special(*last) => {
45 $f(init)?;
46 $crate::write_byte!($w, *last, write!($w, "\\u{last:04x}"))?
47 }
48 _ => $f(s)?,
49 }
50 }
51 write!($w, "\"")
52 }};
53}
54
55#[macro_export]
59macro_rules! write_bytes {
60 ($w:ident, $s:ident) => {{
61 write!($w, "b\"")?;
62 $s.iter()
63 .try_for_each(|c| $crate::write_byte!($w, *c, write!($w, "\\x{c:02x}")))?;
64 write!($w, "\"")
65 }};
66}
67
68macro_rules! write_seq {
69 ($w:ident, $pp:expr, $level:expr, $xs:expr, $f:expr) => {{
70 let indent = &$pp.indent;
71 if indent.is_some() {
72 writeln!($w)?;
73 }
74 let mut iter = $xs.into_iter().peekable();
75 while let Some(x) = iter.next() {
76 if let Some(indent) = indent {
77 write!($w, "{}", indent.repeat($level + 1))?;
78 }
79 $f(x)?;
80 if iter.peek().is_some() {
81 write!($w, ",")?;
82 if $pp.sep_space && indent.is_none() {
83 write!($w, " ")?
84 }
85 }
86 if indent.is_some() {
87 writeln!($w)?
88 }
89 }
90 if let Some(indent) = indent {
91 write!($w, "{}", indent.repeat($level))
92 } else {
93 Ok(())
94 }
95 }};
96}
97
98#[derive(Clone, Default)]
100pub struct Colors<S = String> {
101 pub null: S,
103 pub r#false: S,
105 pub r#true: S,
107 pub num: S,
109 pub str: S,
111 pub arr: S,
113 pub obj: S,
115
116 pub bstr: S,
118
119 pub reset: S,
121}
122
123impl Colors {
124 pub fn ansi() -> Self {
126 let mut cols = Colors::default().parse("90:39:39:39:32:1;39:1;39");
127 cols.bstr = "\x1b[31m".into();
128 cols.reset = "\x1b[0m".into();
129 cols
130 }
131
132 pub fn parse(mut self, s: &str) -> Self {
134 let fields = [
135 &mut self.null,
136 &mut self.r#false,
137 &mut self.r#true,
138 &mut self.num,
139 &mut self.str,
140 &mut self.arr,
141 &mut self.obj,
142 ];
143 for (style, field) in s.split(':').zip(fields) {
144 *field = alloc::format!("\x1b[{style}m");
145 }
146 self
147 }
148}
149
150#[derive(Clone, Default)]
152pub struct Pp<S = String> {
153 pub indent: Option<S>,
155 pub sort_keys: bool,
157 pub colors: Colors<S>,
159 pub sep_space: bool,
165}
166
167impl Pp {
168 pub fn write_str(
170 &self,
171 w: &mut dyn Write,
172 f: impl FnOnce(&mut dyn Write) -> io::Result<()>,
173 ) -> io::Result<()> {
174 write!(w, "{}", self.colors.str)?;
175 f(w)?;
176 write!(w, "{}", self.colors.reset)
177 }
178}
179
180macro_rules! write_val {
189 ($w:ident, $pp:ident, $level:expr, $v:ident, $f:expr) => {{
190 macro_rules! color {
191 ($style:ident, $g:expr) => {{
192 write!($w, "{}", $pp.colors.$style)?;
193 $g?;
194 write!($w, "{}", $pp.colors.reset)
195 }};
196 }
197 match $v {
198 Val::Null => color!(null, write!($w, "null")),
199 Val::Bool(true) => color!(r#true, write!($w, "true")),
200 Val::Bool(false) => color!(r#false, write!($w, "false")),
201 Val::Num(n) => color!(num, write!($w, "{n}")),
202 Val::Str(b, $crate::Tag::Bytes) => color!(bstr, $crate::write_bytes!($w, b)),
203 Val::Str(s, $crate::Tag::Utf8) => color!(
204 str,
205 write_utf8!($w, s, |part| write!($w, "{}", $crate::bstr(part)))
206 ),
207 Val::Arr(a) => {
208 color!(arr, write!($w, "["))?;
209 if !a.is_empty() {
210 write_seq!($w, $pp, $level, &**a, |x| $f($level + 1, x))?;
211 }
212 color!(arr, write!($w, "]"))
213 }
214 Val::Obj(o) => {
215 color!(obj, write!($w, "{{"))?;
216 macro_rules! kv {
217 ($kv:expr) => {{
218 let (k, v) = $kv;
219 $f($level + 1, k)?;
220 color!(obj, write!($w, ":"))?;
221 if $pp.sep_space {
222 write!($w, " ")?;
223 }
224 $f($level + 1, v)
225 }};
226 }
227 if !o.is_empty() {
228 if $pp.sort_keys {
229 let mut o: alloc::vec::Vec<_> = o.iter().collect();
230 o.sort_by_key(|(k, _v)| *k);
231 write_seq!($w, $pp, $level, o, |x| kv!(x))
232 } else {
233 write_seq!($w, $pp, $level, &**o, |x| kv!(x))
234 }?
235 }
236 color!(obj, write!($w, "}}"))
237 }
238 }
239 }};
240}
241
242type WriteFn = fn(&mut dyn Write, &Pp, usize, &Val) -> io::Result<()>;
243type FormatFn = fn(&mut Formatter, &Pp, usize, &Val) -> fmt::Result;
244
245pub fn write_with(w: &mut dyn Write, pp: &Pp, level: usize, v: &Val, f: WriteFn) -> io::Result<()> {
247 match v {
248 Val::Str(s, Tag::Utf8) => pp.write_str(w, |w| write_utf8!(w, s, |part| w.write_all(part))),
249 _ => write_val!(w, pp, level, v, |level, x| f(w, pp, level, x)),
250 }
251}
252
253pub fn format_with(w: &mut Formatter, pp: &Pp, level: usize, v: &Val, f: FormatFn) -> fmt::Result {
257 write_val!(w, pp, level, v, |level, x| f(w, pp, level, x))
258}
259
260pub fn write(w: &mut dyn Write, pp: &Pp, level: usize, v: &Val) -> io::Result<()> {
288 write_with(w, pp, level, v, write)
289}
290
291pub(crate) fn format(w: &mut Formatter, pp: &Pp, level: usize, v: &Val) -> fmt::Result {
292 format_with(w, pp, level, v, format)
293}