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