Skip to main content

rquickjs_serde/
ser.rs

1use alloc::string::ToString as _;
2
3use rquickjs::{Array, Ctx, Object, String as JSString, Value};
4use serde::{Serialize, ser};
5
6use crate::err::{Error, Result};
7
8/// `Serializer` is a serializer for [Value] values, implementing the `serde::Serializer` trait.
9///
10/// This struct is responsible for converting Rust types into [Value] using the Serde
11/// serialization framework.
12///
13/// ```
14/// # use rquickjs::{Runtime, Context, Value};
15/// # use rquickjs_serde::Serializer;
16/// # use serde::Serializer as _;
17/// #
18/// let rt = Runtime::new().unwrap();
19/// let ctx = Context::full(&rt).unwrap();
20/// ctx.with(|ctx| {
21///     let mut serializer = Serializer::from_context(ctx.clone()).unwrap();
22///     let value = serializer.serialize_u32(42).unwrap();
23///     assert!(value.is_number());
24/// });
25/// ```
26pub struct Serializer<'js> {
27    pub context: Ctx<'js>,
28}
29
30pub struct SeqSerializer<'se, 'js> {
31    ser: &'se mut Serializer<'js>,
32    value: Array<'js>,
33}
34
35pub struct TupleVariantSerializer<'se, 'js> {
36    ser: &'se mut Serializer<'js>,
37    wrapper: Object<'js>,
38    value: Array<'js>,
39}
40
41pub struct MapSerializer<'se, 'js> {
42    ser: &'se mut Serializer<'js>,
43    value: Object<'js>,
44    /** current map key, will be left `None` for structs */
45    key: Option<Value<'js>>,
46}
47
48pub struct StructVariantSerializer<'se, 'js> {
49    ser: &'se mut Serializer<'js>,
50    wrapper: Object<'js>,
51    value: Object<'js>,
52}
53
54impl<'se, 'js> SeqSerializer<'se, 'js> {
55    fn new(ser: &'se mut Serializer<'js>) -> Result<Self> {
56        let value = Array::new(ser.context.clone()).map_err(Error::new)?;
57
58        Ok(Self { ser, value })
59    }
60}
61
62impl<'se, 'js> TupleVariantSerializer<'se, 'js> {
63    fn new(ser: &'se mut Serializer<'js>, variant: &'static str) -> Result<Self> {
64        let wrapper = Object::new(ser.context.clone()).map_err(Error::new)?;
65        let value = Array::new(ser.context.clone()).map_err(Error::new)?;
66        wrapper.set(variant, value.clone()).map_err(Error::new)?;
67
68        Ok(Self {
69            ser,
70            wrapper,
71            value,
72        })
73    }
74}
75
76impl<'se, 'js> MapSerializer<'se, 'js> {
77    fn new(ser: &'se mut Serializer<'js>) -> Result<Self> {
78        let value = Object::new(ser.context.clone()).map_err(Error::new)?;
79        Ok(Self {
80            ser,
81            value,
82            key: None,
83        })
84    }
85}
86impl<'se, 'js> StructVariantSerializer<'se, 'js> {
87    fn new(ser: &'se mut Serializer<'js>, variant: &'static str) -> Result<Self> {
88        let wrapper = Object::new(ser.context.clone()).map_err(Error::new)?;
89        let value = Object::new(ser.context.clone()).map_err(Error::new)?;
90        wrapper.set(variant, value.clone()).map_err(Error::new)?;
91
92        Ok(Self {
93            ser,
94            wrapper,
95            value,
96        })
97    }
98}
99
100impl<'js> Serializer<'js> {
101    pub fn from_context(context: Ctx<'js>) -> Result<Self> {
102        Ok(Self {
103            context: context.clone(),
104        })
105    }
106}
107impl<'js, 'se> ser::Serializer for &'se mut Serializer<'js> {
108    type Ok = Value<'js>;
109    type Error = Error;
110
111    type SerializeSeq = SeqSerializer<'se, 'js>;
112    type SerializeTuple = SeqSerializer<'se, 'js>;
113    type SerializeTupleStruct = SeqSerializer<'se, 'js>;
114    type SerializeTupleVariant = TupleVariantSerializer<'se, 'js>;
115    type SerializeMap = MapSerializer<'se, 'js>;
116    type SerializeStruct = MapSerializer<'se, 'js>;
117    type SerializeStructVariant = StructVariantSerializer<'se, 'js>;
118
119    fn serialize_i8(self, v: i8) -> Result<Self::Ok> {
120        self.serialize_i32(i32::from(v))
121    }
122
123    fn serialize_i16(self, v: i16) -> Result<Self::Ok> {
124        self.serialize_i32(i32::from(v))
125    }
126
127    fn serialize_i32(self, v: i32) -> Result<Self::Ok> {
128        Ok(Value::new_int(self.context.clone(), v))
129    }
130
131    fn serialize_i64(self, v: i64) -> Result<Self::Ok> {
132        Ok(Value::new_number(self.context.clone(), v as _))
133    }
134
135    fn serialize_u8(self, v: u8) -> Result<Self::Ok> {
136        self.serialize_i32(i32::from(v))
137    }
138
139    fn serialize_u16(self, v: u16) -> Result<Self::Ok> {
140        self.serialize_i32(i32::from(v))
141    }
142
143    fn serialize_u32(self, v: u32) -> Result<Self::Ok> {
144        // NOTE: See optimization note in serialize_f64.
145        self.serialize_f64(f64::from(v))
146    }
147
148    fn serialize_u64(self, v: u64) -> Result<Self::Ok> {
149        Ok(Value::new_number(self.context.clone(), v as _))
150    }
151
152    fn serialize_f32(self, v: f32) -> Result<Self::Ok> {
153        // NOTE: See optimization note in serialize_f64.
154        self.serialize_f64(f64::from(v))
155    }
156
157    fn serialize_f64(self, v: f64) -> Result<Self::Ok> {
158        // NOTE: QuickJS will create a number value backed by an i32 when the value is within
159        // the i32::MIN..=i32::MAX as an optimization. Otherwise the value will be backed by a f64.
160        Ok(Value::new_float(self.context.clone(), v))
161    }
162
163    fn serialize_bool(self, b: bool) -> Result<Self::Ok> {
164        Ok(Value::new_bool(self.context.clone(), b))
165    }
166
167    fn serialize_char(self, v: char) -> Result<Self::Ok> {
168        self.serialize_str(&v.to_string())
169    }
170
171    fn serialize_str(self, v: &str) -> Result<Self::Ok> {
172        let js_string = JSString::from_str(self.context.clone(), v).map_err(Error::new)?;
173        Ok(Value::from(js_string))
174    }
175
176    fn serialize_none(self) -> Result<Self::Ok> {
177        self.serialize_unit()
178    }
179
180    fn serialize_unit(self) -> Result<Self::Ok> {
181        Ok(Value::new_null(self.context.clone()))
182    }
183
184    fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok> {
185        self.serialize_unit()
186    }
187
188    fn serialize_some<T>(self, value: &T) -> Result<Self::Ok>
189    where
190        T: ?Sized + Serialize,
191    {
192        value.serialize(self)
193    }
194
195    fn serialize_unit_variant(
196        self,
197        _name: &'static str,
198        _variant_index: u32,
199        variant: &'static str,
200    ) -> Result<Self::Ok> {
201        self.serialize_str(variant)
202    }
203
204    fn serialize_newtype_struct<T>(self, _name: &'static str, value: &T) -> Result<Self::Ok>
205    where
206        T: ?Sized + Serialize,
207    {
208        value.serialize(self)
209    }
210
211    fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq> {
212        SeqSerializer::new(self)
213    }
214
215    fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple> {
216        SeqSerializer::new(self)
217    }
218
219    fn serialize_tuple_struct(
220        self,
221        _name: &'static str,
222        len: usize,
223    ) -> Result<Self::SerializeTupleStruct> {
224        self.serialize_seq(Some(len))
225    }
226
227    fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap> {
228        MapSerializer::new(self)
229    }
230
231    fn serialize_struct(self, _name: &'static str, _len: usize) -> Result<Self::SerializeStruct> {
232        MapSerializer::new(self)
233    }
234
235    fn serialize_struct_variant(
236        self,
237        _name: &'static str,
238        _variant_index: u32,
239        variant: &'static str,
240        _len: usize,
241    ) -> Result<Self::SerializeStructVariant> {
242        StructVariantSerializer::new(self, variant)
243    }
244
245    fn serialize_tuple_variant(
246        self,
247        _name: &'static str,
248        _variant_index: u32,
249        variant: &'static str,
250        _len: usize,
251    ) -> Result<Self::SerializeTupleVariant> {
252        TupleVariantSerializer::new(self, variant)
253    }
254
255    fn serialize_newtype_variant<T>(
256        self,
257        _name: &'static str,
258        _variant_index: u32,
259        variant: &'static str,
260        value: &T,
261    ) -> Result<Self::Ok>
262    where
263        T: ?Sized + Serialize,
264    {
265        let obj = Object::new(self.context.clone()).map_err(Error::new)?;
266        let value = value.serialize(&mut *self)?;
267        obj.set(variant, value).map_err(Error::new)?;
268        Ok(obj.into())
269    }
270
271    fn serialize_bytes(self, _: &[u8]) -> Result<Self::Ok> {
272        Err(Error::new("Cannot serialize bytes"))
273    }
274}
275
276impl<'se, 'js> ser::SerializeSeq for SeqSerializer<'se, 'js> {
277    type Ok = Value<'js>;
278    type Error = Error;
279
280    fn serialize_element<T>(&mut self, value: &T) -> Result<()>
281    where
282        T: ?Sized + Serialize,
283    {
284        self.value
285            .set(self.value.len(), value.serialize(&mut *self.ser)?)
286            .map_err(Error::new)
287    }
288
289    fn end(self) -> Result<Self::Ok> {
290        Ok(self.value.into())
291    }
292}
293
294impl<'se, 'js> ser::SerializeTuple for SeqSerializer<'se, 'js> {
295    type Ok = Value<'js>;
296    type Error = Error;
297
298    fn serialize_element<T>(&mut self, value: &T) -> Result<()>
299    where
300        T: ?Sized + Serialize,
301    {
302        self.value
303            .set(self.value.len(), value.serialize(&mut *self.ser)?)
304            .map_err(Error::new)
305    }
306
307    fn end(self) -> Result<Self::Ok> {
308        Ok(self.value.into())
309    }
310}
311
312impl<'se, 'js> ser::SerializeTupleStruct for SeqSerializer<'se, 'js> {
313    type Ok = Value<'js>;
314    type Error = Error;
315
316    fn serialize_field<T>(&mut self, value: &T) -> Result<()>
317    where
318        T: ?Sized + Serialize,
319    {
320        self.value
321            .set(self.value.len(), value.serialize(&mut *self.ser)?)
322            .map_err(Error::new)
323    }
324
325    fn end(self) -> Result<Self::Ok> {
326        Ok(self.value.into())
327    }
328}
329
330impl<'se, 'js> ser::SerializeTupleVariant for TupleVariantSerializer<'se, 'js> {
331    type Ok = Value<'js>;
332    type Error = Error;
333
334    fn serialize_field<T>(&mut self, value: &T) -> Result<()>
335    where
336        T: ?Sized + Serialize,
337    {
338        self.value
339            .set(self.value.len(), value.serialize(&mut *self.ser)?)
340            .map_err(Error::new)
341    }
342
343    fn end(self) -> Result<Self::Ok> {
344        Ok(self.wrapper.into())
345    }
346}
347
348impl<'se, 'js> ser::SerializeMap for MapSerializer<'se, 'js> {
349    type Ok = Value<'js>;
350    type Error = Error;
351
352    fn serialize_key<T>(&mut self, key: &T) -> Result<()>
353    where
354        T: ?Sized + Serialize,
355    {
356        self.key = Some(key.serialize(&mut *self.ser)?);
357        Ok(())
358    }
359
360    fn serialize_value<T>(&mut self, value: &T) -> Result<()>
361    where
362        T: ?Sized + Serialize,
363    {
364        let key = self
365            .key
366            .take()
367            .ok_or_else(|| Error::new("serialize_value before serialize_key"))?;
368
369        let value = value.serialize(&mut *self.ser)?;
370        self.value.set(key, value).map_err(Error::new)
371    }
372
373    fn end(self) -> Result<Self::Ok> {
374        Ok(self.value.into())
375    }
376}
377
378impl<'se, 'js> ser::SerializeStruct for MapSerializer<'se, 'js> {
379    type Ok = Value<'js>;
380    type Error = Error;
381
382    fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
383    where
384        T: ?Sized + Serialize,
385    {
386        let value = value.serialize(&mut *self.ser)?;
387        self.value.set(key, value).map_err(Error::new)?;
388        Ok(())
389    }
390
391    fn end(self) -> Result<Self::Ok> {
392        Ok(self.value.into())
393    }
394}
395
396impl<'se, 'js> ser::SerializeStructVariant for StructVariantSerializer<'se, 'js> {
397    type Ok = Value<'js>;
398    type Error = Error;
399
400    fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
401    where
402        T: ?Sized + Serialize,
403    {
404        let value = value.serialize(&mut *self.ser)?;
405        self.value.set(key, value).map_err(Error::new)?;
406        Ok(())
407    }
408
409    fn end(self) -> Result<Self::Ok> {
410        Ok(self.wrapper.into())
411    }
412}
413
414#[cfg(test)]
415mod tests {
416    use std::collections::BTreeMap;
417
418    use rquickjs::{Ctx, Function, Object, Value};
419    use serde::{Serialize, Serializer};
420
421    use super::Serializer as ValueSerializer;
422    use crate::err::Result;
423    use crate::test::Runtime;
424    use crate::{MAX_SAFE_INTEGER, MIN_SAFE_INTEGER};
425    use quickcheck::quickcheck;
426
427    fn with_serializer<F: FnMut(&mut ValueSerializer) -> Result<bool>>(
428        rt: &Runtime,
429        mut w: F,
430    ) -> Result<bool> {
431        rt.context().with(|c| {
432            let mut serializer = ValueSerializer::from_context(c.clone()).unwrap();
433            w(&mut serializer)
434        })
435    }
436
437    quickcheck! {
438        fn test_i16(v: i16) -> Result<bool> {
439            let rt = Runtime::default();
440            with_serializer(&rt, |serializer| {
441                let value = serializer.serialize_i16(v)?;
442                Ok(value.is_int())
443            })
444        }
445
446        fn test_i32(v: i32) -> Result<bool> {
447            let rt = Runtime::default();
448            with_serializer(&rt, |serializer| {
449                let value = serializer.serialize_i32(v)?;
450                Ok(value.is_int())
451            })
452        }
453
454        fn test_i64(v: i64) -> Result<bool> {
455            let rt = Runtime::default();
456            with_serializer(&rt, |serializer| {
457                if (MIN_SAFE_INTEGER..=MAX_SAFE_INTEGER).contains(&v) {
458                    let value = serializer.serialize_i64(v)?;
459                    Ok(value.is_number())
460                } else {
461                    let value = serializer.serialize_f64(v as f64)?;
462                    Ok(value.is_number())
463                }
464            })
465        }
466
467        fn test_u64(v: u64) -> Result<bool> {
468            let rt = Runtime::default();
469            with_serializer(&rt, |serializer| {
470                if v <= MAX_SAFE_INTEGER as u64 {
471                    let value =  serializer.serialize_u64(v)?;
472                    Ok(value.is_number())
473                } else {
474                    let value =  serializer.serialize_f64(v as f64)?;
475                    Ok(value.is_number())
476                }
477            })
478        }
479
480        fn test_u16(v: u16) -> Result<bool> {
481            let rt = Runtime::default();
482
483            with_serializer(&rt, |serializer| {
484                let value = serializer.serialize_u16(v)?;
485                Ok(value.is_int())
486            })
487        }
488
489        fn test_u32(v: u32) -> Result<bool> {
490            let rt = Runtime::default();
491            with_serializer(&rt, |serializer| {
492                let value = serializer.serialize_u32(v)?;
493                // QuickJS optimizes numbers in the range of [i32::MIN..=i32::MAX]
494                // as ints
495                if v > i32::MAX as u32 {
496                    Ok(value.is_float())
497                } else {
498                    Ok(value.is_int())
499                }
500            })
501
502        }
503
504        fn test_f32(v: f32) -> Result<bool> {
505            let rt = Runtime::default();
506            with_serializer(&rt, |serializer| {
507                let value = serializer.serialize_f32(v)?;
508
509                if v == 0.0_f32 {
510                    if v.is_sign_positive() {
511                        return  Ok(value.is_int());
512                    }
513
514
515                    if v.is_sign_negative() {
516                        return Ok(value.is_float());
517                    }
518                }
519
520                // The same (int) optimization is happening at this point,
521                // but here we need to account for signs
522                let zero_fractional_part = v.fract() == 0.0;
523                let range = (i32::MIN as f32)..=(i32::MAX as f32);
524
525                if zero_fractional_part && range.contains(&v) {
526                    Ok(value.is_int())
527                } else {
528                    Ok(value.is_float())
529                }
530            })
531        }
532
533        fn test_f64(v: f64) -> Result<bool> {
534            let rt = Runtime::default();
535            with_serializer(&rt, |serializer| {
536                let value = serializer.serialize_f64(v)?;
537
538                if v == 0.0_f64 {
539                    if v.is_sign_positive() {
540                        return  Ok(value.is_int());
541                    }
542
543
544                    if v.is_sign_negative() {
545                        return Ok(value.is_float());
546                    }
547                }
548
549                // The same (int) optimization is happening at this point,
550                // but here we need to account for signs
551                let zero_fractional_part = v.fract() == 0.0;
552                let range = (i32::MIN as f64)..=(i32::MAX as f64);
553
554                if zero_fractional_part && range.contains(&v) {
555                    Ok(value.is_int())
556                } else {
557                    Ok(value.is_float())
558                }
559            })
560        }
561
562        fn test_bool(v: bool) -> Result<bool> {
563            let rt = Runtime::default();
564            with_serializer(&rt, |serializer| {
565                let value =  serializer.serialize_bool(v)?;
566                Ok(value.is_bool())
567            })
568        }
569
570        fn test_str(v: String) -> Result<bool> {
571            let rt = Runtime::default();
572            with_serializer(&rt, |serializer| {
573                let value = serializer.serialize_str(v.as_str())?;
574
575                Ok(value.is_string())
576            })
577        }
578    }
579
580    #[test]
581    fn test_null() -> Result<()> {
582        let rt = Runtime::default();
583
584        rt.context().with(|cx| {
585            let mut serializer = ValueSerializer::from_context(cx.clone()).unwrap();
586            let value = serializer.serialize_unit().unwrap();
587
588            assert!(value.is_null());
589        });
590        Ok(())
591    }
592
593    #[test]
594    fn test_nan() -> Result<()> {
595        let rt = Runtime::default();
596
597        rt.context().with(|cx| {
598            let mut serializer = ValueSerializer::from_context(cx.clone()).unwrap();
599            let value = serializer.serialize_f64(f64::NAN).unwrap();
600            assert!(value.is_number());
601        });
602        Ok(())
603    }
604
605    #[test]
606    fn test_infinity() -> Result<()> {
607        let rt = Runtime::default();
608        rt.context().with(|cx| {
609            let mut serializer = ValueSerializer::from_context(cx.clone()).unwrap();
610            let value = serializer.serialize_f64(f64::INFINITY).unwrap();
611            assert!(value.is_number());
612        });
613        Ok(())
614    }
615
616    #[test]
617    fn test_negative_infinity() -> Result<()> {
618        let rt = Runtime::default();
619        rt.context().with(|cx| {
620            let mut serializer = ValueSerializer::from_context(cx.clone()).unwrap();
621            let value = serializer.serialize_f64(f64::NEG_INFINITY).unwrap();
622            assert!(value.is_number());
623        });
624        Ok(())
625    }
626
627    #[test]
628    fn test_map() {
629        let rt = Runtime::default();
630
631        rt.context().with(|cx| {
632            let mut serializer = ValueSerializer::from_context(cx.clone()).unwrap();
633
634            let mut map = BTreeMap::new();
635            map.insert("foo", "bar");
636            map.insert("toto", "titi");
637
638            let value = map.serialize(&mut serializer).unwrap();
639
640            assert!(value.is_object())
641        });
642    }
643
644    #[test]
645    fn test_struct_into_map() {
646        let rt = Runtime::default();
647
648        rt.context().with(|cx| {
649            let mut serializer = ValueSerializer::from_context(cx.clone()).unwrap();
650
651            #[derive(serde::Serialize)]
652            struct MyObject {
653                foo: String,
654                bar: u32,
655            }
656
657            let my_object = MyObject {
658                foo: "hello".to_string(),
659                bar: 1337,
660            };
661            let value = my_object.serialize(&mut serializer).unwrap();
662
663            assert!(value.is_object());
664        });
665    }
666
667    #[test]
668    fn test_sequence() {
669        let rt = Runtime::default();
670
671        rt.context().with(|cx| {
672            let mut serializer = ValueSerializer::from_context(cx.clone()).unwrap();
673
674            let sequence = vec!["hello", "world"];
675
676            let value = sequence.serialize(&mut serializer).unwrap();
677
678            assert!(value.is_array());
679            assert_eq!(r#"["hello","world"]"#, json_stringify(cx.clone(), value));
680        });
681    }
682
683    #[test]
684    fn test_enum_unit() {
685        let rt = Runtime::default();
686
687        #[derive(Debug, Clone, Copy, PartialEq, Serialize)]
688        enum Test {
689            One,
690        }
691
692        rt.context().with(|cx| {
693            let mut serializer = ValueSerializer::from_context(cx.clone()).unwrap();
694
695            let src = Test::One;
696
697            let value = src.serialize(&mut serializer).unwrap();
698
699            let inner: String = value.as_string().unwrap().to_string().unwrap();
700            assert_eq!("One", inner);
701        });
702    }
703
704    #[test]
705    fn test_enum_newtype() {
706        let rt = Runtime::default();
707
708        #[derive(Debug, Clone, Copy, PartialEq, Serialize)]
709        enum Test {
710            Item(i32),
711        }
712
713        rt.context().with(|cx| {
714            let mut serializer = ValueSerializer::from_context(cx.clone()).unwrap();
715            let src = Test::Item(10);
716            let value = src.serialize(&mut serializer).unwrap();
717
718            assert_eq!(r#"{"Item":10}"#, json_stringify(cx.clone(), value));
719        });
720    }
721
722    #[test]
723    fn test_enum_struct() {
724        let rt = Runtime::default();
725
726        #[derive(Debug, Clone, Copy, PartialEq, Serialize)]
727        enum Test {
728            One { a: i32 },
729        }
730
731        rt.context().with(|cx| {
732            let src = Test::One { a: 6 };
733
734            let mut serializer = ValueSerializer::from_context(cx.clone()).unwrap();
735            let value = src.serialize(&mut serializer).unwrap();
736
737            assert_eq!(r#"{"One":{"a":6}}"#, json_stringify(cx.clone(), value));
738        });
739    }
740
741    #[test]
742    fn test_enum_tuple() {
743        let rt = Runtime::default();
744
745        #[derive(Debug, Clone, Copy, PartialEq, Serialize)]
746        enum Test {
747            One(i32, i32),
748        }
749
750        rt.context().with(|cx| {
751            let mut serializer = ValueSerializer::from_context(cx.clone()).unwrap();
752            let src = Test::One(1, 2);
753            let value = src.serialize(&mut serializer).unwrap();
754
755            assert_eq!(r#"{"One":[1,2]}"#, json_stringify(cx.clone(), value));
756        });
757    }
758
759    fn json_stringify<'js>(cx: Ctx<'js>, value: Value<'js>) -> String {
760        let obj: Object = cx.globals().get("JSON").unwrap();
761        let stringify: Function = obj.get("stringify").unwrap();
762        let str: String = stringify.call((value,)).unwrap();
763        str
764    }
765}