nyoom_json/
lib.rs

1#![doc = include_str!("../README.md")]
2#![no_std]
3
4use core::mem::ManuallyDrop;
5
6#[cfg(feature = "alloc")]
7extern crate alloc;
8#[cfg(feature = "alloc")]
9use alloc::string::String;
10
11use sealed::sealed;
12
13mod escape;
14mod write_to_json;
15pub use write_to_json::*;
16
17#[inline]
18#[cold]
19fn cold() {}
20
21/// Any buffer which JSON may be written into.
22pub trait JsonBuffer {
23    fn push(&mut self, c: char);
24    fn push_str(&mut self, s: &str);
25    fn reserve(&mut self, l: usize);
26}
27
28impl<S> JsonBuffer for &mut S
29where
30    S: JsonBuffer,
31{
32    #[inline(always)]
33    fn push(&mut self, c: char) {
34        (*self).push(c)
35    }
36
37    #[inline(always)]
38    fn push_str(&mut self, s: &str) {
39        (*self).push_str(s)
40    }
41
42    #[inline(always)]
43    fn reserve(&mut self, l: usize) {
44        (*self).reserve(l)
45    }
46}
47
48#[cfg(feature = "alloc")]
49impl JsonBuffer for String {
50    #[inline(always)]
51    fn push(&mut self, c: char) {
52        self.push(c)
53    }
54
55    #[inline(always)]
56    fn push_str(&mut self, s: &str) {
57        self.push_str(s)
58    }
59
60    #[inline(always)]
61    fn reserve(&mut self, l: usize) {
62        self.reserve(l)
63    }
64}
65
66/// A general JSON serializer, over a mutable buffer of some sort.
67/// # Examples
68/// ```
69/// use nyoom_json::Serializer;
70///
71/// let mut out = String::new();
72/// let mut ser = Serializer::new(&mut out);
73///
74/// let mut obj = ser.object();
75/// obj.field("kind", "cat");
76/// obj.field("has_been_fed", false);
77/// obj.field("meow_decibels", 45);
78/// obj.end();
79///
80/// let mut arr = ser.array();
81/// arr.add("friends");
82/// arr.add("romans");
83/// arr.add("countrymen");
84/// arr.end();
85///
86/// ser.end();
87/// ```
88#[repr(transparent)]
89pub struct Serializer<'a, S: JsonBuffer> {
90    buf: &'a mut S,
91}
92
93impl<'a, S: JsonBuffer> Serializer<'a, S> {
94    /// Creates a new serializer over a JSON output buffer.
95    pub fn new(buf: &mut S) -> Serializer<S> {
96        Serializer { buf }
97    }
98
99    /// Writes out a single primitive JSON value.
100    /// # Examples
101    ///
102    /// ```
103    /// use nyoom_json::Serializer;
104    ///
105    /// let mut out = String::new();
106    /// let mut ser = Serializer::new(&mut out);
107    /// ser.write(3);
108    /// ```
109    pub fn write(&mut self, val: impl WriteToJson<S>) {
110        val.write_to_json(self.buf)
111    }
112
113    /// Starts serialization of an array.
114    /// # Examples
115    ///
116    /// ```
117    /// use nyoom_json::Serializer;
118    ///
119    /// let mut out = String::new();
120    /// let mut ser = Serializer::new(&mut out);
121    ///
122    /// let mut arr = ser.array();
123    /// arr.add("friends");
124    /// arr.add("romans");
125    /// arr.add("countrymen");
126    /// arr.end();
127    /// ```
128    pub fn array(&mut self) -> ArrayWriter<S> {
129        ArrayWriter::start(self.buf)
130    }
131
132    /// Starts serialization of an object.
133    /// # Examples
134    ///
135    /// ```
136    /// use nyoom_json::Serializer;
137    ///
138    /// let mut out = String::new();
139    /// let mut ser = Serializer::new(&mut out);
140    ///
141    /// let mut obj = ser.object();
142    /// obj.field("kind", "cat");
143    /// obj.field("has_been_fed", false);
144    /// obj.field("meow_decibels", 45);
145    /// obj.end();
146    /// ```
147    pub fn object(&mut self) -> ObjectWriter<S> {
148        ObjectWriter::start(self.buf)
149    }
150
151    /// Ends the serializer.
152    pub fn end(self) {}
153}
154
155/// A serializer that is only able to serialize a single value. See documentation of [Serializer](Serializer)
156pub struct SingleValueSerializer<'a, S: JsonBuffer> {
157    guard: ManuallyDrop<&'a mut S>,
158}
159
160impl<'a, S: JsonBuffer> SingleValueSerializer<'a, S> {
161    pub fn new(val: &'a mut S) -> SingleValueSerializer<'a, S> {
162        SingleValueSerializer {
163            guard: ManuallyDrop::new(val),
164        }
165    }
166
167    pub fn write(mut self, val: impl WriteToJson<S>) {
168        let buf = unsafe { ManuallyDrop::<&'a mut S>::take(&mut self.guard) };
169        val.write_to_json(buf);
170        core::mem::forget(self);
171    }
172
173    pub fn array(mut self) -> ArrayWriter<'a, S> {
174        let buf = unsafe { ManuallyDrop::<&'a mut S>::take(&mut self.guard) };
175        let w = ArrayWriter::start(buf);
176        core::mem::forget(self);
177        w
178    }
179
180    pub fn object(mut self) -> ObjectWriter<'a, S> {
181        let buf = unsafe { ManuallyDrop::<&'a mut S>::take(&mut self.guard) };
182        let w = ObjectWriter::start(buf);
183        core::mem::forget(self);
184        w
185    }
186}
187
188impl<'a, S: JsonBuffer> Drop for SingleValueSerializer<'a, S> {
189    fn drop(&mut self) {
190        unsafe { ManuallyDrop::<&'a mut S>::take(&mut self.guard).push_str("null") };
191    }
192}
193
194/// Serializer for a JSON array.
195pub struct ArrayWriter<'a, S: JsonBuffer> {
196    buf: &'a mut S,
197    first_element: bool,
198}
199
200impl<'a, S: JsonBuffer> ArrayWriter<'a, S> {
201    fn start(buf: &'a mut S) -> ArrayWriter<'a, S> {
202        buf.push('[');
203        ArrayWriter {
204            buf,
205            first_element: true,
206        }
207    }
208
209    fn comma(&mut self) {
210        match self.first_element {
211            true => {
212                cold();
213                self.first_element = false
214            }
215            false => self.buf.push(','),
216        }
217    }
218
219    /// Adds a single primitive JSON value to this array.
220    /// # Examples
221    ///
222    /// ```
223    /// # use nyoom_json::Serializer;
224    /// #
225    /// # let mut out = String::new();
226    /// # let mut ser = Serializer::new(&mut out);
227    /// #
228    /// let mut arr = ser.array();
229    /// arr.add("friends");
230    /// arr.add("romans");
231    /// arr.add("countrymen");
232    /// arr.end();
233    /// ```
234    pub fn add(&mut self, val: impl WriteToJson<S>) {
235        self.comma();
236        val.write_to_json(self.buf)
237    }
238
239    /// Adds a slice of a JSON primitive to this array.
240    /// # Examples
241    ///
242    /// ```
243    /// # use nyoom_json::Serializer;
244    /// #
245    /// # let mut out = String::new();
246    /// # let mut ser = Serializer::new(&mut out);
247    /// #
248    /// let mut arr = ser.array();
249    /// arr.extend(&["friends", "romans", "countrymen"]);
250    /// arr.end();
251    /// ```
252    pub fn extend<V: WriteToJson<S>>(&mut self, vals: impl IntoIterator<Item = V>) {
253        for val in vals {
254            self.add(val);
255        }
256    }
257
258    /// Adds an arbitrary JSON object to this array.
259    ///
260    /// # Arguments
261    ///
262    /// * `encoder` - A closure that encodes a single value into the array.
263    ///
264    /// # Examples
265    ///
266    /// ```
267    /// # use nyoom_json::Serializer;
268    /// #
269    /// # let mut out = String::new();
270    /// # let mut ser = Serializer::new(&mut out);
271    /// #
272    /// let mut arr = ser.array();
273    /// arr.add_complex(|mut ser| {
274    ///     let mut obj = ser.object();
275    ///     obj.field("kitten", true);
276    ///     obj.field("cuteness", 10.0);
277    /// });
278    /// arr.end();
279    /// ```
280    pub fn add_complex<F, O>(&mut self, encoder: F) -> O
281    where
282        F: FnOnce(SingleValueSerializer<&mut S>) -> O,
283    {
284        self.comma();
285        encoder(SingleValueSerializer::new(&mut self.buf))
286    }
287
288    /// Adds a JSON object to this array.
289    ///
290    /// # Examples
291    ///
292    /// ```
293    /// # use nyoom_json::Serializer;
294    /// #
295    /// # let mut out = String::new();
296    /// # let mut ser = Serializer::new(&mut out);
297    /// #
298    /// let mut arr = ser.array();
299    ///
300    /// let mut obj = arr.add_object();
301    /// obj.field("kitten", true);
302    /// obj.field("cuteness", 10.0);
303    /// obj.end();
304    ///
305    /// arr.end();
306    /// ```
307    pub fn add_object(&mut self) -> ObjectWriter<S> {
308        self.comma();
309        ObjectWriter::start(self.buf)
310    }
311
312    /// Adds a JSON array.. to this array.
313    ///
314    /// # Examples
315    ///
316    /// ```
317    /// # use nyoom_json::Serializer;
318    /// #
319    /// # let mut out = String::new();
320    /// # let mut ser = Serializer::new(&mut out);
321    /// #
322    /// let mut arr = ser.array();
323    ///
324    /// let mut inner_arr = arr.add_array();
325    /// inner_arr.extend(&[1,2,3]);
326    /// inner_arr.end();
327    ///
328    /// arr.end();
329    /// ```
330    pub fn add_array(&mut self) -> ArrayWriter<S> {
331        self.comma();
332        ArrayWriter::start(self.buf)
333    }
334
335    /// Finishes out the array. Equivalent to drop(arr);
336    pub fn end(self) {}
337}
338
339impl<S: JsonBuffer> Drop for ArrayWriter<'_, S> {
340    fn drop(&mut self) {
341        self.buf.push(']');
342    }
343}
344
345/// A key for a JSON object's field.
346#[sealed]
347pub trait Key {
348    fn write<S: JsonBuffer>(self, out: &mut S);
349}
350
351#[sealed]
352impl Key for UnescapedStr<'_> {
353    fn write<S: JsonBuffer>(self, out: &mut S) {
354        self.write_to_json(out)
355    }
356}
357
358#[sealed]
359impl<T: AsRef<str>> Key for T {
360    fn write<S: JsonBuffer>(self, out: &mut S) {
361        self.as_ref().write_to_json(out)
362    }
363}
364
365/// A serializer for a JSON object.
366pub struct ObjectWriter<'a, S: JsonBuffer> {
367    buf: &'a mut S,
368    first_element: bool,
369}
370
371impl<'a, S: JsonBuffer> ObjectWriter<'a, S> {
372    fn start(buf: &'a mut S) -> ObjectWriter<S> {
373        buf.push('{');
374        ObjectWriter {
375            buf,
376            first_element: true,
377        }
378    }
379
380    fn comma(&mut self) {
381        match self.first_element {
382            true => {
383                cold();
384                self.first_element = false
385            }
386            false => self.buf.push(','),
387        }
388    }
389
390    fn key<K: Key>(&mut self, key: K) {
391        self.comma();
392        key.write(&mut self.buf);
393        self.buf.push(':');
394    }
395
396    /// Adds a field to this object.
397    ///
398    /// # Examples
399    /// ```
400    /// # use nyoom_json::Serializer;
401    /// #
402    /// # let mut out = String::new();
403    /// # let mut ser = Serializer::new(&mut out);
404    /// #
405    /// let mut obj = ser.object();
406    /// obj.field("kind", "cat");
407    /// obj.field("has_been_fed", false);
408    /// obj.field("meow_decibels", 45);
409    /// obj.end();
410    /// ```
411    pub fn field<K: Key>(&mut self, key: K, val: impl WriteToJson<S>) {
412        self.key(key);
413        val.write_to_json(self.buf);
414    }
415
416    /// Adds an arbitrary JSON object to this object.
417    ///
418    /// # Arguments
419    ///
420    /// * `key` - the key for the field
421    /// * `encoder` - A closure that encodes a single value into the field. It may return an arbitrary value that will be passed back to the caller.
422    ///
423    /// # Examples
424    ///
425    /// ```
426    /// # use nyoom_json::Serializer;
427    /// #
428    /// # let mut out = String::new();
429    /// # let mut ser = Serializer::new(&mut out);
430    /// #
431    /// let mut obj = ser.object();
432    /// obj.complex_field("numbers", |mut ser| {
433    ///     let mut arr = ser.array();
434    ///     arr.add(1);
435    ///     arr.add(2);
436    ///     arr.add("three");
437    /// });
438    /// obj.end()
439    /// ```
440    pub fn complex_field<K, F, O>(&mut self, key: K, encode: F) -> O
441    where
442        K: Key,
443        F: FnOnce(SingleValueSerializer<&mut S>) -> O,
444    {
445        self.key(key);
446        encode(SingleValueSerializer::new(&mut self.buf))
447    }
448
449    /// Adds a JSON object field to this object.
450    ///
451    /// # Examples
452    ///
453    /// ```
454    /// # use nyoom_json::Serializer;
455    /// #
456    /// # let mut out = String::new();
457    /// # let mut ser = Serializer::new(&mut out);
458    /// #
459    /// let mut obj = ser.object();
460    /// obj.field("kitten", true);
461    /// obj.field("cuteness", 10.0);
462    ///
463    /// let mut bed = obj.object_field("bed");
464    /// bed.field("cozy", true);
465    /// bed.field("wear_and_tear", 2.0);
466    /// bed.end();
467    ///
468    /// obj.end();
469    /// ```
470    pub fn object_field<K: Key>(&mut self, key: K) -> ObjectWriter<S> {
471        self.key(key);
472        ObjectWriter::start(self.buf)
473    }
474
475    /// Adds a JSON array field to this object.
476    ///
477    /// # Examples
478    ///
479    /// ```
480    /// # use nyoom_json::Serializer;
481    /// #
482    /// # let mut out = String::new();
483    /// # let mut ser = Serializer::new(&mut out);
484    /// #
485    /// let mut arr = ser.array();
486    ///
487    /// let mut obj = arr.add_object();
488    /// obj.field("kitten", true);
489    /// obj.field("cuteness", 10.0);
490    ///
491    /// let mut toys = obj.array_field("toys");
492    /// toys.extend(&["mouse", "ball", "string", "box", "scratcher"]);
493    /// toys.end();
494    ///
495    /// obj.end();
496    ///
497    /// arr.end();
498    /// ```
499    pub fn array_field<K: Key>(&mut self, key: K) -> ArrayWriter<S> {
500        self.key(key);
501        ArrayWriter::start(self.buf)
502    }
503
504    pub fn end(self) {}
505}
506
507impl<S: JsonBuffer> Drop for ObjectWriter<'_, S> {
508    fn drop(&mut self) {
509        self.buf.push('}');
510    }
511}