1use core::num::NonZero;
2use facet_core::{Def, Facet, FieldAttribute, StructKind};
3use facet_reflect::Peek;
4use std::io::{self, Write};
5
6use crate::First;
7
8pub fn to_string<'a, T: Facet<'a>>(value: &T) -> String {
10 let peek = Peek::new(value);
11 let mut output = Vec::new();
12 serialize(&peek, true, &mut output).unwrap();
13 String::from_utf8(output).unwrap()
14}
15
16pub fn peek_to_string(peek: &Peek<'_, '_>) -> String {
18 let mut output = Vec::new();
19 serialize(peek, true, &mut output).unwrap();
20 String::from_utf8(output).unwrap()
21}
22
23pub fn to_writer<'a, T: Facet<'a>, W: Write>(value: &T, writer: &mut W) -> io::Result<()> {
25 let peek = Peek::new(value);
26 serialize(&peek, true, writer)
27}
28
29pub fn peek_to_writer<W: Write>(peek: &Peek<'_, '_>, writer: &mut W) -> io::Result<()> {
31 serialize(peek, true, writer)
32}
33
34#[derive(Debug)]
36enum SerializeTask<'a, 'mem, 'facet> {
37 Value {
38 peek: Peek<'mem, 'facet>,
39 delimit: bool,
40 },
41 ScalarValue(Peek<'mem, 'facet>),
42 StartStruct {
43 struct_peek: Peek<'mem, 'facet>,
44 delimit: bool,
45 },
46 StructField {
47 field_peek: Peek<'mem, 'facet>,
48 field_name: &'a str,
49 should_delimit: bool,
50 is_first: bool,
51 },
52 EndStruct {
53 delimit: bool,
54 },
55 StartList(Peek<'mem, 'facet>),
56 ListItem {
57 item_peek: Peek<'mem, 'facet>,
58 is_first: bool,
59 },
60 EndList,
61 StartTuple(Peek<'mem, 'facet>),
62 TupleItem {
63 item_peek: Peek<'mem, 'facet>,
64 is_first: bool,
65 },
66 EndTuple,
67 StartMap {
68 map_peek: Peek<'mem, 'facet>,
69 delimit: bool,
70 },
71 MapEntry {
72 key: Peek<'mem, 'facet>,
73 value: Peek<'mem, 'facet>,
74 is_first: bool,
75 },
76 EndMap {
77 delimit: bool,
78 },
79 StartEnum {
80 enum_peek: Peek<'mem, 'facet>,
81 delimit: bool,
83 },
86 EnumStructField {
87 field: &'a facet_core::Field,
88 field_peek: Peek<'mem, 'facet>,
89 field_name: &'a str,
90 is_first: bool,
91 },
92 EnumTupleField {
93 field: &'a facet_core::Field,
94 field_peek: Peek<'mem, 'facet>,
95 is_first: bool,
96 },
97 EndEnum {
98 delimit: bool,
99 is_struct: bool,
100 is_transparent: bool,
101 },
102 StartOption(Peek<'mem, 'facet>),
103}
104
105fn serialize<W: Write>(peek: &Peek<'_, '_>, delimit: bool, writer: &mut W) -> io::Result<()> {
107 use facet_core::{
108 StructDef,
109 StructKind::{Tuple, TupleStruct},
110 };
111
112 let mut stack = Vec::new();
113 stack.push(SerializeTask::Value {
114 peek: *peek,
115 delimit,
116 });
117
118 while let Some(task) = stack.pop() {
119 match task {
120 SerializeTask::Value { peek, delimit } => match peek.shape().def {
121 Def::Scalar(_) => {
122 stack.push(SerializeTask::ScalarValue(peek));
123 }
124 Def::Struct(StructDef {
125 kind: Tuple | TupleStruct,
126 ..
127 }) => {
128 stack.push(SerializeTask::StartTuple(peek));
129 }
130 Def::Struct(_) => {
131 stack.push(SerializeTask::StartStruct {
132 struct_peek: peek,
133 delimit,
134 });
135 }
136 Def::List(_) => {
137 stack.push(SerializeTask::StartList(peek));
138 }
139 Def::Map(_) => {
140 stack.push(SerializeTask::StartMap {
141 map_peek: peek,
142 delimit,
143 });
144 }
145 Def::Enum(_) => {
146 stack.push(SerializeTask::StartEnum {
147 enum_peek: peek,
148 delimit,
149 });
150 }
151 Def::Option(_) => {
152 stack.push(SerializeTask::StartOption(peek));
153 }
154 _ => {
155 return Err(io::Error::new(
156 io::ErrorKind::Other,
157 format!("Unsupported type: {}", peek.shape()),
158 ));
159 }
160 },
161 SerializeTask::ScalarValue(peek) => {
162 serialize_scalar(&peek, writer)?;
163 }
164 SerializeTask::StartStruct {
165 struct_peek,
166 delimit,
167 } => {
168 let struct_peek = struct_peek.into_struct().map_err(|e| {
169 io::Error::new(io::ErrorKind::Other, format!("Not a struct: {}", e))
170 })?;
171
172 if delimit {
173 write!(writer, "{{")?;
174 }
175
176 let fields = struct_peek
178 .fields_for_serialize()
179 .with_first()
180 .collect::<Vec<_>>();
181
182 stack.push(SerializeTask::EndStruct { delimit });
183
184 for (first, (field, field_peek)) in fields.into_iter().rev() {
185 let field_name = field.name;
186
187 let should_delimit = !field.has_arbitrary_attr("flatten");
189
190 stack.push(SerializeTask::StructField {
191 field_peek,
192 field_name,
193 should_delimit,
194 is_first: first,
195 });
196 }
197 }
198 SerializeTask::StructField {
199 field_peek,
200 field_name,
201 should_delimit,
202 is_first,
203 ..
204 } => {
205 if !is_first {
206 write!(writer, ",")?;
207 }
208
209 if should_delimit {
211 write_json_string(writer, field_name)?;
212 write!(writer, ":")?;
213 }
214
215 stack.push(SerializeTask::Value {
217 peek: field_peek,
218 delimit: should_delimit,
219 });
220 }
221 SerializeTask::EndStruct { delimit } => {
222 if delimit {
223 write!(writer, "}}")?;
224 }
225 }
226 SerializeTask::StartList(peek) => {
227 let list_peek = peek.into_list().map_err(|e| {
228 io::Error::new(io::ErrorKind::Other, format!("Not a list: {}", e))
229 })?;
230
231 write!(writer, "[")?;
232
233 let items = list_peek.iter().with_first().collect::<Vec<_>>();
235 stack.push(SerializeTask::EndList);
236
237 for (first, item_peek) in items.into_iter().rev() {
238 stack.push(SerializeTask::ListItem {
239 item_peek,
240 is_first: first,
241 });
242 }
243 }
244 SerializeTask::ListItem {
245 item_peek,
246 is_first,
247 } => {
248 if !is_first {
249 write!(writer, ",")?;
250 }
251
252 stack.push(SerializeTask::Value {
253 peek: item_peek,
254 delimit: true,
255 });
256 }
257 SerializeTask::EndList => {
258 write!(writer, "]")?;
259 }
260 SerializeTask::StartTuple(peek) => {
261 let struct_peek = peek.into_struct().map_err(|e| {
262 io::Error::new(io::ErrorKind::Other, format!("Not a struct: {}", e))
263 })?;
264
265 write!(writer, "[")?;
266
267 let fields = struct_peek
269 .fields_for_serialize()
270 .with_first()
271 .collect::<Vec<_>>();
272
273 stack.push(SerializeTask::EndTuple);
274
275 for (first, (_, item_peek)) in fields.into_iter().rev() {
276 stack.push(SerializeTask::TupleItem {
277 item_peek,
278 is_first: first,
279 });
280 }
281 }
282 SerializeTask::TupleItem {
283 item_peek,
284 is_first,
285 } => {
286 if !is_first {
287 write!(writer, ",")?;
288 }
289
290 stack.push(SerializeTask::Value {
291 peek: item_peek,
292 delimit: true,
293 });
294 }
295 SerializeTask::EndTuple => {
296 write!(writer, "]")?;
297 }
298 SerializeTask::StartMap { map_peek, delimit } => {
299 let map_peek = map_peek.into_map().map_err(|e| {
300 io::Error::new(io::ErrorKind::Other, format!("Not a map: {}", e))
301 })?;
302
303 if delimit {
304 write!(writer, "{{")?;
305 }
306
307 let entries = map_peek.iter().with_first().collect::<Vec<_>>();
309 stack.push(SerializeTask::EndMap { delimit });
310
311 for (first, (key, value)) in entries.into_iter().rev() {
312 stack.push(SerializeTask::MapEntry {
313 key,
314 value,
315 is_first: first,
316 });
317 }
318 }
319 SerializeTask::MapEntry {
320 key,
321 value,
322 is_first,
323 } => {
324 if !is_first {
325 write!(writer, ",")?;
326 }
327
328 match key.shape().def {
330 Def::Scalar(_) => {
331 if key.shape().is_type::<String>() {
333 let key_str = key.get::<String>().unwrap();
334 write_json_string(writer, key_str)?;
335 } else {
336 write!(writer, "\"{}\"", key)?;
338 }
339 }
340 _ => {
341 return Err(io::Error::new(
342 io::ErrorKind::Other,
343 format!("Map keys must be scalar types, got: {}", key.shape()),
344 ));
345 }
346 }
347
348 write!(writer, ":")?;
349
350 stack.push(SerializeTask::Value {
352 peek: value,
353 delimit: true,
354 });
355 }
356 SerializeTask::EndMap { delimit } => {
357 if delimit {
358 write!(writer, "}}")?;
359 }
360 }
361 SerializeTask::StartEnum { enum_peek, delimit } => {
362 let enum_peek = enum_peek.into_enum().map_err(|e| {
363 io::Error::new(io::ErrorKind::Other, format!("Not a map: {}", e))
364 })?;
365 let variant = enum_peek.active_variant();
366 let variant_name = variant.name;
367 let is_empty = variant.data.fields.is_empty();
368 let is_struct = variant.data.kind == StructKind::Struct;
369 if is_empty {
370 write_json_string(writer, variant_name)?;
372 } else {
373 if delimit {
375 write!(writer, "{{")?;
376 }
377 write_json_string(writer, variant_name)?;
378 write!(writer, ":")?;
379
380 let is_transparent = crate::variant_is_transparent(enum_peek.active_variant());
381
382 stack.push(SerializeTask::EndEnum {
383 delimit,
384 is_struct,
385 is_transparent,
386 });
387
388 if is_struct {
389 write!(writer, "{{")?;
391
392 let fields = enum_peek
394 .fields_for_serialize()
395 .with_first()
396 .collect::<Vec<_>>();
397
398 for (first, (field, field_peek)) in fields.into_iter().rev() {
399 stack.push(SerializeTask::EnumStructField {
400 field,
401 field_peek,
402 field_name: field.name,
403 is_first: first,
404 });
405 }
406 } else if is_transparent {
407 if let Some(field) = enum_peek.field(0) {
409 stack.push(SerializeTask::Value {
410 peek: field,
411 delimit: true,
412 });
413 } else {
414 return Err(io::Error::new(
415 io::ErrorKind::Other,
416 "Failed to access enum field",
417 ));
418 }
419 } else {
420 write!(writer, "[")?;
422
423 let fields = enum_peek
425 .fields_for_serialize()
426 .with_first()
427 .collect::<Vec<_>>();
428
429 for (first, (field, field_peek)) in fields.into_iter().rev() {
430 stack.push(SerializeTask::EnumTupleField {
431 field,
432 field_peek,
433 is_first: first,
434 });
435 }
436 }
437 }
438 }
439 SerializeTask::EnumStructField {
440 field_peek,
441 field_name,
442 is_first,
443 field,
444 } => {
445 if !is_first {
446 write!(writer, ",")?;
447 }
448
449 let should_delimit = field
450 .attributes
451 .iter()
452 .any(|&attr| attr == FieldAttribute::Arbitrary("flatten"));
453
454 write_json_string(writer, field_name)?;
455 write!(writer, ":")?;
456
457 stack.push(SerializeTask::Value {
458 peek: field_peek,
459 delimit: should_delimit,
460 });
461 }
462 SerializeTask::EnumTupleField {
463 field_peek,
464 is_first,
465 field,
466 ..
467 } => {
468 if !is_first {
469 write!(writer, ",")?;
470 }
471
472 let should_delimit = field
473 .attributes
474 .iter()
475 .any(|&attr| attr == FieldAttribute::Arbitrary("flatten"));
476
477 stack.push(SerializeTask::Value {
478 peek: field_peek,
479 delimit: should_delimit,
480 });
481 }
482 SerializeTask::EndEnum {
483 delimit,
484 is_struct,
485 is_transparent,
486 } => {
487 if is_struct {
488 write!(writer, "}}")?;
489 } else if !is_transparent {
490 write!(writer, "]")?;
491 }
492
493 if delimit {
494 write!(writer, "}}")?;
495 }
496 }
497 SerializeTask::StartOption(peek) => {
498 let option_peek = peek.into_option().map_err(|e| {
499 io::Error::new(io::ErrorKind::Other, format!("Not an option: {}", e))
500 })?;
501
502 if option_peek.is_none() {
503 write!(writer, "null")?;
504 } else {
505 let value = option_peek.value().ok_or_else(|| {
506 io::Error::new(io::ErrorKind::Other, "Failed to get option value")
507 })?;
508
509 stack.push(SerializeTask::Value {
510 peek: value,
511 delimit: true,
512 });
513 }
514 }
515 }
516 }
517
518 Ok(())
519}
520
521fn serialize_scalar<W: Write>(peek: &Peek<'_, '_>, writer: &mut W) -> io::Result<()> {
523 if peek.shape().is_type::<bool>() {
525 let value = peek.get::<bool>().unwrap();
526 write!(writer, "{}", if *value { "true" } else { "false" })
527 } else if peek.shape().is_type::<String>() {
528 let value = peek.get::<String>().unwrap();
529 write_json_string(writer, value)
530 } else if peek.shape().is_type::<&str>() {
531 let value = peek.get::<&str>().unwrap();
532 write_json_string(writer, value)
533 } else if peek.shape().is_type::<alloc::borrow::Cow<'_, str>>() {
534 let value = peek.get::<alloc::borrow::Cow<'_, str>>().unwrap();
535 write_json_string(writer, value)
536 }
537 else if peek.shape().is_type::<u8>() {
539 let value = peek.get::<u8>().unwrap();
540 write!(writer, "{}", value)
541 } else if peek.shape().is_type::<u16>() {
542 let value = peek.get::<u16>().unwrap();
543 write!(writer, "{}", value)
544 } else if peek.shape().is_type::<u32>() {
545 let value = peek.get::<u32>().unwrap();
546 write!(writer, "{}", value)
547 } else if peek.shape().is_type::<u64>() {
548 let value = peek.get::<u64>().unwrap();
549 write!(writer, "{}", value)
550 } else if peek.shape().is_type::<usize>() {
551 let value = peek.get::<usize>().unwrap();
552 write!(writer, "{}", value)
553 } else if peek.shape().is_type::<i8>() {
554 let value = peek.get::<i8>().unwrap();
555 write!(writer, "{}", value)
556 } else if peek.shape().is_type::<i16>() {
557 let value = peek.get::<i16>().unwrap();
558 write!(writer, "{}", value)
559 } else if peek.shape().is_type::<i32>() {
560 let value = peek.get::<i32>().unwrap();
561 write!(writer, "{}", value)
562 } else if peek.shape().is_type::<i64>() {
563 let value = peek.get::<i64>().unwrap();
564 write!(writer, "{}", value)
565 } else if peek.shape().is_type::<isize>() {
566 let value = peek.get::<isize>().unwrap();
567 write!(writer, "{}", value)
568 }
569 else if peek.shape().is_type::<NonZero<u8>>() {
571 let value = peek.get::<NonZero<u8>>().unwrap();
572 write!(writer, "{}", value)
573 } else if peek.shape().is_type::<NonZero<u16>>() {
574 let value = peek.get::<NonZero<u16>>().unwrap();
575 write!(writer, "{}", value)
576 } else if peek.shape().is_type::<NonZero<u32>>() {
577 let value = peek.get::<NonZero<u32>>().unwrap();
578 write!(writer, "{}", value)
579 } else if peek.shape().is_type::<NonZero<u64>>() {
580 let value = peek.get::<NonZero<u64>>().unwrap();
581 write!(writer, "{}", value)
582 } else if peek.shape().is_type::<NonZero<usize>>() {
583 let value = peek.get::<NonZero<usize>>().unwrap();
584 write!(writer, "{}", value)
585 } else if peek.shape().is_type::<NonZero<i8>>() {
586 let value = peek.get::<NonZero<i8>>().unwrap();
587 write!(writer, "{}", value)
588 } else if peek.shape().is_type::<NonZero<i16>>() {
589 let value = peek.get::<NonZero<i16>>().unwrap();
590 write!(writer, "{}", value)
591 } else if peek.shape().is_type::<NonZero<i32>>() {
592 let value = peek.get::<NonZero<i32>>().unwrap();
593 write!(writer, "{}", value)
594 } else if peek.shape().is_type::<NonZero<i64>>() {
595 let value = peek.get::<NonZero<i64>>().unwrap();
596 write!(writer, "{}", value)
597 } else if peek.shape().is_type::<NonZero<isize>>() {
598 let value = peek.get::<NonZero<isize>>().unwrap();
599 write!(writer, "{}", value)
600 }
601 else if peek.shape().is_type::<f32>() {
603 let value = peek.get::<f32>().unwrap();
604 write!(writer, "{}", value)
605 } else if peek.shape().is_type::<f64>() {
606 let value = peek.get::<f64>().unwrap();
607 write!(writer, "{}", value)
608 } else {
609 Err(io::Error::new(
610 io::ErrorKind::Other,
611 format!("Unsupported scalar type: {}", peek.shape()),
612 ))
613 }
614}
615
616fn write_json_string<W: Write>(writer: &mut W, s: &str) -> io::Result<()> {
618 write!(writer, "\"")?;
619
620 for c in s.chars() {
621 match c {
622 '"' => write!(writer, "\\\"")?,
623 '\\' => write!(writer, "\\\\")?,
624 '\n' => write!(writer, "\\n")?,
625 '\r' => write!(writer, "\\r")?,
626 '\t' => write!(writer, "\\t")?,
627 '\u{08}' => write!(writer, "\\b")?,
628 '\u{0C}' => write!(writer, "\\f")?,
629 c if c.is_control() => write!(writer, "\\u{:04x}", c as u32)?,
630 c => write!(writer, "{}", c)?,
631 }
632 }
633
634 write!(writer, "\"")
635}