json_writer/
lib.rs

1#![doc = include_str!("../README.md")]
2
3use core::fmt;
4
5///
6/// Helper for appending a JSON object to the borrowed buffer.
7///
8/// Appends '{' on creation.
9/// Appends '}' when dropped.
10///
11pub struct JSONObjectWriter<'a, Writer: JSONWriter = String> {
12	///
13	/// Mutable borrow of buffer
14	///
15	/// Consider using the methods instead of using this field directly.
16	/// This field should not be used unless you know what you are doing.
17	///
18	pub writer: &'a mut Writer,
19	empty: bool,
20}
21
22///
23/// Helper for appending a JSON array to the borrowed buffer.
24///
25/// Appends '[' on creation.
26/// Appends ']' when dropped.
27///
28pub struct JSONArrayWriter<'a, Writer: JSONWriter = String> {
29	///
30	/// Mutable borrow of buffer
31	///
32	/// Consider using the methods instead of using this field directly.
33	/// This field should not be used unless you know what you are doing.
34	///
35	pub writer: &'a mut Writer,
36	empty: bool,
37}
38
39/// Build a string using the `fmt::Write` impl
40pub struct JSONStringWriter<'a, Writer: JSONWriter = String> {
41	/// The generic writer
42	pub writer: &'a mut Writer,
43}
44
45impl<'a, Writer: JSONWriter> JSONStringWriter<'a, Writer> {
46	/// Creates a new JSONStringWriter that writes to the given buffer. Writes '"' to the buffer immediately.
47	#[inline(always)]
48	pub fn new(writer: &mut Writer) -> JSONStringWriter<'_, Writer> {
49		writer.json_begin_string();
50		JSONStringWriter { writer }
51	}
52
53	///
54	/// Drops the JSONStringWriter.
55	/// Dropping causes '"' to be appended to the buffer.
56	///
57	#[inline(always)]
58	pub fn end(self) {
59		drop(self)
60	}
61}
62
63impl<'a, Writer: JSONWriter> fmt::Write for JSONStringWriter<'a, Writer> {
64	#[inline(always)]
65	fn write_str(&mut self, s: &str) -> fmt::Result {
66		self.writer.json_string_part(s);
67		Ok(())
68	}
69}
70
71impl<Writer: JSONWriter> Drop for JSONStringWriter<'_, Writer> {
72	#[inline(always)]
73	fn drop(&mut self) {
74		self.writer.json_end_string()
75	}
76}
77
78#[doc(hidden)]
79#[derive(Debug, Copy, Clone)]
80pub struct Null();
81
82///
83/// Writer trait for custom formatting and output
84///
85/// You most likely want to use `JSONObjectWriter` or `JSONArrayWriter` instead of using this directly
86///
87pub trait JSONWriter {
88	/// Writes null
89	#[inline(always)]
90	fn json_null(&mut self) {
91		self.json_fragment("null");
92	}
93
94	/// Writes true or false
95	fn json_bool(&mut self, value: bool) {
96		self.json_fragment(if value { "true" } else { "false" });
97	}
98
99	/// Quotes and escapes the given string and writes the result to output with delimiting quotes.
100	fn json_string(&mut self, value: &str);
101
102	/// Quotes and escapes the given string and writes the result to output without delimiting quotes.
103	fn json_string_part(&mut self, value: &str);
104
105	/// Converts number to string and writes it. Writes null for NaN and infinity
106	#[inline(never)]
107	fn json_number_f64(&mut self, value: f64) {
108		if !value.is_finite() {
109			// JSON does not allow infinite or nan values. In browsers JSON.stringify(Number.NaN) = "null"
110			self.json_null();
111			return;
112		}
113
114		let mut buf = ryu::Buffer::new();
115		let mut result = buf.format_finite(value);
116		if result.ends_with(".0") {
117			result = unsafe { result.get_unchecked(..result.len() - 2) };
118		}
119		self.json_number_str(result);
120	}
121
122	/// Writes a number that has already been converted to string
123	#[inline(always)]
124	fn json_number_str(&mut self, value: &str) {
125		self.json_fragment(value);
126	}
127
128	/// Called at the start of writing an object. Writes the opening bracket
129	#[inline(always)]
130	fn json_begin_object(&mut self) {
131		self.json_fragment("{");
132	}
133
134	/// Called after writing all key-value pairs of an object.
135	///
136	/// `empty` is `true` when the object contains no key-value pairs.
137	#[inline(always)]
138	fn json_end_object(&mut self, _empty: bool) {
139		self.json_fragment("}");
140	}
141
142	/// Called at the start of writing an array.
143	#[inline(always)]
144	fn json_begin_array(&mut self) {
145		self.json_fragment("[");
146	}
147
148	/// Called after writing all items of an array.
149	///
150	/// `empty` is `true` when the array contains no items.
151	#[inline(always)]
152	fn json_end_array(&mut self, _empty: bool) {
153		self.json_fragment("]");
154	}
155
156	/// Writes a double-quote.
157	///
158	/// Called when creating a JSONStringWriter
159	#[inline(always)]
160	fn json_begin_string(&mut self) {
161		self.json_fragment("\"");
162	}
163
164	/// Writes a double-quote.
165	///
166	/// Called when dropping a JSONStringWriter
167	#[inline(always)]
168	fn json_end_string(&mut self) {
169		self.json_fragment("\"");
170	}
171
172	/// Called before each key-value pair in an object and each item in an array.
173	///
174	#[inline]
175	fn json_begin_array_value(&mut self, first: bool) {
176		if !first {
177			self.json_fragment(",");
178		}
179	}
180
181	/// writes a comma when not first entry, escapes and writes the key and a colon
182	fn json_object_key(&mut self, key: &str, first: bool) {
183		if !first {
184			self.json_fragment(",");
185		}
186		self.json_string(key);
187		self.json_fragment(":");
188	}
189
190	/// write a raw json fragment
191	fn json_fragment(&mut self, value: &str);
192}
193
194///
195/// Represents the null value in json.
196///
197/// **Note**: Option::None may be used instead in most cases.
198///
199pub static NULL: Null = Null();
200
201impl<W: JSONWriter> JSONObjectWriter<'_, W> {
202	///
203	/// Creates a new JSONObjectWriter that writes to the given buffer. Writes '{' to the buffer immediately.
204	///
205	#[inline(always)]
206	pub fn new(writer: &mut W) -> JSONObjectWriter<'_, W> {
207		writer.json_begin_object();
208		JSONObjectWriter {
209			writer,
210			empty: true,
211		}
212	}
213
214	///
215	/// Starts writing a nested object with given key:
216	///
217	/// Esacapes key, writes "\"key\":{" and returns a JSONObjectWriter
218	///
219	#[inline(always)]
220	pub fn object<'a>(&'a mut self, key: &str) -> JSONObjectWriter<'a, W> {
221		self.write_key(key);
222		JSONObjectWriter::new(self.writer)
223	}
224
225	///
226	/// Starts writing a nested array with given key:
227	///
228	/// Esacapes key, writes "\"key\":[" and returns a JSONArrayWriter.
229	///
230	#[inline(always)]
231	pub fn array<'a>(&'a mut self, key: &str) -> JSONArrayWriter<'a, W> {
232		self.write_key(key);
233		JSONArrayWriter::new(self.writer)
234	}
235
236	///
237	/// Escapes and appends key:value to the buffer
238	///
239	#[inline(always)]
240	pub fn value<T: JSONWriterValue>(&mut self, key: &str, value: T) {
241		self.write_key(key);
242		value.write_json(self.writer);
243	}
244
245	/// Write string with the given key, where the body of the string is built up using the
246	/// `JSONStringWriter` that impls the `fmt::Write` trait and so can be used in the `write!` macro.
247	#[inline(always)]
248	pub fn string_writer(&mut self, key: &str) -> JSONStringWriter<'_, W> {
249		self.write_key(key);
250		JSONStringWriter::new(self.writer)
251	}
252
253	///
254	/// Writes a key without any value.
255	///
256	/// Consider using the methods value(key, value), object(key) and array(key) instead of using this method directly.
257	///
258	/// <p style="background:rgba(255,181,77,0.16);padding:0.75em;">
259	/// <strong>Warning:</strong>
260	/// If you use this method, you will have to write the value to the buffer yourself afterwards.
261	/// </p>
262	///
263	pub fn write_key(&mut self, key: &str) {
264		self.writer.json_object_key(key, self.empty);
265		self.empty = false;
266	}
267
268	///
269	/// Drops the writer.
270	/// Dropping causes '}' to be appended to the buffer.
271	///
272	#[inline(always)]
273	pub fn end(self) {
274		drop(self);
275	}
276}
277
278impl JSONObjectWriter<'_, String> {
279	///
280	/// Writes the entire buffer to given writer and clears entire buffer on success.
281	///
282	#[inline(always)]
283	pub fn output_buffered_data<Writer: std::io::Write>(
284		&mut self,
285		writer: &mut Writer,
286	) -> Result<usize, std::io::Error> {
287		output_buffer_to(self.writer, writer)
288	}
289
290	///
291	/// Returns buffer length in bytes
292	///
293	#[inline(always)]
294	pub fn buffer_len(&self) -> usize {
295		self.writer.len()
296	}
297}
298
299impl<'a, W: JSONWriter> Drop for JSONObjectWriter<'a, W> {
300	#[inline(always)]
301	fn drop(&mut self) {
302		self.writer.json_end_object(self.empty);
303	}
304}
305
306impl<W: JSONWriter> JSONArrayWriter<'_, W> {
307	///
308	/// Creates a new JSONArrayWriter that writes to the given buffer. Writes '[' to the buffer immediately.
309	///
310	#[inline(always)]
311	pub fn new(writer: &mut W) -> JSONArrayWriter<'_, W> {
312		writer.json_begin_array();
313		JSONArrayWriter {
314			writer,
315			empty: true,
316		}
317	}
318
319	///
320	/// Starts writing a nested object as array entry.
321	///
322	/// Writes '{' and returns a JSONObjectWriter
323	///
324	#[inline(always)]
325	pub fn object(&mut self) -> JSONObjectWriter<'_, W> {
326		self.write_comma();
327		JSONObjectWriter::new(self.writer)
328	}
329
330	///
331	/// Starts writing a nested array as array entry.
332	///
333	/// Writes '[' and returns a JSONArrayWriter
334	///
335	#[inline(always)]
336	pub fn array(&mut self) -> JSONArrayWriter<'_, W> {
337		self.write_comma();
338		JSONArrayWriter::new(self.writer)
339	}
340
341	///
342	/// Writes given value as array entry
343	///
344	#[inline(always)]
345	pub fn value<T: JSONWriterValue>(&mut self, value: T) {
346		self.write_comma();
347		value.write_json(self.writer);
348	}
349
350	/// Write string with the given key, where the body of the string is built up using the
351	/// `JSONStringWriter` that impls the `fmt::Write` trait and so can be used in the `write!` macro.
352	#[inline(always)]
353	pub fn string_writer(&mut self) -> JSONStringWriter<'_, W> {
354		self.write_comma();
355		JSONStringWriter::new(self.writer)
356	}
357
358	///
359	/// Writes a comma unless at the beginning of the array
360	///
361	/// <p style="background:rgba(255,181,77,0.16);padding:0.75em;">
362	/// <strong>Warning:</strong>
363	/// If you use this method, you will have to write the value to the buffer yourself afterwards.
364	/// </p>
365	///
366	#[inline]
367	pub fn write_comma(&mut self) {
368		self.writer.json_begin_array_value(self.empty);
369		self.empty = false;
370	}
371
372	///
373	/// Drops the writer.
374	/// Dropping causes ']' to be appended to the buffer.
375	///
376	#[inline(always)]
377	pub fn end(self) {
378		drop(self);
379	}
380}
381
382impl<W: JSONWriter> Drop for JSONArrayWriter<'_, W> {
383	#[inline(always)]
384	fn drop(&mut self) {
385		self.writer.json_end_array(self.empty);
386	}
387}
388
389impl JSONArrayWriter<'_, String> {
390	///
391	/// Writes the entire buffer to given writer and clears entire buffer on success.
392	///
393	#[inline(always)]
394	pub fn output_buffered_data<Writer: std::io::Write>(
395		&mut self,
396		writer: &mut Writer,
397	) -> Result<usize, std::io::Error> {
398		output_buffer_to(self.writer, writer)
399	}
400
401	///
402	/// Returns buffer length in bytes
403	///
404	#[inline(always)]
405	pub fn buffer_len(&self) -> usize {
406		self.writer.len()
407	}
408}
409
410impl JSONWriter for String {
411	#[inline(always)]
412	fn json_string(&mut self, value: &str) {
413		write_string(self, value);
414	}
415
416	#[inline(always)]
417	fn json_string_part(&mut self, value: &str) {
418		write_part_of_string(self, value);
419	}
420
421	#[inline(always)]
422	fn json_fragment(&mut self, value: &str) {
423		self.push_str(value);
424	}
425
426	/// Called at the start of writing an object.
427	#[inline(always)]
428	fn json_begin_object(&mut self) {
429		self.push('{');
430	}
431
432	/// Called after writing all key-value pairs of an object.
433	///
434	/// `empty` is `true` when the object contains no key-value pairs.
435	#[inline(always)]
436	fn json_end_object(&mut self, _empty: bool) {
437		self.push('}');
438	}
439
440	/// Called at the start of writing an array.
441	#[inline(always)]
442	fn json_begin_array(&mut self) {
443		self.push('[');
444	}
445
446	/// Called after writing all items of an array.
447	///
448	/// `empty` is `true` when the array contains no items.
449	#[inline(always)]
450	fn json_end_array(&mut self, _empty: bool) {
451		self.push(']');
452	}
453
454	/// Called before each key-value pair in an object and each item in an array.
455	///
456	#[inline]
457	fn json_begin_array_value(&mut self, first: bool) {
458		if !first {
459			self.push(',');
460		}
461	}
462
463	/// Called before each key-value pair in an object and each item in an array.
464	///
465	fn json_object_key(&mut self, key: &str, first: bool) {
466		if !first {
467			self.push(',');
468		}
469		write_string(self, key);
470		self.push(':');
471	}
472
473	#[inline(always)]
474	fn json_begin_string(&mut self) {
475		self.push('"');
476	}
477
478	#[inline(always)]
479	fn json_end_string(&mut self) {
480		self.push('"');
481	}
482}
483
484/// Formats JSON in a human-readable format with whitespace, newlines, and indentation.
485pub struct PrettyJSONWriter<'a> {
486	/// Result
487	pub buffer: &'a mut String,
488	indent: &'a str,
489	depth: usize,
490}
491
492impl PrettyJSONWriter<'_> {
493	/// Creates a new human-readable formatter with two spaces for indentation.
494	pub fn new(buffer: &mut String) -> PrettyJSONWriter<'_> {
495		// Same default as serde_json::ser::PrettyFormatter
496		PrettyJSONWriter {
497			buffer,
498			indent: "  ",
499			depth: 0,
500		}
501	}
502
503	/// Creates a new formatter using `indent` for indentation.
504	pub fn with_indent<'a>(buffer: &'a mut String, indent: &'a str) -> PrettyJSONWriter<'a> {
505		PrettyJSONWriter {
506			buffer,
507			indent,
508			depth: 0,
509		}
510	}
511
512	fn write_indent(&mut self) {
513		for _ in 0..self.depth {
514			self.buffer.push_str(self.indent);
515		}
516	}
517}
518
519impl JSONWriter for PrettyJSONWriter<'_> {
520	fn json_begin_object(&mut self) {
521		self.depth += 1;
522		self.buffer.push('{');
523	}
524
525	fn json_end_object(&mut self, empty: bool) {
526		self.depth -= 1;
527		if !empty {
528			self.buffer.push('\n');
529			self.write_indent();
530		}
531		self.buffer.push('}');
532	}
533
534	fn json_begin_array(&mut self) {
535		self.depth += 1;
536		self.buffer.push('[');
537	}
538
539	fn json_end_array(&mut self, empty: bool) {
540		self.depth -= 1;
541		if !empty {
542			self.buffer.push('\n');
543			self.write_indent();
544		}
545		self.buffer.push(']');
546	}
547
548	fn json_begin_array_value(&mut self, first: bool) {
549		self.buffer.push_str(if first { "\n" } else { ",\n" });
550		self.write_indent();
551	}
552
553	fn json_object_key(&mut self, key: &str, first: bool) {
554		self.buffer.push_str(if first { "\n" } else { ",\n" });
555		self.write_indent();
556		write_string(self.buffer, key);
557		self.buffer.push_str(": ");
558	}
559
560	fn json_string(&mut self, value: &str) {
561		write_string(self.buffer, value);
562	}
563
564	fn json_string_part(&mut self, value: &str) {
565		write_part_of_string(self.buffer, value);
566	}
567
568	fn json_fragment(&mut self, value: &str) {
569		self.buffer.push_str(value);
570	}
571}
572
573///
574/// Types with this trait can be converted to JSON
575///
576pub trait JSONWriterValue {
577	///
578	/// Appends a JSON representation of self to the output buffer
579	///
580	fn write_json<W: JSONWriter>(self, writer: &mut W);
581}
582
583impl JSONWriterValue for &str {
584	#[inline(always)]
585	fn write_json<W: JSONWriter>(self, writer: &mut W) {
586		writer.json_string(self);
587	}
588}
589
590impl JSONWriterValue for &std::borrow::Cow<'_, str> {
591	#[inline(always)]
592	fn write_json<W: JSONWriter>(self, writer: &mut W) {
593		writer.json_string(AsRef::as_ref(self));
594	}
595}
596
597impl JSONWriterValue for &String {
598	#[inline(always)]
599	fn write_json<W: JSONWriter>(self, writer: &mut W) {
600		writer.json_string(self);
601	}
602}
603
604impl JSONWriterValue for f64 {
605	#[inline(always)]
606	fn write_json<W: JSONWriter>(self, writer: &mut W) {
607		writer.json_number_f64(self);
608	}
609}
610
611impl JSONWriterValue for f32 {
612	#[inline(always)]
613	fn write_json<W: JSONWriter>(self, writer: &mut W) {
614		writer.json_number_f64(self as f64);
615	}
616}
617
618impl JSONWriterValue for u128 {
619	#[inline(always)]
620	fn write_json<W: JSONWriter>(self, writer: &mut W) {
621		let mut buf = itoa::Buffer::new();
622		writer.json_number_str(buf.format(self));
623	}
624}
625
626impl JSONWriterValue for i128 {
627	#[inline(always)]
628	fn write_json<W: JSONWriter>(self, writer: &mut W) {
629		let mut buf = itoa::Buffer::new();
630		writer.json_number_str(buf.format(self));
631	}
632}
633
634impl JSONWriterValue for u64 {
635	#[inline(always)]
636	fn write_json<W: JSONWriter>(self, writer: &mut W) {
637		let mut buf = itoa::Buffer::new();
638		writer.json_number_str(buf.format(self));
639	}
640}
641
642impl JSONWriterValue for i64 {
643	#[inline(always)]
644	fn write_json<W: JSONWriter>(self, writer: &mut W) {
645		let mut buf = itoa::Buffer::new();
646		writer.json_number_str(buf.format(self));
647	}
648}
649
650impl JSONWriterValue for u32 {
651	#[inline(always)]
652	fn write_json<W: JSONWriter>(self, writer: &mut W) {
653		let mut buf = itoa::Buffer::new();
654		writer.json_number_str(buf.format(self));
655	}
656}
657
658impl JSONWriterValue for i32 {
659	#[inline(always)]
660	fn write_json<W: JSONWriter>(self, writer: &mut W) {
661		let mut buf = itoa::Buffer::new();
662		writer.json_number_str(buf.format(self));
663	}
664}
665
666impl JSONWriterValue for u16 {
667	#[inline(always)]
668	fn write_json<W: JSONWriter>(self, writer: &mut W) {
669		let mut buf = itoa::Buffer::new();
670		writer.json_number_str(buf.format(self));
671	}
672}
673
674impl JSONWriterValue for i16 {
675	#[inline(always)]
676	fn write_json<W: JSONWriter>(self, writer: &mut W) {
677		let mut buf = itoa::Buffer::new();
678		writer.json_number_str(buf.format(self));
679	}
680}
681
682impl JSONWriterValue for u8 {
683	#[inline(always)]
684	fn write_json<W: JSONWriter>(self, writer: &mut W) {
685		let mut buf = itoa::Buffer::new();
686		writer.json_number_str(buf.format(self));
687	}
688}
689
690impl JSONWriterValue for i8 {
691	#[inline(always)]
692	fn write_json<W: JSONWriter>(self, writer: &mut W) {
693		let mut buf = itoa::Buffer::new();
694		writer.json_number_str(buf.format(self));
695	}
696}
697
698impl JSONWriterValue for bool {
699	#[inline(always)]
700	fn write_json<W: JSONWriter>(self, writer: &mut W) {
701		writer.json_bool(self);
702	}
703}
704
705impl JSONWriterValue for Null {
706	#[inline(always)]
707	fn write_json<W: JSONWriter>(self, writer: &mut W) {
708		writer.json_null();
709	}
710}
711
712impl<T: JSONWriterValue + Copy> JSONWriterValue for &T {
713	#[inline(always)]
714	fn write_json<W: JSONWriter>(self, writer: &mut W) {
715		(*self).write_json(writer);
716	}
717}
718
719impl<T: JSONWriterValue> JSONWriterValue for Option<T> {
720	#[inline]
721	fn write_json<W: JSONWriter>(self, writer: &mut W) {
722		match self {
723			None => {
724				writer.json_null();
725			}
726			Some(value) => {
727				value.write_json(writer);
728			}
729		}
730	}
731}
732
733impl<Item> JSONWriterValue for &Vec<Item>
734where
735	for<'b> &'b Item: JSONWriterValue,
736{
737	#[inline(always)]
738	fn write_json<W: JSONWriter>(self, writer: &mut W) {
739		self.as_slice().write_json(writer);
740	}
741}
742
743impl<Item> JSONWriterValue for &[Item]
744where
745	for<'b> &'b Item: JSONWriterValue,
746{
747	fn write_json<W: JSONWriter>(self, writer: &mut W) {
748		let mut array = JSONArrayWriter::new(writer);
749		for item in self.iter() {
750			array.value(item);
751		}
752	}
753}
754
755impl<Key: AsRef<str>, Item> JSONWriterValue for &std::collections::HashMap<Key, Item>
756where
757	for<'b> &'b Item: JSONWriterValue,
758{
759	fn write_json<W: JSONWriter>(self, writer: &mut W) {
760		let mut obj = JSONObjectWriter::new(writer);
761		for (key, value) in self.iter() {
762			obj.value(key.as_ref(), value);
763		}
764	}
765}
766
767impl<Key: AsRef<str>, Item> JSONWriterValue for &std::collections::BTreeMap<Key, Item>
768where
769	for<'b> &'b Item: JSONWriterValue,
770{
771	fn write_json<W: JSONWriter>(self, writer: &mut W) {
772		let mut obj = JSONObjectWriter::new(writer);
773		for (key, value) in self.iter() {
774			obj.value(key.as_ref(), value);
775		}
776	}
777}
778
779///
780/// Converts given value to a json string.
781///
782#[inline]
783pub fn to_json_string<T: JSONWriterValue>(v: T) -> String {
784	let mut result = String::new();
785	v.write_json(&mut result);
786	return result;
787}
788
789fn output_buffer_to<Writer: std::io::Write>(
790	buffer: &mut String,
791	writer: &mut Writer,
792) -> Result<usize, std::io::Error> {
793	match writer.write_all(buffer.as_bytes()) {
794		Ok(_) => {
795			let len = buffer.len();
796			buffer.clear();
797			Ok(len)
798		}
799		Err(err) => Err(err),
800	}
801}
802
803///
804/// Quotes and escapes input and appends result to output buffer
805///
806#[inline(never)]
807pub fn write_string(output_buffer: &mut String, input: &str) {
808	output_buffer.push('"');
809	write_part_of_string_impl(output_buffer, input);
810	output_buffer.push('"');
811}
812
813///
814/// Escapes input and appends result to output buffer without adding quotes.
815///
816#[inline(never)]
817pub fn write_part_of_string(output_buffer: &mut String, input: &str) {
818	write_part_of_string_impl(output_buffer, input);
819}
820
821const fn get_replacements() -> [u8; 256] {
822	// NOTE: Only characters smaller than 128 are allowed here.
823	// Trying to escape values above 128 would generate invalid utf-8 output
824	// -----
825	// see https://www.json.org/json-en.html
826	let mut result = [0u8; 256];
827	// Escape everything from 0 to 0x1F
828	let mut i = 0;
829	while i < 0x20 {
830		result[i] = b'u';
831		i += 1;
832	}
833	result[b'\"' as usize] = b'"';
834	result[b'\\' as usize] = b'\\';
835	result[b'/' as usize] = b'/';
836	result[8] = b'b';
837	result[0xc] = b'f';
838	result[b'\n' as usize] = b'n';
839	result[b'\r' as usize] = b'r';
840	result[b'\t' as usize] = b't';
841	result[0] = b'u';
842
843	return result;
844}
845
846static REPLACEMENTS: [u8; 256] = get_replacements();
847static HEX: [u8; 16] = *b"0123456789ABCDEF";
848
849///
850/// Escapes and append part of string
851///
852#[inline(always)]
853fn write_part_of_string_impl(output_buffer: &mut String, input: &str) {
854	// All of the relevant characters are in the ansi range (<128).
855	// This means we can safely ignore any utf-8 characters and iterate over the bytes directly
856	let mut num_bytes_written: usize = 0;
857	let mut index: usize = 0;
858	let bytes = input.as_bytes();
859	while index < bytes.len() {
860		let cur_byte = bytes[index];
861		let replacement = REPLACEMENTS[cur_byte as usize];
862		if replacement != 0 {
863			if num_bytes_written < index {
864				// Checks can be omitted here:
865				// We know that index is smaller than the output_buffer length.
866				// We also know that num_bytes_written is smaller than index
867				// We also know that the boundaries are not in the middle of an utf-8 multi byte sequence, because those characters are not escaped
868				output_buffer.push_str(unsafe { input.get_unchecked(num_bytes_written..index) });
869			}
870			if replacement == b'u' {
871				let bytes: [u8; 6] = [
872					b'\\',
873					b'u',
874					b'0',
875					b'0',
876					HEX[((cur_byte / 16) & 0xF) as usize],
877					HEX[(cur_byte & 0xF) as usize],
878				];
879				// Checks can be omitted here: We know bytes is a valid utf-8 string (see above)
880				output_buffer.push_str(unsafe { std::str::from_utf8_unchecked(&bytes) });
881			} else {
882				let bytes: [u8; 2] = [b'\\', replacement];
883				// Checks can be omitted here: We know bytes is a valid utf-8 string, because the replacement table only contains characters smaller than 128
884				output_buffer.push_str(unsafe { std::str::from_utf8_unchecked(&bytes) });
885			}
886			num_bytes_written = index + 1;
887		}
888		index += 1;
889	}
890	if num_bytes_written < bytes.len() {
891		// Checks can be omitted here:
892		// We know that num_bytes_written is smaller than index
893		// We also know that num_bytes_written not in the middle of an utf-8 multi byte sequence, because those are not escaped
894		output_buffer.push_str(unsafe { input.get_unchecked(num_bytes_written..bytes.len()) });
895	}
896}
897
898#[cfg(test)]
899mod tests {
900	use super::*;
901
902	#[test]
903	fn test_array() {
904		let mut buffer = String::new();
905		let mut array = JSONArrayWriter::new(&mut buffer);
906		array.value(0u8);
907		array.value(1i32);
908		array.value("2");
909		array.value("\"<script>1/2</script>\"");
910		let mut nested_arr = array.array();
911		nested_arr.value("nested");
912		nested_arr.end();
913		let mut nested_obj = array.object();
914		nested_obj.value("ä\töü", "ä\töü");
915		nested_obj.end();
916		let nested_obj2 = array.object();
917		nested_obj2.end();
918		drop(array);
919
920		assert_eq!(buffer, "[0,1,\"2\",\"\\\"<script>1\\/2<\\/script>\\\"\",[\"nested\"],{\"ä\\töü\":\"ä\\töü\"},{}]");
921	}
922
923	#[test]
924	fn test_array_range() {
925		let bytes = b"ABC";
926		assert_eq!(to_json_string(&bytes[..]), "[65,66,67]");
927
928		let mut v = Vec::<u8>::new();
929		v.extend_from_slice(bytes);
930		assert_eq!(to_json_string(&v), "[65,66,67]");
931	}
932
933	#[test]
934	fn test_object() {
935		let mut map = std::collections::HashMap::<String, String>::new();
936		map.insert("a".to_owned(), "a".to_owned());
937		assert_eq!(to_json_string(&map), "{\"a\":\"a\"}");
938	}
939
940	#[allow(clippy::approx_constant)]
941	#[test]
942	fn test_numbers() {
943		// unsigned
944		assert_eq!(to_json_string(1u8), "1");
945		assert_eq!(to_json_string(1u16), "1");
946		assert_eq!(to_json_string(1u32), "1");
947		assert_eq!(to_json_string(u8::MAX), "255");
948		assert_eq!(to_json_string(u16::MAX), "65535");
949		assert_eq!(to_json_string(u32::MAX), "4294967295");
950		assert_eq!(to_json_string(u64::MAX), "18446744073709551615");
951		assert_eq!(
952			to_json_string(u128::MAX),
953			"340282366920938463463374607431768211455"
954		);
955
956		// signed
957		assert_eq!(to_json_string(-1i8), "-1");
958		assert_eq!(to_json_string(-1i16), "-1");
959		assert_eq!(to_json_string(-1i32), "-1");
960		assert_eq!(to_json_string(-1i64), "-1");
961		assert_eq!(to_json_string(-1i128), "-1");
962
963		// float
964		assert_eq!(to_json_string(0f32), "0");
965		assert_eq!(to_json_string(2f32), "2");
966		assert_eq!(to_json_string(-2f32), "-2");
967
968		assert_eq!(to_json_string(0f64), "0");
969		assert_eq!(to_json_string(2f64), "2");
970		assert_eq!(to_json_string(-2f64), "-2");
971		assert_eq!(to_json_string(3.141592653589793), "3.141592653589793");
972		assert_eq!(to_json_string(0.1f64), "0.1");
973		assert_eq!(to_json_string(-0.1f64), "-0.1");
974		//assert_eq!(to_json_string(-5.0/3.0), "-1.6666666666666667");
975		assert_eq!(to_json_string(1.5e30f64), "1.5e30");
976		assert_eq!(
977			to_json_string(-2.220446049250313e-16f64),
978			"-2.220446049250313e-16"
979		);
980
981		assert_eq!(to_json_string(1.0 / 0.0), "null");
982		assert_eq!(to_json_string(f64::INFINITY), "null");
983		assert_eq!(to_json_string(f64::NEG_INFINITY), "null");
984		assert_eq!(to_json_string(f64::NAN), "null");
985	}
986
987	#[test]
988	fn test_dtoa() {
989		assert_dtoa(0.0);
990		assert_dtoa(1.0);
991		assert_dtoa(-1.0);
992		assert_dtoa(2.0);
993		//assert_dtoa(-5.0/3.0);
994	}
995
996	fn assert_dtoa(v: f64) {
997		let a = v.to_string();
998		let mut b = String::new();
999		b.json_number_f64(v);
1000		assert_eq!(b, a);
1001	}
1002
1003	#[test]
1004	fn test_strings() {
1005		assert_eq!(
1006			to_json_string("中文\0\x08\x09\"\\\n\r\t</script>"),
1007			"\"中文\\u0000\\b\\t\\\"\\\\\\n\\r\\t<\\/script>\""
1008		);
1009	}
1010
1011	#[test]
1012	fn test_basic_example() {
1013		let mut object_str = String::new();
1014		{
1015			let mut object_writer = JSONObjectWriter::new(&mut object_str);
1016			object_writer.value("number", 42i32);
1017		}
1018		assert_eq!(&object_str, "{\"number\":42}");
1019	}
1020
1021	#[allow(clippy::approx_constant)]
1022	#[test]
1023	fn test_misc_examples() {
1024		// Values
1025		assert_eq!(to_json_string("Hello World\n"), "\"Hello World\\n\"");
1026		assert_eq!(to_json_string(3.141592653589793f64), "3.141592653589793");
1027		assert_eq!(to_json_string(true), "true");
1028		assert_eq!(to_json_string(false), "false");
1029		assert_eq!(to_json_string(NULL), "null");
1030
1031		// Options of values
1032		assert_eq!(to_json_string(Option::<u8>::Some(42)), "42");
1033		assert_eq!(to_json_string(Option::<u8>::None), "null");
1034
1035		// Slices and vectors
1036		let numbers: [u8; 4] = [1, 2, 3, 4];
1037		assert_eq!(to_json_string(&numbers[..]), "[1,2,3,4]");
1038		let numbers_vec: Vec<u8> = vec![1u8, 2u8, 3u8, 4u8];
1039		assert_eq!(to_json_string(&numbers_vec), "[1,2,3,4]");
1040		let strings: [&str; 4] = ["a", "b", "c", "d"];
1041		assert_eq!(to_json_string(&strings[..]), "[\"a\",\"b\",\"c\",\"d\"]");
1042
1043		// Hash-maps:
1044		let mut map = std::collections::HashMap::<String, String>::new();
1045		map.insert("Hello".to_owned(), "World".to_owned());
1046		assert_eq!(to_json_string(&map), "{\"Hello\":\"World\"}");
1047
1048		// Objects:
1049		let mut object_str = String::new();
1050		let mut object_writer = JSONObjectWriter::new(&mut object_str);
1051
1052		// Values
1053		object_writer.value("number", 42i32);
1054		object_writer.value("slice", &numbers[..]);
1055
1056		// Nested arrays
1057		let mut nested_array = object_writer.array("array");
1058		nested_array.value(42u32);
1059		nested_array.value("?");
1060		nested_array.end();
1061
1062		// Nested objects
1063		let nested_object = object_writer.object("object");
1064		nested_object.end();
1065
1066		object_writer.end();
1067		assert_eq!(
1068			&object_str,
1069			"{\"number\":42,\"slice\":[1,2,3,4],\"array\":[42,\"?\"],\"object\":{}}"
1070		);
1071	}
1072
1073	#[test]
1074	fn test_string_writer() {
1075		use core::fmt::Write;
1076
1077		let mut object_str = String::new();
1078		let mut object_writer = JSONObjectWriter::new(&mut object_str);
1079
1080		let name = r#"zenora "bariella""#;
1081		let color = "yellow";
1082		object_writer.value("name", name);
1083		let mut w = object_writer.string_writer("compound");
1084		write!(w, "{name} : {color}").unwrap();
1085		w.end();
1086
1087		object_writer.value("number", 42i32);
1088
1089		{
1090			let mut array = object_writer.array("tools");
1091			let prefix = "air";
1092			array.value("hammer");
1093			write!(array.string_writer(), "{prefix}-hammer").unwrap();
1094			write!(array.string_writer(), "{prefix}-saw").unwrap();
1095		}
1096
1097		object_writer.end();
1098
1099		eprintln!("{}", object_str);
1100
1101		assert_eq!(
1102			&object_str,
1103			r#"{"name":"zenora \"bariella\"","compound":"zenora \"bariella\" : yellow","number":42,"tools":["hammer","air-hammer","air-saw"]}"#
1104		)
1105	}
1106
1107	#[test]
1108	fn test_duplicate_keys() {
1109		let mut object_str = String::new();
1110		{
1111			let mut object_writer = JSONObjectWriter::new(&mut object_str);
1112			object_writer.value("number", 42i32);
1113			object_writer.value("number", 43i32);
1114		}
1115		// Duplicates are not checked, this is by design!
1116		assert_eq!(&object_str, "{\"number\":42,\"number\":43}");
1117	}
1118
1119	#[test]
1120	fn test_flush() {
1121		// this could also be a file writer.
1122		let mut writer = Vec::<u8>::new();
1123
1124		let mut buffer = String::new();
1125		let mut array = JSONArrayWriter::new(&mut buffer);
1126		for i in 1i32..=1000000i32 {
1127			array.value(i);
1128			if array.buffer_len() > 2000 {
1129				array.output_buffered_data(&mut writer).unwrap();
1130			}
1131		}
1132		array.end();
1133		std::io::Write::write_all(&mut writer, buffer.as_bytes()).unwrap();
1134
1135		assert!(buffer.len() <= 4000, "Buffer too long");
1136		assert_eq!(
1137			&writer[writer.len() - b",999999,1000000]".len()..],
1138			b",999999,1000000]"
1139		);
1140	}
1141
1142	#[test]
1143	fn test_encoding() {
1144		for c in 0x00..0x20 {
1145			let c = char::from(c);
1146			let json = to_json_string(c.to_string().as_str());
1147			assert!(&json[0..2] == "\"\\");
1148		}
1149		assert_eq!(
1150			to_json_string("</script >\0\x1F"),
1151			"\"<\\/script >\\u0000\\u001F\""
1152		);
1153	}
1154
1155	#[test]
1156	fn test_pretty() {
1157		let mut buffer = String::new();
1158		let mut formatter = PrettyJSONWriter::with_indent(&mut buffer, "   ");
1159		let mut writer = JSONObjectWriter::new(&mut formatter);
1160		{
1161			let mut nested_writer = writer.object("nested");
1162			nested_writer.value("a", 3);
1163			nested_writer.value("b", &vec![0, 1, 4]);
1164		}
1165		writer.value("c", &vec![true, false, true]);
1166		writer.value("d", NULL);
1167		// empty object
1168		writer.object("e");
1169		writer.array("f");
1170		writer.end();
1171		assert_eq!(
1172			formatter.buffer,
1173			r#"{
1174   "nested": {
1175      "a": 3,
1176      "b": [
1177         0,
1178         1,
1179         4
1180      ]
1181   },
1182   "c": [
1183      true,
1184      false,
1185      true
1186   ],
1187   "d": null,
1188   "e": {},
1189   "f": []
1190}"#
1191		);
1192	}
1193}