facet_json/
serialize.rs

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