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#[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#[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#[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#[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#[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#[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
77struct Json;
79
80#[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#[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}