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
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 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 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 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 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}