facet_json/
lib.rs

1#![cfg_attr(not(feature = "std"), no_std)]
2#![warn(missing_docs)]
3#![warn(clippy::std_instead_of_core)]
4#![warn(clippy::std_instead_of_alloc)]
5#![forbid(unsafe_code)]
6#![doc = include_str!("../README.md")]
7
8#[cfg(feature = "std")]
9use std::io::{self, Write};
10
11use facet_core::Facet;
12pub use facet_deserialize::{DeserError, DeserErrorKind, DeserErrorMessage};
13use facet_reflect::Peek;
14
15extern crate alloc;
16
17#[cfg(feature = "std")]
18mod iterative;
19#[cfg(feature = "std")]
20mod recursive;
21mod tokenizer;
22
23const MAX_RECURSION_DEPTH: usize = 100;
24
25/// Deserialize JSON from a given byte slice
26#[cfg(feature = "std")]
27pub fn from_slice<'input, 'facet, 'shape, T: Facet<'facet>>(
28    input: &'input [u8],
29) -> Result<T, DeserError<'input, 'shape>>
30where
31    'input: 'facet,
32{
33    recursive::from_slice(input, 0)
34}
35
36/// Deserialize JSON from a given string
37#[cfg(feature = "std")]
38pub fn from_str<'input, 'facet, 'shape, T: Facet<'facet>>(
39    input: &'input str,
40) -> Result<T, DeserError<'input, 'shape>>
41where
42    'input: 'facet,
43{
44    recursive::from_str(input, 0)
45}
46
47/// Serializes a value to JSON
48#[cfg(feature = "std")]
49pub fn to_string<'input, 'facet, T: Facet<'facet>>(value: &'input T) -> String {
50    recursive::to_string(value, 0)
51}
52
53/// Serializes a Peek instance to JSON
54#[cfg(feature = "std")]
55pub fn peek_to_string<'input, 'facet, 'shape>(peek: Peek<'input, 'facet, 'shape>) -> String {
56    recursive::peek_to_string(peek, 0)
57}
58
59/// Serializes a value to a writer in JSON format
60#[cfg(feature = "std")]
61pub fn to_writer<'mem, 'facet, T: Facet<'facet>, W: Write>(
62    value: &'mem T,
63    writer: &mut W,
64) -> io::Result<()> {
65    recursive::to_writer(value, writer)
66}
67
68/// Serializes a Peek instance to a writer in JSON format
69#[cfg(feature = "std")]
70pub fn peek_to_writer<'mem, 'facet, 'shape, W: Write>(
71    peek: Peek<'mem, 'facet, 'shape>,
72    writer: &mut W,
73) -> io::Result<()> {
74    recursive::peek_to_writer(peek, None, 0, writer)
75}
76
77/// The JSON format
78struct Json;
79
80/// Properly escapes and writes a JSON string
81#[cfg(feature = "std")]
82fn write_json_string<W: Write>(writer: &mut W, s: &str) -> io::Result<()> {
83    writer.write_all(b"\"")?;
84
85    for c in s.chars() {
86        write_json_escaped_char(writer, c)?;
87    }
88
89    writer.write_all(b"\"")
90}
91
92/// Writes a single JSON escaped character
93#[cfg(feature = "std")]
94fn write_json_escaped_char<W: Write>(writer: &mut W, c: char) -> io::Result<()> {
95    match c {
96        '"' => writer.write_all(b"\\\""),
97        '\\' => writer.write_all(b"\\\\"),
98        '\n' => writer.write_all(b"\\n"),
99        '\r' => writer.write_all(b"\\r"),
100        '\t' => writer.write_all(b"\\t"),
101        '\u{08}' => writer.write_all(b"\\b"),
102        '\u{0C}' => writer.write_all(b"\\f"),
103        c if c.is_control() => {
104            let mut buf = [0; 6];
105            let s = format!("{:04x}", c as u32);
106            buf[0] = b'\\';
107            buf[1] = b'u';
108            buf[2] = s.as_bytes()[0];
109            buf[3] = s.as_bytes()[1];
110            buf[4] = s.as_bytes()[2];
111            buf[5] = s.as_bytes()[3];
112            writer.write_all(&buf)
113        }
114        c => {
115            let mut buf = [0; 4];
116            let len = c.encode_utf8(&mut buf).len();
117            writer.write_all(&buf[..len])
118        }
119    }
120}
121
122fn variant_is_newtype_like(variant: &facet_core::Variant) -> bool {
123    variant.data.kind == facet_core::StructKind::Tuple && variant.data.fields.len() == 1
124}