diff --git a/src/de.rs b/src/de.rs index 85fce94..9c2584f 100644 --- a/src/de.rs +++ b/src/de.rs @@ -12,7 +12,7 @@ use rquickjs::{ }, }; use serde::{ - de::{self, IntoDeserializer, Unexpected}, + de::{self, IntoDeserializer}, forward_to_deserialize_any, }; @@ -292,16 +292,30 @@ impl<'de> de::Deserializer<'de> for &mut Deserializer<'de> { self.value = v; } - // Now require a primitive string. - let s = if let Some(s) = self.value.as_string() { - s.to_string() - .unwrap_or_else(|e| to_string_lossy(self.value.ctx(), s, e)) - } else { - return Err(Error::new("expected a string for enum unit variant")); - }; + if let Some(obj) = self.value.as_object() { + let (variant, value): (String, Value<'de>) = obj + .props::() + .next() + .ok_or_else(|| Error::new("expected enum object with one key"))? + .map_err(Error::new)?; - // Hand Serde an EnumAccess that only supports unit variants. - visitor.visit_enum(UnitEnumAccess { variant: s }) + visitor.visit_enum(EnumAccessImpl { + variant, + value: Some(value.clone()), + }) + } else if let Some(s) = self.value.as_string() { + // Now require a primitive string. + let s = s + .to_string() + .unwrap_or_else(|e| to_string_lossy(self.value.ctx(), s, e)); + + visitor.visit_enum(EnumAccessImpl { + variant: s, + value: None, + }) + } else { + Err(Error::new("expected a string or object for enum")) + } } forward_to_deserialize_any! { @@ -592,60 +606,69 @@ fn get_index<'a>(obj: &Object<'a>, idx: usize) -> rquickjs::Result> { } /// A helper struct for deserializing enums containing unit variants. -struct UnitEnumAccess { +struct EnumAccessImpl<'de> { variant: String, + value: Option>, } -impl<'de> de::EnumAccess<'de> for UnitEnumAccess { +impl<'de> de::EnumAccess<'de> for EnumAccessImpl<'de> { type Error = Error; - type Variant = UnitOnlyVariant; + type Variant = VariantAccessImpl<'de>; fn variant_seed(self, seed: V) -> Result<(V::Value, Self::Variant)> where V: de::DeserializeSeed<'de>, { - let v = seed.deserialize(self.variant.into_deserializer())?; - Ok((v, UnitOnlyVariant)) + let val = seed.deserialize(self.variant.into_deserializer())?; + Ok((val, VariantAccessImpl { value: self.value })) } } -struct UnitOnlyVariant; +struct VariantAccessImpl<'de> { + value: Option>, +} -impl<'de> de::VariantAccess<'de> for UnitOnlyVariant { +impl<'de> de::VariantAccess<'de> for VariantAccessImpl<'de> { type Error = Error; fn unit_variant(self) -> Result<()> { - Ok(()) + match self.value { + None => Ok(()), + Some(_) => Err(Error::new("expected unit variant")), + } } - fn newtype_variant_seed(self, _seed: T) -> Result + fn newtype_variant_seed(self, seed: T) -> Result where T: de::DeserializeSeed<'de>, { - Err(de::Error::invalid_type( - Unexpected::NewtypeVariant, - &"unit variant", - )) + let value = self + .value + .ok_or_else(|| Error::new("expected value for newtype variant"))?; + + seed.deserialize(&mut Deserializer::from(value)) } - fn tuple_variant(self, _len: usize, _visitor: V) -> Result + fn tuple_variant(self, _len: usize, visitor: V) -> Result where V: de::Visitor<'de>, { - Err(de::Error::invalid_type( - Unexpected::TupleVariant, - &"unit variant", - )) + let value = self + .value + .ok_or_else(|| Error::new("expected tuple variant"))?; + + de::Deserializer::deserialize_seq(&mut Deserializer::from(value), visitor) } - fn struct_variant(self, _fields: &'static [&'static str], _visitor: V) -> Result + fn struct_variant(self, _fields: &'static [&'static str], visitor: V) -> Result where V: de::Visitor<'de>, { - Err(de::Error::invalid_type( - Unexpected::StructVariant, - &"unit variant", - )) + let value = self + .value + .ok_or_else(|| Error::new("expected struct variant"))?; + + de::Deserializer::deserialize_map(&mut Deserializer::from(value), visitor) } } @@ -887,7 +910,7 @@ mod tests { } #[test] - fn test_enum() { + fn test_enum_unit() { let rt = Runtime::default(); #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] @@ -905,6 +928,59 @@ mod tests { }); } + #[test] + fn test_enum_newtype() { + let rt = Runtime::default(); + + #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] + enum Test { + One(i32), + Two(i32), + } + + rt.context().with(|cx| { + let left = Test::One(6); + let value = to_value(cx, left).unwrap(); + let right: Test = from_value(value).unwrap(); + assert_eq!(left, right); + }); + } + + #[test] + fn test_enum_struct() { + let rt = Runtime::default(); + + #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] + enum Test { + One { a: i32 }, + Two(i32), + } + + rt.context().with(|cx| { + let left = Test::One { a: 6 }; + let value = to_value(cx, left).unwrap(); + let right: Test = from_value(value).unwrap(); + assert_eq!(left, right); + }); + } + + #[test] + fn test_enum_tuple() { + let rt = Runtime::default(); + + #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] + enum Test { + One(i32, i32), + } + + rt.context().with(|cx| { + let left = Test::One(1, 2); + let value = to_value(cx, left).unwrap(); + let right: Test = from_value(value).unwrap(); + assert_eq!(left, right); + }); + } + #[test] fn test_short_bigint() { let rt = Runtime::default(); diff --git a/src/lib.rs b/src/lib.rs index 6b0a78a..c9bba6a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -73,8 +73,7 @@ where T: Serialize, { let mut serializer = Serializer::from_context(context)?; - value.serialize(&mut serializer)?; - Ok(serializer.value) + value.serialize(&mut serializer) } /// Interpret a `rquickjs::Value` as an instance of type `T`. @@ -418,8 +417,8 @@ mod tests { let rt = Runtime::default(); rt.context().with(|cx| { let mut serializer = ValueSerializer::from_context(cx).unwrap(); - expected.serialize(&mut serializer).unwrap(); - let mut deserializer = ValueDeserializer::from(serializer.value); + let value = expected.serialize(&mut serializer).unwrap(); + let mut deserializer = ValueDeserializer::from(value); A::deserialize(&mut deserializer).unwrap() }) } diff --git a/src/ser.rs b/src/ser.rs index 19a1519..e11f35f 100644 --- a/src/ser.rs +++ b/src/ser.rs @@ -1,6 +1,6 @@ use alloc::string::ToString as _; -use rquickjs::{Array, Ctx, Object, String as JSString, Value, object::Property}; +use rquickjs::{Array, Ctx, Object, String as JSString, Value}; use serde::{Serialize, ser}; use crate::err::{Error, Result}; @@ -19,115 +19,173 @@ use crate::err::{Error, Result}; /// let ctx = Context::full(&rt).unwrap(); /// ctx.with(|ctx| { /// let mut serializer = Serializer::from_context(ctx.clone()).unwrap(); -/// serializer.serialize_u32(42).unwrap(); -/// assert!(serializer.value.is_number()); +/// let value = serializer.serialize_u32(42).unwrap(); +/// assert!(value.is_number()); /// }); /// ``` pub struct Serializer<'js> { pub context: Ctx<'js>, - pub value: Value<'js>, - pub key: Value<'js>, +} + +pub struct SeqSerializer<'se, 'js> { + ser: &'se mut Serializer<'js>, + value: Array<'js>, +} + +pub struct TupleVariantSerializer<'se, 'js> { + ser: &'se mut Serializer<'js>, + wrapper: Object<'js>, + value: Array<'js>, +} + +pub struct MapSerializer<'se, 'js> { + ser: &'se mut Serializer<'js>, + value: Object<'js>, + /** current map key, will be left `None` for structs */ + key: Option>, +} + +pub struct StructVariantSerializer<'se, 'js> { + ser: &'se mut Serializer<'js>, + wrapper: Object<'js>, + value: Object<'js>, +} + +impl<'se, 'js> SeqSerializer<'se, 'js> { + fn new(ser: &'se mut Serializer<'js>) -> Result { + let value = Array::new(ser.context.clone()).map_err(Error::new)?; + + Ok(Self { ser, value }) + } +} + +impl<'se, 'js> TupleVariantSerializer<'se, 'js> { + fn new(ser: &'se mut Serializer<'js>, variant: &'static str) -> Result { + let wrapper = Object::new(ser.context.clone()).map_err(Error::new)?; + let value = Array::new(ser.context.clone()).map_err(Error::new)?; + wrapper.set(variant, value.clone()).map_err(Error::new)?; + + Ok(Self { + ser, + wrapper, + value, + }) + } +} + +impl<'se, 'js> MapSerializer<'se, 'js> { + fn new(ser: &'se mut Serializer<'js>) -> Result { + let value = Object::new(ser.context.clone()).map_err(Error::new)?; + Ok(Self { + ser, + value, + key: None, + }) + } +} +impl<'se, 'js> StructVariantSerializer<'se, 'js> { + fn new(ser: &'se mut Serializer<'js>, variant: &'static str) -> Result { + let wrapper = Object::new(ser.context.clone()).map_err(Error::new)?; + let value = Object::new(ser.context.clone()).map_err(Error::new)?; + wrapper.set(variant, value.clone()).map_err(Error::new)?; + + Ok(Self { + ser, + wrapper, + value, + }) + } } impl<'js> Serializer<'js> { pub fn from_context(context: Ctx<'js>) -> Result { Ok(Self { context: context.clone(), - value: Value::new_undefined(context.clone()), - key: Value::new_undefined(context), }) } } - -impl ser::Serializer for &mut Serializer<'_> { - type Ok = (); +impl<'js, 'se> ser::Serializer for &'se mut Serializer<'js> { + type Ok = Value<'js>; type Error = Error; - type SerializeSeq = Self; - type SerializeTuple = Self; - type SerializeTupleStruct = Self; - type SerializeTupleVariant = Self; - type SerializeMap = Self; - type SerializeStruct = Self; - type SerializeStructVariant = Self; + type SerializeSeq = SeqSerializer<'se, 'js>; + type SerializeTuple = SeqSerializer<'se, 'js>; + type SerializeTupleStruct = SeqSerializer<'se, 'js>; + type SerializeTupleVariant = TupleVariantSerializer<'se, 'js>; + type SerializeMap = MapSerializer<'se, 'js>; + type SerializeStruct = MapSerializer<'se, 'js>; + type SerializeStructVariant = StructVariantSerializer<'se, 'js>; - fn serialize_i8(self, v: i8) -> Result<()> { + fn serialize_i8(self, v: i8) -> Result { self.serialize_i32(i32::from(v)) } - fn serialize_i16(self, v: i16) -> Result<()> { + fn serialize_i16(self, v: i16) -> Result { self.serialize_i32(i32::from(v)) } - fn serialize_i32(self, v: i32) -> Result<()> { - self.value = Value::new_int(self.context.clone(), v); - Ok(()) + fn serialize_i32(self, v: i32) -> Result { + Ok(Value::new_int(self.context.clone(), v)) } - fn serialize_i64(self, v: i64) -> Result<()> { - self.value = Value::new_number(self.context.clone(), v as _); - Ok(()) + fn serialize_i64(self, v: i64) -> Result { + Ok(Value::new_number(self.context.clone(), v as _)) } - fn serialize_u8(self, v: u8) -> Result<()> { + fn serialize_u8(self, v: u8) -> Result { self.serialize_i32(i32::from(v)) } - fn serialize_u16(self, v: u16) -> Result<()> { + fn serialize_u16(self, v: u16) -> Result { self.serialize_i32(i32::from(v)) } - fn serialize_u32(self, v: u32) -> Result<()> { + fn serialize_u32(self, v: u32) -> Result { // NOTE: See optimization note in serialize_f64. self.serialize_f64(f64::from(v)) } - fn serialize_u64(self, v: u64) -> Result<()> { - self.value = Value::new_number(self.context.clone(), v as _); - Ok(()) + fn serialize_u64(self, v: u64) -> Result { + Ok(Value::new_number(self.context.clone(), v as _)) } - fn serialize_f32(self, v: f32) -> Result<()> { + fn serialize_f32(self, v: f32) -> Result { // NOTE: See optimization note in serialize_f64. self.serialize_f64(f64::from(v)) } - fn serialize_f64(self, v: f64) -> Result<()> { + fn serialize_f64(self, v: f64) -> Result { // NOTE: QuickJS will create a number value backed by an i32 when the value is within // the i32::MIN..=i32::MAX as an optimization. Otherwise the value will be backed by a f64. - self.value = Value::new_float(self.context.clone(), v); - Ok(()) + Ok(Value::new_float(self.context.clone(), v)) } - fn serialize_bool(self, b: bool) -> Result<()> { - self.value = Value::new_bool(self.context.clone(), b); - Ok(()) + fn serialize_bool(self, b: bool) -> Result { + Ok(Value::new_bool(self.context.clone(), b)) } - fn serialize_char(self, v: char) -> Result<()> { + fn serialize_char(self, v: char) -> Result { self.serialize_str(&v.to_string()) } - fn serialize_str(self, v: &str) -> Result<()> { + fn serialize_str(self, v: &str) -> Result { let js_string = JSString::from_str(self.context.clone(), v).map_err(Error::new)?; - self.value = Value::from(js_string); - Ok(()) + Ok(Value::from(js_string)) } - fn serialize_none(self) -> Result<()> { + fn serialize_none(self) -> Result { self.serialize_unit() } - fn serialize_unit(self) -> Result<()> { - self.value = Value::new_null(self.context.clone()); - Ok(()) + fn serialize_unit(self) -> Result { + Ok(Value::new_null(self.context.clone())) } - fn serialize_unit_struct(self, _name: &'static str) -> Result<()> { + fn serialize_unit_struct(self, _name: &'static str) -> Result { self.serialize_unit() } - fn serialize_some(self, value: &T) -> Result<()> + fn serialize_some(self, value: &T) -> Result where T: ?Sized + Serialize, { @@ -139,11 +197,11 @@ impl ser::Serializer for &mut Serializer<'_> { _name: &'static str, _variant_index: u32, variant: &'static str, - ) -> Result<()> { + ) -> Result { self.serialize_str(variant) } - fn serialize_newtype_struct(self, _name: &'static str, value: &T) -> Result<()> + fn serialize_newtype_struct(self, _name: &'static str, value: &T) -> Result where T: ?Sized + Serialize, { @@ -151,13 +209,11 @@ impl ser::Serializer for &mut Serializer<'_> { } fn serialize_seq(self, _len: Option) -> Result { - let arr = Array::new(self.context.clone()).map_err(Error::new)?; - self.value = arr.into_value(); - Ok(self) + SeqSerializer::new(self) } - fn serialize_tuple(self, len: usize) -> Result { - self.serialize_seq(Some(len)) + fn serialize_tuple(self, _len: usize) -> Result { + SeqSerializer::new(self) } fn serialize_tuple_struct( @@ -169,33 +225,31 @@ impl ser::Serializer for &mut Serializer<'_> { } fn serialize_map(self, _len: Option) -> Result { - let obj = Object::new(self.context.clone()).map_err(Error::new)?; - self.value = Value::from(obj); - Ok(self) + MapSerializer::new(self) } - fn serialize_struct(self, _name: &'static str, len: usize) -> Result { - self.serialize_map(Some(len)) + fn serialize_struct(self, _name: &'static str, _len: usize) -> Result { + MapSerializer::new(self) } fn serialize_struct_variant( self, _name: &'static str, _variant_index: u32, - _variant: &'static str, - len: usize, + variant: &'static str, + _len: usize, ) -> Result { - self.serialize_map(Some(len)) + StructVariantSerializer::new(self, variant) } fn serialize_tuple_variant( self, _name: &'static str, _variant_index: u32, - _variant: &'static str, - len: usize, + variant: &'static str, + _len: usize, ) -> Result { - self.serialize_map(Some(len)) + TupleVariantSerializer::new(self, variant) } fn serialize_newtype_variant( @@ -204,132 +258,102 @@ impl ser::Serializer for &mut Serializer<'_> { _variant_index: u32, variant: &'static str, value: &T, - ) -> Result<()> + ) -> Result where T: ?Sized + Serialize, { let obj = Object::new(self.context.clone()).map_err(Error::new)?; - value.serialize(&mut *self)?; - obj.set(variant, self.value.clone()).map_err(Error::new)?; - self.value = Value::from(obj); - - Ok(()) + let value = value.serialize(&mut *self)?; + obj.set(variant, value).map_err(Error::new)?; + Ok(obj.into()) } - fn serialize_bytes(self, _: &[u8]) -> Result<()> { + fn serialize_bytes(self, _: &[u8]) -> Result { Err(Error::new("Cannot serialize bytes")) } } -impl ser::SerializeSeq for &mut Serializer<'_> { - type Ok = (); +impl<'se, 'js> ser::SerializeSeq for SeqSerializer<'se, 'js> { + type Ok = Value<'js>; type Error = Error; fn serialize_element(&mut self, value: &T) -> Result<()> where T: ?Sized + Serialize, { - let mut element_serializer = Serializer::from_context(self.context.clone())?; - value.serialize(&mut element_serializer)?; - - if let Some(v) = self.value.as_array() { - return v - .set(v.len(), element_serializer.value.clone()) - .map_err(Error::new); - } - Err(Error::new("Expected to be an array")) + self.value + .set(self.value.len(), value.serialize(&mut *self.ser)?) + .map_err(Error::new) } - fn end(self) -> Result<()> { - Ok(()) + fn end(self) -> Result { + Ok(self.value.into()) } } -impl ser::SerializeTuple for &mut Serializer<'_> { - type Ok = (); +impl<'se, 'js> ser::SerializeTuple for SeqSerializer<'se, 'js> { + type Ok = Value<'js>; type Error = Error; fn serialize_element(&mut self, value: &T) -> Result<()> where T: ?Sized + Serialize, { - let mut element_serializer = Serializer::from_context(self.context.clone())?; - value.serialize(&mut element_serializer)?; - - if let Some(v) = self.value.as_array() { - return v - .set(v.len(), element_serializer.value.clone()) - .map_err(Error::new); - } - - Err(Error::new("Expected to be an array")) + self.value + .set(self.value.len(), value.serialize(&mut *self.ser)?) + .map_err(Error::new) } - fn end(self) -> Result<()> { - Ok(()) + fn end(self) -> Result { + Ok(self.value.into()) } } -impl ser::SerializeTupleStruct for &mut Serializer<'_> { - type Ok = (); +impl<'se, 'js> ser::SerializeTupleStruct for SeqSerializer<'se, 'js> { + type Ok = Value<'js>; type Error = Error; fn serialize_field(&mut self, value: &T) -> Result<()> where T: ?Sized + Serialize, { - let mut field_serializer = Serializer::from_context(self.context.clone())?; - value.serialize(&mut field_serializer)?; - if let Some(v) = self.value.as_array() { - return v - .set(v.len(), field_serializer.value.clone()) - .map_err(Error::new); - } - - Err(Error::new("Expected to be an array")) + self.value + .set(self.value.len(), value.serialize(&mut *self.ser)?) + .map_err(Error::new) } - fn end(self) -> Result<()> { - Ok(()) + fn end(self) -> Result { + Ok(self.value.into()) } } -impl ser::SerializeTupleVariant for &mut Serializer<'_> { - type Ok = (); +impl<'se, 'js> ser::SerializeTupleVariant for TupleVariantSerializer<'se, 'js> { + type Ok = Value<'js>; type Error = Error; fn serialize_field(&mut self, value: &T) -> Result<()> where T: ?Sized + Serialize, { - let mut field_serializer = Serializer::from_context(self.context.clone())?; - value.serialize(&mut field_serializer)?; - - if let Some(v) = self.value.as_array() { - return v - .set(v.len(), field_serializer.value.clone()) - .map_err(Error::new); - } - - Err(Error::new("Expected to be an array")) + self.value + .set(self.value.len(), value.serialize(&mut *self.ser)?) + .map_err(Error::new) } - fn end(self) -> Result<()> { - Ok(()) + fn end(self) -> Result { + Ok(self.wrapper.into()) } } -impl ser::SerializeMap for &mut Serializer<'_> { - type Ok = (); +impl<'se, 'js> ser::SerializeMap for MapSerializer<'se, 'js> { + type Ok = Value<'js>; type Error = Error; fn serialize_key(&mut self, key: &T) -> Result<()> where T: ?Sized + Serialize, { - let mut key_serializer = Serializer::from_context(self.context.clone())?; - key.serialize(&mut key_serializer)?; - self.key = key_serializer.value; + self.key = Some(key.serialize(&mut *self.ser)?); Ok(()) } @@ -337,72 +361,53 @@ impl ser::SerializeMap for &mut Serializer<'_> { where T: ?Sized + Serialize, { - let mut map_serializer = Serializer::from_context(self.context.clone())?; - value.serialize(&mut map_serializer)?; - if let Some(o) = self.value.as_object() { - let prop = Property::from(map_serializer.value.clone()) - .writable() - .configurable() - .enumerable(); - o.prop::<_, _, _>(self.key.clone(), prop) - .map_err(Error::new) - } else { - Err(Error::new("Expected to be an object")) - } + let key = self + .key + .take() + .ok_or_else(|| Error::new("serialize_value before serialize_key"))?; + + let value = value.serialize(&mut *self.ser)?; + self.value.set(key, value).map_err(Error::new) } - fn end(self) -> Result<()> { - Ok(()) + fn end(self) -> Result { + Ok(self.value.into()) } } -impl ser::SerializeStruct for &mut Serializer<'_> { - type Ok = (); +impl<'se, 'js> ser::SerializeStruct for MapSerializer<'se, 'js> { + type Ok = Value<'js>; type Error = Error; fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<()> where T: ?Sized + Serialize, { - let mut field_serializer = Serializer::from_context(self.context.clone())?; - value.serialize(&mut field_serializer)?; - - if let Some(o) = self.value.as_object() { - return o - .set(key, field_serializer.value.clone()) - .map_err(Error::new); - } - - Err(Error::new("Expected to be an object")) + let value = value.serialize(&mut *self.ser)?; + self.value.set(key, value).map_err(Error::new)?; + Ok(()) } - fn end(self) -> Result<()> { - Ok(()) + fn end(self) -> Result { + Ok(self.value.into()) } } -impl ser::SerializeStructVariant for &mut Serializer<'_> { - type Ok = (); +impl<'se, 'js> ser::SerializeStructVariant for StructVariantSerializer<'se, 'js> { + type Ok = Value<'js>; type Error = Error; fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<()> where T: ?Sized + Serialize, { - let mut field_serializer = Serializer::from_context(self.context.clone())?; - value.serialize(&mut field_serializer)?; - - if let Some(o) = self.value.as_object() { - return o - .set(key, field_serializer.value.clone()) - .map_err(Error::new); - } - - Err(Error::new("Expected to be an object")) + let value = value.serialize(&mut *self.ser)?; + self.value.set(key, value).map_err(Error::new)?; + Ok(()) } - fn end(self) -> Result<()> { - Ok(()) + fn end(self) -> Result { + Ok(self.wrapper.into()) } } @@ -410,6 +415,7 @@ impl ser::SerializeStructVariant for &mut Serializer<'_> { mod tests { use std::collections::BTreeMap; + use rquickjs::{Ctx, Function, Object, Value}; use serde::{Serialize, Serializer}; use super::Serializer as ValueSerializer; @@ -432,16 +438,16 @@ mod tests { fn test_i16(v: i16) -> Result { let rt = Runtime::default(); with_serializer(&rt, |serializer| { - serializer.serialize_i16(v)?; - Ok(serializer.value.is_int()) + let value = serializer.serialize_i16(v)?; + Ok(value.is_int()) }) } fn test_i32(v: i32) -> Result { let rt = Runtime::default(); with_serializer(&rt, |serializer| { - serializer.serialize_i32(v)?; - Ok(serializer.value.is_int()) + let value = serializer.serialize_i32(v)?; + Ok(value.is_int()) }) } @@ -449,11 +455,11 @@ mod tests { let rt = Runtime::default(); with_serializer(&rt, |serializer| { if (MIN_SAFE_INTEGER..=MAX_SAFE_INTEGER).contains(&v) { - serializer.serialize_i64(v)?; - Ok(serializer.value.is_number()) + let value = serializer.serialize_i64(v)?; + Ok(value.is_number()) } else { - serializer.serialize_f64(v as f64)?; - Ok(serializer.value.is_number()) + let value = serializer.serialize_f64(v as f64)?; + Ok(value.is_number()) } }) } @@ -462,11 +468,11 @@ mod tests { let rt = Runtime::default(); with_serializer(&rt, |serializer| { if v <= MAX_SAFE_INTEGER as u64 { - serializer.serialize_u64(v)?; - Ok(serializer.value.is_number()) + let value = serializer.serialize_u64(v)?; + Ok(value.is_number()) } else { - serializer.serialize_f64(v as f64)?; - Ok(serializer.value.is_number()) + let value = serializer.serialize_f64(v as f64)?; + Ok(value.is_number()) } }) } @@ -475,21 +481,21 @@ mod tests { let rt = Runtime::default(); with_serializer(&rt, |serializer| { - serializer.serialize_u16(v)?; - Ok(serializer.value.is_int()) + let value = serializer.serialize_u16(v)?; + Ok(value.is_int()) }) } fn test_u32(v: u32) -> Result { let rt = Runtime::default(); with_serializer(&rt, |serializer| { - serializer.serialize_u32(v)?; + let value = serializer.serialize_u32(v)?; // QuickJS optimizes numbers in the range of [i32::MIN..=i32::MAX] // as ints if v > i32::MAX as u32 { - Ok(serializer.value.is_float()) + Ok(value.is_float()) } else { - Ok(serializer.value.is_int()) + Ok(value.is_int()) } }) @@ -498,16 +504,16 @@ mod tests { fn test_f32(v: f32) -> Result { let rt = Runtime::default(); with_serializer(&rt, |serializer| { - serializer.serialize_f32(v)?; + let value = serializer.serialize_f32(v)?; if v == 0.0_f32 { if v.is_sign_positive() { - return Ok(serializer.value.is_int()); + return Ok(value.is_int()); } if v.is_sign_negative() { - return Ok(serializer.value.is_float()); + return Ok(value.is_float()); } } @@ -517,9 +523,9 @@ mod tests { let range = (i32::MIN as f32)..=(i32::MAX as f32); if zero_fractional_part && range.contains(&v) { - Ok(serializer.value.is_int()) + Ok(value.is_int()) } else { - Ok(serializer.value.is_float()) + Ok(value.is_float()) } }) } @@ -527,16 +533,16 @@ mod tests { fn test_f64(v: f64) -> Result { let rt = Runtime::default(); with_serializer(&rt, |serializer| { - serializer.serialize_f64(v)?; + let value = serializer.serialize_f64(v)?; if v == 0.0_f64 { if v.is_sign_positive() { - return Ok(serializer.value.is_int()); + return Ok(value.is_int()); } if v.is_sign_negative() { - return Ok(serializer.value.is_float()); + return Ok(value.is_float()); } } @@ -546,9 +552,9 @@ mod tests { let range = (i32::MIN as f64)..=(i32::MAX as f64); if zero_fractional_part && range.contains(&v) { - Ok(serializer.value.is_int()) + Ok(value.is_int()) } else { - Ok(serializer.value.is_float()) + Ok(value.is_float()) } }) } @@ -556,17 +562,17 @@ mod tests { fn test_bool(v: bool) -> Result { let rt = Runtime::default(); with_serializer(&rt, |serializer| { - serializer.serialize_bool(v)?; - Ok(serializer.value.is_bool()) + let value = serializer.serialize_bool(v)?; + Ok(value.is_bool()) }) } fn test_str(v: String) -> Result { let rt = Runtime::default(); with_serializer(&rt, |serializer| { - serializer.serialize_str(v.as_str())?; + let value = serializer.serialize_str(v.as_str())?; - Ok(serializer.value.is_string()) + Ok(value.is_string()) }) } } @@ -577,9 +583,9 @@ mod tests { rt.context().with(|cx| { let mut serializer = ValueSerializer::from_context(cx.clone()).unwrap(); - serializer.serialize_unit().unwrap(); + let value = serializer.serialize_unit().unwrap(); - assert!(serializer.value.is_null()); + assert!(value.is_null()); }); Ok(()) } @@ -590,8 +596,8 @@ mod tests { rt.context().with(|cx| { let mut serializer = ValueSerializer::from_context(cx.clone()).unwrap(); - serializer.serialize_f64(f64::NAN).unwrap(); - assert!(serializer.value.is_number()); + let value = serializer.serialize_f64(f64::NAN).unwrap(); + assert!(value.is_number()); }); Ok(()) } @@ -601,8 +607,8 @@ mod tests { let rt = Runtime::default(); rt.context().with(|cx| { let mut serializer = ValueSerializer::from_context(cx.clone()).unwrap(); - serializer.serialize_f64(f64::INFINITY).unwrap(); - assert!(serializer.value.is_number()); + let value = serializer.serialize_f64(f64::INFINITY).unwrap(); + assert!(value.is_number()); }); Ok(()) } @@ -612,8 +618,8 @@ mod tests { let rt = Runtime::default(); rt.context().with(|cx| { let mut serializer = ValueSerializer::from_context(cx.clone()).unwrap(); - serializer.serialize_f64(f64::NEG_INFINITY).unwrap(); - assert!(serializer.value.is_number()); + let value = serializer.serialize_f64(f64::NEG_INFINITY).unwrap(); + assert!(value.is_number()); }); Ok(()) } @@ -629,9 +635,9 @@ mod tests { map.insert("foo", "bar"); map.insert("toto", "titi"); - map.serialize(&mut serializer).unwrap(); + let value = map.serialize(&mut serializer).unwrap(); - assert!(serializer.value.is_object()) + assert!(value.is_object()) }); } @@ -652,9 +658,9 @@ mod tests { foo: "hello".to_string(), bar: 1337, }; - my_object.serialize(&mut serializer).unwrap(); + let value = my_object.serialize(&mut serializer).unwrap(); - assert!(serializer.value.is_object()); + assert!(value.is_object()); }); } @@ -667,9 +673,93 @@ mod tests { let sequence = vec!["hello", "world"]; - sequence.serialize(&mut serializer).unwrap(); + let value = sequence.serialize(&mut serializer).unwrap(); + + assert!(value.is_array()); + assert_eq!(r#"["hello","world"]"#, json_stringify(cx.clone(), value)); + }); + } + + #[test] + fn test_enum_unit() { + let rt = Runtime::default(); + + #[derive(Debug, Clone, Copy, PartialEq, Serialize)] + enum Test { + One, + } + + rt.context().with(|cx| { + let mut serializer = ValueSerializer::from_context(cx.clone()).unwrap(); + + let src = Test::One; + + let value = src.serialize(&mut serializer).unwrap(); + + let inner: String = value.as_string().unwrap().to_string().unwrap(); + assert_eq!("One", inner); + }); + } + + #[test] + fn test_enum_newtype() { + let rt = Runtime::default(); + + #[derive(Debug, Clone, Copy, PartialEq, Serialize)] + enum Test { + Item(i32), + } + + rt.context().with(|cx| { + let mut serializer = ValueSerializer::from_context(cx.clone()).unwrap(); + let src = Test::Item(10); + let value = src.serialize(&mut serializer).unwrap(); + + assert_eq!(r#"{"Item":10}"#, json_stringify(cx.clone(), value)); + }); + } + + #[test] + fn test_enum_struct() { + let rt = Runtime::default(); + + #[derive(Debug, Clone, Copy, PartialEq, Serialize)] + enum Test { + One { a: i32 }, + } + + rt.context().with(|cx| { + let src = Test::One { a: 6 }; + + let mut serializer = ValueSerializer::from_context(cx.clone()).unwrap(); + let value = src.serialize(&mut serializer).unwrap(); - assert!(serializer.value.is_array()); + assert_eq!(r#"{"One":{"a":6}}"#, json_stringify(cx.clone(), value)); }); } + + #[test] + fn test_enum_tuple() { + let rt = Runtime::default(); + + #[derive(Debug, Clone, Copy, PartialEq, Serialize)] + enum Test { + One(i32, i32), + } + + rt.context().with(|cx| { + let mut serializer = ValueSerializer::from_context(cx.clone()).unwrap(); + let src = Test::One(1, 2); + let value = src.serialize(&mut serializer).unwrap(); + + assert_eq!(r#"{"One":[1,2]}"#, json_stringify(cx.clone(), value)); + }); + } + + fn json_stringify<'js>(cx: Ctx<'js>, value: Value<'js>) -> String { + let obj: Object = cx.globals().get("JSON").unwrap(); + let stringify: Function = obj.get("stringify").unwrap(); + let str: String = stringify.call((value,)).unwrap(); + str + } }