1#[cfg(feature = "alloc")]
2use alloc::borrow::Cow;
3#[cfg(feature = "alloc")]
4use alloc::string::String;
5#[cfg(feature = "alloc")]
6use alloc::vec::Vec;
7
8use crate::JsonWrite;
9use crate::WriteJsonKey;
10
11#[cfg(feature = "alloc")]
12pub trait ToJsonValue {
13 fn to_json_value(&self) -> String;
14}
15
16#[cfg(feature = "alloc")]
17impl<T> ToJsonValue for T
18where
19 T: WriteJsonValue + ?Sized,
20{
21 fn to_json_value(&self) -> String {
22 let mut result = String::new();
23 let _ = self.write_json_value(&mut result);
24 result
25 }
26}
27
28pub trait WriteJsonValue {
29 fn write_json_value<W: JsonWrite + ?Sized>(&self, writer: &mut W) -> core::fmt::Result;
30}
31
32impl WriteJsonValue for bool {
33 fn write_json_value<W: JsonWrite + ?Sized>(&self, writer: &mut W) -> core::fmt::Result {
34 write!(writer, "{self}")
35 }
36}
37
38impl WriteJsonValue for u8 {
39 fn write_json_value<W: JsonWrite + ?Sized>(&self, writer: &mut W) -> core::fmt::Result {
40 write!(writer, "{self}")
41 }
42}
43
44impl WriteJsonValue for i8 {
45 fn write_json_value<W: JsonWrite + ?Sized>(&self, writer: &mut W) -> core::fmt::Result {
46 write!(writer, "{self}")
47 }
48}
49
50impl WriteJsonValue for u16 {
51 fn write_json_value<W: JsonWrite + ?Sized>(&self, writer: &mut W) -> core::fmt::Result {
52 write!(writer, "{self}")
53 }
54}
55
56impl WriteJsonValue for i16 {
57 fn write_json_value<W: JsonWrite + ?Sized>(&self, writer: &mut W) -> core::fmt::Result {
58 write!(writer, "{self}")
59 }
60}
61
62impl WriteJsonValue for u32 {
63 fn write_json_value<W: JsonWrite + ?Sized>(&self, writer: &mut W) -> core::fmt::Result {
64 write!(writer, "{self}")
65 }
66}
67
68impl WriteJsonValue for i32 {
69 fn write_json_value<W: JsonWrite + ?Sized>(&self, writer: &mut W) -> core::fmt::Result {
70 write!(writer, "{self}")
71 }
72}
73
74impl WriteJsonValue for u64 {
75 fn write_json_value<W: JsonWrite + ?Sized>(&self, writer: &mut W) -> core::fmt::Result {
76 write!(writer, "{self}")
77 }
78}
79
80impl WriteJsonValue for i64 {
81 fn write_json_value<W: JsonWrite + ?Sized>(&self, writer: &mut W) -> core::fmt::Result {
82 write!(writer, "{self}")
83 }
84}
85
86impl WriteJsonValue for u128 {
87 fn write_json_value<W: JsonWrite + ?Sized>(&self, writer: &mut W) -> core::fmt::Result {
88 write!(writer, "{self}")
89 }
90}
91
92impl WriteJsonValue for i128 {
93 fn write_json_value<W: JsonWrite + ?Sized>(&self, writer: &mut W) -> core::fmt::Result {
94 write!(writer, "{self}")
95 }
96}
97
98impl WriteJsonValue for f32 {
99 fn write_json_value<W: JsonWrite + ?Sized>(&self, writer: &mut W) -> core::fmt::Result {
100 if self.is_nan() || self.is_infinite() {
101 None::<Self>.write_json_value(writer)
102 } else {
103 if self % 1.0 == 0.0 {
104 write!(writer, "{self}.0")
105 } else {
106 write!(writer, "{self}")
107 }
108 }
109 }
110}
111
112impl WriteJsonValue for f64 {
113 fn write_json_value<W: JsonWrite + ?Sized>(&self, writer: &mut W) -> core::fmt::Result {
114 if self.is_nan() || self.is_infinite() {
115 None::<Self>.write_json_value(writer)
116 } else {
117 if self % 1.0 == 0.0 {
118 write!(writer, "{self}.0")
119 } else {
120 write!(writer, "{self}")
121 }
122 }
123 }
124}
125
126impl WriteJsonValue for char {
127 fn write_json_value<W: JsonWrite + ?Sized>(&self, writer: &mut W) -> core::fmt::Result {
128 let mut buf = [0; 4];
129 let v = self.encode_utf8(&mut buf);
130 v.write_json_value(writer)
131 }
132}
133
134impl WriteJsonValue for str {
135 fn write_json_value<W: JsonWrite + ?Sized>(&self, writer: &mut W) -> core::fmt::Result {
136 write_json_str(self, writer)
137 }
138}
139
140#[cfg(feature = "alloc")]
141impl WriteJsonValue for String {
142 fn write_json_value<W: JsonWrite + ?Sized>(&self, writer: &mut W) -> core::fmt::Result {
143 self.as_str().write_json_value(writer)
144 }
145}
146
147#[cfg(feature = "alloc")]
148impl WriteJsonValue for Cow<'_, str> {
149 fn write_json_value<W: JsonWrite + ?Sized>(&self, writer: &mut W) -> core::fmt::Result {
150 self.as_ref().write_json_value(writer)
151 }
152}
153
154impl<T: WriteJsonValue> WriteJsonValue for Option<T> {
155 fn write_json_value<W: JsonWrite + ?Sized>(&self, writer: &mut W) -> core::fmt::Result {
156 match self {
157 Some(v) => v.write_json_value(writer),
158 None => write_json_null(writer),
159 }
160 }
161}
162
163impl<V: WriteJsonValue> WriteJsonValue for [V] {
164 fn write_json_value<W: JsonWrite + ?Sized>(&self, writer: &mut W) -> core::fmt::Result {
165 writer.open_array()?;
166 let mut iter = self.iter();
167 if let Some(v) = iter.next() {
168 writer.value(v)?;
169 }
170 for v in iter {
171 writer.val_sep()?;
172 writer.space()?;
173 writer.value(v)?;
174 }
175 writer.close_array()?;
176 Ok(())
177 }
178}
179
180impl<V: WriteJsonValue, const N: usize> WriteJsonValue for [V; N] {
181 fn write_json_value<W: JsonWrite + ?Sized>(&self, writer: &mut W) -> core::fmt::Result {
182 self.as_slice().write_json_value(writer)
183 }
184}
185
186#[cfg(feature = "alloc")]
187impl<V: WriteJsonValue> WriteJsonValue for Vec<V> {
188 fn write_json_value<W: JsonWrite + ?Sized>(&self, writer: &mut W) -> core::fmt::Result {
189 self.as_slice().write_json_value(writer)
190 }
191}
192
193#[cfg(feature = "alloc")]
194impl<K: WriteJsonKey, V: WriteJsonValue> WriteJsonValue for alloc::collections::BTreeMap<K, V> {
195 fn write_json_value<W: JsonWrite + ?Sized>(&self, writer: &mut W) -> core::fmt::Result {
196 write_json_object(self.iter(), writer)
197 }
198}
199
200#[cfg(feature = "std")]
201impl<K: WriteJsonKey, V: WriteJsonValue> WriteJsonValue for std::collections::HashMap<K, V> {
202 fn write_json_value<W: JsonWrite + ?Sized>(&self, writer: &mut W) -> core::fmt::Result {
203 write_json_object(self.iter(), writer)
204 }
205}
206
207impl<V: WriteJsonValue + ?Sized> WriteJsonValue for &V {
208 fn write_json_value<W: JsonWrite + ?Sized>(&self, writer: &mut W) -> core::fmt::Result {
209 (*self).write_json_value(writer)
210 }
211}
212
213pub(crate) fn write_json_null<W: JsonWrite + ?Sized>(writer: &mut W) -> core::fmt::Result {
214 write!(writer, "null")
215}
216
217pub(crate) fn write_json_str<W: JsonWrite + ?Sized>(
218 value: &str,
219 writer: &mut W,
220) -> core::fmt::Result {
221 write!(writer, "\"")?;
222 format_escaped_str_contents(writer, value)?;
223 write!(writer, "\"")?;
224 Ok(())
225}
226
227fn format_escaped_str_contents<W>(writer: &mut W, value: &str) -> core::fmt::Result
228where
229 W: ?Sized + JsonWrite,
230{
231 let mut bytes = value.as_bytes();
232
233 let mut i = 0;
234 while i < bytes.len() {
235 let (string_run, rest) = bytes.split_at(i);
236 let (&byte, rest) = rest.split_first().unwrap();
237
238 let escape = ESCAPE[byte as usize];
239
240 i += 1;
241 if escape == 0 {
242 continue;
243 }
244
245 bytes = rest;
246 i = 0;
247
248 let string_run = unsafe { core::str::from_utf8_unchecked(string_run) };
250 if !string_run.is_empty() {
251 write!(writer, "{string_run}")?;
252 }
253
254 let char_escape = match escape {
255 BB => CharEscape::Backspace,
256 TT => CharEscape::Tab,
257 NN => CharEscape::LineFeed,
258 FF => CharEscape::FormFeed,
259 RR => CharEscape::CarriageReturn,
260 QU => CharEscape::Quote,
261 BS => CharEscape::ReverseSolidus,
262 UU => CharEscape::AsciiControl(byte),
263 _ => unsafe { core::hint::unreachable_unchecked() },
265 };
266 write_char_escape(writer, char_escape)?;
267 }
268
269 let string_run = unsafe { core::str::from_utf8_unchecked(bytes) };
271 if string_run.is_empty() {
272 return Ok(());
273 }
274
275 write!(writer, "{string_run}")?;
276 Ok(())
277}
278
279const BB: u8 = b'b'; const TT: u8 = b't'; const NN: u8 = b'n'; const FF: u8 = b'f'; const RR: u8 = b'r'; const QU: u8 = b'"'; const BS: u8 = b'\\'; const UU: u8 = b'u'; const __: u8 = 0;
288
289static ESCAPE: [u8; 256] = [
292 UU, UU, UU, UU, UU, UU, UU, UU, BB, TT, NN, UU, FF, RR, UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, UU, __, __, QU, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, BS, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, ];
310
311enum CharEscape {
313 Quote,
315 ReverseSolidus,
317 Backspace,
319 FormFeed,
321 LineFeed,
323 CarriageReturn,
325 Tab,
327 AsciiControl(u8),
330}
331
332fn write_char_escape<W>(writer: &mut W, char_escape: CharEscape) -> core::fmt::Result
333where
334 W: ?Sized + JsonWrite,
335{
336 let escape_char = match char_escape {
337 CharEscape::Quote => '"',
338 CharEscape::ReverseSolidus => '\\',
339 CharEscape::Backspace => 'b',
340 CharEscape::FormFeed => 'f',
341 CharEscape::LineFeed => 'n',
342 CharEscape::CarriageReturn => 'r',
343 CharEscape::Tab => 't',
344 CharEscape::AsciiControl(_) => 'u',
345 };
346
347 match char_escape {
348 CharEscape::AsciiControl(byte) => {
349 static HEX_DIGITS: [u8; 16] = *b"0123456789abcdef";
350 let first = HEX_DIGITS[(byte >> 4) as usize] as char;
351 let second = HEX_DIGITS[(byte & 0xF) as usize] as char;
352 write!(writer, "\\{escape_char}00{first}{second}")
353 }
354 _ => {
355 write!(writer, "\\{escape_char}")
356 }
357 }
358}
359
360fn write_json_object<
361 'i,
362 I: Iterator<Item = (&'i K, &'i V)>,
363 K: WriteJsonKey + 'i,
364 V: WriteJsonValue + 'i,
365 W: JsonWrite + ?Sized,
366>(
367 mut iter: I,
368 writer: &mut W,
369) -> core::fmt::Result {
370 writer.open_object()?;
371 let mut trailing_space = false;
372 if let Some((key, value)) = iter.next() {
373 writer.space()?;
374 writer.key(key)?;
375 writer.keyval_sep()?;
376 writer.space()?;
377 writer.value(value)?;
378 trailing_space = true;
379 }
380 for (key, value) in iter {
381 writer.val_sep()?;
382 writer.space()?;
383 writer.key(key)?;
384 writer.keyval_sep()?;
385 writer.space()?;
386 writer.value(value)?;
387 }
388 if trailing_space {
389 writer.space()?;
390 }
391 writer.close_object()?;
392 Ok(())
393}