facet_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_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//! There are three deserialization functions:
23//!
24//! - [`from_slice`]: Deserializes into owned types (`T: Facet<'static>`)
25//! - [`from_slice_borrowed`]: Deserializes with zero-copy borrowing from the input buffer
26//! - [`from_slice_with_shape`]: Deserializes into `Value` using runtime shape information
27//!
28//! ```
29//! use facet_postcard::from_slice;
30//!
31//! // Postcard encoding: [length=3, true, false, true]
32//! let bytes = &[0x03, 0x01, 0x00, 0x01];
33//! let result: Vec<bool> = from_slice(bytes).unwrap();
34//! assert_eq!(result, vec![true, false, true]);
35//! ```
36//!
37//! Both functions automatically select the best deserialization tier:
38//! - **Tier-2 (Format JIT)**: Fastest path for compatible types (primitives, structs, vecs, simple enums)
39//! - **Tier-0 (Reflection)**: Fallback for all other types (nested enums, complex types)
40//!
41//! This ensures all `Facet` types can be deserialized.
42
43#![cfg_attr(not(feature = "jit"), forbid(unsafe_code))]
44
45extern crate alloc;
46
47mod error;
48mod parser;
49mod serialize;
50mod shape_deser;
51
52#[cfg(feature = "jit")]
53pub mod jit;
54
55#[cfg(feature = "axum")]
56mod axum;
57
58#[cfg(feature = "axum")]
59pub use axum::{Postcard, PostcardRejection, PostcardSerializeRejection};
60pub use error::{PostcardError, SerializeError};
61#[cfg(feature = "jit")]
62pub use jit::PostcardJitFormat;
63pub use parser::PostcardParser;
64pub use serialize::{Writer, peek_to_vec, to_vec, to_vec_with_shape, to_writer_fallible};
65pub use shape_deser::from_slice_with_shape;
66
67// Re-export DeserializeError for convenience
68pub use facet_format::DeserializeError;
69
70/// Deserialize a value from postcard bytes into an owned type.
71///
72/// This is the recommended default for most use cases. The input does not need
73/// to outlive the result, making it suitable for deserializing from temporary
74/// buffers (e.g., HTTP request bodies).
75///
76/// Types containing `&str` or `&[u8]` fields cannot be deserialized with this
77/// function; use `String`/`Vec<u8>` or `Cow<str>`/`Cow<[u8]>` instead. For
78/// zero-copy deserialization into borrowed types, use [`from_slice_borrowed`].
79///
80/// # Example
81///
82/// ```
83/// use facet::Facet;
84/// use facet_postcard::from_slice;
85///
86/// #[derive(Facet, Debug, PartialEq)]
87/// struct Point {
88/// x: i32,
89/// y: i32,
90/// }
91///
92/// // Postcard encoding: [x=10 (zigzag), y=20 (zigzag)]
93/// let bytes = &[0x14, 0x28];
94/// let point: Point = from_slice(bytes).unwrap();
95/// assert_eq!(point.x, 10);
96/// assert_eq!(point.y, 20);
97/// ```
98pub fn from_slice<T>(input: &[u8]) -> Result<T, DeserializeError<PostcardError>>
99where
100 T: facet_core::Facet<'static>,
101{
102 use facet_format::FormatDeserializer;
103 let parser = PostcardParser::new(input);
104 let mut de = FormatDeserializer::new_owned(parser);
105 de.deserialize()
106}
107
108/// Deserialize a value from postcard bytes, allowing zero-copy borrowing.
109///
110/// This variant requires the input to outlive the result (`'input: 'facet`),
111/// enabling zero-copy deserialization of byte slices as `&[u8]` or `Cow<[u8]>`.
112///
113/// Use this when you need maximum performance and can guarantee the input
114/// buffer outlives the deserialized value. For most use cases, prefer
115/// [`from_slice`] which doesn't have lifetime requirements.
116///
117/// # Example
118///
119/// ```
120/// use facet::Facet;
121/// use facet_postcard::from_slice_borrowed;
122///
123/// #[derive(Facet, Debug, PartialEq)]
124/// struct Message<'a> {
125/// id: u32,
126/// data: &'a [u8],
127/// }
128///
129/// // Postcard encoding: [id=1, data_len=3, 0xAB, 0xCD, 0xEF]
130/// let bytes = &[0x01, 0x03, 0xAB, 0xCD, 0xEF];
131/// let msg: Message = from_slice_borrowed(bytes).unwrap();
132/// assert_eq!(msg.id, 1);
133/// assert_eq!(msg.data, &[0xAB, 0xCD, 0xEF]);
134/// ```
135pub fn from_slice_borrowed<'input, 'facet, T>(
136 input: &'input [u8],
137) -> Result<T, DeserializeError<PostcardError>>
138where
139 T: facet_core::Facet<'facet>,
140 'input: 'facet,
141{
142 use facet_format::FormatDeserializer;
143 let parser = PostcardParser::new(input);
144 let mut de = FormatDeserializer::new(parser);
145 de.deserialize()
146}