facet_serialize/
lib.rs

1#![cfg_attr(not(feature = "std"), no_std)]
2#![warn(missing_docs)]
3#![warn(clippy::std_instead_of_core)]
4#![warn(clippy::std_instead_of_alloc)]
5#![deny(unsafe_code)]
6#![doc = include_str!("../README.md")]
7
8extern crate alloc;
9
10use alloc::string::String;
11use alloc::vec::Vec;
12
13use facet_core::{Def, Facet, Field, ShapeAttribute, StructKind};
14use facet_reflect::{HasFields, Peek, PeekList, PeekMap, PeekStruct};
15use log::debug;
16
17mod debug_serializer;
18
19fn variant_is_newtype_like(variant: &facet_core::Variant) -> bool {
20    variant.data.kind == facet_core::StructKind::Tuple && variant.data.fields.len() == 1
21}
22
23// --- Serializer Trait Definition ---
24
25/// A trait for implementing format-specific serialization logic.
26/// The core iterative serializer uses this trait to output data.
27pub trait Serializer {
28    /// The error type returned by serialization methods
29    type Error;
30
31    /// Serialize an unsigned 8-bit integer.
32    fn serialize_u8(&mut self, value: u8) -> Result<(), Self::Error>;
33
34    /// Serialize an unsigned 16-bit integer.
35    fn serialize_u16(&mut self, value: u16) -> Result<(), Self::Error>;
36
37    /// Serialize an unsigned 32-bit integer.
38    fn serialize_u32(&mut self, value: u32) -> Result<(), Self::Error>;
39
40    /// Serialize an unsigned 64-bit integer.
41    fn serialize_u64(&mut self, value: u64) -> Result<(), Self::Error>;
42
43    /// Serialize an unsigned 128-bit integer.
44    fn serialize_u128(&mut self, value: u128) -> Result<(), Self::Error>;
45
46    /// Serialize a `usize` integer.
47    fn serialize_usize(&mut self, value: usize) -> Result<(), Self::Error>;
48
49    /// Serialize a signed 8-bit integer.
50    fn serialize_i8(&mut self, value: i8) -> Result<(), Self::Error>;
51
52    /// Serialize a signed 16-bit integer.
53    fn serialize_i16(&mut self, value: i16) -> Result<(), Self::Error>;
54
55    /// Serialize a signed 32-bit integer.
56    fn serialize_i32(&mut self, value: i32) -> Result<(), Self::Error>;
57
58    /// Serialize a signed 64-bit integer.
59    fn serialize_i64(&mut self, value: i64) -> Result<(), Self::Error>;
60
61    /// Serialize a signed 128-bit integer.
62    fn serialize_i128(&mut self, value: i128) -> Result<(), Self::Error>;
63
64    /// Serialize an `isize` integer.
65    fn serialize_isize(&mut self, value: isize) -> Result<(), Self::Error>;
66
67    /// Serialize a single-precision floating-point value.
68    fn serialize_f32(&mut self, value: f32) -> Result<(), Self::Error>;
69
70    /// Serialize a double-precision floating-point value.
71    fn serialize_f64(&mut self, value: f64) -> Result<(), Self::Error>;
72
73    /// Serialize a boolean value.
74    fn serialize_bool(&mut self, value: bool) -> Result<(), Self::Error>;
75
76    /// Serialize a character.
77    fn serialize_char(&mut self, value: char) -> Result<(), Self::Error>;
78
79    /// Serialize a UTF-8 string slice.
80    fn serialize_str(&mut self, value: &str) -> Result<(), Self::Error>;
81
82    /// Serialize a raw byte slice.
83    fn serialize_bytes(&mut self, value: &[u8]) -> Result<(), Self::Error>;
84
85    // Special values
86
87    /// Serialize a `None` variant of an Option type.
88    fn serialize_none(&mut self) -> Result<(), Self::Error>;
89
90    /// Serialize a unit value `()`.
91    fn serialize_unit(&mut self) -> Result<(), Self::Error>;
92
93    // Enum specific values
94
95    /// Serialize a unit variant of an enum (no data).
96    ///
97    /// # Arguments
98    ///
99    /// * `variant_index` - The index of the variant.
100    /// * `variant_name` - The name of the variant.
101    fn serialize_unit_variant(
102        &mut self,
103        variant_index: usize,
104        variant_name: &'static str,
105    ) -> Result<(), Self::Error>;
106
107    /// Begin serializing an object/map-like value.
108    ///
109    /// # Arguments
110    ///
111    /// * `len` - The number of fields, if known.
112    fn start_object(&mut self, len: Option<usize>) -> Result<(), Self::Error>;
113
114    /// Signal the end of serializing an object/map-like value.
115    fn end_object(&mut self) -> Result<(), Self::Error>;
116
117    /// Begin serializing an array/sequence-like value.
118    ///
119    /// # Arguments
120    ///
121    /// * `len` - The number of elements, if known.
122    fn start_array(&mut self, len: Option<usize>) -> Result<(), Self::Error>;
123
124    /// Signal the end of serializing an array/sequence-like value.
125    fn end_array(&mut self) -> Result<(), Self::Error>;
126
127    /// Begin serializing a map/dictionary-like value.
128    ///
129    /// # Arguments
130    ///
131    /// * `len` - The number of entries, if known.
132    fn start_map(&mut self, len: Option<usize>) -> Result<(), Self::Error>;
133
134    /// Signal the end of serializing a map/dictionary-like value.
135    fn end_map(&mut self) -> Result<(), Self::Error>;
136
137    // For objects/maps
138
139    /// Serialize a field name (for objects and maps).
140    ///
141    /// # Arguments
142    ///
143    /// * `name` - The field or key name to serialize.
144    fn serialize_field_name(&mut self, name: &'static str) -> Result<(), Self::Error>;
145}
146
147// --- Iterative Serialization Logic ---
148
149/// Task items for the serialization stack.
150#[derive(Debug)]
151enum SerializeTask<'mem, 'facet> {
152    Value(Peek<'mem, 'facet>, Option<Field>),
153    // End markers
154    EndObject,
155    EndArray,
156    EndMap,
157    // Tasks to push sub-elements onto the stack
158    ObjectFields(PeekStruct<'mem, 'facet>),
159    ArrayItems(PeekList<'mem, 'facet>),
160    TupleStructFields(PeekStruct<'mem, 'facet>),
161    MapEntries(PeekMap<'mem, 'facet>),
162    // Field-related tasks
163    SerializeFieldName(&'static str),
164    SerializeMapKey(Peek<'mem, 'facet>),
165    SerializeMapValue(Peek<'mem, 'facet>),
166}
167
168/// Serializes a `Peek` value using the provided `Serializer`.
169///
170/// This function uses an iterative approach with a stack to avoid recursion depth limits.
171pub fn serialize_iterative<S>(peek: Peek<'_, '_>, serializer: &mut S) -> Result<(), S::Error>
172where
173    S: Serializer,
174{
175    let mut stack = Vec::new();
176    stack.push(SerializeTask::Value(peek, None));
177
178    while let Some(task) = stack.pop() {
179        match task {
180            SerializeTask::Value(mut cpeek, maybe_field) => {
181                debug!("Serializing a value");
182
183                if cpeek
184                    .shape()
185                    .attributes
186                    .iter()
187                    .any(|attr| matches!(attr, ShapeAttribute::Transparent))
188                {
189                    let old_shape = cpeek.shape();
190
191                    // then serialize the inner shape instead
192                    let ps = cpeek.into_struct().unwrap();
193                    cpeek = ps.field(0).unwrap();
194
195                    let new_shape = cpeek.shape();
196                    debug!(
197                        "{old_shape} is transparent, let's serialize the inner {new_shape} instead"
198                    );
199                }
200
201                match cpeek.shape().def {
202                    Def::Scalar(_) => {
203                        let cpeek = cpeek.innermost_peek();
204
205                        // Handle the unit type explicitly first if it's classified as Scalar
206                        if cpeek.shape().is_type::<()>() {
207                            serializer.serialize_unit()?
208                        }
209                        // Dispatch to appropriate scalar serialization method based on type
210                        else if cpeek.shape().is_type::<bool>() {
211                            let value = cpeek.get::<bool>().unwrap();
212                            serializer.serialize_bool(*value)?
213                        } else if cpeek.shape().is_type::<String>() {
214                            let value = cpeek.get::<String>().unwrap();
215                            serializer.serialize_str(value)?
216                        } else if cpeek.shape().is_type::<alloc::borrow::Cow<'_, str>>() {
217                            let value = cpeek.get::<alloc::borrow::Cow<'_, str>>().unwrap();
218                            serializer.serialize_str(value.as_ref())?
219                        } else if cpeek.shape().is_type::<&str>() {
220                            let value = cpeek.get::<&str>().unwrap();
221                            serializer.serialize_str(value)?
222                        } else if cpeek.shape().is_type::<char>() {
223                            let value = cpeek.get::<char>().unwrap();
224                            serializer.serialize_char(*value)?
225                        }
226                        // Integer types
227                        else if cpeek.shape().is_type::<u8>() {
228                            let value = cpeek.get::<u8>().unwrap();
229                            serializer.serialize_u8(*value)?
230                        } else if cpeek.shape().is_type::<u16>() {
231                            let value = cpeek.get::<u16>().unwrap();
232                            serializer.serialize_u16(*value)?
233                        } else if cpeek.shape().is_type::<u32>() {
234                            let value = cpeek.get::<u32>().unwrap();
235                            serializer.serialize_u32(*value)?
236                        } else if cpeek.shape().is_type::<u64>() {
237                            let value = cpeek.get::<u64>().unwrap();
238                            serializer.serialize_u64(*value)?
239                        } else if cpeek.shape().is_type::<u128>() {
240                            let value = cpeek.get::<u128>().unwrap();
241                            serializer.serialize_u128(*value)?
242                        } else if cpeek.shape().is_type::<usize>() {
243                            let value = cpeek.get::<usize>().unwrap();
244                            serializer.serialize_usize(*value)?
245                        } else if cpeek.shape().is_type::<i8>() {
246                            let value = cpeek.get::<i8>().unwrap();
247                            serializer.serialize_i8(*value)?
248                        } else if cpeek.shape().is_type::<i16>() {
249                            let value = cpeek.get::<i16>().unwrap();
250                            serializer.serialize_i16(*value)?
251                        } else if cpeek.shape().is_type::<i32>() {
252                            let value = cpeek.get::<i32>().unwrap();
253                            serializer.serialize_i32(*value)?
254                        } else if cpeek.shape().is_type::<i64>() {
255                            let value = cpeek.get::<i64>().unwrap();
256                            serializer.serialize_i64(*value)?
257                        } else if cpeek.shape().is_type::<i128>() {
258                            let value = cpeek.get::<i128>().unwrap();
259                            serializer.serialize_i128(*value)?
260                        } else if cpeek.shape().is_type::<isize>() {
261                            let value = cpeek.get::<isize>().unwrap();
262                            serializer.serialize_isize(*value)?
263                        }
264                        // Float types
265                        else if cpeek.shape().is_type::<f32>() {
266                            let value = cpeek.get::<f32>().unwrap();
267                            serializer.serialize_f32(*value)?
268                        } else if cpeek.shape().is_type::<f64>() {
269                            let value = cpeek.get::<f64>().unwrap();
270                            serializer.serialize_f64(*value)?
271                        } else {
272                            panic!("Unsupported shape: {}", cpeek.shape());
273                        }
274                    }
275                    Def::Struct(sd) => {
276                        debug!("cpeek.shape(): {}", cpeek.shape());
277                        match sd.kind {
278                            StructKind::Unit => {
279                                // Correctly handle unit struct type when encountered as a value
280                                serializer.serialize_unit()?;
281                            }
282                            StructKind::Tuple | StructKind::TupleStruct => {
283                                let peek_struct = cpeek.into_struct().unwrap();
284                                let fields = peek_struct.fields_for_serialize().count();
285                                serializer.start_array(Some(fields))?;
286                                stack.push(SerializeTask::EndArray);
287                                stack.push(SerializeTask::TupleStructFields(peek_struct));
288                            }
289                            StructKind::Struct => {
290                                let peek_struct = cpeek.into_struct().unwrap();
291                                let fields = peek_struct.fields_for_serialize().count();
292                                serializer.start_object(Some(fields))?;
293                                stack.push(SerializeTask::EndObject);
294                                stack.push(SerializeTask::ObjectFields(peek_struct));
295                            }
296                            _ => {
297                                unreachable!()
298                            }
299                        }
300                    }
301                    Def::Enum(_) => {
302                        let peek_enum = cpeek.into_enum().unwrap();
303                        let variant = peek_enum.active_variant();
304                        let variant_index = peek_enum.variant_index();
305                        let flattened = maybe_field.map(|f| f.flattened).unwrap_or_default();
306
307                        if variant.data.fields.is_empty() {
308                            // Unit variant
309                            serializer.serialize_unit_variant(variant_index, variant.name)?;
310                        } else {
311                            if !flattened {
312                                // For now, treat all enum variants with data as objects
313                                serializer.start_object(Some(1))?;
314                                stack.push(SerializeTask::EndObject);
315
316                                // Serialize variant name as field name
317                                serializer.serialize_field_name(variant.name)?;
318                            }
319
320                            if variant_is_newtype_like(variant) {
321                                // Newtype variant - serialize the inner value directly
322                                let fields = peek_enum.fields_for_serialize().collect::<Vec<_>>();
323                                let (field, field_peek) = fields[0];
324                                // TODO: error if `skip_serialize` is set?
325                                stack.push(SerializeTask::Value(field_peek, Some(field)));
326                            } else if variant.data.kind == StructKind::Tuple
327                                || variant.data.kind == StructKind::TupleStruct
328                            {
329                                // Tuple variant - serialize as array
330                                let fields = peek_enum.fields_for_serialize().count();
331                                serializer.start_array(Some(fields))?;
332                                stack.push(SerializeTask::EndArray);
333
334                                // Push fields in reverse order for tuple variant
335                                for (field, field_peek) in peek_enum.fields_for_serialize().rev() {
336                                    stack.push(SerializeTask::Value(field_peek, Some(field)));
337                                }
338                            } else {
339                                // Struct variant - serialize as object
340                                let fields = peek_enum.fields_for_serialize().count();
341                                serializer.start_object(Some(fields))?;
342                                stack.push(SerializeTask::EndObject);
343
344                                // Push fields in reverse order for struct variant
345                                for (field, field_peek) in peek_enum.fields_for_serialize().rev() {
346                                    stack.push(SerializeTask::Value(field_peek, Some(field)));
347                                    stack.push(SerializeTask::SerializeFieldName(field.name));
348                                }
349                            }
350                        }
351                    }
352                    Def::List(_) | Def::Array(_) | Def::Slice(_) => {
353                        let peek_list = cpeek.into_list().unwrap();
354                        let len = peek_list.len();
355                        serializer.start_array(Some(len))?;
356                        stack.push(SerializeTask::EndArray);
357                        stack.push(SerializeTask::ArrayItems(peek_list));
358                    }
359                    Def::Map(_) => {
360                        let peek_map = cpeek.into_map().unwrap();
361                        let len = peek_map.len();
362                        serializer.start_map(Some(len))?;
363                        stack.push(SerializeTask::EndMap);
364                        stack.push(SerializeTask::MapEntries(peek_map));
365                    }
366                    Def::Option(_) => {
367                        let opt = cpeek.into_option().unwrap();
368                        if let Some(inner_peek) = opt.value() {
369                            stack.push(SerializeTask::Value(inner_peek, None));
370                        } else {
371                            serializer.serialize_none()?;
372                        }
373                    }
374                    Def::SmartPointer(_) => {
375                        let _sp = cpeek.into_smart_pointer().unwrap();
376                        panic!("TODO: Implement serialization for smart pointers");
377                    }
378                    Def::FunctionPointer(_) => {
379                        // Serialize function pointers as units or some special representation
380                        serializer.serialize_unit()?;
381                    }
382                    _ => {
383                        // Default case for any other definitions
384                        serializer.serialize_unit()?;
385                    }
386                }
387            }
388
389            // --- Pushing sub-elements onto the stack ---
390            SerializeTask::ObjectFields(peek_struct) => {
391                // Push fields in reverse order for stack processing
392                for (field, field_peek) in peek_struct.fields_for_serialize().rev() {
393                    stack.push(SerializeTask::Value(field_peek, Some(field)));
394                    stack.push(SerializeTask::SerializeFieldName(field.name));
395                }
396            }
397            SerializeTask::TupleStructFields(peek_struct) => {
398                // Push fields in reverse order
399                for (field, field_peek) in peek_struct.fields_for_serialize().rev() {
400                    stack.push(SerializeTask::Value(field_peek, Some(field)));
401                }
402            }
403            SerializeTask::ArrayItems(peek_list) => {
404                // Push items in reverse order
405                let items: Vec<_> = peek_list.iter().collect();
406                for item_peek in items.into_iter().rev() {
407                    stack.push(SerializeTask::Value(item_peek, None));
408                }
409            }
410            SerializeTask::MapEntries(peek_map) => {
411                // Push entries in reverse order (key, value pairs)
412                let entries = peek_map.iter().collect::<Vec<_>>();
413                for (key_peek, value_peek) in entries.into_iter().rev() {
414                    stack.push(SerializeTask::SerializeMapValue(value_peek));
415                    stack.push(SerializeTask::SerializeMapKey(key_peek));
416                }
417            }
418
419            // --- Field name and map key/value handling ---
420            SerializeTask::SerializeFieldName(name) => {
421                serializer.serialize_field_name(name)?;
422            }
423            SerializeTask::SerializeMapKey(key_peek) => {
424                stack.push(SerializeTask::Value(key_peek, None));
425            }
426            SerializeTask::SerializeMapValue(value_peek) => {
427                stack.push(SerializeTask::Value(value_peek, None));
428            }
429
430            // --- End composite type tasks ---
431            SerializeTask::EndObject => {
432                serializer.end_object()?;
433            }
434            SerializeTask::EndArray => {
435                serializer.end_array()?;
436            }
437            SerializeTask::EndMap => {
438                serializer.end_map()?;
439            }
440        }
441    }
442
443    // Successful completion
444    Ok(())
445}
446
447// --- Helper Trait for Ergonomics ---
448
449/// Extension trait to simplify calling the generic serializer.
450pub trait Serialize<'a>: Facet<'a> {
451    /// Serialize this value using the provided `Serializer`.
452    fn serialize<S: Serializer>(&self, serializer: &mut S) -> Result<(), S::Error>;
453}
454
455impl<'a, T> Serialize<'a> for T
456where
457    T: Facet<'a>,
458{
459    /// Serialize this value using the provided `Serializer`.
460    fn serialize<S: Serializer>(&self, serializer: &mut S) -> Result<(), S::Error> {
461        let peek = Peek::new(self);
462        serialize_iterative(peek, serializer)
463    }
464}