1use alloc::string::ToString as _;
2
3use rquickjs::{Array, Ctx, Object, String as JSString, Value, object::Property};
4use serde::{Serialize, ser};
5
6use crate::err::{Error, Result};
7
8pub 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 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 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 self.serialize_f64(f64::from(v))
155 }
156
157 fn serialize_f64(self, v: f64) -> Result<Self::Ok> {
158 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 let prop = Property::from(value).writable().configurable().enumerable();
371 self.value.prop::<_, _, _>(key, prop).map_err(Error::new)
372 }
373
374 fn end(self) -> Result<Self::Ok> {
375 Ok(self.value.into())
376 }
377}
378
379impl<'se, 'js> ser::SerializeStruct for MapSerializer<'se, 'js> {
380 type Ok = Value<'js>;
381 type Error = Error;
382
383 fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
384 where
385 T: ?Sized + Serialize,
386 {
387 let value = value.serialize(&mut *self.ser)?;
388 self.value.set(key, value).map_err(Error::new)?;
389 Ok(())
390 }
391
392 fn end(self) -> Result<Self::Ok> {
393 Ok(self.value.into())
394 }
395}
396
397impl<'se, 'js> ser::SerializeStructVariant for StructVariantSerializer<'se, 'js> {
398 type Ok = Value<'js>;
399 type Error = Error;
400
401 fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
402 where
403 T: ?Sized + Serialize,
404 {
405 let value = value.serialize(&mut *self.ser)?;
406 self.value.set(key, value).map_err(Error::new)?;
407 Ok(())
408 }
409
410 fn end(self) -> Result<Self::Ok> {
411 Ok(self.wrapper.into())
412 }
413}
414
415#[cfg(test)]
416mod tests {
417 use std::collections::BTreeMap;
418
419 use rquickjs::{Ctx, Function, Object, Value};
420 use serde::{Serialize, Serializer};
421
422 use super::Serializer as ValueSerializer;
423 use crate::err::Result;
424 use crate::test::Runtime;
425 use crate::{MAX_SAFE_INTEGER, MIN_SAFE_INTEGER};
426 use quickcheck::quickcheck;
427
428 fn with_serializer<F: FnMut(&mut ValueSerializer) -> Result<bool>>(
429 rt: &Runtime,
430 mut w: F,
431 ) -> Result<bool> {
432 rt.context().with(|c| {
433 let mut serializer = ValueSerializer::from_context(c.clone()).unwrap();
434 w(&mut serializer)
435 })
436 }
437
438 quickcheck! {
439 fn test_i16(v: i16) -> Result<bool> {
440 let rt = Runtime::default();
441 with_serializer(&rt, |serializer| {
442 let value = serializer.serialize_i16(v)?;
443 Ok(value.is_int())
444 })
445 }
446
447 fn test_i32(v: i32) -> Result<bool> {
448 let rt = Runtime::default();
449 with_serializer(&rt, |serializer| {
450 let value = serializer.serialize_i32(v)?;
451 Ok(value.is_int())
452 })
453 }
454
455 fn test_i64(v: i64) -> Result<bool> {
456 let rt = Runtime::default();
457 with_serializer(&rt, |serializer| {
458 if (MIN_SAFE_INTEGER..=MAX_SAFE_INTEGER).contains(&v) {
459 let value = serializer.serialize_i64(v)?;
460 Ok(value.is_number())
461 } else {
462 let value = serializer.serialize_f64(v as f64)?;
463 Ok(value.is_number())
464 }
465 })
466 }
467
468 fn test_u64(v: u64) -> Result<bool> {
469 let rt = Runtime::default();
470 with_serializer(&rt, |serializer| {
471 if v <= MAX_SAFE_INTEGER as u64 {
472 let value = serializer.serialize_u64(v)?;
473 Ok(value.is_number())
474 } else {
475 let value = serializer.serialize_f64(v as f64)?;
476 Ok(value.is_number())
477 }
478 })
479 }
480
481 fn test_u16(v: u16) -> Result<bool> {
482 let rt = Runtime::default();
483
484 with_serializer(&rt, |serializer| {
485 let value = serializer.serialize_u16(v)?;
486 Ok(value.is_int())
487 })
488 }
489
490 fn test_u32(v: u32) -> Result<bool> {
491 let rt = Runtime::default();
492 with_serializer(&rt, |serializer| {
493 let value = serializer.serialize_u32(v)?;
494 if v > i32::MAX as u32 {
497 Ok(value.is_float())
498 } else {
499 Ok(value.is_int())
500 }
501 })
502
503 }
504
505 fn test_f32(v: f32) -> Result<bool> {
506 let rt = Runtime::default();
507 with_serializer(&rt, |serializer| {
508 let value = serializer.serialize_f32(v)?;
509
510 if v == 0.0_f32 {
511 if v.is_sign_positive() {
512 return Ok(value.is_int());
513 }
514
515
516 if v.is_sign_negative() {
517 return Ok(value.is_float());
518 }
519 }
520
521 let zero_fractional_part = v.fract() == 0.0;
524 let range = (i32::MIN as f32)..=(i32::MAX as f32);
525
526 if zero_fractional_part && range.contains(&v) {
527 Ok(value.is_int())
528 } else {
529 Ok(value.is_float())
530 }
531 })
532 }
533
534 fn test_f64(v: f64) -> Result<bool> {
535 let rt = Runtime::default();
536 with_serializer(&rt, |serializer| {
537 let value = serializer.serialize_f64(v)?;
538
539 if v == 0.0_f64 {
540 if v.is_sign_positive() {
541 return Ok(value.is_int());
542 }
543
544
545 if v.is_sign_negative() {
546 return Ok(value.is_float());
547 }
548 }
549
550 let zero_fractional_part = v.fract() == 0.0;
553 let range = (i32::MIN as f64)..=(i32::MAX as f64);
554
555 if zero_fractional_part && range.contains(&v) {
556 Ok(value.is_int())
557 } else {
558 Ok(value.is_float())
559 }
560 })
561 }
562
563 fn test_bool(v: bool) -> Result<bool> {
564 let rt = Runtime::default();
565 with_serializer(&rt, |serializer| {
566 let value = serializer.serialize_bool(v)?;
567 Ok(value.is_bool())
568 })
569 }
570
571 fn test_str(v: String) -> Result<bool> {
572 let rt = Runtime::default();
573 with_serializer(&rt, |serializer| {
574 let value = serializer.serialize_str(v.as_str())?;
575
576 Ok(value.is_string())
577 })
578 }
579 }
580
581 #[test]
582 fn test_null() -> Result<()> {
583 let rt = Runtime::default();
584
585 rt.context().with(|cx| {
586 let mut serializer = ValueSerializer::from_context(cx.clone()).unwrap();
587 let value = serializer.serialize_unit().unwrap();
588
589 assert!(value.is_null());
590 });
591 Ok(())
592 }
593
594 #[test]
595 fn test_nan() -> Result<()> {
596 let rt = Runtime::default();
597
598 rt.context().with(|cx| {
599 let mut serializer = ValueSerializer::from_context(cx.clone()).unwrap();
600 let value = serializer.serialize_f64(f64::NAN).unwrap();
601 assert!(value.is_number());
602 });
603 Ok(())
604 }
605
606 #[test]
607 fn test_infinity() -> Result<()> {
608 let rt = Runtime::default();
609 rt.context().with(|cx| {
610 let mut serializer = ValueSerializer::from_context(cx.clone()).unwrap();
611 let value = serializer.serialize_f64(f64::INFINITY).unwrap();
612 assert!(value.is_number());
613 });
614 Ok(())
615 }
616
617 #[test]
618 fn test_negative_infinity() -> Result<()> {
619 let rt = Runtime::default();
620 rt.context().with(|cx| {
621 let mut serializer = ValueSerializer::from_context(cx.clone()).unwrap();
622 let value = serializer.serialize_f64(f64::NEG_INFINITY).unwrap();
623 assert!(value.is_number());
624 });
625 Ok(())
626 }
627
628 #[test]
629 fn test_map() {
630 let rt = Runtime::default();
631
632 rt.context().with(|cx| {
633 let mut serializer = ValueSerializer::from_context(cx.clone()).unwrap();
634
635 let mut map = BTreeMap::new();
636 map.insert("foo", "bar");
637 map.insert("toto", "titi");
638
639 let value = map.serialize(&mut serializer).unwrap();
640
641 assert!(value.is_object())
642 });
643 }
644
645 #[test]
646 fn test_map_proto_key_is_own_data_property() {
647 let rt = Runtime::default();
648
649 rt.context().with(|cx| {
650 let mut serializer = ValueSerializer::from_context(cx.clone()).unwrap();
651
652 let mut map = BTreeMap::new();
653 map.insert("__proto__", "bar");
654
655 let value = map.serialize(&mut serializer).unwrap();
656
657 assert_has_own_proto_data_property(cx, value, "'bar'");
658 });
659 }
660
661 #[test]
662 fn test_struct_into_map() {
663 let rt = Runtime::default();
664
665 rt.context().with(|cx| {
666 let mut serializer = ValueSerializer::from_context(cx.clone()).unwrap();
667
668 #[derive(serde::Serialize)]
669 struct MyObject {
670 foo: String,
671 bar: u32,
672 }
673
674 let my_object = MyObject {
675 foo: "hello".to_string(),
676 bar: 1337,
677 };
678 let value = my_object.serialize(&mut serializer).unwrap();
679
680 assert!(value.is_object());
681 });
682 }
683
684 #[test]
685 fn test_sequence() {
686 let rt = Runtime::default();
687
688 rt.context().with(|cx| {
689 let mut serializer = ValueSerializer::from_context(cx.clone()).unwrap();
690
691 let sequence = vec!["hello", "world"];
692
693 let value = sequence.serialize(&mut serializer).unwrap();
694
695 assert!(value.is_array());
696 assert_eq!(r#"["hello","world"]"#, json_stringify(cx.clone(), value));
697 });
698 }
699
700 #[test]
701 fn test_enum_unit() {
702 let rt = Runtime::default();
703
704 #[derive(Debug, Clone, Copy, PartialEq, Serialize)]
705 enum Test {
706 One,
707 }
708
709 rt.context().with(|cx| {
710 let mut serializer = ValueSerializer::from_context(cx.clone()).unwrap();
711
712 let src = Test::One;
713
714 let value = src.serialize(&mut serializer).unwrap();
715
716 let inner: String = value.as_string().unwrap().to_string().unwrap();
717 assert_eq!("One", inner);
718 });
719 }
720
721 #[test]
722 fn test_enum_newtype() {
723 let rt = Runtime::default();
724
725 #[derive(Debug, Clone, Copy, PartialEq, Serialize)]
726 enum Test {
727 Item(i32),
728 }
729
730 rt.context().with(|cx| {
731 let mut serializer = ValueSerializer::from_context(cx.clone()).unwrap();
732 let src = Test::Item(10);
733 let value = src.serialize(&mut serializer).unwrap();
734
735 assert_eq!(r#"{"Item":10}"#, json_stringify(cx.clone(), value));
736 });
737 }
738
739 #[test]
740 fn test_enum_struct() {
741 let rt = Runtime::default();
742
743 #[derive(Debug, Clone, Copy, PartialEq, Serialize)]
744 enum Test {
745 One { a: i32 },
746 }
747
748 rt.context().with(|cx| {
749 let src = Test::One { a: 6 };
750
751 let mut serializer = ValueSerializer::from_context(cx.clone()).unwrap();
752 let value = src.serialize(&mut serializer).unwrap();
753
754 assert_eq!(r#"{"One":{"a":6}}"#, json_stringify(cx.clone(), value));
755 });
756 }
757
758 #[test]
759 fn test_enum_tuple() {
760 let rt = Runtime::default();
761
762 #[derive(Debug, Clone, Copy, PartialEq, Serialize)]
763 enum Test {
764 One(i32, i32),
765 }
766
767 rt.context().with(|cx| {
768 let mut serializer = ValueSerializer::from_context(cx.clone()).unwrap();
769 let src = Test::One(1, 2);
770 let value = src.serialize(&mut serializer).unwrap();
771
772 assert_eq!(r#"{"One":[1,2]}"#, json_stringify(cx.clone(), value));
773 });
774 }
775
776 fn assert_has_own_proto_data_property<'js>(
777 cx: Ctx<'js>,
778 value: Value<'js>,
779 expected_value_source: &str,
780 ) {
781 cx.globals().set("__rquickjs_serde_value", value).unwrap();
782 let assertion = format!(
783 "Object.getPrototypeOf(__rquickjs_serde_value) === Object.prototype && \
784 Object.prototype.hasOwnProperty.call(__rquickjs_serde_value, '__proto__') && \
785 Object.getOwnPropertyDescriptor(__rquickjs_serde_value, '__proto__').value === {expected_value_source}"
786 );
787 assert!(cx.eval::<bool, _>(assertion.as_str()).unwrap());
788 }
789
790 fn json_stringify<'js>(cx: Ctx<'js>, value: Value<'js>) -> String {
791 let obj: Object = cx.globals().get("JSON").unwrap();
792 let stringify: Function = obj.get("stringify").unwrap();
793 let str: String = stringify.call((value,)).unwrap();
794 str
795 }
796}