1use facet_reflect::{Peek, PeekValue};
2use log::trace;
3use std::collections::VecDeque;
4use std::io::{self, Write};
5use std::num::NonZero;
6
7macro_rules! prim {
8 ($pv:expr, $writer:expr, $type:ty) => {
9 if $pv.shape().is_type::<$type>() {
10 let value = unsafe { $pv.data().as_ref::<$type>() };
11 return write!($writer, "{}", value);
12 }
13 };
14}
15
16macro_rules! prims {
17 ($pv:expr, $writer:expr, $type:ty, $($types:ty),*) => {
18 prim!($pv, $writer, $type);
19 prims!($pv, $writer, $($types),*);
20 };
21 ($pv:expr, $writer:expr, $type:ty) => {
22 prim!($pv, $writer, $type);
23 };
24}
25
26macro_rules! int {
27 ($pv:expr, $writer:expr, $type:ty) => {
28 prim!($pv, $writer, $type);
29 prim!($pv, $writer, NonZero<$type>);
30 };
31}
32
33macro_rules! ints {
34 ($pv:expr, $writer:expr, $type:ty, $($types:ty),*) => {
35 int!($pv, $writer, $type);
36 ints!($pv, $writer, $($types),*);
37 };
38 ($pv:expr, $writer:expr, $type:ty) => {
39 int!($pv, $writer, $type);
40 };
41}
42
43macro_rules! string {
44 ($pv:expr, $writer:expr, $type:ty) => {
45 if $pv.shape().is_type::<$type>() {
46 let value = unsafe { $pv.data().as_ref::<$type>() };
47 return write!($writer, "\"{}\"", value.escape_debug());
48 }
49 };
50}
51
52macro_rules! strings {
53 ($pv:expr, $writer:expr, $type:ty, $($types:ty),*) => {
54 string!($pv, $writer, $type);
55 strings!($pv, $writer, $($types),*);
56 };
57 ($pv:expr, $writer:expr, $type:ty) => {
58 string!($pv, $writer, $type);
59 };
60}
61
62fn peek_value_to_json<W: Write>(pv: PeekValue, writer: &mut W) -> io::Result<()> {
63 if pv.shape().is_type::<()>() {
64 return write!(writer, "null");
65 }
66 prims!(pv, writer, bool, f32, f64);
67 ints!(
68 pv, writer, u8, i8, u16, i16, u32, i32, u64, i64, u128, i128, usize, isize
69 );
70 strings!(pv, writer, String, std::borrow::Cow<'_, str>, &str);
71
72 write!(writer, "\"<unsupported type>\"")?;
73 Ok(())
74}
75
76pub fn to_json<W: Write>(peek: Peek<'_>, writer: &mut W, indent: bool) -> io::Result<()> {
78 #[derive(Debug)]
79 enum StackItem<'mem> {
80 Value {
81 peek: Peek<'mem>,
82 level: usize,
83 },
84 StructField {
85 field_name: String,
86 peek: Peek<'mem>,
87 level: usize,
88 is_first: bool,
89 },
90 StructEnd {
91 level: usize,
92 had_fields: bool,
93 },
94 ListItem {
95 peek: Peek<'mem>,
96 level: usize,
97 is_first: bool,
98 },
99 ListEnd {
100 level: usize,
101 had_items: bool,
102 },
103 MapEntry {
104 key: Peek<'mem>,
105 value: Peek<'mem>,
106 level: usize,
107 is_first: bool,
108 },
109 MapEnd {
110 level: usize,
111 had_entries: bool,
112 },
113 }
114
115 let mut stack: VecDeque<StackItem> = VecDeque::new();
116 stack.push_back(StackItem::Value { peek, level: 0 });
117
118 while let Some(item) = stack.pop_front() {
119 match item {
120 StackItem::Value { peek, level } => {
121 match peek {
122 Peek::Value(pv) => {
123 peek_value_to_json(pv, writer)?;
124 }
125 Peek::Struct(ps) => {
126 write!(writer, "{{")?;
127 if indent {
128 writeln!(writer)?
129 }
130
131 let fields: Vec<_> = ps.fields().collect();
132 stack.push_front(StackItem::StructEnd {
133 level,
134 had_fields: !fields.is_empty(),
135 });
136
137 for (i, field) in fields.into_iter().enumerate().rev() {
139 stack.push_front(StackItem::StructField {
140 field_name: field.0.to_string(),
141 peek: field.1,
142 level,
143 is_first: i == 0,
144 });
145 }
146 }
147 Peek::List(pl) => {
148 write!(writer, "[")?;
149 if indent {
150 writeln!(writer)?
151 }
152
153 let mut items = Vec::new();
154 let mut index = 0;
155 while let Some(item) = pl.item_at(index) {
156 items.push(item);
157 index += 1;
158 }
159
160 stack.push_front(StackItem::ListEnd {
161 level,
162 had_items: !items.is_empty(),
163 });
164
165 for (i, item) in items.into_iter().enumerate().rev() {
167 stack.push_front(StackItem::ListItem {
168 peek: item,
169 level,
170 is_first: i == 0,
171 });
172 }
173 }
174 Peek::Map(pm) => {
175 write!(writer, "{{")?;
176 if indent {
177 writeln!(writer)?
178 }
179
180 let entries: Vec<(PeekValue<'_>, Peek<'_>)> = pm
182 .iter()
183 .map(|(key, value)| (key.as_value(), value))
184 .collect();
185
186 stack.push_front(StackItem::MapEnd {
187 level,
188 had_entries: !entries.is_empty(),
189 });
190
191 for (i, (key, value)) in entries.into_iter().enumerate().rev() {
193 stack.push_front(StackItem::MapEntry {
194 key: Peek::Value(key),
195 value,
196 level,
197 is_first: i == 0,
198 });
199 }
200 }
201 Peek::Option(popt) => {
202 if let Some(p) = popt.value() {
203 peek_value_to_json(p.as_value(), writer)?
204 } else {
205 write!(writer, "null")?
206 }
207 }
208 _ => todo!("unsupported peek type: {:?}", peek),
209 }
210 }
211 StackItem::StructField {
212 field_name,
213 peek,
214 level,
215 is_first,
216 } => {
217 if !is_first {
218 write!(writer, ",")?;
219 if indent {
220 writeln!(writer)?
221 }
222 }
223
224 if indent {
225 write!(writer, "{:indent$}", "", indent = (level + 1) * 2)?
226 }
227 write!(writer, "\"{}\":", field_name)?;
228 if indent {
229 write!(writer, " ")?
230 }
231
232 stack.push_front(StackItem::Value {
233 peek,
234 level: level + 1,
235 });
236 }
237 StackItem::StructEnd { level, had_fields } => {
238 if had_fields && indent {
239 writeln!(writer)?;
240 write!(writer, "{:indent$}", "", indent = level * 2)?
241 }
242 write!(writer, "}}")?
243 }
244 StackItem::ListItem {
245 peek,
246 level,
247 is_first,
248 } => {
249 if !is_first {
250 write!(writer, ",")?;
251 if indent {
252 writeln!(writer)?
253 }
254 }
255
256 if indent {
257 write!(writer, "{:indent$}", "", indent = (level + 1) * 2)?
258 }
259
260 stack.push_front(StackItem::Value {
261 peek,
262 level: level + 1,
263 });
264 }
265 StackItem::ListEnd { level, had_items } => {
266 if had_items && indent {
267 writeln!(writer)?;
268 write!(writer, "{:indent$}", "", indent = level * 2)?
269 }
270 write!(writer, "]")?
271 }
272 StackItem::MapEntry {
273 key,
274 value,
275 level,
276 is_first,
277 } => {
278 if !is_first {
279 write!(writer, ",")?;
280 if indent {
281 writeln!(writer)?
282 }
283 }
284
285 if indent {
286 write!(writer, "{:indent$}", "", indent = (level + 1) * 2)?
287 }
288
289 let mut temp_writer = Vec::new();
291 let mut temp_stack = VecDeque::new();
292 temp_stack.push_back(StackItem::Value {
293 peek: key,
294 level: 0,
295 });
296
297 while let Some(temp_item) = temp_stack.pop_front() {
298 match temp_item {
299 StackItem::Value { peek, level: _ } => match peek {
300 Peek::Value(pv) => {
301 trace!("{:?}", pv.shape());
302 peek_value_to_json(pv, &mut temp_writer)?
303 }
304 _ => write!(&mut temp_writer, "\"<complex_key>\"")?,
305 },
306 _ => {
307 write!(&mut temp_writer, "\"<invalid_key>\"")?
309 }
310 }
311 }
312
313 let key_string = String::from_utf8(temp_writer).unwrap();
314 write!(writer, "{}:", key_string)?;
315
316 if indent {
317 write!(writer, " ")?
318 }
319
320 stack.push_front(StackItem::Value {
321 peek: value,
322 level: level + 1,
323 });
324 }
325 StackItem::MapEnd { level, had_entries } => {
326 if had_entries && indent {
327 writeln!(writer)?;
328 write!(writer, "{:indent$}", "", indent = level * 2)?
329 }
330 write!(writer, "}}")?
331 }
332 }
333 }
334
335 Ok(())
336}
337
338pub fn to_json_string(peek: Peek<'_>, indent: bool) -> String {
362 let mut buffer = Vec::new();
363 to_json(peek, &mut buffer, indent).unwrap();
364 String::from_utf8(buffer).unwrap()
365}