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
11pub use facet_deserialize::{DeserError, DeserErrorKind, DeserErrorMessage};
12
13extern crate alloc;
14
15mod deserialize;
16pub use deserialize::*;
17
18#[cfg(feature = "std")]
19mod serialize;
20#[cfg(feature = "std")]
21pub use serialize::*;
22
23mod tokenizer;
24
25struct Json;
27
28#[cfg(feature = "std")]
30#[inline]
31fn write_json_string<W: Write>(writer: &mut W, s: &str) -> io::Result<()> {
32 const STEP_SIZE: usize = 16;
45 type Window = u128;
46 type Chunk = [u8; STEP_SIZE];
47
48 writer.write_all(b"\"")?;
49
50 let mut idx = 0;
51 while idx + STEP_SIZE < s.len() {
52 let slice = &s.as_bytes()[idx..idx + STEP_SIZE];
53 let chunk = Chunk::try_from(slice).unwrap();
56 let window = Window::from_ne_bytes(chunk);
57 let completely_ascii = window & 0x80808080808080808080808080808080 == 0;
64 let quote_free = !contains_0x22(window);
65 let backslash_free = !contains_0x5c(window);
66 let control_char_free = top_three_bits_set(window);
67 if completely_ascii && quote_free && backslash_free && control_char_free {
68 writer.write_all(slice)?;
70 idx += STEP_SIZE;
71 } else {
72 let mut chars = s[idx..].chars();
75 for c in (&mut chars).take(STEP_SIZE) {
76 write_json_escaped_char(writer, c)?;
77 }
78 let bytes_consumed = chars.as_str().as_ptr() as usize - (s.as_ptr() as usize + idx);
79 idx += bytes_consumed;
80 }
81 }
82
83 for c in s[idx..].chars() {
87 write_json_escaped_char(writer, c)?;
88 }
89
90 writer.write_all(b"\"")
91}
92
93#[cfg(feature = "std")]
95#[inline]
96fn write_json_escaped_char<W: Write>(writer: &mut W, c: char) -> io::Result<()> {
97 match c {
98 '"' => writer.write_all(b"\\\""),
99 '\\' => writer.write_all(b"\\\\"),
100 '\n' => writer.write_all(b"\\n"),
101 '\r' => writer.write_all(b"\\r"),
102 '\t' => writer.write_all(b"\\t"),
103 '\u{08}' => writer.write_all(b"\\b"),
104 '\u{0C}' => writer.write_all(b"\\f"),
105 c if c.is_ascii_control() => {
106 let mut buf = [0; 6];
107 let s = format!("{:04x}", c as u32);
108 buf[0] = b'\\';
109 buf[1] = b'u';
110 buf[2] = s.as_bytes()[0];
111 buf[3] = s.as_bytes()[1];
112 buf[4] = s.as_bytes()[2];
113 buf[5] = s.as_bytes()[3];
114 writer.write_all(&buf)
115 }
116 c if c.is_ascii() => {
117 writer.write_all(&[c as u8])?;
118 Ok(())
119 }
120 c => {
121 let mut buf = [0; 4];
122 let len = c.encode_utf8(&mut buf).len();
123 writer.write_all(&buf[..len])
124 }
125 }
126}
127
128fn contains_0x22(val: u128) -> bool {
129 let xor_result = val ^ 0x22222222222222222222222222222222;
130 let has_zero = (xor_result.wrapping_sub(0x01010101010101010101010101010101))
131 & !xor_result
132 & 0x80808080808080808080808080808080;
133 has_zero != 0
134}
135
136fn contains_0x5c(val: u128) -> bool {
137 let xor_result = val ^ 0x5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c;
138 let has_zero = (xor_result.wrapping_sub(0x01010101010101010101010101010101))
139 & !xor_result
140 & 0x80808080808080808080808080808080;
141 has_zero != 0
142}
143
144fn top_three_bits_set(value: u128) -> bool {
146 let mask = 0xe0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0;
147 let masked = value & mask;
148 let has_zero = (masked.wrapping_sub(0x01010101010101010101010101010101))
149 & !masked
150 & 0x80808080808080808080808080808080;
151 has_zero == 0
152}