Deserialize large numbers.

This commit is contained in:
Stephen Chung 2022-11-23 16:13:57 +08:00
parent 31292e683d
commit 9f5b68549a
6 changed files with 273 additions and 186 deletions

View File

@ -4,6 +4,11 @@ Rhai Release Notes
Version 1.12.0
==============
Buf fixes
---------
* Integer numbers that are too large to deserialize into `INT` now fall back to `Decimal` or `FLOAT` instead of silently truncating.
Net features
------------

View File

@ -47,7 +47,7 @@ impl<'de> DynamicDeserializer<'de> {
)
}
#[inline(always)]
fn deserialize_int<V: Visitor<'de>>(self, v: crate::INT, visitor: V) -> RhaiResultOf<V::Value> {
fn deserialize_int<V: Visitor<'de>>(v: crate::INT, visitor: V) -> RhaiResultOf<V::Value> {
#[cfg(not(feature = "only_i32"))]
return visitor.visit_i64(v);
#[cfg(feature = "only_i32")]
@ -185,7 +185,7 @@ impl<'de> Deserializer<'de> for DynamicDeserializer<'de> {
fn deserialize_i8<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
if let Ok(v) = self.0.as_int() {
self.deserialize_int(v, visitor)
Self::deserialize_int(v, visitor)
} else {
self.0
.downcast_ref::<i8>()
@ -195,7 +195,7 @@ impl<'de> Deserializer<'de> for DynamicDeserializer<'de> {
fn deserialize_i16<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
if let Ok(v) = self.0.as_int() {
self.deserialize_int(v, visitor)
Self::deserialize_int(v, visitor)
} else {
self.0
.downcast_ref::<i16>()
@ -205,7 +205,7 @@ impl<'de> Deserializer<'de> for DynamicDeserializer<'de> {
fn deserialize_i32<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
if let Ok(v) = self.0.as_int() {
self.deserialize_int(v, visitor)
Self::deserialize_int(v, visitor)
} else if cfg!(feature = "only_i32") {
self.type_error()
} else {
@ -217,7 +217,7 @@ impl<'de> Deserializer<'de> for DynamicDeserializer<'de> {
fn deserialize_i64<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
if let Ok(v) = self.0.as_int() {
self.deserialize_int(v, visitor)
Self::deserialize_int(v, visitor)
} else if cfg!(not(feature = "only_i32")) {
self.type_error()
} else {
@ -229,7 +229,7 @@ impl<'de> Deserializer<'de> for DynamicDeserializer<'de> {
fn deserialize_i128<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
if let Ok(v) = self.0.as_int() {
self.deserialize_int(v, visitor)
Self::deserialize_int(v, visitor)
} else if cfg!(not(feature = "only_i32")) {
self.type_error()
} else {
@ -241,7 +241,7 @@ impl<'de> Deserializer<'de> for DynamicDeserializer<'de> {
fn deserialize_u8<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
if let Ok(v) = self.0.as_int() {
self.deserialize_int(v, visitor)
Self::deserialize_int(v, visitor)
} else {
self.0
.downcast_ref::<u8>()
@ -251,7 +251,7 @@ impl<'de> Deserializer<'de> for DynamicDeserializer<'de> {
fn deserialize_u16<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
if let Ok(v) = self.0.as_int() {
self.deserialize_int(v, visitor)
Self::deserialize_int(v, visitor)
} else {
self.0
.downcast_ref::<u16>()
@ -261,7 +261,7 @@ impl<'de> Deserializer<'de> for DynamicDeserializer<'de> {
fn deserialize_u32<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
if let Ok(v) = self.0.as_int() {
self.deserialize_int(v, visitor)
Self::deserialize_int(v, visitor)
} else {
self.0
.downcast_ref::<u32>()
@ -271,7 +271,7 @@ impl<'de> Deserializer<'de> for DynamicDeserializer<'de> {
fn deserialize_u64<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
if let Ok(v) = self.0.as_int() {
self.deserialize_int(v, visitor)
Self::deserialize_int(v, visitor)
} else {
self.0
.downcast_ref::<u64>()
@ -281,7 +281,7 @@ impl<'de> Deserializer<'de> for DynamicDeserializer<'de> {
fn deserialize_u128<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
if let Ok(v) = self.0.as_int() {
self.deserialize_int(v, visitor)
Self::deserialize_int(v, visitor)
} else {
self.0
.downcast_ref::<u128>()
@ -296,21 +296,21 @@ impl<'de> Deserializer<'de> for DynamicDeserializer<'de> {
.downcast_ref::<f32>()
.map_or_else(|| self.type_error(), |&x| _visitor.visit_f32(x));
#[cfg(feature = "no_float")]
#[cfg(feature = "decimal")]
#[allow(unreachable_code)]
{
use rust_decimal::prelude::ToPrimitive;
#[cfg(feature = "decimal")]
{
use rust_decimal::prelude::ToPrimitive;
return self
.0
.downcast_ref::<rust_decimal::Decimal>()
.and_then(|&x| x.to_f32())
.map_or_else(|| self.type_error(), |v| _visitor.visit_f32(v));
return self
.0
.downcast_ref::<rust_decimal::Decimal>()
.and_then(|&x| x.to_f32())
.map_or_else(|| self.type_error(), |v| _visitor.visit_f32(v));
}
self.type_error_str("f32")
}
#[cfg(feature = "no_float")]
#[cfg(not(feature = "decimal"))]
return self.type_error_str("f32");
}
fn deserialize_f64<V: Visitor<'de>>(self, _visitor: V) -> RhaiResultOf<V::Value> {
@ -320,21 +320,21 @@ impl<'de> Deserializer<'de> for DynamicDeserializer<'de> {
.downcast_ref::<f64>()
.map_or_else(|| self.type_error(), |&x| _visitor.visit_f64(x));
#[cfg(feature = "no_float")]
#[cfg(feature = "decimal")]
#[allow(unreachable_code)]
{
use rust_decimal::prelude::ToPrimitive;
#[cfg(feature = "decimal")]
{
use rust_decimal::prelude::ToPrimitive;
return self
.0
.downcast_ref::<rust_decimal::Decimal>()
.and_then(|&x| x.to_f64())
.map_or_else(|| self.type_error(), |v| _visitor.visit_f64(v));
return self
.0
.downcast_ref::<rust_decimal::Decimal>()
.and_then(|&x| x.to_f64())
.map_or_else(|| self.type_error(), |v| _visitor.visit_f64(v));
}
self.type_error_str("f64")
}
#[cfg(feature = "no_float")]
#[cfg(not(feature = "decimal"))]
return self.type_error_str("f64");
}
fn deserialize_char<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
@ -517,10 +517,9 @@ impl<'de, ITER: Iterator<Item = &'de Dynamic>> serde::de::SeqAccess<'de>
seed: T,
) -> RhaiResultOf<Option<T::Value>> {
// Deserialize each item coming out of the iterator.
match self.iter.next() {
Some(item) => seed.deserialize(item.into_deserializer()).map(Some),
None => Ok(None),
}
self.iter.next().map_or(Ok(None), |item| {
seed.deserialize(item.into_deserializer()).map(Some)
})
}
}
@ -553,10 +552,10 @@ impl<'de, K: Iterator<Item = &'de str>, V: Iterator<Item = &'de Dynamic>> serde:
seed: S,
) -> RhaiResultOf<Option<S::Value>> {
// Deserialize each `Identifier` key coming out of the keys iterator.
match self.keys.next().map(<_>::into_deserializer) {
Some(d) => seed.deserialize(d).map(Some),
None => Ok(None),
}
self.keys
.next()
.map(<_>::into_deserializer)
.map_or(Ok(None), |d| seed.deserialize(d).map(Some))
}
fn next_value_seed<S: serde::de::DeserializeSeed<'de>>(

View File

@ -1,6 +1,7 @@
//! Implementations of [`serde::Deserialize`].
use crate::{Dynamic, Identifier, ImmutableString, Scope, INT};
use num_traits::FromPrimitive;
use serde::{
de::{Error, SeqAccess, Visitor},
Deserialize, Deserializer,
@ -38,14 +39,43 @@ impl<'de> Visitor<'de> for DynamicVisitor {
#[inline]
fn visit_i64<E: Error>(self, v: i64) -> Result<Self::Value, E> {
#[cfg(not(feature = "only_i32"))]
{
Ok(v.into())
}
return Ok(v.into());
#[cfg(feature = "only_i32")]
if v > i32::MAX as i64 {
Ok(Dynamic::from(v))
} else {
self.visit_i32(v as i32)
if v <= INT::MAX as i64 {
return Ok(Dynamic::from(v as INT));
}
#[allow(unreachable_code)]
{
#[cfg(feature = "decimal")]
if let Some(n) = rust_decimal::Decimal::from_i64(v) {
return Ok(Dynamic::from_decimal(n));
}
#[cfg(not(feature = "no_float"))]
return Ok(Dynamic::from_float(v as crate::FLOAT));
Err(Error::custom(format!("integer number too large: {}", v)))
}
}
#[inline]
fn visit_i128<E: Error>(self, v: i128) -> Result<Self::Value, E> {
if v <= i128::from(INT::MAX) {
return Ok(Dynamic::from(v as INT));
}
#[allow(unreachable_code)]
{
#[cfg(feature = "decimal")]
if let Some(n) = rust_decimal::Decimal::from_i128(v) {
return Ok(Dynamic::from_decimal(n));
}
#[cfg(not(feature = "no_float"))]
return Ok(Dynamic::from_float(v as crate::FLOAT));
Err(Error::custom(format!("integer number too large: {}", v)))
}
}
#[inline(always)]
@ -59,57 +89,79 @@ impl<'de> Visitor<'de> for DynamicVisitor {
#[inline]
fn visit_u32<E: Error>(self, v: u32) -> Result<Self::Value, E> {
#[cfg(not(feature = "only_i32"))]
{
Ok(INT::from(v).into())
}
return Ok(Dynamic::from(v as INT));
#[cfg(feature = "only_i32")]
if v > i32::MAX as u32 {
Ok(Dynamic::from(v))
} else {
self.visit_i32(v as i32)
if v <= INT::MAX as i32 {
return Ok(Dynamic::from(v as INT));
}
#[allow(unreachable_code)]
{
#[cfg(feature = "decimal")]
if let Some(n) = rust_decimal::Decimal::from_u32(v) {
return Ok(Dynamic::from_decimal(n));
}
#[cfg(not(feature = "no_float"))]
return Ok(Dynamic::from_float(v as crate::FLOAT));
Err(Error::custom(format!("integer number too large: {}", v)))
}
}
#[inline]
fn visit_u64<E: Error>(self, v: u64) -> Result<Self::Value, E> {
#[cfg(not(feature = "only_i32"))]
if v > i64::MAX as u64 {
Ok(Dynamic::from(v))
} else {
self.visit_i64(v as i64)
if v <= INT::MAX as u64 {
return Ok(Dynamic::from(v as INT));
}
#[cfg(feature = "only_i32")]
if v > i32::MAX as u64 {
Ok(Dynamic::from(v))
} else {
self.visit_i32(v as i32)
#[cfg(feature = "decimal")]
if let Some(n) = rust_decimal::Decimal::from_u64(v) {
return Ok(Dynamic::from_decimal(n));
}
#[cfg(not(feature = "no_float"))]
return Ok(Dynamic::from_float(v as crate::FLOAT));
#[allow(unreachable_code)]
Err(Error::custom(format!("integer number too large: {}", v)))
}
#[inline]
fn visit_u128<E: Error>(self, v: u128) -> Result<Self::Value, E> {
if v <= INT::MAX as u128 {
return Ok(Dynamic::from(v as INT));
}
#[cfg(feature = "decimal")]
if let Some(n) = rust_decimal::Decimal::from_u128(v) {
return Ok(Dynamic::from_decimal(n));
}
#[cfg(not(feature = "no_float"))]
return Ok(Dynamic::from_float(v as crate::FLOAT));
#[allow(unreachable_code)]
Err(Error::custom(format!("integer number too large: {}", v)))
}
#[cfg(not(feature = "no_float"))]
#[inline(always)]
fn visit_f32<E: Error>(self, v: f32) -> Result<Self::Value, E> {
#[cfg(not(feature = "f32_float"))]
return self.visit_f64(v as f64);
#[cfg(feature = "f32_float")]
return Ok(v.into());
Ok(crate::FLOAT::from(v).into())
}
#[cfg(not(feature = "no_float"))]
#[inline(always)]
fn visit_f64<E: Error>(self, v: f64) -> Result<Self::Value, E> {
#[cfg(not(feature = "f32_float"))]
return Ok(v.into());
#[cfg(feature = "f32_float")]
return self.visit_f32(v as f32);
Ok(crate::FLOAT::from(v).into())
}
#[cfg(feature = "no_float")]
#[cfg(feature = "decimal")]
#[inline]
fn visit_f32<E: Error>(self, v: f32) -> Result<Self::Value, E> {
use rust_decimal::Decimal;
use std::convert::TryFrom;
Decimal::try_from(v)
rust_decimal::Decimal::try_from(v)
.map(|v| v.into())
.map_err(Error::custom)
}
@ -117,10 +169,9 @@ impl<'de> Visitor<'de> for DynamicVisitor {
#[cfg(feature = "decimal")]
#[inline]
fn visit_f64<E: Error>(self, v: f64) -> Result<Self::Value, E> {
use rust_decimal::Decimal;
use std::convert::TryFrom;
Decimal::try_from(v)
rust_decimal::Decimal::try_from(v)
.map(|v| v.into())
.map_err(Error::custom)
}
@ -216,10 +267,9 @@ impl<'de> Deserialize<'de> for Scope<'de> {
where
A: SeqAccess<'de>,
{
let mut scope = match access.size_hint() {
Some(size) => Scope::with_capacity(size),
None => Scope::new(),
};
let mut scope = access
.size_hint()
.map_or_else(Scope::new, Scope::with_capacity);
while let Some(ScopeEntry {
name,

View File

@ -1,6 +1,7 @@
//! Implement serialization support of [`Dynamic`][crate::Dynamic] for [`serde`].
use crate::{Dynamic, Identifier, Position, RhaiError, RhaiResult, RhaiResultOf, ERR};
use crate::{Dynamic, Identifier, Position, RhaiError, RhaiResult, RhaiResultOf, ERR, INT};
use num_traits::FromPrimitive;
use serde::ser::{
Error, SerializeMap, SerializeSeq, SerializeStruct, SerializeTuple, SerializeTupleStruct,
};
@ -112,152 +113,164 @@ impl Serializer for &mut DynamicSerializer {
#[inline(always)]
fn serialize_i8(self, v: i8) -> RhaiResultOf<Self::Ok> {
#[cfg(not(feature = "only_i32"))]
return self.serialize_i64(i64::from(v));
#[cfg(feature = "only_i32")]
return self.serialize_i32(i32::from(v));
Ok(INT::from(v).into())
}
#[inline(always)]
fn serialize_i16(self, v: i16) -> RhaiResultOf<Self::Ok> {
#[cfg(not(feature = "only_i32"))]
return self.serialize_i64(i64::from(v));
#[cfg(feature = "only_i32")]
return self.serialize_i32(i32::from(v));
Ok(INT::from(v).into())
}
#[inline(always)]
fn serialize_i32(self, v: i32) -> RhaiResultOf<Self::Ok> {
#[cfg(not(feature = "only_i32"))]
return self.serialize_i64(i64::from(v));
#[cfg(feature = "only_i32")]
return Ok(v.into());
Ok(INT::from(v).into())
}
#[inline]
fn serialize_i64(self, v: i64) -> RhaiResultOf<Self::Ok> {
#[cfg(not(feature = "only_i32"))]
{
Ok(v.into())
}
return Ok(v.into());
#[cfg(feature = "only_i32")]
if v > i32::MAX as i64 {
Ok(Dynamic::from(v))
} else {
self.serialize_i32(v as i32)
if v <= INT::MAX as i64 {
return Ok(Dynamic::from(v as INT));
}
#[allow(unreachable_code)]
{
#[cfg(feature = "decimal")]
if let Some(n) = rust_decimal::Decimal::from_i64(v) {
return Ok(Dynamic::from_decimal(n));
}
#[cfg(not(feature = "no_float"))]
return Ok(Dynamic::from_float(v as crate::FLOAT));
Err(Error::custom(format!("integer number too large: {}", v)))
}
}
#[inline]
fn serialize_i128(self, v: i128) -> RhaiResultOf<Self::Ok> {
#[cfg(not(feature = "only_i32"))]
if v > i64::MAX as i128 {
Ok(Dynamic::from(v))
} else {
self.serialize_i64(v as i64)
if v <= i128::from(INT::MAX) {
return Ok(Dynamic::from(v as INT));
}
#[cfg(feature = "only_i32")]
if v > i32::MAX as i128 {
Ok(Dynamic::from(v))
} else {
self.serialize_i32(v as i32)
#[allow(unreachable_code)]
{
#[cfg(feature = "decimal")]
if let Some(n) = rust_decimal::Decimal::from_i128(v) {
return Ok(Dynamic::from_decimal(n));
}
#[cfg(not(feature = "no_float"))]
return Ok(Dynamic::from_float(v as crate::FLOAT));
Err(Error::custom(format!("integer number too large: {}", v)))
}
}
#[inline(always)]
fn serialize_u8(self, v: u8) -> RhaiResultOf<Self::Ok> {
#[cfg(not(feature = "only_i32"))]
return self.serialize_i64(i64::from(v));
#[cfg(feature = "only_i32")]
return self.serialize_i32(i32::from(v));
Ok(INT::from(v).into())
}
#[inline(always)]
fn serialize_u16(self, v: u16) -> RhaiResultOf<Self::Ok> {
#[cfg(not(feature = "only_i32"))]
return self.serialize_i64(i64::from(v));
#[cfg(feature = "only_i32")]
return self.serialize_i32(i32::from(v));
Ok(INT::from(v).into())
}
#[inline]
fn serialize_u32(self, v: u32) -> RhaiResultOf<Self::Ok> {
#[cfg(not(feature = "only_i32"))]
{
self.serialize_i64(i64::from(v))
}
return Ok(Dynamic::from(v as INT));
#[cfg(feature = "only_i32")]
if v > i32::MAX as u32 {
Ok(Dynamic::from(v))
} else {
self.serialize_i32(v as i32)
if v <= INT::MAX as i32 {
return Ok(Dynamic::from(v as INT));
}
#[allow(unreachable_code)]
{
#[cfg(feature = "decimal")]
if let Some(n) = rust_decimal::Decimal::from_u32(v) {
return Ok(Dynamic::from_decimal(n));
}
#[cfg(not(feature = "no_float"))]
return Ok(Dynamic::from_float(v as crate::FLOAT));
Err(Error::custom(format!("integer number too large: {}", v)))
}
}
#[inline]
fn serialize_u64(self, v: u64) -> RhaiResultOf<Self::Ok> {
#[cfg(not(feature = "only_i32"))]
if v > i64::MAX as u64 {
Ok(Dynamic::from(v))
} else {
self.serialize_i64(v as i64)
if v <= INT::MAX as u64 {
return Ok(Dynamic::from(v as INT));
}
#[cfg(feature = "only_i32")]
if v > i32::MAX as u64 {
Ok(Dynamic::from(v))
} else {
self.serialize_i32(v as i32)
#[cfg(feature = "decimal")]
if let Some(n) = rust_decimal::Decimal::from_u64(v) {
return Ok(Dynamic::from_decimal(n));
}
#[cfg(not(feature = "no_float"))]
return Ok(Dynamic::from_float(v as crate::FLOAT));
#[allow(unreachable_code)]
Err(Error::custom(format!("integer number too large: {}", v)))
}
#[inline]
fn serialize_u128(self, v: u128) -> RhaiResultOf<Self::Ok> {
#[cfg(not(feature = "only_i32"))]
if v > i64::MAX as u128 {
Ok(Dynamic::from(v))
} else {
self.serialize_i64(v as i64)
if v <= INT::MAX as u128 {
return Ok(Dynamic::from(v as INT));
}
#[cfg(feature = "only_i32")]
if v > i32::MAX as u128 {
Ok(Dynamic::from(v))
} else {
self.serialize_i32(v as i32)
#[cfg(feature = "decimal")]
if let Some(n) = rust_decimal::Decimal::from_u128(v) {
return Ok(Dynamic::from_decimal(n));
}
#[cfg(not(feature = "no_float"))]
return Ok(Dynamic::from_float(v as crate::FLOAT));
#[allow(unreachable_code)]
Err(Error::custom(format!("integer number too large: {}", v)))
}
#[cfg(not(feature = "no_float"))]
#[inline(always)]
fn serialize_f32(self, v: f32) -> RhaiResultOf<Self::Ok> {
Ok(crate::FLOAT::from(v).into())
}
#[cfg(not(feature = "no_float"))]
#[inline(always)]
fn serialize_f64(self, v: f64) -> RhaiResultOf<Self::Ok> {
Ok(crate::FLOAT::from(v).into())
}
#[cfg(feature = "no_float")]
#[cfg(feature = "decimal")]
#[inline]
fn serialize_f32(self, v: f32) -> RhaiResultOf<Self::Ok> {
#[cfg(any(not(feature = "no_float"), not(feature = "decimal")))]
return Ok(Dynamic::from(v));
use std::convert::TryFrom;
#[cfg(feature = "no_float")]
#[cfg(feature = "decimal")]
{
use rust_decimal::Decimal;
use std::convert::TryFrom;
Decimal::try_from(v)
.map(|v| v.into())
.map_err(Error::custom)
}
rust_decimal::Decimal::try_from(v)
.map(|v| v.into())
.map_err(Error::custom)
}
#[cfg(feature = "no_float")]
#[cfg(feature = "decimal")]
#[inline]
fn serialize_f64(self, v: f64) -> RhaiResultOf<Self::Ok> {
#[cfg(any(not(feature = "no_float"), not(feature = "decimal")))]
return Ok(Dynamic::from(v));
use std::convert::TryFrom;
#[cfg(feature = "no_float")]
#[cfg(feature = "decimal")]
{
use rust_decimal::Decimal;
use std::convert::TryFrom;
Decimal::try_from(v)
.map(|v| v.into())
.map_err(Error::custom)
}
rust_decimal::Decimal::try_from(v)
.map(|v| v.into())
.map_err(Error::custom)
}
#[inline(always)]
@ -332,10 +345,7 @@ impl Serializer for &mut DynamicSerializer {
_value: &T,
) -> RhaiResultOf<Self::Ok> {
#[cfg(not(feature = "no_object"))]
{
let content = to_dynamic(_value)?;
make_variant(_variant, content)
}
return Ok(make_variant(_variant, to_dynamic(_value)?));
#[cfg(feature = "no_object")]
return Err(ERR::ErrorMismatchDataType(
"".into(),
@ -688,7 +698,7 @@ impl serde::ser::SerializeTupleVariant for TupleVariantSerializer {
#[inline]
fn end(self) -> RhaiResultOf<Self::Ok> {
make_variant(self.variant, self.array.into())
Ok(make_variant(self.variant, self.array.into()))
}
}
@ -716,14 +726,14 @@ impl serde::ser::SerializeStructVariant for StructVariantSerializer {
#[inline]
fn end(self) -> RhaiResultOf<Self::Ok> {
make_variant(self.variant, self.map.into())
Ok(make_variant(self.variant, self.map.into()))
}
}
#[cfg(not(feature = "no_object"))]
#[inline]
fn make_variant(variant: &'static str, value: Dynamic) -> RhaiResult {
fn make_variant(variant: &'static str, value: Dynamic) -> Dynamic {
let mut map = crate::Map::new();
map.insert(variant.into(), value);
Ok(map.into())
map.into()
}

View File

@ -58,7 +58,7 @@ impl Serialize for Dynamic {
#[cfg(not(feature = "no_index"))]
Union::Array(ref a, ..) => (**a).serialize(ser),
#[cfg(not(feature = "no_index"))]
Union::Blob(ref a, ..) => ser.serialize_bytes(&**a),
Union::Blob(ref a, ..) => ser.serialize_bytes(a),
#[cfg(not(feature = "no_object"))]
Union::Map(ref m, ..) => {
let mut map = ser.serialize_map(Some(m.len()))?;

View File

@ -13,22 +13,20 @@ use rhai::Array;
use rhai::Map;
#[cfg(not(feature = "no_float"))]
use rhai::FLOAT;
#[cfg(feature = "no_float")]
#[cfg(feature = "decimal")]
use rust_decimal::Decimal;
#[test]
fn test_serde_ser_primary_types() -> Result<(), Box<EvalAltResult>> {
assert!(to_dynamic(42_u64)?.is_int());
assert!(to_dynamic(u64::MAX)?.is::<u64>());
assert!(to_dynamic(42 as INT)?.is_int());
assert!(to_dynamic(true)?.is_bool());
assert!(to_dynamic(())?.is_unit());
#[cfg(not(feature = "no_float"))]
{
assert!(to_dynamic(123.456_f64)?.is::<f64>());
assert!(to_dynamic(123.456_f32)?.is::<f32>());
assert!(to_dynamic(123.456_f64)?.is::<FLOAT>());
assert!(to_dynamic(123.456_f32)?.is::<FLOAT>());
}
#[cfg(feature = "no_float")]
@ -749,6 +747,31 @@ fn test_serde_json() -> serde_json::Result<()> {
Ok(())
}
#[test]
#[cfg(feature = "metadata")]
#[cfg(feature = "decimal")]
#[cfg(not(feature = "no_float"))]
fn test_serde_json_numbers() -> serde_json::Result<()> {
use std::str::FromStr;
let d: Dynamic = serde_json::from_str("100000000000")?;
assert!(d.is::<INT>());
assert_eq!(d.as_int().unwrap(), 100000000000);
let d: Dynamic = serde_json::from_str("10000000000000000000")?;
assert!(d.is::<Decimal>());
assert_eq!(
d.as_decimal().unwrap(),
Decimal::from_str("10000000000000000000").unwrap()
);
let d: Dynamic = serde_json::from_str("10000000000000000000000000")?;
assert!(d.is::<FLOAT>());
assert_eq!(d.as_float().unwrap(), 10000000000000000000000000.0);
Ok(())
}
#[test]
#[cfg(not(feature = "no_object"))]
fn test_serde_optional() -> Result<(), Box<EvalAltResult>> {