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, 'facet, T: Facet<'facet>>(
28 input: &'input [u8],
29) -> Result<T, DeserError<'input>> {
30 recursive::from_slice(input, 0)
31}
32
33#[cfg(feature = "std")]
35pub fn from_str<'input: 'facet, 'facet, T: Facet<'facet>>(
36 input: &'input str,
37) -> Result<T, DeserError<'input>> {
38 recursive::from_str(input, 0)
39}
40
41#[cfg(feature = "std")]
46pub fn from_str_static_error<'input: 'facet, 'facet, T: Facet<'facet>>(
47 input: &'input str,
48) -> Result<T, DeserError<'input>> {
49 recursive::from_str_static_error(input, 0)
50}
51
52#[cfg(feature = "std")]
54pub fn to_string<'facet, T: Facet<'facet>>(value: &T) -> String {
55 recursive::to_string(value, 0)
56}
57
58#[cfg(feature = "std")]
60pub fn peek_to_string<'facet: 'input, 'input: 'facet>(peek: Peek<'input, 'facet>) -> String {
61 recursive::peek_to_string(peek, 0)
62}
63
64#[cfg(feature = "std")]
66pub fn to_writer<'mem: 'facet, 'facet, T: Facet<'facet>, W: Write>(
67 value: &'mem T,
68 writer: &mut W,
69) -> io::Result<()> {
70 recursive::to_writer(value, writer)
71}
72
73#[cfg(feature = "std")]
75pub fn peek_to_writer<'mem: 'facet, 'facet, W: Write>(
76 peek: Peek<'mem, 'facet>,
77 writer: &mut W,
78) -> io::Result<()> {
79 recursive::peek_to_writer(peek, None, 0, writer)
80}
81
82struct Json;
84
85#[cfg(feature = "std")]
87fn write_json_string<W: Write>(writer: &mut W, s: &str) -> io::Result<()> {
88 writer.write_all(b"\"")?;
89
90 for c in s.chars() {
91 write_json_escaped_char(writer, c)?;
92 }
93
94 writer.write_all(b"\"")
95}
96
97#[cfg(feature = "std")]
99fn write_json_escaped_char<W: Write>(writer: &mut W, c: char) -> io::Result<()> {
100 match c {
101 '"' => writer.write_all(b"\\\""),
102 '\\' => writer.write_all(b"\\\\"),
103 '\n' => writer.write_all(b"\\n"),
104 '\r' => writer.write_all(b"\\r"),
105 '\t' => writer.write_all(b"\\t"),
106 '\u{08}' => writer.write_all(b"\\b"),
107 '\u{0C}' => writer.write_all(b"\\f"),
108 c if c.is_control() => {
109 let mut buf = [0; 6];
110 let s = format!("{:04x}", c as u32);
111 buf[0] = b'\\';
112 buf[1] = b'u';
113 buf[2] = s.as_bytes()[0];
114 buf[3] = s.as_bytes()[1];
115 buf[4] = s.as_bytes()[2];
116 buf[5] = s.as_bytes()[3];
117 writer.write_all(&buf)
118 }
119 c => {
120 let mut buf = [0; 4];
121 let len = c.encode_utf8(&mut buf).len();
122 writer.write_all(&buf[..len])
123 }
124 }
125}
126
127fn variant_is_newtype_like(variant: &facet_core::Variant) -> bool {
128 variant.data.kind == facet_core::StructKind::Tuple && variant.data.fields.len() == 1
129}