facet_json/
serialize.rs

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
8/// Serializes a value to JSON
9pub 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, &mut output).unwrap();
13    String::from_utf8(output).unwrap()
14}
15
16/// Serializes a Peek instance to JSON
17pub fn peek_to_string(peek: &Peek<'_, '_>) -> String {
18    let mut output = Vec::new();
19    serialize(peek, &mut output).unwrap();
20    String::from_utf8(output).unwrap()
21}
22
23/// Serializes a value to a writer in JSON format
24pub 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, writer)
27}
28
29/// Serializes a Peek instance to a writer in JSON format
30pub fn peek_to_writer<W: Write>(peek: &Peek<'_, '_>, writer: &mut W) -> io::Result<()> {
31    serialize(peek, writer)
32}
33
34/// The core serialization function
35fn serialize<W: Write>(peek: &Peek<'_, '_>, writer: &mut W) -> io::Result<()> {
36    use facet_core::{
37        StructDef,
38        StructKind::{Tuple, TupleStruct},
39    };
40
41    match peek.shape().def {
42        Def::Scalar(_) => serialize_scalar(peek, writer),
43        Def::Struct(StructDef {
44            kind: Tuple | TupleStruct,
45            ..
46        }) => serialize_tuple(peek, writer),
47        Def::Struct(_) => serialize_struct(peek, writer),
48        Def::List(_) => serialize_list(peek, writer),
49        Def::Map(_) => serialize_map(peek, writer),
50        Def::Enum(_) => serialize_enum(peek, writer),
51        Def::Option(_) => serialize_option(peek, writer),
52        _ => Err(io::Error::new(
53            io::ErrorKind::Other,
54            format!("Unsupported type: {}", peek.shape()),
55        )),
56    }
57}
58
59/// Serializes a scalar value to JSON
60fn serialize_scalar<W: Write>(peek: &Peek<'_, '_>, writer: &mut W) -> io::Result<()> {
61    // Handle basic scalar types
62    if peek.shape().is_type::<bool>() {
63        let value = peek.get::<bool>().unwrap();
64        write!(writer, "{}", if *value { "true" } else { "false" })
65    } else if peek.shape().is_type::<String>() {
66        let value = peek.get::<String>().unwrap();
67        write_json_string(writer, value)
68    } else if peek.shape().is_type::<&str>() {
69        let value = peek.get::<&str>().unwrap();
70        write_json_string(writer, value)
71    } else if peek.shape().is_type::<alloc::borrow::Cow<'_, str>>() {
72        let value = peek.get::<alloc::borrow::Cow<'_, str>>().unwrap();
73        write_json_string(writer, value)
74    }
75    // Integer types
76    else if peek.shape().is_type::<u8>() {
77        let value = peek.get::<u8>().unwrap();
78        write!(writer, "{}", value)
79    } else if peek.shape().is_type::<u16>() {
80        let value = peek.get::<u16>().unwrap();
81        write!(writer, "{}", value)
82    } else if peek.shape().is_type::<u32>() {
83        let value = peek.get::<u32>().unwrap();
84        write!(writer, "{}", value)
85    } else if peek.shape().is_type::<u64>() {
86        let value = peek.get::<u64>().unwrap();
87        write!(writer, "{}", value)
88    } else if peek.shape().is_type::<usize>() {
89        let value = peek.get::<usize>().unwrap();
90        write!(writer, "{}", value)
91    } else if peek.shape().is_type::<i8>() {
92        let value = peek.get::<i8>().unwrap();
93        write!(writer, "{}", value)
94    } else if peek.shape().is_type::<i16>() {
95        let value = peek.get::<i16>().unwrap();
96        write!(writer, "{}", value)
97    } else if peek.shape().is_type::<i32>() {
98        let value = peek.get::<i32>().unwrap();
99        write!(writer, "{}", value)
100    } else if peek.shape().is_type::<i64>() {
101        let value = peek.get::<i64>().unwrap();
102        write!(writer, "{}", value)
103    } else if peek.shape().is_type::<isize>() {
104        let value = peek.get::<isize>().unwrap();
105        write!(writer, "{}", value)
106    }
107    // NonZero types
108    else if peek.shape().is_type::<NonZero<u8>>() {
109        let value = peek.get::<NonZero<u8>>().unwrap();
110        write!(writer, "{}", value)
111    } else if peek.shape().is_type::<NonZero<u16>>() {
112        let value = peek.get::<NonZero<u16>>().unwrap();
113        write!(writer, "{}", value)
114    } else if peek.shape().is_type::<NonZero<u32>>() {
115        let value = peek.get::<NonZero<u32>>().unwrap();
116        write!(writer, "{}", value)
117    } else if peek.shape().is_type::<NonZero<u64>>() {
118        let value = peek.get::<NonZero<u64>>().unwrap();
119        write!(writer, "{}", value)
120    } else if peek.shape().is_type::<NonZero<usize>>() {
121        let value = peek.get::<NonZero<usize>>().unwrap();
122        write!(writer, "{}", value)
123    } else if peek.shape().is_type::<NonZero<i8>>() {
124        let value = peek.get::<NonZero<i8>>().unwrap();
125        write!(writer, "{}", value)
126    } else if peek.shape().is_type::<NonZero<i16>>() {
127        let value = peek.get::<NonZero<i16>>().unwrap();
128        write!(writer, "{}", value)
129    } else if peek.shape().is_type::<NonZero<i32>>() {
130        let value = peek.get::<NonZero<i32>>().unwrap();
131        write!(writer, "{}", value)
132    } else if peek.shape().is_type::<NonZero<i64>>() {
133        let value = peek.get::<NonZero<i64>>().unwrap();
134        write!(writer, "{}", value)
135    } else if peek.shape().is_type::<NonZero<isize>>() {
136        let value = peek.get::<NonZero<isize>>().unwrap();
137        write!(writer, "{}", value)
138    }
139    // Float types
140    else if peek.shape().is_type::<f32>() {
141        let value = peek.get::<f32>().unwrap();
142        write!(writer, "{}", value)
143    } else if peek.shape().is_type::<f64>() {
144        let value = peek.get::<f64>().unwrap();
145        write!(writer, "{}", value)
146    } else {
147        Err(io::Error::new(
148            io::ErrorKind::Other,
149            format!("Unsupported scalar type: {}", peek.shape()),
150        ))
151    }
152}
153
154/// Serializes a struct to JSON
155fn serialize_struct<W: Write>(peek: &Peek<'_, '_>, writer: &mut W) -> io::Result<()> {
156    let struct_peek = peek
157        .into_struct()
158        .map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Not a struct: {}", e)))?;
159
160    write!(writer, "{{")?;
161
162    for (first, (field, field_peek)) in struct_peek.fields_for_serialize().with_first() {
163        if !first {
164            write!(writer, ",")?;
165        }
166
167        // Check for rename attribute
168        let field_name = field
169            .attributes
170            .iter()
171            .find_map(|attr| {
172                if let FieldAttribute::Rename(name) = attr {
173                    Some(*name)
174                } else {
175                    None
176                }
177            })
178            .unwrap_or(field.name);
179
180        // Write field name
181        write_json_string(writer, field_name)?;
182        write!(writer, ":")?;
183
184        // Write field value
185        serialize(&field_peek, writer)?;
186    }
187
188    write!(writer, "}}")?;
189
190    Ok(())
191}
192
193/// Serializes a list to JSON
194fn serialize_list<W: Write>(peek: &Peek<'_, '_>, writer: &mut W) -> io::Result<()> {
195    let list_peek = peek
196        .into_list()
197        .map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Not a list: {}", e)))?;
198
199    write!(writer, "[")?;
200
201    for (first, item_peek) in list_peek.iter().with_first() {
202        if !first {
203            write!(writer, ",")?;
204        }
205
206        serialize(&item_peek, writer)?;
207    }
208
209    write!(writer, "]")?;
210
211    Ok(())
212}
213
214/// Serializes a tuple (struct) to JSON
215fn serialize_tuple<W: Write>(peek: &Peek<'_, '_>, writer: &mut W) -> io::Result<()> {
216    let struct_peek = peek
217        .into_struct()
218        .map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Not a struct: {}", e)))?;
219
220    write!(writer, "[")?;
221
222    for (first, (_, item_peek)) in struct_peek.fields_for_serialize().with_first() {
223        if !first {
224            write!(writer, ",")?;
225        }
226
227        serialize(&item_peek, writer)?;
228    }
229
230    write!(writer, "]")?;
231
232    Ok(())
233}
234
235/// Serializes a map to JSON
236fn serialize_map<W: Write>(peek: &Peek<'_, '_>, writer: &mut W) -> io::Result<()> {
237    let map_peek = peek
238        .into_map()
239        .map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Not a map: {}", e)))?;
240
241    write!(writer, "{{")?;
242
243    for (first, (key, value)) in map_peek.iter().with_first() {
244        if !first {
245            write!(writer, ",")?;
246        }
247
248        // For map, keys must be converted to strings
249        match key.shape().def {
250            Def::Scalar(_) => {
251                // Try to convert key to string
252                if key.shape().is_type::<String>() {
253                    let key_str = key.get::<String>().unwrap();
254                    write_json_string(writer, key_str)?;
255                } else {
256                    // For other scalar types, use their Display implementation
257                    write!(writer, "\"{}\"", key)?;
258                }
259            }
260            _ => {
261                return Err(io::Error::new(
262                    io::ErrorKind::Other,
263                    format!("Map keys must be scalar types, got: {}", key.shape()),
264                ));
265            }
266        }
267
268        write!(writer, ":")?;
269
270        // Write map value
271        serialize(&value, writer)?;
272    }
273
274    write!(writer, "}}")?;
275
276    Ok(())
277}
278
279/// Serializes an enum to JSON
280fn serialize_enum<W: Write>(peek: &Peek<'_, '_>, writer: &mut W) -> io::Result<()> {
281    let enum_peek = peek
282        .into_enum()
283        .map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Not an enum: {}", e)))?;
284
285    let variant = enum_peek.active_variant();
286    let variant_name = variant.name;
287
288    // Check if this is a unit variant or a variant with data
289    if variant.data.fields.is_empty() {
290        // Unit variant - just output the name as a string
291        write_json_string(writer, variant_name)
292    } else {
293        // Variant with data - output as an object with a single key
294        write!(writer, "{{")?;
295        write_json_string(writer, variant_name)?;
296        write!(writer, ":")?;
297
298        // Multi-field variant - output as an array or object depending on variant type
299        let is_struct = variant.data.kind == StructKind::Struct;
300
301        if is_struct {
302            // Struct variant - output as an object
303            write!(writer, "{{")?;
304
305            for (first, (field, field_peek)) in enum_peek.fields_for_serialize().with_first() {
306                if !first {
307                    write!(writer, ",")?;
308                }
309
310                write_json_string(writer, field.name)?;
311                write!(writer, ":")?;
312                serialize(&field_peek, writer)?;
313            }
314
315            write!(writer, "}}")?
316        } else {
317            // Tuple variant - output as an array if has more than 1 element, otherwise just output
318            // the element.
319
320            if crate::variant_is_transparent(variant) {
321                let field = enum_peek.field(0).ok_or_else(|| {
322                    io::Error::new(io::ErrorKind::Other, "Failed to access enum field")
323                })?;
324                serialize(&field, writer)?;
325            } else {
326                write!(writer, "[")?;
327
328                for (first, (_field, field_peek)) in enum_peek.fields_for_serialize().with_first() {
329                    if !first {
330                        write!(writer, ",")?;
331                    }
332                    serialize(&field_peek, writer)?;
333                }
334
335                write!(writer, "]")?;
336            }
337        }
338
339        write!(writer, "}}")?;
340        Ok(())
341    }
342}
343
344/// Serializes an `Option<T>` to JSON
345fn serialize_option<W: Write>(peek: &Peek<'_, '_>, writer: &mut W) -> io::Result<()> {
346    let option_peek = peek
347        .into_option()
348        .map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Not an option: {}", e)))?;
349
350    if option_peek.is_none() {
351        write!(writer, "null")
352    } else {
353        let value = option_peek
354            .value()
355            .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "Failed to get option value"))?;
356        serialize(&value, writer)
357    }
358}
359
360/// Properly escapes and writes a JSON string
361fn write_json_string<W: Write>(writer: &mut W, s: &str) -> io::Result<()> {
362    write!(writer, "\"")?;
363
364    for c in s.chars() {
365        match c {
366            '"' => write!(writer, "\\\"")?,
367            '\\' => write!(writer, "\\\\")?,
368            '\n' => write!(writer, "\\n")?,
369            '\r' => write!(writer, "\\r")?,
370            '\t' => write!(writer, "\\t")?,
371            '\u{08}' => write!(writer, "\\b")?,
372            '\u{0C}' => write!(writer, "\\f")?,
373            c if c.is_control() => write!(writer, "\\u{:04x}", c as u32)?,
374            c => write!(writer, "{}", c)?,
375        }
376    }
377
378    write!(writer, "\"")
379}