1#![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
8extern crate alloc;
9
10use alloc::vec::Vec;
11pub use facet_deserialize::{DeserError, DeserErrorKind, DeserErrorMessage};
12
13mod deserialize;
14pub use deserialize::*;
15
16mod serialize;
17pub use serialize::*;
18
19mod tokenizer;
20
21struct Json;
23
24pub trait JsonWrite {
26 fn write(&mut self, buf: &[u8]);
28
29 fn reserve(&mut self, additional: usize);
31}
32
33impl JsonWrite for &mut Vec<u8> {
34 fn write(&mut self, buf: &[u8]) {
35 self.extend(buf);
36 }
37
38 fn reserve(&mut self, additional: usize) {
39 Vec::reserve(self, additional)
40 }
41}
42
43impl JsonWrite for Vec<u8> {
44 fn write(&mut self, buf: &[u8]) {
45 self.extend(buf);
46 }
47
48 fn reserve(&mut self, additional: usize) {
49 Vec::reserve(self, additional)
50 }
51}
52
53#[inline]
55fn write_json_string<W: JsonWrite>(writer: &mut W, s: &str) {
56 const STEP_SIZE: usize = Window::BITS as usize / 8;
69 type Window = u128;
70 type Chunk = [u8; STEP_SIZE];
71
72 writer.write(b"\"");
73
74 let mut s = s;
75 while let Some(Ok(chunk)) = s.as_bytes().get(..STEP_SIZE).map(Chunk::try_from) {
76 let window = Window::from_ne_bytes(chunk);
77 let completely_ascii = window & 0x80808080808080808080808080808080 == 0;
84 let quote_free = !contains_0x22(window);
85 let backslash_free = !contains_0x5c(window);
86 let control_char_free = top_three_bits_set(window);
87 if completely_ascii && quote_free && backslash_free && control_char_free {
88 writer.write(&chunk);
90 s = &s[STEP_SIZE..];
91 } else {
92 let mut chars = s.chars();
95 let mut count = STEP_SIZE;
96 for c in &mut chars {
97 write_json_escaped_char(writer, c);
98 count = count.saturating_sub(c.len_utf8());
99 if count == 0 {
100 break;
102 }
103 }
104 s = chars.as_str();
105 }
106 }
107
108 for c in s.chars() {
112 write_json_escaped_char(writer, c);
113 }
114
115 writer.write(b"\"")
116}
117
118#[inline]
120fn write_json_escaped_char<W: JsonWrite>(writer: &mut W, c: char) {
121 match c {
122 '"' => writer.write(b"\\\""),
123 '\\' => writer.write(b"\\\\"),
124 '\n' => writer.write(b"\\n"),
125 '\r' => writer.write(b"\\r"),
126 '\t' => writer.write(b"\\t"),
127 '\u{08}' => writer.write(b"\\b"),
128 '\u{0C}' => writer.write(b"\\f"),
129 c if c.is_ascii_control() => {
130 let code_point = c as u32;
131 let to_hex = |d: u32| char::from_digit(d, 16).unwrap() as u8;
133 let buf = [
134 b'\\',
135 b'u',
136 to_hex((code_point >> 12) & 0xF),
137 to_hex((code_point >> 8) & 0xF),
138 to_hex((code_point >> 4) & 0xF),
139 to_hex(code_point & 0xF),
140 ];
141 writer.write(&buf);
142 }
143 c if c.is_ascii() => {
144 writer.write(&[c as u8]);
145 }
146 c => {
147 let mut buf = [0; 4];
148 let len = c.encode_utf8(&mut buf).len();
149 writer.write(&buf[..len])
150 }
151 }
152}
153
154#[inline]
155fn contains_0x22(val: u128) -> bool {
156 let xor_result = val ^ 0x22222222222222222222222222222222;
157 let has_zero = (xor_result.wrapping_sub(0x01010101010101010101010101010101))
158 & !xor_result
159 & 0x80808080808080808080808080808080;
160 has_zero != 0
161}
162
163#[inline]
164fn contains_0x5c(val: u128) -> bool {
165 let xor_result = val ^ 0x5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c;
166 let has_zero = (xor_result.wrapping_sub(0x01010101010101010101010101010101))
167 & !xor_result
168 & 0x80808080808080808080808080808080;
169 has_zero != 0
170}
171
172#[inline]
174fn top_three_bits_set(value: u128) -> bool {
175 let xor_result = value & 0xe0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0;
176 let has_zero = (xor_result.wrapping_sub(0x01010101010101010101010101010101))
177 & !xor_result
178 & 0x80808080808080808080808080808080;
179 has_zero == 0
180}