facet_format_postcard/lib.rs
1//! Postcard binary format for facet.
2//!
3//! This crate provides serialization and deserialization for the postcard binary format.
4//!
5//! # Serialization
6//!
7//! Serialization supports all types that implement [`facet_core::Facet`]:
8//!
9//! ```
10//! use facet::Facet;
11//! use facet_format_postcard::to_vec;
12//!
13//! #[derive(Facet)]
14//! struct Point { x: i32, y: i32 }
15//!
16//! let point = Point { x: 10, y: 20 };
17//! let bytes = to_vec(&point).unwrap();
18//! ```
19//!
20//! # Deserialization
21//!
22//! Deserialization uses a multi-tier approach:
23//!
24//! ```ignore
25//! use facet_format_postcard::from_slice;
26//!
27//! let bytes = &[0x03, 0x01, 0x00, 0x01];
28//! let result: Vec<bool> = from_slice(bytes).unwrap();
29//! ```
30//!
31//! The `from_slice` function automatically selects the best deserialization tier:
32//! - **Tier-2 (Format JIT)**: Fastest path for compatible types (primitives, structs, vecs, simple enums)
33//! - **Tier-0 (Reflection)**: Fallback for all other types (nested enums, complex types)
34//!
35//! This ensures all `Facet` types can be deserialized, making this crate a complete
36//! replacement for `facet-postcard`.
37
38#![cfg_attr(not(feature = "jit"), forbid(unsafe_code))]
39
40extern crate alloc;
41
42mod error;
43mod parser;
44mod serialize;
45
46#[cfg(feature = "jit")]
47pub mod jit;
48
49#[cfg(feature = "axum")]
50mod axum;
51
52#[cfg(feature = "axum")]
53pub use axum::{Postcard, PostcardRejection, PostcardSerializeRejection};
54pub use error::{PostcardError, SerializeError};
55#[cfg(feature = "jit")]
56pub use jit::PostcardJitFormat;
57pub use parser::PostcardParser;
58pub use serialize::{Writer, to_vec, to_writer_fallible};
59
60// Re-export DeserializeError for convenience
61pub use facet_format::DeserializeError;
62
63/// Deserialize a value from postcard bytes.
64///
65/// This tries Tier-2 JIT deserialization first, then falls back to Tier-0
66/// reflection-based deserialization if the type isn't Tier-2 compatible.
67///
68/// # Example
69///
70/// ```
71/// use facet_format_postcard::from_slice;
72///
73/// // Postcard encoding: [length=3, true, false, true]
74/// let bytes = &[0x03, 0x01, 0x00, 0x01];
75/// let result: Vec<bool> = from_slice(bytes).unwrap();
76/// assert_eq!(result, vec![true, false, true]);
77/// ```
78#[cfg(feature = "jit")]
79pub fn from_slice<'de, T>(input: &'de [u8]) -> Result<T, DeserializeError<PostcardError>>
80where
81 T: facet_core::Facet<'de>,
82{
83 let mut parser = PostcardParser::new(input);
84
85 // Try Tier-2 format JIT first (fastest path)
86 match facet_format::jit::try_deserialize_format::<T, _>(&mut parser) {
87 Some(result) => result,
88 // Fall back to Tier-0 (reflection-based deserialization)
89 None => {
90 use facet_format::FormatDeserializer;
91 FormatDeserializer::new(parser).deserialize()
92 }
93 }
94}
95
96/// Deserialize a value from postcard bytes (non-JIT fallback).
97///
98/// This function is only available when the `jit` feature is disabled.
99/// It uses Tier-0 reflection-based deserialization, which is slower than JIT
100/// but works on all platforms including WASM.
101#[cfg(not(feature = "jit"))]
102pub fn from_slice<'de, T>(input: &'de [u8]) -> Result<T, DeserializeError<PostcardError>>
103where
104 T: facet_core::Facet<'de>,
105{
106 use facet_format::FormatDeserializer;
107 let parser = PostcardParser::new(input);
108 FormatDeserializer::new(parser).deserialize()
109}