facet_json/lib.rs
1// Note: unsafe code is used for lifetime transmutes in from_slice_into/from_str_into
2// when BORROW=false, mirroring the approach used in facet-format's FormatDeserializer.
3
4//! JSON parser and serializer using facet-format.
5//!
6//! This crate provides JSON support via the `FormatParser` trait.
7
8extern crate alloc;
9
10/// Trace-level logging macro that forwards to `tracing::trace!` when the `tracing` feature is enabled.
11#[cfg(feature = "tracing")]
12#[allow(unused_macros)]
13macro_rules! trace {
14 ($($arg:tt)*) => {
15 ::tracing::trace!($($arg)*)
16 };
17}
18
19/// Trace-level logging macro (no-op when `tracing` feature is disabled).
20#[cfg(not(feature = "tracing"))]
21#[allow(unused_macros)]
22macro_rules! trace {
23 ($($arg:tt)*) => {};
24}
25
26/// Debug-level logging macro that forwards to `tracing::debug!` when the `tracing` feature is enabled.
27#[cfg(feature = "tracing")]
28#[allow(unused_macros)]
29macro_rules! debug {
30 ($($arg:tt)*) => {
31 ::tracing::debug!($($arg)*)
32 };
33}
34
35/// Debug-level logging macro (no-op when `tracing` feature is disabled).
36#[cfg(not(feature = "tracing"))]
37#[allow(unused_macros)]
38macro_rules! debug {
39 ($($arg:tt)*) => {};
40}
41
42#[allow(unused_imports)]
43pub(crate) use debug;
44use facet_reflect::Partial;
45#[allow(unused_imports)]
46pub(crate) use trace;
47
48mod error;
49mod parser;
50mod raw_json;
51mod scanner;
52mod serializer;
53
54#[cfg(feature = "axum")]
55mod axum;
56
57#[cfg(feature = "axum")]
58pub use axum::{Json, JsonRejection};
59
60pub use error::JsonError;
61pub use parser::JsonParser;
62pub use raw_json::RawJson;
63pub use serializer::{
64 BytesFormat, HexBytesOptions, JsonSerializeError, JsonSerializer, SerializeOptions,
65 peek_to_string, peek_to_string_pretty, peek_to_string_with_options, peek_to_writer_std,
66 peek_to_writer_std_pretty, peek_to_writer_std_with_options, to_string, to_string_pretty,
67 to_string_with_options, to_vec, to_vec_pretty, to_vec_with_options, to_writer_std,
68 to_writer_std_pretty, to_writer_std_with_options,
69};
70
71// Re-export DeserializeError for convenience
72pub use facet_format::DeserializeError;
73
74/// Deserialize a value from a JSON string into an owned type.
75///
76/// This is the recommended default for most use cases. The input does not need
77/// to outlive the result, making it suitable for deserializing from temporary
78/// buffers (e.g., HTTP request bodies).
79///
80/// Types containing `&str` fields cannot be deserialized with this function;
81/// use `String` or `Cow<str>` instead. For zero-copy deserialization into
82/// borrowed types, use [`from_str_borrowed`].
83///
84/// # Example
85///
86/// ```
87/// use facet::Facet;
88/// use facet_json::from_str;
89///
90/// #[derive(Facet, Debug, PartialEq)]
91/// struct Person {
92/// name: String,
93/// age: u32,
94/// }
95///
96/// let json = r#"{"name": "Alice", "age": 30}"#;
97/// let person: Person = from_str(json).unwrap();
98/// assert_eq!(person.name, "Alice");
99/// assert_eq!(person.age, 30);
100/// ```
101pub fn from_str<T>(input: &str) -> Result<T, DeserializeError>
102where
103 T: facet_core::Facet<'static>,
104{
105 use facet_format::FormatDeserializer;
106 // TRUSTED_UTF8 = true: input came from &str, so it's valid UTF-8
107 let mut parser = JsonParser::<true>::new(input.as_bytes());
108 let mut de = FormatDeserializer::new_owned(&mut parser);
109 de.deserialize_root()
110}
111
112/// Deserialize a value from JSON bytes into an owned type.
113///
114/// This is the recommended default for most use cases. The input does not need
115/// to outlive the result, making it suitable for deserializing from temporary
116/// buffers (e.g., HTTP request bodies).
117///
118/// Types containing `&str` fields cannot be deserialized with this function;
119/// use `String` or `Cow<str>` instead. For zero-copy deserialization into
120/// borrowed types, use [`from_slice_borrowed`].
121///
122/// # Example
123///
124/// ```
125/// use facet::Facet;
126/// use facet_json::from_slice;
127///
128/// #[derive(Facet, Debug, PartialEq)]
129/// struct Point {
130/// x: i32,
131/// y: i32,
132/// }
133///
134/// let json = br#"{"x": 10, "y": 20}"#;
135/// let point: Point = from_slice(json).unwrap();
136/// assert_eq!(point.x, 10);
137/// assert_eq!(point.y, 20);
138/// ```
139pub fn from_slice<T>(input: &[u8]) -> Result<T, DeserializeError>
140where
141 T: facet_core::Facet<'static>,
142{
143 use facet_format::FormatDeserializer;
144 let mut parser = JsonParser::<false>::new(input);
145 let mut de = FormatDeserializer::new_owned(&mut parser);
146 de.deserialize_root()
147}
148
149/// Deserialize a value from a JSON string, allowing zero-copy borrowing.
150///
151/// This variant requires the input to outlive the result (`'input: 'facet`),
152/// enabling zero-copy deserialization of string fields as `&str` or `Cow<str>`.
153///
154/// Use this when you need maximum performance and can guarantee the input
155/// buffer outlives the deserialized value. For most use cases, prefer
156/// [`from_str`] which doesn't have lifetime requirements.
157///
158/// # Example
159///
160/// ```
161/// use facet::Facet;
162/// use facet_json::from_str_borrowed;
163///
164/// #[derive(Facet, Debug, PartialEq)]
165/// struct Person<'a> {
166/// name: &'a str,
167/// age: u32,
168/// }
169///
170/// let json = r#"{"name": "Alice", "age": 30}"#;
171/// let person: Person = from_str_borrowed(json).unwrap();
172/// assert_eq!(person.name, "Alice");
173/// assert_eq!(person.age, 30);
174/// ```
175pub fn from_str_borrowed<'input, 'facet, T>(input: &'input str) -> Result<T, DeserializeError>
176where
177 T: facet_core::Facet<'facet>,
178 'input: 'facet,
179{
180 use facet_format::FormatDeserializer;
181 // TRUSTED_UTF8 = true: input came from &str, so it's valid UTF-8
182 let mut parser = JsonParser::<true>::new(input.as_bytes());
183 let mut de = FormatDeserializer::new(&mut parser);
184 de.deserialize_root()
185}
186
187/// Deserialize a value from JSON bytes, allowing zero-copy borrowing.
188///
189/// This variant requires the input to outlive the result (`'input: 'facet`),
190/// enabling zero-copy deserialization of string fields as `&str` or `Cow<str>`.
191///
192/// Use this when you need maximum performance and can guarantee the input
193/// buffer outlives the deserialized value. For most use cases, prefer
194/// [`from_slice`] which doesn't have lifetime requirements.
195///
196/// # Example
197///
198/// ```
199/// use facet::Facet;
200/// use facet_json::from_slice_borrowed;
201///
202/// #[derive(Facet, Debug, PartialEq)]
203/// struct Point<'a> {
204/// label: &'a str,
205/// x: i32,
206/// y: i32,
207/// }
208///
209/// let json = br#"{"label": "origin", "x": 0, "y": 0}"#;
210/// let point: Point = from_slice_borrowed(json).unwrap();
211/// assert_eq!(point.label, "origin");
212/// ```
213pub fn from_slice_borrowed<'input, 'facet, T>(input: &'input [u8]) -> Result<T, DeserializeError>
214where
215 T: facet_core::Facet<'facet>,
216 'input: 'facet,
217{
218 use facet_format::FormatDeserializer;
219 let mut parser = JsonParser::<false>::new(input);
220 let mut de = FormatDeserializer::new(&mut parser);
221 de.deserialize_root()
222}
223
224/// Deserialize JSON from a string into an existing Partial.
225///
226/// This is useful for reflection-based deserialization where you don't have
227/// a concrete type `T` at compile time, only its Shape metadata. The Partial
228/// must already be allocated for the target type.
229///
230/// This version produces owned strings (no borrowing from input).
231///
232/// # Example
233///
234/// ```
235/// use facet::Facet;
236/// use facet_json::from_str_into;
237/// use facet_reflect::Partial;
238///
239/// #[derive(Facet, Debug, PartialEq)]
240/// struct Person {
241/// name: String,
242/// age: u32,
243/// }
244///
245/// let json = r#"{"name": "Alice", "age": 30}"#;
246/// let partial = Partial::alloc_owned::<Person>().unwrap();
247/// let partial = from_str_into(json, partial).unwrap();
248/// let value = partial.build().unwrap();
249/// let person: Person = value.materialize().unwrap();
250/// assert_eq!(person.name, "Alice");
251/// assert_eq!(person.age, 30);
252/// ```
253pub fn from_str_into<'facet>(
254 input: &str,
255 partial: Partial<'facet, false>,
256) -> Result<Partial<'facet, false>, DeserializeError> {
257 use facet_format::{FormatDeserializer, MetaSource};
258 // TRUSTED_UTF8 = true: input came from &str, so it's valid UTF-8
259 let mut parser = JsonParser::<true>::new(input.as_bytes());
260 let mut de = FormatDeserializer::new_owned(&mut parser);
261
262 // SAFETY: The deserializer expects Partial<'input, false> where 'input is the
263 // lifetime of the JSON bytes. Since BORROW=false, no data is borrowed from the
264 // input, so the actual 'facet lifetime of the Partial is independent of 'input.
265 // We transmute to satisfy the type system, then transmute back after deserialization.
266 #[allow(unsafe_code)]
267 let partial: Partial<'_, false> =
268 unsafe { core::mem::transmute::<Partial<'facet, false>, Partial<'_, false>>(partial) };
269
270 let partial = de.deserialize_into(partial, MetaSource::FromEvents)?;
271
272 // SAFETY: Same reasoning - no borrowed data since BORROW=false.
273 #[allow(unsafe_code)]
274 let partial: Partial<'facet, false> =
275 unsafe { core::mem::transmute::<Partial<'_, false>, Partial<'facet, false>>(partial) };
276
277 Ok(partial)
278}
279
280/// Deserialize JSON from bytes into an existing Partial.
281///
282/// This is useful for reflection-based deserialization where you don't have
283/// a concrete type `T` at compile time, only its Shape metadata. The Partial
284/// must already be allocated for the target type.
285///
286/// This version produces owned strings (no borrowing from input).
287///
288/// # Example
289///
290/// ```
291/// use facet::Facet;
292/// use facet_json::from_slice_into;
293/// use facet_reflect::Partial;
294///
295/// #[derive(Facet, Debug, PartialEq)]
296/// struct Point {
297/// x: i32,
298/// y: i32,
299/// }
300///
301/// let json = br#"{"x": 10, "y": 20}"#;
302/// let partial = Partial::alloc_owned::<Point>().unwrap();
303/// let partial = from_slice_into(json, partial).unwrap();
304/// let value = partial.build().unwrap();
305/// let point: Point = value.materialize().unwrap();
306/// assert_eq!(point.x, 10);
307/// assert_eq!(point.y, 20);
308/// ```
309pub fn from_slice_into<'facet>(
310 input: &[u8],
311 partial: Partial<'facet, false>,
312) -> Result<Partial<'facet, false>, DeserializeError> {
313 use facet_format::{FormatDeserializer, MetaSource};
314 let mut parser = JsonParser::<false>::new(input);
315 let mut de = FormatDeserializer::new_owned(&mut parser);
316
317 // SAFETY: The deserializer expects Partial<'input, false> where 'input is the
318 // lifetime of the JSON bytes. Since BORROW=false, no data is borrowed from the
319 // input, so the actual 'facet lifetime of the Partial is independent of 'input.
320 // We transmute to satisfy the type system, then transmute back after deserialization.
321 #[allow(unsafe_code)]
322 let partial: Partial<'_, false> =
323 unsafe { core::mem::transmute::<Partial<'facet, false>, Partial<'_, false>>(partial) };
324
325 let partial = de.deserialize_into(partial, MetaSource::FromEvents)?;
326
327 // SAFETY: Same reasoning - no borrowed data since BORROW=false.
328 #[allow(unsafe_code)]
329 let partial: Partial<'facet, false> =
330 unsafe { core::mem::transmute::<Partial<'_, false>, Partial<'facet, false>>(partial) };
331
332 Ok(partial)
333}
334
335/// Deserialize JSON from a string into an existing Partial, allowing zero-copy borrowing.
336///
337/// This variant requires the input to outlive the Partial's lifetime (`'input: 'facet`),
338/// enabling zero-copy deserialization of string fields as `&str` or `Cow<str>`.
339///
340/// This is useful for reflection-based deserialization where you don't have
341/// a concrete type `T` at compile time, only its Shape metadata.
342///
343/// # Example
344///
345/// ```
346/// use facet::Facet;
347/// use facet_json::from_str_into_borrowed;
348/// use facet_reflect::Partial;
349///
350/// #[derive(Facet, Debug, PartialEq)]
351/// struct Person<'a> {
352/// name: &'a str,
353/// age: u32,
354/// }
355///
356/// let json = r#"{"name": "Alice", "age": 30}"#;
357/// let partial = Partial::alloc::<Person>().unwrap();
358/// let partial = from_str_into_borrowed(json, partial).unwrap();
359/// let value = partial.build().unwrap();
360/// let person: Person = value.materialize().unwrap();
361/// assert_eq!(person.name, "Alice");
362/// assert_eq!(person.age, 30);
363/// ```
364pub fn from_str_into_borrowed<'input, 'facet>(
365 input: &'input str,
366 partial: Partial<'facet, true>,
367) -> Result<Partial<'facet, true>, DeserializeError>
368where
369 'input: 'facet,
370{
371 use facet_format::{FormatDeserializer, MetaSource};
372 // TRUSTED_UTF8 = true: input came from &str, so it's valid UTF-8
373 let mut parser = JsonParser::<true>::new(input.as_bytes());
374 let mut de = FormatDeserializer::new(&mut parser);
375 de.deserialize_into(partial, MetaSource::FromEvents)
376}
377
378/// Deserialize JSON from bytes into an existing Partial, allowing zero-copy borrowing.
379///
380/// This variant requires the input to outlive the Partial's lifetime (`'input: 'facet`),
381/// enabling zero-copy deserialization of string fields as `&str` or `Cow<str>`.
382///
383/// This is useful for reflection-based deserialization where you don't have
384/// a concrete type `T` at compile time, only its Shape metadata.
385///
386/// # Example
387///
388/// ```
389/// use facet::Facet;
390/// use facet_json::from_slice_into_borrowed;
391/// use facet_reflect::Partial;
392///
393/// #[derive(Facet, Debug, PartialEq)]
394/// struct Point<'a> {
395/// label: &'a str,
396/// x: i32,
397/// y: i32,
398/// }
399///
400/// let json = br#"{"label": "origin", "x": 0, "y": 0}"#;
401/// let partial = Partial::alloc::<Point>().unwrap();
402/// let partial = from_slice_into_borrowed(json, partial).unwrap();
403/// let value = partial.build().unwrap();
404/// let point: Point = value.materialize().unwrap();
405/// assert_eq!(point.label, "origin");
406/// ```
407pub fn from_slice_into_borrowed<'input, 'facet>(
408 input: &'input [u8],
409 partial: Partial<'facet, true>,
410) -> Result<Partial<'facet, true>, DeserializeError>
411where
412 'input: 'facet,
413{
414 use facet_format::{FormatDeserializer, MetaSource};
415 let mut parser = JsonParser::<false>::new(input);
416 let mut de = FormatDeserializer::new(&mut parser);
417 de.deserialize_into(partial, MetaSource::FromEvents)
418}