rquickjs_serde/
ser.rs

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