1extern crate alloc;
2
3use alloc::{string::String, vec::Vec};
4
5use facet_core::Facet;
6use facet_format::{FormatSerializer, ScalarValue, SerializeError, serialize_root};
7use facet_reflect::Peek;
8
9#[derive(Debug, Clone)]
11pub struct SerializeOptions {
12 pub pretty: bool,
14
15 pub indent: &'static str,
17}
18
19impl Default for SerializeOptions {
20 fn default() -> Self {
21 Self {
22 pretty: false,
23 indent: " ",
24 }
25 }
26}
27
28impl SerializeOptions {
29 pub fn new() -> Self {
31 Self::default()
32 }
33
34 pub const fn pretty(mut self) -> Self {
36 self.pretty = true;
37 self
38 }
39
40 pub const fn indent(mut self, indent: &'static str) -> Self {
42 self.indent = indent;
43 self.pretty = true;
44 self
45 }
46}
47
48#[derive(Debug)]
49pub struct JsonSerializeError {
50 msg: &'static str,
51}
52
53impl core::fmt::Display for JsonSerializeError {
54 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
55 f.write_str(self.msg)
56 }
57}
58
59impl std::error::Error for JsonSerializeError {}
60
61#[derive(Debug, Clone, Copy)]
62enum Ctx {
63 Struct { first: bool },
64 Seq { first: bool },
65}
66
67pub struct JsonSerializer {
69 out: Vec<u8>,
70 stack: Vec<Ctx>,
71 options: SerializeOptions,
72}
73
74impl JsonSerializer {
75 pub fn new() -> Self {
77 Self::with_options(SerializeOptions::default())
78 }
79
80 pub const fn with_options(options: SerializeOptions) -> Self {
82 Self {
83 out: Vec::new(),
84 stack: Vec::new(),
85 options,
86 }
87 }
88
89 pub fn finish(self) -> Vec<u8> {
91 self.out
92 }
93
94 const fn depth(&self) -> usize {
96 self.stack.len()
97 }
98
99 fn write_indent(&mut self) {
101 if self.options.pretty {
102 self.out.push(b'\n');
103 for _ in 0..self.depth() {
104 self.out.extend_from_slice(self.options.indent.as_bytes());
105 }
106 }
107 }
108
109 fn before_value(&mut self) -> Result<(), JsonSerializeError> {
110 match self.stack.last_mut() {
111 Some(Ctx::Seq { first }) => {
112 if !*first {
113 self.out.push(b',');
114 }
115 *first = false;
116 self.write_indent();
117 }
118 Some(Ctx::Struct { .. }) => {
119 }
121 None => {}
122 }
123 Ok(())
124 }
125
126 fn write_json_string(&mut self, s: &str) {
131 const STEP_SIZE: usize = 16; type Chunk = [u8; STEP_SIZE];
133
134 self.out.push(b'"');
135
136 let mut s = s;
137 while let Some(Ok(chunk)) = s.as_bytes().get(..STEP_SIZE).map(Chunk::try_from) {
138 let window = u128::from_ne_bytes(chunk);
139 let completely_ascii = window & 0x80808080808080808080808080808080 == 0;
145 let quote_free = !contains_byte(window, 0x22);
146 let backslash_free = !contains_byte(window, 0x5c);
147 let control_char_free = no_control_chars(window);
148
149 if completely_ascii && quote_free && backslash_free && control_char_free {
150 self.out.extend_from_slice(&chunk);
152 s = &s[STEP_SIZE..];
153 } else {
154 let mut chars = s.chars();
156 let mut count = STEP_SIZE;
157 for c in &mut chars {
158 self.write_json_escaped_char(c);
159 count = count.saturating_sub(c.len_utf8());
160 if count == 0 {
161 break;
162 }
163 }
164 s = chars.as_str();
165 }
166 }
167
168 for c in s.chars() {
170 self.write_json_escaped_char(c);
171 }
172
173 self.out.push(b'"');
174 }
175
176 #[inline]
177 fn write_json_escaped_char(&mut self, c: char) {
178 match c {
179 '"' => self.out.extend_from_slice(b"\\\""),
180 '\\' => self.out.extend_from_slice(b"\\\\"),
181 '\n' => self.out.extend_from_slice(b"\\n"),
182 '\r' => self.out.extend_from_slice(b"\\r"),
183 '\t' => self.out.extend_from_slice(b"\\t"),
184 '\u{08}' => self.out.extend_from_slice(b"\\b"),
185 '\u{0C}' => self.out.extend_from_slice(b"\\f"),
186 c if c.is_ascii_control() => {
187 let code_point = c as u32;
188 let to_hex = |d: u32| {
189 if d < 10 {
190 b'0' + d as u8
191 } else {
192 b'a' + (d - 10) as u8
193 }
194 };
195 let buf = [
196 b'\\',
197 b'u',
198 to_hex((code_point >> 12) & 0xF),
199 to_hex((code_point >> 8) & 0xF),
200 to_hex((code_point >> 4) & 0xF),
201 to_hex(code_point & 0xF),
202 ];
203 self.out.extend_from_slice(&buf);
204 }
205 c if c.is_ascii() => {
206 self.out.push(c as u8);
207 }
208 c => {
209 let mut buf = [0u8; 4];
210 let len = c.encode_utf8(&mut buf).len();
211 self.out.extend_from_slice(&buf[..len]);
212 }
213 }
214 }
215}
216
217#[inline]
220const fn contains_byte(val: u128, byte: u8) -> bool {
221 let mask = 0x01010101010101010101010101010101u128 * (byte as u128);
222 let xor_result = val ^ mask;
223 let has_zero = (xor_result.wrapping_sub(0x01010101010101010101010101010101))
224 & !xor_result
225 & 0x80808080808080808080808080808080;
226 has_zero != 0
227}
228
229#[inline]
232const fn no_control_chars(value: u128) -> bool {
233 let masked = value & 0xe0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0;
234 let has_zero = (masked.wrapping_sub(0x01010101010101010101010101010101))
235 & !masked
236 & 0x80808080808080808080808080808080;
237 has_zero == 0
238}
239
240impl Default for JsonSerializer {
241 fn default() -> Self {
242 Self::new()
243 }
244}
245
246impl FormatSerializer for JsonSerializer {
247 type Error = JsonSerializeError;
248
249 fn begin_struct(&mut self) -> Result<(), Self::Error> {
250 self.before_value()?;
251 self.out.push(b'{');
252 self.stack.push(Ctx::Struct { first: true });
253 Ok(())
254 }
255
256 fn field_key(&mut self, key: &str) -> Result<(), Self::Error> {
257 match self.stack.last_mut() {
258 Some(Ctx::Struct { first }) => {
259 if !*first {
260 self.out.push(b',');
261 }
262 *first = false;
263 self.write_indent();
264 self.write_json_string(key);
265 self.out.push(b':');
266 if self.options.pretty {
267 self.out.push(b' ');
268 }
269 Ok(())
270 }
271 _ => Err(JsonSerializeError {
272 msg: "field_key called outside of a struct",
273 }),
274 }
275 }
276
277 fn end_struct(&mut self) -> Result<(), Self::Error> {
278 match self.stack.pop() {
279 Some(Ctx::Struct { first }) => {
280 if !first {
282 self.write_indent();
283 }
284 self.out.push(b'}');
285 Ok(())
286 }
287 _ => Err(JsonSerializeError {
288 msg: "end_struct called without matching begin_struct",
289 }),
290 }
291 }
292
293 fn begin_seq(&mut self) -> Result<(), Self::Error> {
294 self.before_value()?;
295 self.out.push(b'[');
296 self.stack.push(Ctx::Seq { first: true });
297 Ok(())
298 }
299
300 fn end_seq(&mut self) -> Result<(), Self::Error> {
301 match self.stack.pop() {
302 Some(Ctx::Seq { first }) => {
303 if !first {
305 self.write_indent();
306 }
307 self.out.push(b']');
308 Ok(())
309 }
310 _ => Err(JsonSerializeError {
311 msg: "end_seq called without matching begin_seq",
312 }),
313 }
314 }
315
316 fn scalar(&mut self, scalar: ScalarValue<'_>) -> Result<(), Self::Error> {
317 self.before_value()?;
318 match scalar {
319 ScalarValue::Null | ScalarValue::Unit => self.out.extend_from_slice(b"null"),
320 ScalarValue::Bool(v) => {
321 if v {
322 self.out.extend_from_slice(b"true")
323 } else {
324 self.out.extend_from_slice(b"false")
325 }
326 }
327 ScalarValue::Char(c) => {
328 self.out.push(b'"');
329 self.write_json_escaped_char(c);
330 self.out.push(b'"');
331 }
332 ScalarValue::I64(v) => {
333 #[cfg(feature = "fast")]
334 self.out
335 .extend_from_slice(itoa::Buffer::new().format(v).as_bytes());
336 #[cfg(not(feature = "fast"))]
337 self.out.extend_from_slice(v.to_string().as_bytes());
338 }
339 ScalarValue::U64(v) => {
340 #[cfg(feature = "fast")]
341 self.out
342 .extend_from_slice(itoa::Buffer::new().format(v).as_bytes());
343 #[cfg(not(feature = "fast"))]
344 self.out.extend_from_slice(v.to_string().as_bytes());
345 }
346 ScalarValue::I128(v) => {
347 #[cfg(feature = "fast")]
348 self.out
349 .extend_from_slice(itoa::Buffer::new().format(v).as_bytes());
350 #[cfg(not(feature = "fast"))]
351 self.out.extend_from_slice(v.to_string().as_bytes());
352 }
353 ScalarValue::U128(v) => {
354 #[cfg(feature = "fast")]
355 self.out
356 .extend_from_slice(itoa::Buffer::new().format(v).as_bytes());
357 #[cfg(not(feature = "fast"))]
358 self.out.extend_from_slice(v.to_string().as_bytes());
359 }
360 ScalarValue::F64(v) => {
361 #[cfg(feature = "fast")]
362 self.out
363 .extend_from_slice(zmij::Buffer::new().format(v).as_bytes());
364 #[cfg(not(feature = "fast"))]
365 self.out.extend_from_slice(v.to_string().as_bytes());
366 }
367 ScalarValue::Str(s) => self.write_json_string(&s),
368 ScalarValue::Bytes(_) => {
369 return Err(JsonSerializeError {
370 msg: "bytes serialization unsupported for json",
371 });
372 }
373 }
374 Ok(())
375 }
376
377 fn raw_serialize_shape(&self) -> Option<&'static facet_core::Shape> {
378 Some(crate::RawJson::SHAPE)
379 }
380
381 fn raw_scalar(&mut self, content: &str) -> Result<(), Self::Error> {
382 self.before_value()?;
384 self.out.extend_from_slice(content.as_bytes());
385 Ok(())
386 }
387
388 fn format_namespace(&self) -> Option<&'static str> {
389 Some("json")
390 }
391}
392
393pub fn to_vec<'facet, T>(value: &'_ T) -> Result<Vec<u8>, SerializeError<JsonSerializeError>>
409where
410 T: Facet<'facet> + ?Sized,
411{
412 to_vec_with_options(value, &SerializeOptions::default())
413}
414
415pub fn to_vec_pretty<'facet, T>(value: &'_ T) -> Result<Vec<u8>, SerializeError<JsonSerializeError>>
431where
432 T: Facet<'facet> + ?Sized,
433{
434 to_vec_with_options(value, &SerializeOptions::default().pretty())
435}
436
437pub fn to_vec_with_options<'facet, T>(
459 value: &'_ T,
460 options: &SerializeOptions,
461) -> Result<Vec<u8>, SerializeError<JsonSerializeError>>
462where
463 T: Facet<'facet> + ?Sized,
464{
465 let mut serializer = JsonSerializer::with_options(options.clone());
466 serialize_root(&mut serializer, Peek::new(value))?;
467 Ok(serializer.finish())
468}
469
470pub fn to_string<'facet, T>(value: &'_ T) -> Result<String, SerializeError<JsonSerializeError>>
486where
487 T: Facet<'facet> + ?Sized,
488{
489 let bytes = to_vec(value)?;
490 Ok(String::from_utf8(bytes).expect("JSON output should always be valid UTF-8"))
492}
493
494pub fn to_string_pretty<'facet, T>(
510 value: &'_ T,
511) -> Result<String, SerializeError<JsonSerializeError>>
512where
513 T: Facet<'facet> + ?Sized,
514{
515 let bytes = to_vec_pretty(value)?;
516 Ok(String::from_utf8(bytes).expect("JSON output should always be valid UTF-8"))
517}
518
519pub fn to_string_with_options<'facet, T>(
541 value: &'_ T,
542 options: &SerializeOptions,
543) -> Result<String, SerializeError<JsonSerializeError>>
544where
545 T: Facet<'facet> + ?Sized,
546{
547 let bytes = to_vec_with_options(value, options)?;
548 Ok(String::from_utf8(bytes).expect("JSON output should always be valid UTF-8"))
549}
550
551pub fn peek_to_string<'input, 'facet>(
573 peek: Peek<'input, 'facet>,
574) -> Result<String, SerializeError<JsonSerializeError>> {
575 peek_to_string_with_options(peek, &SerializeOptions::default())
576}
577
578pub fn peek_to_string_pretty<'input, 'facet>(
595 peek: Peek<'input, 'facet>,
596) -> Result<String, SerializeError<JsonSerializeError>> {
597 peek_to_string_with_options(peek, &SerializeOptions::default().pretty())
598}
599
600pub fn peek_to_string_with_options<'input, 'facet>(
620 peek: Peek<'input, 'facet>,
621 options: &SerializeOptions,
622) -> Result<String, SerializeError<JsonSerializeError>> {
623 let mut serializer = JsonSerializer::with_options(options.clone());
624 serialize_root(&mut serializer, peek)?;
625 let bytes = serializer.finish();
626 Ok(String::from_utf8(bytes).expect("JSON output should always be valid UTF-8"))
627}
628
629pub fn to_writer_std<'facet, W, T>(writer: W, value: &T) -> std::io::Result<()>
651where
652 W: std::io::Write,
653 T: Facet<'facet> + ?Sized,
654{
655 peek_to_writer_std(writer, Peek::new(value))
656}
657
658pub fn to_writer_std_pretty<'facet, W, T>(writer: W, value: &T) -> std::io::Result<()>
678where
679 W: std::io::Write,
680 T: Facet<'facet> + ?Sized,
681{
682 peek_to_writer_std_pretty(writer, Peek::new(value))
683}
684
685pub fn to_writer_std_with_options<'facet, W, T>(
712 writer: W,
713 value: &T,
714 options: &SerializeOptions,
715) -> std::io::Result<()>
716where
717 W: std::io::Write,
718 T: Facet<'facet> + ?Sized,
719{
720 peek_to_writer_std_with_options(writer, Peek::new(value), options)
721}
722
723pub fn peek_to_writer_std<'input, 'facet, W>(
725 writer: W,
726 peek: Peek<'input, 'facet>,
727) -> std::io::Result<()>
728where
729 W: std::io::Write,
730{
731 peek_to_writer_std_with_options(writer, peek, &SerializeOptions::default())
732}
733
734pub fn peek_to_writer_std_pretty<'input, 'facet, W>(
736 writer: W,
737 peek: Peek<'input, 'facet>,
738) -> std::io::Result<()>
739where
740 W: std::io::Write,
741{
742 peek_to_writer_std_with_options(writer, peek, &SerializeOptions::default().pretty())
743}
744
745pub fn peek_to_writer_std_with_options<'input, 'facet, W>(
747 mut writer: W,
748 peek: Peek<'input, 'facet>,
749 options: &SerializeOptions,
750) -> std::io::Result<()>
751where
752 W: std::io::Write,
753{
754 let mut serializer = JsonSerializer::with_options(options.clone());
757 serialize_root(&mut serializer, peek)
758 .map_err(|e| std::io::Error::other(alloc::format!("{:?}", e)))?;
759 writer.write_all(&serializer.finish())
760}