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