facet_format_postcard/
serialize.rs

1//! Serialization support for postcard format.
2//!
3//! This module provides serialization functions using custom traversal logic
4//! optimized for binary formats. Unlike text formats (JSON, YAML), postcard
5//! needs:
6//! - No struct delimiters or field names
7//! - Variant indices instead of variant names
8//! - Type-precise integer encoding (u8 raw, larger varint, signed zigzag)
9//! - Length prefixes before sequences
10
11extern crate alloc;
12
13use alloc::borrow::Cow;
14use alloc::vec::Vec;
15
16use facet_core::{Def, StructKind, Type, UserType};
17use facet_reflect::{HasFields, Peek};
18
19use crate::error::SerializeError;
20
21/// A trait for writing bytes during serialization with error handling.
22///
23/// This trait enables custom serialization targets that can report errors,
24/// such as buffer overflow. It's designed to support use cases like buffer
25/// pooling where you need to detect when a fixed-size buffer is too small.
26///
27/// # Example
28///
29/// ```
30/// use facet_format_postcard::{Writer, SerializeError};
31///
32/// struct PooledWriter {
33///     buf: Vec<u8>,  // In practice, this would be from a buffer pool
34///     overflow: Option<Vec<u8>>,
35/// }
36///
37/// impl Writer for PooledWriter {
38///     fn write_byte(&mut self, byte: u8) -> Result<(), SerializeError> {
39///         // Try pooled buffer first, fall back to Vec on overflow
40///         if let Some(ref mut overflow) = self.overflow {
41///             overflow.push(byte);
42///         } else if self.buf.len() < self.buf.capacity() {
43///             self.buf.push(byte);
44///         } else {
45///             // Overflow - allocate Vec and transfer contents
46///             let mut overflow = Vec::new();
47///             overflow.extend_from_slice(&self.buf);
48///             overflow.push(byte);
49///             self.overflow = Some(overflow);
50///         }
51///         Ok(())
52///     }
53///
54///     fn write_bytes(&mut self, bytes: &[u8]) -> Result<(), SerializeError> {
55///         if let Some(ref mut overflow) = self.overflow {
56///             overflow.extend_from_slice(bytes);
57///         } else if self.buf.len() + bytes.len() <= self.buf.capacity() {
58///             self.buf.extend_from_slice(bytes);
59///         } else {
60///             // Overflow - allocate Vec and transfer contents
61///             let mut overflow = Vec::new();
62///             overflow.extend_from_slice(&self.buf);
63///             overflow.extend_from_slice(bytes);
64///             self.overflow = Some(overflow);
65///         }
66///         Ok(())
67///     }
68/// }
69/// ```
70pub trait Writer {
71    /// Write a single byte to the writer.
72    fn write_byte(&mut self, byte: u8) -> Result<(), SerializeError>;
73
74    /// Write a slice of bytes to the writer.
75    fn write_bytes(&mut self, bytes: &[u8]) -> Result<(), SerializeError>;
76}
77
78impl Writer for Vec<u8> {
79    fn write_byte(&mut self, byte: u8) -> Result<(), SerializeError> {
80        self.push(byte);
81        Ok(())
82    }
83
84    fn write_bytes(&mut self, bytes: &[u8]) -> Result<(), SerializeError> {
85        self.extend_from_slice(bytes);
86        Ok(())
87    }
88}
89
90/// Serializes any Facet type to postcard bytes.
91///
92/// # Example
93/// ```
94/// use facet::Facet;
95/// use facet_format_postcard::to_vec;
96///
97/// #[derive(Debug, Facet)]
98/// struct Point {
99///     x: i32,
100///     y: i32,
101/// }
102///
103/// let point = Point { x: 10, y: 20 };
104/// let bytes = to_vec(&point).unwrap();
105/// ```
106pub fn to_vec<T>(value: &T) -> Result<Vec<u8>, SerializeError>
107where
108    T: facet_core::Facet<'static>,
109{
110    let mut buffer = Vec::new();
111    to_writer_fallible(value, &mut buffer)?;
112    Ok(buffer)
113}
114
115/// Serializes any Facet type to a custom writer implementing the fallible `Writer` trait.
116///
117/// This function allows external crates to implement custom serialization targets
118/// that can report errors, such as buffer overflow. This is useful for use cases
119/// like buffer pooling where you need to detect when a fixed-size buffer is too
120/// small and transparently fall back to heap allocation.
121///
122/// # Example
123/// ```
124/// use facet::Facet;
125/// use facet_format_postcard::{to_writer_fallible, Writer, SerializeError};
126///
127/// #[derive(Debug, Facet)]
128/// struct Point {
129///     x: i32,
130///     y: i32,
131/// }
132///
133/// struct CustomWriter {
134///     buffer: Vec<u8>,
135/// }
136///
137/// impl Writer for CustomWriter {
138///     fn write_byte(&mut self, byte: u8) -> Result<(), SerializeError> {
139///         self.buffer.push(byte);
140///         Ok(())
141///     }
142///
143///     fn write_bytes(&mut self, bytes: &[u8]) -> Result<(), SerializeError> {
144///         self.buffer.extend_from_slice(bytes);
145///         Ok(())
146///     }
147/// }
148///
149/// let point = Point { x: 10, y: 20 };
150/// let mut writer = CustomWriter { buffer: Vec::new() };
151/// to_writer_fallible(&point, &mut writer).unwrap();
152/// ```
153pub fn to_writer_fallible<T, W>(value: &T, writer: &mut W) -> Result<(), SerializeError>
154where
155    T: facet_core::Facet<'static>,
156    W: Writer,
157{
158    let peek = Peek::new(value);
159    serialize_value(peek, writer)
160}
161
162/// Core serialization function using custom traversal for postcard format.
163fn serialize_value<W: Writer>(peek: Peek<'_, '_>, writer: &mut W) -> Result<(), SerializeError> {
164    match (peek.shape().def, peek.shape().ty) {
165        (Def::Scalar, _) => {
166            let peek = peek.innermost_peek();
167            serialize_scalar(peek, writer)
168        }
169        (Def::List(ld), _) => {
170            // Special case for Vec<u8> - serialize as bytes
171            if ld.t().is_type::<u8>() && peek.shape().is_type::<Vec<u8>>() {
172                let bytes = peek.get::<Vec<u8>>().map_err(|e| {
173                    SerializeError::Custom(alloc::format!("Failed to get Vec<u8>: {}", e))
174                })?;
175                write_varint(bytes.len() as u64, writer)?;
176                return writer.write_bytes(bytes);
177            }
178            // Special case for Bytes - serialize as bytes
179            #[cfg(feature = "bytes")]
180            if ld.t().is_type::<u8>() && peek.shape().type_identifier == "Bytes" {
181                use bytes::Bytes;
182                let bytes = peek.get::<Bytes>().map_err(|e| {
183                    SerializeError::Custom(alloc::format!("Failed to get Bytes: {}", e))
184                })?;
185                write_varint(bytes.len() as u64, writer)?;
186                return writer.write_bytes(bytes);
187            }
188            // Special case for BytesMut - serialize as bytes
189            #[cfg(feature = "bytes")]
190            if ld.t().is_type::<u8>() && peek.shape().type_identifier == "BytesMut" {
191                use bytes::BytesMut;
192                let bytes_mut = peek.get::<BytesMut>().map_err(|e| {
193                    SerializeError::Custom(alloc::format!("Failed to get BytesMut: {}", e))
194                })?;
195                write_varint(bytes_mut.len() as u64, writer)?;
196                return writer.write_bytes(bytes_mut);
197            }
198            // General list handling
199            let list = peek.into_list_like().map_err(|e| {
200                SerializeError::Custom(alloc::format!("Failed to convert to list: {}", e))
201            })?;
202            let items: Vec<_> = list.iter().collect();
203            write_varint(items.len() as u64, writer)?;
204            for item in items {
205                serialize_value(item, writer)?;
206            }
207            Ok(())
208        }
209        (Def::Array(ad), _) => {
210            if ad.t().is_type::<u8>() {
211                // Serialize byte arrays directly (length already known from type)
212                let list = peek.into_list_like().map_err(|e| {
213                    SerializeError::Custom(alloc::format!("Failed to convert to list: {}", e))
214                })?;
215                let bytes: Vec<u8> = list
216                    .iter()
217                    .map(|p| {
218                        *p.get::<u8>()
219                            .expect("Failed to get u8 from byte array element")
220                    })
221                    .collect();
222                writer.write_bytes(&bytes)
223            } else {
224                // For fixed-size arrays, postcard doesn't write length
225                let list = peek.into_list_like().map_err(|e| {
226                    SerializeError::Custom(alloc::format!("Failed to convert to list: {}", e))
227                })?;
228                for item in list.iter() {
229                    serialize_value(item, writer)?;
230                }
231                Ok(())
232            }
233        }
234        (Def::Slice(sd), _) => {
235            if sd.t().is_type::<u8>() {
236                let bytes = peek.get::<[u8]>().map_err(|e| {
237                    SerializeError::Custom(alloc::format!("Failed to get [u8]: {}", e))
238                })?;
239                write_varint(bytes.len() as u64, writer)?;
240                writer.write_bytes(bytes)
241            } else {
242                let list = peek.into_list_like().map_err(|e| {
243                    SerializeError::Custom(alloc::format!("Failed to convert to list: {}", e))
244                })?;
245                let items: Vec<_> = list.iter().collect();
246                write_varint(items.len() as u64, writer)?;
247                for item in items {
248                    serialize_value(item, writer)?;
249                }
250                Ok(())
251            }
252        }
253        (Def::Map(_), _) => {
254            let map = peek.into_map().map_err(|e| {
255                SerializeError::Custom(alloc::format!("Failed to convert to map: {}", e))
256            })?;
257            let entries: Vec<_> = map.iter().collect();
258            write_varint(entries.len() as u64, writer)?;
259            for (key, value) in entries {
260                serialize_value(key, writer)?;
261                serialize_value(value, writer)?;
262            }
263            Ok(())
264        }
265        (Def::Set(_), _) => {
266            let set = peek.into_set().map_err(|e| {
267                SerializeError::Custom(alloc::format!("Failed to convert to set: {}", e))
268            })?;
269            let items: Vec<_> = set.iter().collect();
270            write_varint(items.len() as u64, writer)?;
271            for item in items {
272                serialize_value(item, writer)?;
273            }
274            Ok(())
275        }
276        (Def::Option(_), _) => {
277            let opt = peek.into_option().map_err(|e| {
278                SerializeError::Custom(alloc::format!("Failed to convert to option: {}", e))
279            })?;
280            if let Some(inner) = opt.value() {
281                writer.write_byte(1)?; // Some
282                serialize_value(inner, writer)
283            } else {
284                writer.write_byte(0) // None
285            }
286        }
287        (Def::Result(_), _) => {
288            let res = peek.into_result().map_err(|e| {
289                SerializeError::Custom(alloc::format!("Failed to convert to result: {}", e))
290            })?;
291            if let Some(ok_value) = res.ok() {
292                // Ok variant - write 0 as variant index, then the value
293                write_varint(0, writer)?;
294                serialize_value(ok_value, writer)
295            } else if let Some(err_value) = res.err() {
296                // Err variant - write 1 as variant index, then the value
297                write_varint(1, writer)?;
298                serialize_value(err_value, writer)
299            } else {
300                Err(SerializeError::Custom("Invalid Result state".into()))
301            }
302        }
303        (Def::Pointer(_), _) => {
304            let ptr = peek.into_pointer().map_err(|e| {
305                SerializeError::Custom(alloc::format!("Failed to convert to pointer: {}", e))
306            })?;
307            if let Some(inner) = ptr.borrow_inner() {
308                serialize_value(inner, writer)
309            } else {
310                Err(SerializeError::Custom(
311                    "Smart pointer without borrow support".into(),
312                ))
313            }
314        }
315        (_, Type::User(UserType::Struct(sd))) => {
316            match sd.kind {
317                StructKind::Unit => {
318                    // Unit structs serialize as nothing
319                    Ok(())
320                }
321                StructKind::Tuple | StructKind::TupleStruct | StructKind::Struct => {
322                    // All struct kinds serialize fields in order without names
323                    let ps = peek.into_struct().map_err(|e| {
324                        SerializeError::Custom(alloc::format!("Failed to convert to struct: {}", e))
325                    })?;
326                    for (_, field_value) in ps.fields_for_serialize() {
327                        serialize_value(field_value, writer)?;
328                    }
329                    Ok(())
330                }
331            }
332        }
333        (_, Type::User(UserType::Enum(et))) => {
334            let pe = peek.into_enum().map_err(|e| {
335                SerializeError::Custom(alloc::format!("Failed to convert to enum: {}", e))
336            })?;
337            let variant = pe
338                .active_variant()
339                .map_err(|_| SerializeError::Custom("Failed to get active variant".into()))?;
340            let variant_idx = et
341                .variants
342                .iter()
343                .position(|v| v.name == variant.name)
344                .unwrap_or(0);
345
346            // Write variant index as varint
347            write_varint(variant_idx as u64, writer)?;
348
349            if variant.data.fields.is_empty() {
350                // Unit variant - nothing more to write
351                Ok(())
352            } else {
353                // Serialize fields in order
354                for (_, field_value) in pe.fields_for_serialize() {
355                    serialize_value(field_value, writer)?;
356                }
357                Ok(())
358            }
359        }
360        (_, Type::Pointer(_)) => {
361            // Handle string types
362            if let Some(s) = peek.as_str() {
363                write_varint(s.len() as u64, writer)?;
364                writer.write_bytes(s.as_bytes())
365            } else if let Some(bytes) = peek.as_bytes() {
366                write_varint(bytes.len() as u64, writer)?;
367                writer.write_bytes(bytes)
368            } else {
369                let innermost = peek.innermost_peek();
370                if innermost.shape() != peek.shape() {
371                    serialize_value(innermost, writer)
372                } else {
373                    Err(SerializeError::Custom("Unknown pointer type".into()))
374                }
375            }
376        }
377        _ => Err(SerializeError::Custom(alloc::format!(
378            "Unsupported type: {:?}",
379            peek.shape().ty
380        ))),
381    }
382}
383
384/// Serialize a scalar value with type-precise encoding.
385fn serialize_scalar<W: Writer>(peek: Peek<'_, '_>, writer: &mut W) -> Result<(), SerializeError> {
386    use facet_reflect::ScalarType;
387
388    // Check for opaque scalar types that need special handling first
389
390    // Camino types (UTF-8 paths)
391    #[cfg(feature = "camino")]
392    if peek.shape().type_identifier == "Utf8PathBuf" {
393        use camino::Utf8PathBuf;
394        let path = peek.get::<Utf8PathBuf>().map_err(|e| {
395            SerializeError::Custom(alloc::format!("Failed to get Utf8PathBuf: {}", e))
396        })?;
397        let s = path.as_str();
398        write_varint(s.len() as u64, writer)?;
399        return writer.write_bytes(s.as_bytes());
400    }
401    #[cfg(feature = "camino")]
402    if peek.shape().type_identifier == "Utf8Path" {
403        use camino::Utf8Path;
404        let path = peek
405            .get::<Utf8Path>()
406            .map_err(|e| SerializeError::Custom(alloc::format!("Failed to get Utf8Path: {}", e)))?;
407        let s = path.as_str();
408        write_varint(s.len() as u64, writer)?;
409        return writer.write_bytes(s.as_bytes());
410    }
411
412    // UUID - serialize as 16 bytes (native format)
413    #[cfg(feature = "uuid")]
414    if peek.shape().type_identifier == "Uuid" {
415        use uuid::Uuid;
416        let uuid = peek
417            .get::<Uuid>()
418            .map_err(|e| SerializeError::Custom(alloc::format!("Failed to get Uuid: {}", e)))?;
419        return writer.write_bytes(uuid.as_bytes());
420    }
421
422    // ULID - serialize as 16 bytes (native format)
423    #[cfg(feature = "ulid")]
424    if peek.shape().type_identifier == "Ulid" {
425        use ulid::Ulid;
426        let ulid = peek
427            .get::<Ulid>()
428            .map_err(|e| SerializeError::Custom(alloc::format!("Failed to get Ulid: {}", e)))?;
429        return writer.write_bytes(&ulid.to_bytes());
430    }
431
432    // Jiff date/time types - serialize as RFC3339 strings
433    #[cfg(feature = "jiff02")]
434    if peek.shape().type_identifier == "Zoned" {
435        use jiff::Zoned;
436        let zoned = peek
437            .get::<Zoned>()
438            .map_err(|e| SerializeError::Custom(alloc::format!("Failed to get Zoned: {}", e)))?;
439        let s = zoned.to_string();
440        write_varint(s.len() as u64, writer)?;
441        return writer.write_bytes(s.as_bytes());
442    }
443    #[cfg(feature = "jiff02")]
444    if peek.shape().type_identifier == "Timestamp" {
445        use jiff::Timestamp;
446        let ts = peek.get::<Timestamp>().map_err(|e| {
447            SerializeError::Custom(alloc::format!("Failed to get Timestamp: {}", e))
448        })?;
449        let s = ts.to_string();
450        write_varint(s.len() as u64, writer)?;
451        return writer.write_bytes(s.as_bytes());
452    }
453    #[cfg(feature = "jiff02")]
454    if peek.shape().type_identifier == "DateTime" {
455        use jiff::civil::DateTime;
456        let dt = peek
457            .get::<DateTime>()
458            .map_err(|e| SerializeError::Custom(alloc::format!("Failed to get DateTime: {}", e)))?;
459        let s = dt.to_string();
460        write_varint(s.len() as u64, writer)?;
461        return writer.write_bytes(s.as_bytes());
462    }
463
464    // Chrono date/time types - serialize as RFC3339 strings
465    #[cfg(feature = "chrono")]
466    if peek.shape().type_identifier == "DateTime<Utc>" {
467        use chrono::{DateTime, SecondsFormat, Utc};
468        let dt = peek.get::<DateTime<Utc>>().map_err(|e| {
469            SerializeError::Custom(alloc::format!("Failed to get DateTime<Utc>: {}", e))
470        })?;
471        let s = dt.to_rfc3339_opts(SecondsFormat::AutoSi, true);
472        write_varint(s.len() as u64, writer)?;
473        return writer.write_bytes(s.as_bytes());
474    }
475    #[cfg(feature = "chrono")]
476    if peek.shape().type_identifier == "DateTime<Local>" {
477        use chrono::{DateTime, Local, SecondsFormat};
478        let dt = peek.get::<DateTime<Local>>().map_err(|e| {
479            SerializeError::Custom(alloc::format!("Failed to get DateTime<Local>: {}", e))
480        })?;
481        let s = dt.to_rfc3339_opts(SecondsFormat::AutoSi, false);
482        write_varint(s.len() as u64, writer)?;
483        return writer.write_bytes(s.as_bytes());
484    }
485    #[cfg(feature = "chrono")]
486    if peek.shape().type_identifier == "DateTime<FixedOffset>" {
487        use chrono::{DateTime, FixedOffset, SecondsFormat};
488        let dt = peek.get::<DateTime<FixedOffset>>().map_err(|e| {
489            SerializeError::Custom(alloc::format!("Failed to get DateTime<FixedOffset>: {}", e))
490        })?;
491        let s = dt.to_rfc3339_opts(SecondsFormat::AutoSi, false);
492        write_varint(s.len() as u64, writer)?;
493        return writer.write_bytes(s.as_bytes());
494    }
495    #[cfg(feature = "chrono")]
496    if peek.shape().type_identifier == "NaiveDateTime" {
497        use chrono::NaiveDateTime;
498        let dt = peek.get::<NaiveDateTime>().map_err(|e| {
499            SerializeError::Custom(alloc::format!("Failed to get NaiveDateTime: {}", e))
500        })?;
501        // Use same format as facet-core: RFC3339-like without timezone and fractional seconds
502        let s = dt.format("%Y-%m-%dT%H:%M:%S").to_string();
503        write_varint(s.len() as u64, writer)?;
504        return writer.write_bytes(s.as_bytes());
505    }
506    #[cfg(feature = "chrono")]
507    if peek.shape().type_identifier == "NaiveDate" {
508        use chrono::NaiveDate;
509        let date = peek.get::<NaiveDate>().map_err(|e| {
510            SerializeError::Custom(alloc::format!("Failed to get NaiveDate: {}", e))
511        })?;
512        let s = date.to_string();
513        write_varint(s.len() as u64, writer)?;
514        return writer.write_bytes(s.as_bytes());
515    }
516    #[cfg(feature = "chrono")]
517    if peek.shape().type_identifier == "NaiveTime" {
518        use chrono::NaiveTime;
519        let time = peek.get::<NaiveTime>().map_err(|e| {
520            SerializeError::Custom(alloc::format!("Failed to get NaiveTime: {}", e))
521        })?;
522        let s = time.to_string();
523        write_varint(s.len() as u64, writer)?;
524        return writer.write_bytes(s.as_bytes());
525    }
526
527    // Time crate date/time types - serialize as RFC3339 strings
528    #[cfg(feature = "time")]
529    if peek.shape().type_identifier == "UtcDateTime" {
530        use time::UtcDateTime;
531        let dt = peek.get::<UtcDateTime>().map_err(|e| {
532            SerializeError::Custom(alloc::format!("Failed to get UtcDateTime: {}", e))
533        })?;
534        let s = dt
535            .format(&time::format_description::well_known::Rfc3339)
536            .unwrap_or_else(|_| "<invalid>".to_string());
537        write_varint(s.len() as u64, writer)?;
538        return writer.write_bytes(s.as_bytes());
539    }
540    #[cfg(feature = "time")]
541    if peek.shape().type_identifier == "OffsetDateTime" {
542        use time::OffsetDateTime;
543        let dt = peek.get::<OffsetDateTime>().map_err(|e| {
544            SerializeError::Custom(alloc::format!("Failed to get OffsetDateTime: {}", e))
545        })?;
546        let s = dt
547            .format(&time::format_description::well_known::Rfc3339)
548            .unwrap_or_else(|_| "<invalid>".to_string());
549        write_varint(s.len() as u64, writer)?;
550        return writer.write_bytes(s.as_bytes());
551    }
552
553    // OrderedFloat - serialize as the inner float
554    #[cfg(feature = "ordered-float")]
555    if peek.shape().type_identifier == "OrderedFloat" {
556        // Check if it's OrderedFloat<f32> or OrderedFloat<f64> by looking at the inner shape
557        if let Some(inner_shape) = peek.shape().inner {
558            if inner_shape.is_type::<f32>() {
559                use ordered_float::OrderedFloat;
560                let val = peek.get::<OrderedFloat<f32>>().map_err(|e| {
561                    SerializeError::Custom(alloc::format!("Failed to get OrderedFloat<f32>: {}", e))
562                })?;
563                return writer.write_bytes(&val.0.to_le_bytes());
564            } else if inner_shape.is_type::<f64>() {
565                use ordered_float::OrderedFloat;
566                let val = peek.get::<OrderedFloat<f64>>().map_err(|e| {
567                    SerializeError::Custom(alloc::format!("Failed to get OrderedFloat<f64>: {}", e))
568                })?;
569                return writer.write_bytes(&val.0.to_le_bytes());
570            }
571        }
572    }
573
574    // NotNan - serialize as the inner float
575    #[cfg(feature = "ordered-float")]
576    if peek.shape().type_identifier == "NotNan" {
577        // Check if it's NotNan<f32> or NotNan<f64> by looking at the inner shape
578        if let Some(inner_shape) = peek.shape().inner {
579            if inner_shape.is_type::<f32>() {
580                use ordered_float::NotNan;
581                let val = peek.get::<NotNan<f32>>().map_err(|e| {
582                    SerializeError::Custom(alloc::format!("Failed to get NotNan<f32>: {}", e))
583                })?;
584                return writer.write_bytes(&val.into_inner().to_le_bytes());
585            } else if inner_shape.is_type::<f64>() {
586                use ordered_float::NotNan;
587                let val = peek.get::<NotNan<f64>>().map_err(|e| {
588                    SerializeError::Custom(alloc::format!("Failed to get NotNan<f64>: {}", e))
589                })?;
590                return writer.write_bytes(&val.into_inner().to_le_bytes());
591            }
592        }
593    }
594
595    match peek.scalar_type() {
596        Some(ScalarType::Unit) => Ok(()),
597        Some(ScalarType::Bool) => {
598            let v = *peek
599                .get::<bool>()
600                .map_err(|e| SerializeError::Custom(alloc::format!("Failed to get bool: {}", e)))?;
601            writer.write_byte(if v { 1 } else { 0 })
602        }
603        Some(ScalarType::Char) => {
604            let c = *peek
605                .get::<char>()
606                .map_err(|e| SerializeError::Custom(alloc::format!("Failed to get char: {}", e)))?;
607            let mut buf = [0; 4];
608            let s = c.encode_utf8(&mut buf);
609            write_varint(s.len() as u64, writer)?;
610            writer.write_bytes(s.as_bytes())
611        }
612        Some(ScalarType::Str) => {
613            let s = peek
614                .get::<str>()
615                .map_err(|e| SerializeError::Custom(alloc::format!("Failed to get str: {}", e)))?;
616            write_varint(s.len() as u64, writer)?;
617            writer.write_bytes(s.as_bytes())
618        }
619        Some(ScalarType::String) => {
620            let s = peek.get::<alloc::string::String>().map_err(|e| {
621                SerializeError::Custom(alloc::format!("Failed to get String: {}", e))
622            })?;
623            write_varint(s.len() as u64, writer)?;
624            writer.write_bytes(s.as_bytes())
625        }
626        Some(ScalarType::CowStr) => {
627            let s = peek.get::<Cow<'_, str>>().map_err(|e| {
628                SerializeError::Custom(alloc::format!("Failed to get Cow<str>: {}", e))
629            })?;
630            write_varint(s.len() as u64, writer)?;
631            writer.write_bytes(s.as_bytes())
632        }
633        Some(ScalarType::F32) => {
634            let v = *peek
635                .get::<f32>()
636                .map_err(|e| SerializeError::Custom(alloc::format!("Failed to get f32: {}", e)))?;
637            writer.write_bytes(&v.to_le_bytes())
638        }
639        Some(ScalarType::F64) => {
640            let v = *peek
641                .get::<f64>()
642                .map_err(|e| SerializeError::Custom(alloc::format!("Failed to get f64: {}", e)))?;
643            writer.write_bytes(&v.to_le_bytes())
644        }
645        Some(ScalarType::U8) => {
646            let v = *peek
647                .get::<u8>()
648                .map_err(|e| SerializeError::Custom(alloc::format!("Failed to get u8: {}", e)))?;
649            writer.write_byte(v)
650        }
651        Some(ScalarType::U16) => {
652            let v = *peek
653                .get::<u16>()
654                .map_err(|e| SerializeError::Custom(alloc::format!("Failed to get u16: {}", e)))?;
655            write_varint(v as u64, writer)
656        }
657        Some(ScalarType::U32) => {
658            let v = *peek
659                .get::<u32>()
660                .map_err(|e| SerializeError::Custom(alloc::format!("Failed to get u32: {}", e)))?;
661            write_varint(v as u64, writer)
662        }
663        Some(ScalarType::U64) => {
664            let v = *peek
665                .get::<u64>()
666                .map_err(|e| SerializeError::Custom(alloc::format!("Failed to get u64: {}", e)))?;
667            write_varint(v, writer)
668        }
669        Some(ScalarType::U128) => {
670            let v = *peek
671                .get::<u128>()
672                .map_err(|e| SerializeError::Custom(alloc::format!("Failed to get u128: {}", e)))?;
673            write_varint_u128(v, writer)
674        }
675        Some(ScalarType::USize) => {
676            let v = *peek.get::<usize>().map_err(|e| {
677                SerializeError::Custom(alloc::format!("Failed to get usize: {}", e))
678            })?;
679            write_varint(v as u64, writer)
680        }
681        Some(ScalarType::I8) => {
682            let v = *peek
683                .get::<i8>()
684                .map_err(|e| SerializeError::Custom(alloc::format!("Failed to get i8: {}", e)))?;
685            writer.write_byte(v as u8)
686        }
687        Some(ScalarType::I16) => {
688            let v = *peek
689                .get::<i16>()
690                .map_err(|e| SerializeError::Custom(alloc::format!("Failed to get i16: {}", e)))?;
691            write_varint_signed(v as i64, writer)
692        }
693        Some(ScalarType::I32) => {
694            let v = *peek
695                .get::<i32>()
696                .map_err(|e| SerializeError::Custom(alloc::format!("Failed to get i32: {}", e)))?;
697            write_varint_signed(v as i64, writer)
698        }
699        Some(ScalarType::I64) => {
700            let v = *peek
701                .get::<i64>()
702                .map_err(|e| SerializeError::Custom(alloc::format!("Failed to get i64: {}", e)))?;
703            write_varint_signed(v, writer)
704        }
705        Some(ScalarType::I128) => {
706            let v = *peek
707                .get::<i128>()
708                .map_err(|e| SerializeError::Custom(alloc::format!("Failed to get i128: {}", e)))?;
709            write_varint_signed_i128(v, writer)
710        }
711        Some(ScalarType::ISize) => {
712            let v = *peek.get::<isize>().map_err(|e| {
713                SerializeError::Custom(alloc::format!("Failed to get isize: {}", e))
714            })?;
715            write_varint_signed(v as i64, writer)
716        }
717        // Network types - serialize as length-prefixed Display strings
718        #[cfg(feature = "net")]
719        Some(ScalarType::IpAddr) => {
720            let v = *peek.get::<core::net::IpAddr>().map_err(|e| {
721                SerializeError::Custom(alloc::format!("Failed to get IpAddr: {}", e))
722            })?;
723            let s = alloc::format!("{}", v);
724            write_varint(s.len() as u64, writer)?;
725            writer.write_bytes(s.as_bytes())
726        }
727        #[cfg(feature = "net")]
728        Some(ScalarType::Ipv4Addr) => {
729            let v = *peek.get::<core::net::Ipv4Addr>().map_err(|e| {
730                SerializeError::Custom(alloc::format!("Failed to get Ipv4Addr: {}", e))
731            })?;
732            let s = alloc::format!("{}", v);
733            write_varint(s.len() as u64, writer)?;
734            writer.write_bytes(s.as_bytes())
735        }
736        #[cfg(feature = "net")]
737        Some(ScalarType::Ipv6Addr) => {
738            let v = *peek.get::<core::net::Ipv6Addr>().map_err(|e| {
739                SerializeError::Custom(alloc::format!("Failed to get Ipv6Addr: {}", e))
740            })?;
741            let s = alloc::format!("{}", v);
742            write_varint(s.len() as u64, writer)?;
743            writer.write_bytes(s.as_bytes())
744        }
745        #[cfg(feature = "net")]
746        Some(ScalarType::SocketAddr) => {
747            let v = *peek.get::<core::net::SocketAddr>().map_err(|e| {
748                SerializeError::Custom(alloc::format!("Failed to get SocketAddr: {}", e))
749            })?;
750            let s = alloc::format!("{}", v);
751            write_varint(s.len() as u64, writer)?;
752            writer.write_bytes(s.as_bytes())
753        }
754        Some(scalar_type) => Err(SerializeError::Custom(alloc::format!(
755            "Unsupported scalar type: {:?}",
756            scalar_type
757        ))),
758        None => {
759            // Handle bytestring::ByteString
760            #[cfg(feature = "bytestring")]
761            if peek.shape() == <bytestring::ByteString as facet_core::Facet>::SHAPE {
762                let bs = peek.get::<bytestring::ByteString>().map_err(|e| {
763                    SerializeError::Custom(alloc::format!("Failed to get ByteString: {}", e))
764                })?;
765                let s: &str = bs.as_ref();
766                write_varint(s.len() as u64, writer)?;
767                return writer.write_bytes(s.as_bytes());
768            }
769
770            // Handle compact_str::CompactString
771            #[cfg(feature = "compact_str")]
772            if peek.shape() == <compact_str::CompactString as facet_core::Facet>::SHAPE {
773                let cs = peek.get::<compact_str::CompactString>().map_err(|e| {
774                    SerializeError::Custom(alloc::format!("Failed to get CompactString: {}", e))
775                })?;
776                let s: &str = cs.as_str();
777                write_varint(s.len() as u64, writer)?;
778                return writer.write_bytes(s.as_bytes());
779            }
780
781            // Handle smartstring::SmartString<LazyCompact>
782            #[cfg(feature = "smartstring")]
783            if peek.shape()
784                == <smartstring::SmartString<smartstring::LazyCompact> as facet_core::Facet>::SHAPE
785            {
786                let ss = peek
787                    .get::<smartstring::SmartString<smartstring::LazyCompact>>()
788                    .map_err(|e| {
789                        SerializeError::Custom(alloc::format!("Failed to get SmartString: {}", e))
790                    })?;
791                let s: &str = ss.as_str();
792                write_varint(s.len() as u64, writer)?;
793                return writer.write_bytes(s.as_bytes());
794            }
795
796            // Try string as fallback for opaque scalars
797            if let Some(s) = peek.as_str() {
798                write_varint(s.len() as u64, writer)?;
799                writer.write_bytes(s.as_bytes())
800            } else if peek.shape().vtable.has_display() {
801                // Fall back to Display for types like SocketAddrV4/V6
802                let s = alloc::format!("{}", peek);
803                write_varint(s.len() as u64, writer)?;
804                writer.write_bytes(s.as_bytes())
805            } else {
806                Err(SerializeError::Custom(alloc::format!(
807                    "Unknown scalar type: {}",
808                    peek.shape().type_identifier
809                )))
810            }
811        }
812    }
813}
814
815/// Write an unsigned varint (LEB128-like encoding used by postcard)
816fn write_varint<W: Writer>(mut value: u64, writer: &mut W) -> Result<(), SerializeError> {
817    loop {
818        let mut byte = (value & 0x7F) as u8;
819        value >>= 7;
820        if value != 0 {
821            byte |= 0x80;
822        }
823        writer.write_byte(byte)?;
824        if value == 0 {
825            break;
826        }
827    }
828    Ok(())
829}
830
831/// Write an unsigned 128-bit varint
832fn write_varint_u128<W: Writer>(mut value: u128, writer: &mut W) -> Result<(), SerializeError> {
833    loop {
834        let mut byte = (value & 0x7F) as u8;
835        value >>= 7;
836        if value != 0 {
837            byte |= 0x80;
838        }
839        writer.write_byte(byte)?;
840        if value == 0 {
841            break;
842        }
843    }
844    Ok(())
845}
846
847/// Write a signed varint using zigzag encoding
848fn write_varint_signed<W: Writer>(value: i64, writer: &mut W) -> Result<(), SerializeError> {
849    // Zigzag encoding: (value << 1) ^ (value >> 63)
850    let encoded = ((value << 1) ^ (value >> 63)) as u64;
851    write_varint(encoded, writer)
852}
853
854/// Write a signed 128-bit varint using zigzag encoding
855fn write_varint_signed_i128<W: Writer>(value: i128, writer: &mut W) -> Result<(), SerializeError> {
856    // Zigzag encoding: (value << 1) ^ (value >> 127)
857    let encoded = ((value << 1) ^ (value >> 127)) as u128;
858    write_varint_u128(encoded, writer)
859}
860
861#[cfg(test)]
862mod tests {
863    use super::*;
864    use facet::Facet;
865    use postcard::to_allocvec as postcard_to_vec;
866    use serde::Serialize;
867
868    #[derive(Facet, Serialize, PartialEq, Debug)]
869    struct SimpleStruct {
870        a: u32,
871        b: alloc::string::String,
872        c: bool,
873    }
874
875    #[test]
876    fn test_simple_struct() {
877        facet_testhelpers::setup();
878
879        let value = SimpleStruct {
880            a: 123,
881            b: "hello".into(),
882            c: true,
883        };
884
885        let facet_bytes = to_vec(&value).unwrap();
886        let postcard_bytes = postcard_to_vec(&value).unwrap();
887
888        assert_eq!(facet_bytes, postcard_bytes);
889    }
890
891    #[test]
892    fn test_u8() {
893        facet_testhelpers::setup();
894
895        #[derive(Facet, Serialize, PartialEq, Debug)]
896        struct U8Struct {
897            value: u8,
898        }
899
900        let value = U8Struct { value: 42 };
901        let facet_bytes = to_vec(&value).unwrap();
902        let postcard_bytes = postcard_to_vec(&value).unwrap();
903        assert_eq!(facet_bytes, postcard_bytes);
904    }
905
906    #[test]
907    fn test_i32() {
908        facet_testhelpers::setup();
909
910        #[derive(Facet, Serialize, PartialEq, Debug)]
911        struct I32Struct {
912            value: i32,
913        }
914
915        let value = I32Struct { value: -100000 };
916        let facet_bytes = to_vec(&value).unwrap();
917        let postcard_bytes = postcard_to_vec(&value).unwrap();
918        assert_eq!(facet_bytes, postcard_bytes);
919    }
920
921    #[test]
922    fn test_string() {
923        facet_testhelpers::setup();
924
925        #[derive(Facet, Serialize, PartialEq, Debug)]
926        struct StringStruct {
927            value: alloc::string::String,
928        }
929
930        let value = StringStruct {
931            value: "hello world".into(),
932        };
933        let facet_bytes = to_vec(&value).unwrap();
934        let postcard_bytes = postcard_to_vec(&value).unwrap();
935        assert_eq!(facet_bytes, postcard_bytes);
936    }
937
938    #[test]
939    fn test_vec() {
940        facet_testhelpers::setup();
941
942        #[derive(Facet, Serialize, PartialEq, Debug)]
943        struct VecStruct {
944            values: Vec<u32>,
945        }
946
947        let value = VecStruct {
948            values: alloc::vec![1, 2, 3, 4, 5],
949        };
950        let facet_bytes = to_vec(&value).unwrap();
951        let postcard_bytes = postcard_to_vec(&value).unwrap();
952        assert_eq!(facet_bytes, postcard_bytes);
953    }
954
955    #[test]
956    fn test_option_some() {
957        facet_testhelpers::setup();
958
959        #[derive(Facet, Serialize, PartialEq, Debug)]
960        struct OptionStruct {
961            value: Option<u32>,
962        }
963
964        let value = OptionStruct { value: Some(42) };
965        let facet_bytes = to_vec(&value).unwrap();
966        let postcard_bytes = postcard_to_vec(&value).unwrap();
967        assert_eq!(facet_bytes, postcard_bytes);
968    }
969
970    #[test]
971    fn test_option_none() {
972        facet_testhelpers::setup();
973
974        #[derive(Facet, Serialize, PartialEq, Debug)]
975        struct OptionStruct {
976            value: Option<u32>,
977        }
978
979        let value = OptionStruct { value: None };
980        let facet_bytes = to_vec(&value).unwrap();
981        let postcard_bytes = postcard_to_vec(&value).unwrap();
982        assert_eq!(facet_bytes, postcard_bytes);
983    }
984
985    #[test]
986    fn test_unit_enum() {
987        facet_testhelpers::setup();
988
989        #[derive(Facet, Serialize, PartialEq, Debug)]
990        #[repr(C)]
991        enum Color {
992            Red,
993            Green,
994            Blue,
995        }
996
997        let facet_bytes = to_vec(&Color::Red).unwrap();
998        let postcard_bytes = postcard_to_vec(&Color::Red).unwrap();
999        assert_eq!(facet_bytes, postcard_bytes);
1000
1001        let facet_bytes = to_vec(&Color::Green).unwrap();
1002        let postcard_bytes = postcard_to_vec(&Color::Green).unwrap();
1003        assert_eq!(facet_bytes, postcard_bytes);
1004
1005        let facet_bytes = to_vec(&Color::Blue).unwrap();
1006        let postcard_bytes = postcard_to_vec(&Color::Blue).unwrap();
1007        assert_eq!(facet_bytes, postcard_bytes);
1008    }
1009
1010    #[test]
1011    fn test_tuple_enum() {
1012        facet_testhelpers::setup();
1013
1014        #[derive(Facet, Serialize, PartialEq, Debug)]
1015        #[repr(C)]
1016        enum Value {
1017            Int(i32),
1018            Text(alloc::string::String),
1019        }
1020
1021        let facet_bytes = to_vec(&Value::Int(42)).unwrap();
1022        let postcard_bytes = postcard_to_vec(&Value::Int(42)).unwrap();
1023        assert_eq!(facet_bytes, postcard_bytes);
1024
1025        let facet_bytes = to_vec(&Value::Text("hello".into())).unwrap();
1026        let postcard_bytes = postcard_to_vec(&Value::Text("hello".into())).unwrap();
1027        assert_eq!(facet_bytes, postcard_bytes);
1028    }
1029
1030    #[test]
1031    fn test_struct_enum() {
1032        facet_testhelpers::setup();
1033
1034        #[derive(Facet, Serialize, PartialEq, Debug)]
1035        #[repr(C)]
1036        enum Message {
1037            Quit,
1038            Move { x: i32, y: i32 },
1039        }
1040
1041        let facet_bytes = to_vec(&Message::Quit).unwrap();
1042        let postcard_bytes = postcard_to_vec(&Message::Quit).unwrap();
1043        assert_eq!(facet_bytes, postcard_bytes);
1044
1045        let facet_bytes = to_vec(&Message::Move { x: 10, y: 20 }).unwrap();
1046        let postcard_bytes = postcard_to_vec(&Message::Move { x: 10, y: 20 }).unwrap();
1047        assert_eq!(facet_bytes, postcard_bytes);
1048    }
1049
1050    #[test]
1051    fn test_to_writer_fallible() {
1052        facet_testhelpers::setup();
1053
1054        struct CustomWriter {
1055            buffer: Vec<u8>,
1056        }
1057
1058        impl Writer for CustomWriter {
1059            fn write_byte(&mut self, byte: u8) -> Result<(), SerializeError> {
1060                self.buffer.push(byte);
1061                Ok(())
1062            }
1063
1064            fn write_bytes(&mut self, bytes: &[u8]) -> Result<(), SerializeError> {
1065                self.buffer.extend_from_slice(bytes);
1066                Ok(())
1067            }
1068        }
1069
1070        let value = SimpleStruct {
1071            a: 123,
1072            b: "hello".into(),
1073            c: true,
1074        };
1075
1076        let mut writer = CustomWriter { buffer: Vec::new() };
1077        to_writer_fallible(&value, &mut writer).unwrap();
1078
1079        let postcard_bytes = postcard_to_vec(&value).unwrap();
1080        assert_eq!(writer.buffer, postcard_bytes);
1081    }
1082}