facet_json/lib.rs
1#![cfg_attr(not(feature = "jit"), forbid(unsafe_code))]
2
3//! JSON parser and serializer using facet-format.
4//!
5//! This crate provides JSON support via the `FormatParser` trait.
6
7extern crate alloc;
8
9/// Trace-level logging macro that forwards to `tracing::trace!` when the `tracing` feature is enabled.
10#[cfg(feature = "tracing")]
11#[allow(unused_macros)]
12macro_rules! trace {
13 ($($arg:tt)*) => {
14 ::tracing::trace!($($arg)*)
15 };
16}
17
18/// Trace-level logging macro (no-op when `tracing` feature is disabled).
19#[cfg(not(feature = "tracing"))]
20#[allow(unused_macros)]
21macro_rules! trace {
22 ($($arg:tt)*) => {};
23}
24
25/// Debug-level logging macro that forwards to `tracing::debug!` when the `tracing` feature is enabled.
26#[cfg(feature = "tracing")]
27#[allow(unused_macros)]
28macro_rules! debug {
29 ($($arg:tt)*) => {
30 ::tracing::debug!($($arg)*)
31 };
32}
33
34/// Debug-level logging macro (no-op when `tracing` feature is disabled).
35#[cfg(not(feature = "tracing"))]
36#[allow(unused_macros)]
37macro_rules! debug {
38 ($($arg:tt)*) => {};
39}
40
41#[allow(unused_imports)]
42pub(crate) use debug;
43#[allow(unused_imports)]
44pub(crate) use trace;
45
46mod adapter;
47mod error;
48mod parser;
49mod raw_json;
50#[cfg(feature = "streaming")]
51mod scan_buffer;
52mod scanner;
53mod serializer;
54
55#[cfg(feature = "streaming")]
56mod streaming_adapter;
57
58#[cfg(feature = "jit")]
59pub mod jit;
60
61#[cfg(feature = "axum")]
62mod axum;
63
64#[cfg(feature = "jit")]
65pub use jit::JsonJitFormat;
66
67#[cfg(feature = "axum")]
68pub use axum::{Json, JsonRejection};
69
70pub use parser::{JsonError, JsonParser};
71pub use raw_json::RawJson;
72pub use serializer::{
73 JsonSerializeError, JsonSerializer, SerializeOptions, peek_to_string, peek_to_string_pretty,
74 peek_to_string_with_options, peek_to_writer_std, peek_to_writer_std_pretty,
75 peek_to_writer_std_with_options, to_string, to_string_pretty, to_string_with_options, to_vec,
76 to_vec_pretty, to_vec_with_options, to_writer_std, to_writer_std_pretty,
77 to_writer_std_with_options,
78};
79
80// Re-export DeserializeError for convenience
81pub use facet_format::DeserializeError;
82
83/// Deserialize a value from a JSON string into an owned type.
84///
85/// This is the recommended default for most use cases. The input does not need
86/// to outlive the result, making it suitable for deserializing from temporary
87/// buffers (e.g., HTTP request bodies).
88///
89/// Types containing `&str` fields cannot be deserialized with this function;
90/// use `String` or `Cow<str>` instead. For zero-copy deserialization into
91/// borrowed types, use [`from_str_borrowed`].
92///
93/// # Example
94///
95/// ```
96/// use facet::Facet;
97/// use facet_json::from_str;
98///
99/// #[derive(Facet, Debug, PartialEq)]
100/// struct Person {
101/// name: String,
102/// age: u32,
103/// }
104///
105/// let json = r#"{"name": "Alice", "age": 30}"#;
106/// let person: Person = from_str(json).unwrap();
107/// assert_eq!(person.name, "Alice");
108/// assert_eq!(person.age, 30);
109/// ```
110pub fn from_str<T>(input: &str) -> Result<T, DeserializeError<JsonError>>
111where
112 T: facet_core::Facet<'static>,
113{
114 from_slice(input.as_bytes())
115}
116
117/// Deserialize a value from JSON bytes into an owned type.
118///
119/// This is the recommended default for most use cases. The input does not need
120/// to outlive the result, making it suitable for deserializing from temporary
121/// buffers (e.g., HTTP request bodies).
122///
123/// Types containing `&str` fields cannot be deserialized with this function;
124/// use `String` or `Cow<str>` instead. For zero-copy deserialization into
125/// borrowed types, use [`from_slice_borrowed`].
126///
127/// # Example
128///
129/// ```
130/// use facet::Facet;
131/// use facet_json::from_slice;
132///
133/// #[derive(Facet, Debug, PartialEq)]
134/// struct Point {
135/// x: i32,
136/// y: i32,
137/// }
138///
139/// let json = br#"{"x": 10, "y": 20}"#;
140/// let point: Point = from_slice(json).unwrap();
141/// assert_eq!(point.x, 10);
142/// assert_eq!(point.y, 20);
143/// ```
144pub fn from_slice<T>(input: &[u8]) -> Result<T, DeserializeError<JsonError>>
145where
146 T: facet_core::Facet<'static>,
147{
148 use facet_format::FormatDeserializer;
149 let parser = JsonParser::new(input);
150 let mut de = FormatDeserializer::new_owned(parser);
151 de.deserialize_root()
152}
153
154/// Deserialize a value from a JSON string, allowing zero-copy borrowing.
155///
156/// This variant requires the input to outlive the result (`'input: 'facet`),
157/// enabling zero-copy deserialization of string fields as `&str` or `Cow<str>`.
158///
159/// Use this when you need maximum performance and can guarantee the input
160/// buffer outlives the deserialized value. For most use cases, prefer
161/// [`from_str`] which doesn't have lifetime requirements.
162///
163/// # Example
164///
165/// ```
166/// use facet::Facet;
167/// use facet_json::from_str_borrowed;
168///
169/// #[derive(Facet, Debug, PartialEq)]
170/// struct Person<'a> {
171/// name: &'a str,
172/// age: u32,
173/// }
174///
175/// let json = r#"{"name": "Alice", "age": 30}"#;
176/// let person: Person = from_str_borrowed(json).unwrap();
177/// assert_eq!(person.name, "Alice");
178/// assert_eq!(person.age, 30);
179/// ```
180pub fn from_str_borrowed<'input, 'facet, T>(
181 input: &'input str,
182) -> Result<T, DeserializeError<JsonError>>
183where
184 T: facet_core::Facet<'facet>,
185 'input: 'facet,
186{
187 from_slice_borrowed(input.as_bytes())
188}
189
190/// Deserialize a value from JSON bytes, allowing zero-copy borrowing.
191///
192/// This variant requires the input to outlive the result (`'input: 'facet`),
193/// enabling zero-copy deserialization of string fields as `&str` or `Cow<str>`.
194///
195/// Use this when you need maximum performance and can guarantee the input
196/// buffer outlives the deserialized value. For most use cases, prefer
197/// [`from_slice`] which doesn't have lifetime requirements.
198///
199/// # Example
200///
201/// ```
202/// use facet::Facet;
203/// use facet_json::from_slice_borrowed;
204///
205/// #[derive(Facet, Debug, PartialEq)]
206/// struct Point<'a> {
207/// label: &'a str,
208/// x: i32,
209/// y: i32,
210/// }
211///
212/// let json = br#"{"label": "origin", "x": 0, "y": 0}"#;
213/// let point: Point = from_slice_borrowed(json).unwrap();
214/// assert_eq!(point.label, "origin");
215/// ```
216pub fn from_slice_borrowed<'input, 'facet, T>(
217 input: &'input [u8],
218) -> Result<T, DeserializeError<JsonError>>
219where
220 T: facet_core::Facet<'facet>,
221 'input: 'facet,
222{
223 use facet_format::FormatDeserializer;
224 let parser = JsonParser::new(input);
225 let mut de = FormatDeserializer::new(parser);
226 de.deserialize_root()
227}
228
229#[cfg(feature = "streaming")]
230mod streaming;
231#[cfg(feature = "futures-io")]
232pub use streaming::from_async_reader_futures;
233#[cfg(feature = "tokio")]
234pub use streaming::from_async_reader_tokio;
235#[cfg(feature = "streaming")]
236pub use streaming::from_reader;