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 pub indent: &'static str,
16}
17
18impl Default for SerializeOptions {
19 fn default() -> Self {
20 Self {
21 pretty: false,
22 indent: " ",
23 }
24 }
25}
26
27impl SerializeOptions {
28 pub fn new() -> Self {
30 Self::default()
31 }
32
33 pub fn pretty(mut self) -> Self {
35 self.pretty = true;
36 self
37 }
38
39 pub fn indent(mut self, indent: &'static str) -> Self {
41 self.indent = indent;
42 self.pretty = true;
43 self
44 }
45}
46
47#[derive(Debug)]
48pub struct JsonSerializeError {
49 msg: &'static str,
50}
51
52impl core::fmt::Display for JsonSerializeError {
53 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
54 f.write_str(self.msg)
55 }
56}
57
58impl std::error::Error for JsonSerializeError {}
59
60#[derive(Debug, Clone, Copy)]
61enum Ctx {
62 Struct { first: bool },
63 Seq { first: bool },
64}
65
66pub struct JsonSerializer {
68 out: Vec<u8>,
69 stack: Vec<Ctx>,
70 options: SerializeOptions,
71}
72
73impl JsonSerializer {
74 pub fn new() -> Self {
76 Self::with_options(SerializeOptions::default())
77 }
78
79 pub fn with_options(options: SerializeOptions) -> Self {
81 Self {
82 out: Vec::new(),
83 stack: Vec::new(),
84 options,
85 }
86 }
87
88 pub fn finish(self) -> Vec<u8> {
90 self.out
91 }
92
93 fn depth(&self) -> usize {
95 self.stack.len()
96 }
97
98 fn write_indent(&mut self) {
100 if self.options.pretty {
101 self.out.push(b'\n');
102 for _ in 0..self.depth() {
103 self.out.extend_from_slice(self.options.indent.as_bytes());
104 }
105 }
106 }
107
108 fn before_value(&mut self) -> Result<(), JsonSerializeError> {
109 match self.stack.last_mut() {
110 Some(Ctx::Seq { first }) => {
111 if !*first {
112 self.out.push(b',');
113 }
114 *first = false;
115 self.write_indent();
116 }
117 Some(Ctx::Struct { .. }) => {
118 }
120 None => {}
121 }
122 Ok(())
123 }
124
125 fn write_json_string(&mut self, s: &str) {
130 const STEP_SIZE: usize = 16; type Chunk = [u8; STEP_SIZE];
132
133 self.out.push(b'"');
134
135 let mut s = s;
136 while let Some(Ok(chunk)) = s.as_bytes().get(..STEP_SIZE).map(Chunk::try_from) {
137 let window = u128::from_ne_bytes(chunk);
138 let completely_ascii = window & 0x80808080808080808080808080808080 == 0;
144 let quote_free = !contains_byte(window, 0x22);
145 let backslash_free = !contains_byte(window, 0x5c);
146 let control_char_free = no_control_chars(window);
147
148 if completely_ascii && quote_free && backslash_free && control_char_free {
149 self.out.extend_from_slice(&chunk);
151 s = &s[STEP_SIZE..];
152 } else {
153 let mut chars = s.chars();
155 let mut count = STEP_SIZE;
156 for c in &mut chars {
157 self.write_json_escaped_char(c);
158 count = count.saturating_sub(c.len_utf8());
159 if count == 0 {
160 break;
161 }
162 }
163 s = chars.as_str();
164 }
165 }
166
167 for c in s.chars() {
169 self.write_json_escaped_char(c);
170 }
171
172 self.out.push(b'"');
173 }
174
175 #[inline]
176 fn write_json_escaped_char(&mut self, c: char) {
177 match c {
178 '"' => self.out.extend_from_slice(b"\\\""),
179 '\\' => self.out.extend_from_slice(b"\\\\"),
180 '\n' => self.out.extend_from_slice(b"\\n"),
181 '\r' => self.out.extend_from_slice(b"\\r"),
182 '\t' => self.out.extend_from_slice(b"\\t"),
183 '\u{08}' => self.out.extend_from_slice(b"\\b"),
184 '\u{0C}' => self.out.extend_from_slice(b"\\f"),
185 c if c.is_ascii_control() => {
186 let code_point = c as u32;
187 let to_hex = |d: u32| {
188 if d < 10 {
189 b'0' + d as u8
190 } else {
191 b'a' + (d - 10) as u8
192 }
193 };
194 let buf = [
195 b'\\',
196 b'u',
197 to_hex((code_point >> 12) & 0xF),
198 to_hex((code_point >> 8) & 0xF),
199 to_hex((code_point >> 4) & 0xF),
200 to_hex(code_point & 0xF),
201 ];
202 self.out.extend_from_slice(&buf);
203 }
204 c if c.is_ascii() => {
205 self.out.push(c as u8);
206 }
207 c => {
208 let mut buf = [0u8; 4];
209 let len = c.encode_utf8(&mut buf).len();
210 self.out.extend_from_slice(&buf[..len]);
211 }
212 }
213 }
214}
215
216#[inline]
219fn contains_byte(val: u128, byte: u8) -> bool {
220 let mask = 0x01010101010101010101010101010101u128 * (byte as u128);
221 let xor_result = val ^ mask;
222 let has_zero = (xor_result.wrapping_sub(0x01010101010101010101010101010101))
223 & !xor_result
224 & 0x80808080808080808080808080808080;
225 has_zero != 0
226}
227
228#[inline]
231fn no_control_chars(value: u128) -> bool {
232 let masked = value & 0xe0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0;
233 let has_zero = (masked.wrapping_sub(0x01010101010101010101010101010101))
234 & !masked
235 & 0x80808080808080808080808080808080;
236 has_zero == 0
237}
238
239impl Default for JsonSerializer {
240 fn default() -> Self {
241 Self::new()
242 }
243}
244
245impl FormatSerializer for JsonSerializer {
246 type Error = JsonSerializeError;
247
248 fn begin_struct(&mut self) -> Result<(), Self::Error> {
249 self.before_value()?;
250 self.out.push(b'{');
251 self.stack.push(Ctx::Struct { first: true });
252 Ok(())
253 }
254
255 fn field_key(&mut self, key: &str) -> Result<(), Self::Error> {
256 match self.stack.last_mut() {
257 Some(Ctx::Struct { first }) => {
258 if !*first {
259 self.out.push(b',');
260 }
261 *first = false;
262 self.write_indent();
263 self.write_json_string(key);
264 self.out.push(b':');
265 if self.options.pretty {
266 self.out.push(b' ');
267 }
268 Ok(())
269 }
270 _ => Err(JsonSerializeError {
271 msg: "field_key called outside of a struct",
272 }),
273 }
274 }
275
276 fn end_struct(&mut self) -> Result<(), Self::Error> {
277 match self.stack.pop() {
278 Some(Ctx::Struct { first }) => {
279 if !first {
281 self.write_indent();
282 }
283 self.out.push(b'}');
284 Ok(())
285 }
286 _ => Err(JsonSerializeError {
287 msg: "end_struct called without matching begin_struct",
288 }),
289 }
290 }
291
292 fn begin_seq(&mut self) -> Result<(), Self::Error> {
293 self.before_value()?;
294 self.out.push(b'[');
295 self.stack.push(Ctx::Seq { first: true });
296 Ok(())
297 }
298
299 fn end_seq(&mut self) -> Result<(), Self::Error> {
300 match self.stack.pop() {
301 Some(Ctx::Seq { first }) => {
302 if !first {
304 self.write_indent();
305 }
306 self.out.push(b']');
307 Ok(())
308 }
309 _ => Err(JsonSerializeError {
310 msg: "end_seq called without matching begin_seq",
311 }),
312 }
313 }
314
315 fn scalar(&mut self, scalar: ScalarValue<'_>) -> Result<(), Self::Error> {
316 self.before_value()?;
317 match scalar {
318 ScalarValue::Null => self.out.extend_from_slice(b"null"),
319 ScalarValue::Bool(v) => {
320 if v {
321 self.out.extend_from_slice(b"true")
322 } else {
323 self.out.extend_from_slice(b"false")
324 }
325 }
326 ScalarValue::Char(c) => {
327 self.out.push(b'"');
328 self.write_json_escaped_char(c);
329 self.out.push(b'"');
330 }
331 ScalarValue::I64(v) => {
332 #[cfg(feature = "fast")]
333 self.out
334 .extend_from_slice(itoa::Buffer::new().format(v).as_bytes());
335 #[cfg(not(feature = "fast"))]
336 self.out.extend_from_slice(v.to_string().as_bytes());
337 }
338 ScalarValue::U64(v) => {
339 #[cfg(feature = "fast")]
340 self.out
341 .extend_from_slice(itoa::Buffer::new().format(v).as_bytes());
342 #[cfg(not(feature = "fast"))]
343 self.out.extend_from_slice(v.to_string().as_bytes());
344 }
345 ScalarValue::I128(v) => {
346 #[cfg(feature = "fast")]
347 self.out
348 .extend_from_slice(itoa::Buffer::new().format(v).as_bytes());
349 #[cfg(not(feature = "fast"))]
350 self.out.extend_from_slice(v.to_string().as_bytes());
351 }
352 ScalarValue::U128(v) => {
353 #[cfg(feature = "fast")]
354 self.out
355 .extend_from_slice(itoa::Buffer::new().format(v).as_bytes());
356 #[cfg(not(feature = "fast"))]
357 self.out.extend_from_slice(v.to_string().as_bytes());
358 }
359 ScalarValue::F64(v) => {
360 #[cfg(feature = "fast")]
361 self.out
362 .extend_from_slice(zmij::Buffer::new().format(v).as_bytes());
363 #[cfg(not(feature = "fast"))]
364 self.out.extend_from_slice(v.to_string().as_bytes());
365 }
366 ScalarValue::Str(s) | ScalarValue::StringlyTyped(s) => self.write_json_string(&s),
367 ScalarValue::Bytes(_) => {
368 return Err(JsonSerializeError {
369 msg: "bytes serialization unsupported for json",
370 });
371 }
372 }
373 Ok(())
374 }
375
376 fn raw_serialize_shape(&self) -> Option<&'static facet_core::Shape> {
377 Some(crate::RawJson::SHAPE)
378 }
379
380 fn raw_scalar(&mut self, content: &str) -> Result<(), Self::Error> {
381 self.before_value()?;
383 self.out.extend_from_slice(content.as_bytes());
384 Ok(())
385 }
386}
387
388pub fn to_vec<'facet, T>(value: &'_ T) -> Result<Vec<u8>, SerializeError<JsonSerializeError>>
404where
405 T: Facet<'facet> + ?Sized,
406{
407 to_vec_with_options(value, &SerializeOptions::default())
408}
409
410pub fn to_vec_pretty<'facet, T>(value: &'_ T) -> Result<Vec<u8>, SerializeError<JsonSerializeError>>
426where
427 T: Facet<'facet> + ?Sized,
428{
429 to_vec_with_options(value, &SerializeOptions::default().pretty())
430}
431
432pub fn to_vec_with_options<'facet, T>(
454 value: &'_ T,
455 options: &SerializeOptions,
456) -> Result<Vec<u8>, SerializeError<JsonSerializeError>>
457where
458 T: Facet<'facet> + ?Sized,
459{
460 let mut serializer = JsonSerializer::with_options(options.clone());
461 serialize_root(&mut serializer, Peek::new(value))?;
462 Ok(serializer.finish())
463}
464
465pub fn to_string<'facet, T>(value: &'_ T) -> Result<String, SerializeError<JsonSerializeError>>
481where
482 T: Facet<'facet> + ?Sized,
483{
484 let bytes = to_vec(value)?;
485 Ok(String::from_utf8(bytes).expect("JSON output should always be valid UTF-8"))
487}
488
489pub fn to_string_pretty<'facet, T>(
505 value: &'_ T,
506) -> Result<String, SerializeError<JsonSerializeError>>
507where
508 T: Facet<'facet> + ?Sized,
509{
510 let bytes = to_vec_pretty(value)?;
511 Ok(String::from_utf8(bytes).expect("JSON output should always be valid UTF-8"))
512}
513
514pub fn to_string_with_options<'facet, T>(
536 value: &'_ T,
537 options: &SerializeOptions,
538) -> Result<String, SerializeError<JsonSerializeError>>
539where
540 T: Facet<'facet> + ?Sized,
541{
542 let bytes = to_vec_with_options(value, options)?;
543 Ok(String::from_utf8(bytes).expect("JSON output should always be valid UTF-8"))
544}
545
546pub fn peek_to_string<'input, 'facet>(
568 peek: Peek<'input, 'facet>,
569) -> Result<String, SerializeError<JsonSerializeError>> {
570 peek_to_string_with_options(peek, &SerializeOptions::default())
571}
572
573pub fn peek_to_string_pretty<'input, 'facet>(
590 peek: Peek<'input, 'facet>,
591) -> Result<String, SerializeError<JsonSerializeError>> {
592 peek_to_string_with_options(peek, &SerializeOptions::default().pretty())
593}
594
595pub fn peek_to_string_with_options<'input, 'facet>(
615 peek: Peek<'input, 'facet>,
616 options: &SerializeOptions,
617) -> Result<String, SerializeError<JsonSerializeError>> {
618 let mut serializer = JsonSerializer::with_options(options.clone());
619 serialize_root(&mut serializer, peek)?;
620 let bytes = serializer.finish();
621 Ok(String::from_utf8(bytes).expect("JSON output should always be valid UTF-8"))
622}
623
624pub fn to_writer_std<'facet, W, T>(writer: W, value: &T) -> std::io::Result<()>
646where
647 W: std::io::Write,
648 T: Facet<'facet> + ?Sized,
649{
650 peek_to_writer_std(writer, Peek::new(value))
651}
652
653pub fn to_writer_std_pretty<'facet, W, T>(writer: W, value: &T) -> std::io::Result<()>
673where
674 W: std::io::Write,
675 T: Facet<'facet> + ?Sized,
676{
677 peek_to_writer_std_pretty(writer, Peek::new(value))
678}
679
680pub fn to_writer_std_with_options<'facet, W, T>(
707 writer: W,
708 value: &T,
709 options: &SerializeOptions,
710) -> std::io::Result<()>
711where
712 W: std::io::Write,
713 T: Facet<'facet> + ?Sized,
714{
715 peek_to_writer_std_with_options(writer, Peek::new(value), options)
716}
717
718pub fn peek_to_writer_std<'input, 'facet, W>(
720 writer: W,
721 peek: Peek<'input, 'facet>,
722) -> std::io::Result<()>
723where
724 W: std::io::Write,
725{
726 peek_to_writer_std_with_options(writer, peek, &SerializeOptions::default())
727}
728
729pub fn peek_to_writer_std_pretty<'input, 'facet, W>(
731 writer: W,
732 peek: Peek<'input, 'facet>,
733) -> std::io::Result<()>
734where
735 W: std::io::Write,
736{
737 peek_to_writer_std_with_options(writer, peek, &SerializeOptions::default().pretty())
738}
739
740pub fn peek_to_writer_std_with_options<'input, 'facet, W>(
742 mut writer: W,
743 peek: Peek<'input, 'facet>,
744 options: &SerializeOptions,
745) -> std::io::Result<()>
746where
747 W: std::io::Write,
748{
749 let mut serializer = JsonSerializer::with_options(options.clone());
752 serialize_root(&mut serializer, peek)
753 .map_err(|e| std::io::Error::other(alloc::format!("{:?}", e)))?;
754 writer.write_all(&serializer.finish())
755}