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::I64(v) => {
327 #[cfg(feature = "fast")]
328 self.out
329 .extend_from_slice(itoa::Buffer::new().format(v).as_bytes());
330 #[cfg(not(feature = "fast"))]
331 self.out.extend_from_slice(v.to_string().as_bytes());
332 }
333 ScalarValue::U64(v) => {
334 #[cfg(feature = "fast")]
335 self.out
336 .extend_from_slice(itoa::Buffer::new().format(v).as_bytes());
337 #[cfg(not(feature = "fast"))]
338 self.out.extend_from_slice(v.to_string().as_bytes());
339 }
340 ScalarValue::I128(v) => {
341 #[cfg(feature = "fast")]
342 self.out
343 .extend_from_slice(itoa::Buffer::new().format(v).as_bytes());
344 #[cfg(not(feature = "fast"))]
345 self.out.extend_from_slice(v.to_string().as_bytes());
346 }
347 ScalarValue::U128(v) => {
348 #[cfg(feature = "fast")]
349 self.out
350 .extend_from_slice(itoa::Buffer::new().format(v).as_bytes());
351 #[cfg(not(feature = "fast"))]
352 self.out.extend_from_slice(v.to_string().as_bytes());
353 }
354 ScalarValue::F64(v) => {
355 #[cfg(feature = "fast")]
356 self.out
357 .extend_from_slice(zmij::Buffer::new().format(v).as_bytes());
358 #[cfg(not(feature = "fast"))]
359 self.out.extend_from_slice(v.to_string().as_bytes());
360 }
361 ScalarValue::Str(s) => self.write_json_string(&s),
362 ScalarValue::Bytes(_) => {
363 return Err(JsonSerializeError {
364 msg: "bytes serialization unsupported for json",
365 });
366 }
367 }
368 Ok(())
369 }
370
371 fn raw_serialize_shape(&self) -> Option<&'static facet_core::Shape> {
372 Some(crate::RawJson::SHAPE)
373 }
374
375 fn raw_scalar(&mut self, content: &str) -> Result<(), Self::Error> {
376 self.before_value()?;
378 self.out.extend_from_slice(content.as_bytes());
379 Ok(())
380 }
381}
382
383pub fn to_vec<'facet, T>(value: &'_ T) -> Result<Vec<u8>, SerializeError<JsonSerializeError>>
399where
400 T: Facet<'facet> + ?Sized,
401{
402 to_vec_with_options(value, &SerializeOptions::default())
403}
404
405pub fn to_vec_pretty<'facet, T>(value: &'_ T) -> Result<Vec<u8>, SerializeError<JsonSerializeError>>
421where
422 T: Facet<'facet> + ?Sized,
423{
424 to_vec_with_options(value, &SerializeOptions::default().pretty())
425}
426
427pub fn to_vec_with_options<'facet, T>(
449 value: &'_ T,
450 options: &SerializeOptions,
451) -> Result<Vec<u8>, SerializeError<JsonSerializeError>>
452where
453 T: Facet<'facet> + ?Sized,
454{
455 let mut serializer = JsonSerializer::with_options(options.clone());
456 serialize_root(&mut serializer, Peek::new(value))?;
457 Ok(serializer.finish())
458}
459
460pub fn to_string<'facet, T>(value: &'_ T) -> Result<String, SerializeError<JsonSerializeError>>
476where
477 T: Facet<'facet> + ?Sized,
478{
479 let bytes = to_vec(value)?;
480 Ok(String::from_utf8(bytes).expect("JSON output should always be valid UTF-8"))
482}
483
484pub fn to_string_pretty<'facet, T>(
500 value: &'_ T,
501) -> Result<String, SerializeError<JsonSerializeError>>
502where
503 T: Facet<'facet> + ?Sized,
504{
505 let bytes = to_vec_pretty(value)?;
506 Ok(String::from_utf8(bytes).expect("JSON output should always be valid UTF-8"))
507}
508
509pub fn to_string_with_options<'facet, T>(
531 value: &'_ T,
532 options: &SerializeOptions,
533) -> Result<String, SerializeError<JsonSerializeError>>
534where
535 T: Facet<'facet> + ?Sized,
536{
537 let bytes = to_vec_with_options(value, options)?;
538 Ok(String::from_utf8(bytes).expect("JSON output should always be valid UTF-8"))
539}
540
541pub fn peek_to_string<'input, 'facet>(
563 peek: Peek<'input, 'facet>,
564) -> Result<String, SerializeError<JsonSerializeError>> {
565 peek_to_string_with_options(peek, &SerializeOptions::default())
566}
567
568pub fn peek_to_string_pretty<'input, 'facet>(
585 peek: Peek<'input, 'facet>,
586) -> Result<String, SerializeError<JsonSerializeError>> {
587 peek_to_string_with_options(peek, &SerializeOptions::default().pretty())
588}
589
590pub fn peek_to_string_with_options<'input, 'facet>(
610 peek: Peek<'input, 'facet>,
611 options: &SerializeOptions,
612) -> Result<String, SerializeError<JsonSerializeError>> {
613 let mut serializer = JsonSerializer::with_options(options.clone());
614 serialize_root(&mut serializer, peek)?;
615 let bytes = serializer.finish();
616 Ok(String::from_utf8(bytes).expect("JSON output should always be valid UTF-8"))
617}
618
619pub fn to_writer_std<'facet, W, T>(writer: W, value: &T) -> std::io::Result<()>
641where
642 W: std::io::Write,
643 T: Facet<'facet> + ?Sized,
644{
645 peek_to_writer_std(writer, Peek::new(value))
646}
647
648pub fn to_writer_std_pretty<'facet, W, T>(writer: W, value: &T) -> std::io::Result<()>
668where
669 W: std::io::Write,
670 T: Facet<'facet> + ?Sized,
671{
672 peek_to_writer_std_pretty(writer, Peek::new(value))
673}
674
675pub fn to_writer_std_with_options<'facet, W, T>(
702 writer: W,
703 value: &T,
704 options: &SerializeOptions,
705) -> std::io::Result<()>
706where
707 W: std::io::Write,
708 T: Facet<'facet> + ?Sized,
709{
710 peek_to_writer_std_with_options(writer, Peek::new(value), options)
711}
712
713pub fn peek_to_writer_std<'input, 'facet, W>(
715 writer: W,
716 peek: Peek<'input, 'facet>,
717) -> std::io::Result<()>
718where
719 W: std::io::Write,
720{
721 peek_to_writer_std_with_options(writer, peek, &SerializeOptions::default())
722}
723
724pub fn peek_to_writer_std_pretty<'input, 'facet, W>(
726 writer: W,
727 peek: Peek<'input, 'facet>,
728) -> std::io::Result<()>
729where
730 W: std::io::Write,
731{
732 peek_to_writer_std_with_options(writer, peek, &SerializeOptions::default().pretty())
733}
734
735pub fn peek_to_writer_std_with_options<'input, 'facet, W>(
737 mut writer: W,
738 peek: Peek<'input, 'facet>,
739 options: &SerializeOptions,
740) -> std::io::Result<()>
741where
742 W: std::io::Write,
743{
744 let mut serializer = JsonSerializer::with_options(options.clone());
747 serialize_root(&mut serializer, peek)
748 .map_err(|e| std::io::Error::other(alloc::format!("{:?}", e)))?;
749 writer.write_all(&serializer.finish())
750}