Deserialize large numbers.
This commit is contained in:
parent
31292e683d
commit
9f5b68549a
@ -4,6 +4,11 @@ Rhai Release Notes
|
|||||||
Version 1.12.0
|
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
|
Net features
|
||||||
------------
|
------------
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ impl<'de> DynamicDeserializer<'de> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
#[inline(always)]
|
#[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"))]
|
#[cfg(not(feature = "only_i32"))]
|
||||||
return visitor.visit_i64(v);
|
return visitor.visit_i64(v);
|
||||||
#[cfg(feature = "only_i32")]
|
#[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> {
|
fn deserialize_i8<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
|
||||||
if let Ok(v) = self.0.as_int() {
|
if let Ok(v) = self.0.as_int() {
|
||||||
self.deserialize_int(v, visitor)
|
Self::deserialize_int(v, visitor)
|
||||||
} else {
|
} else {
|
||||||
self.0
|
self.0
|
||||||
.downcast_ref::<i8>()
|
.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> {
|
fn deserialize_i16<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
|
||||||
if let Ok(v) = self.0.as_int() {
|
if let Ok(v) = self.0.as_int() {
|
||||||
self.deserialize_int(v, visitor)
|
Self::deserialize_int(v, visitor)
|
||||||
} else {
|
} else {
|
||||||
self.0
|
self.0
|
||||||
.downcast_ref::<i16>()
|
.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> {
|
fn deserialize_i32<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
|
||||||
if let Ok(v) = self.0.as_int() {
|
if let Ok(v) = self.0.as_int() {
|
||||||
self.deserialize_int(v, visitor)
|
Self::deserialize_int(v, visitor)
|
||||||
} else if cfg!(feature = "only_i32") {
|
} else if cfg!(feature = "only_i32") {
|
||||||
self.type_error()
|
self.type_error()
|
||||||
} else {
|
} else {
|
||||||
@ -217,7 +217,7 @@ impl<'de> Deserializer<'de> for DynamicDeserializer<'de> {
|
|||||||
|
|
||||||
fn deserialize_i64<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
|
fn deserialize_i64<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
|
||||||
if let Ok(v) = self.0.as_int() {
|
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")) {
|
} else if cfg!(not(feature = "only_i32")) {
|
||||||
self.type_error()
|
self.type_error()
|
||||||
} else {
|
} else {
|
||||||
@ -229,7 +229,7 @@ impl<'de> Deserializer<'de> for DynamicDeserializer<'de> {
|
|||||||
|
|
||||||
fn deserialize_i128<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
|
fn deserialize_i128<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
|
||||||
if let Ok(v) = self.0.as_int() {
|
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")) {
|
} else if cfg!(not(feature = "only_i32")) {
|
||||||
self.type_error()
|
self.type_error()
|
||||||
} else {
|
} else {
|
||||||
@ -241,7 +241,7 @@ impl<'de> Deserializer<'de> for DynamicDeserializer<'de> {
|
|||||||
|
|
||||||
fn deserialize_u8<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
|
fn deserialize_u8<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
|
||||||
if let Ok(v) = self.0.as_int() {
|
if let Ok(v) = self.0.as_int() {
|
||||||
self.deserialize_int(v, visitor)
|
Self::deserialize_int(v, visitor)
|
||||||
} else {
|
} else {
|
||||||
self.0
|
self.0
|
||||||
.downcast_ref::<u8>()
|
.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> {
|
fn deserialize_u16<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
|
||||||
if let Ok(v) = self.0.as_int() {
|
if let Ok(v) = self.0.as_int() {
|
||||||
self.deserialize_int(v, visitor)
|
Self::deserialize_int(v, visitor)
|
||||||
} else {
|
} else {
|
||||||
self.0
|
self.0
|
||||||
.downcast_ref::<u16>()
|
.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> {
|
fn deserialize_u32<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
|
||||||
if let Ok(v) = self.0.as_int() {
|
if let Ok(v) = self.0.as_int() {
|
||||||
self.deserialize_int(v, visitor)
|
Self::deserialize_int(v, visitor)
|
||||||
} else {
|
} else {
|
||||||
self.0
|
self.0
|
||||||
.downcast_ref::<u32>()
|
.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> {
|
fn deserialize_u64<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
|
||||||
if let Ok(v) = self.0.as_int() {
|
if let Ok(v) = self.0.as_int() {
|
||||||
self.deserialize_int(v, visitor)
|
Self::deserialize_int(v, visitor)
|
||||||
} else {
|
} else {
|
||||||
self.0
|
self.0
|
||||||
.downcast_ref::<u64>()
|
.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> {
|
fn deserialize_u128<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
|
||||||
if let Ok(v) = self.0.as_int() {
|
if let Ok(v) = self.0.as_int() {
|
||||||
self.deserialize_int(v, visitor)
|
Self::deserialize_int(v, visitor)
|
||||||
} else {
|
} else {
|
||||||
self.0
|
self.0
|
||||||
.downcast_ref::<u128>()
|
.downcast_ref::<u128>()
|
||||||
@ -296,7 +296,8 @@ impl<'de> Deserializer<'de> for DynamicDeserializer<'de> {
|
|||||||
.downcast_ref::<f32>()
|
.downcast_ref::<f32>()
|
||||||
.map_or_else(|| self.type_error(), |&x| _visitor.visit_f32(x));
|
.map_or_else(|| self.type_error(), |&x| _visitor.visit_f32(x));
|
||||||
|
|
||||||
#[cfg(feature = "no_float")]
|
#[allow(unreachable_code)]
|
||||||
|
{
|
||||||
#[cfg(feature = "decimal")]
|
#[cfg(feature = "decimal")]
|
||||||
{
|
{
|
||||||
use rust_decimal::prelude::ToPrimitive;
|
use rust_decimal::prelude::ToPrimitive;
|
||||||
@ -308,9 +309,8 @@ impl<'de> Deserializer<'de> for DynamicDeserializer<'de> {
|
|||||||
.map_or_else(|| self.type_error(), |v| _visitor.visit_f32(v));
|
.map_or_else(|| self.type_error(), |v| _visitor.visit_f32(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "no_float")]
|
self.type_error_str("f32")
|
||||||
#[cfg(not(feature = "decimal"))]
|
}
|
||||||
return self.type_error_str("f32");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_f64<V: Visitor<'de>>(self, _visitor: V) -> RhaiResultOf<V::Value> {
|
fn deserialize_f64<V: Visitor<'de>>(self, _visitor: V) -> RhaiResultOf<V::Value> {
|
||||||
@ -320,7 +320,8 @@ impl<'de> Deserializer<'de> for DynamicDeserializer<'de> {
|
|||||||
.downcast_ref::<f64>()
|
.downcast_ref::<f64>()
|
||||||
.map_or_else(|| self.type_error(), |&x| _visitor.visit_f64(x));
|
.map_or_else(|| self.type_error(), |&x| _visitor.visit_f64(x));
|
||||||
|
|
||||||
#[cfg(feature = "no_float")]
|
#[allow(unreachable_code)]
|
||||||
|
{
|
||||||
#[cfg(feature = "decimal")]
|
#[cfg(feature = "decimal")]
|
||||||
{
|
{
|
||||||
use rust_decimal::prelude::ToPrimitive;
|
use rust_decimal::prelude::ToPrimitive;
|
||||||
@ -332,9 +333,8 @@ impl<'de> Deserializer<'de> for DynamicDeserializer<'de> {
|
|||||||
.map_or_else(|| self.type_error(), |v| _visitor.visit_f64(v));
|
.map_or_else(|| self.type_error(), |v| _visitor.visit_f64(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "no_float")]
|
self.type_error_str("f64")
|
||||||
#[cfg(not(feature = "decimal"))]
|
}
|
||||||
return self.type_error_str("f64");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_char<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
|
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,
|
seed: T,
|
||||||
) -> RhaiResultOf<Option<T::Value>> {
|
) -> RhaiResultOf<Option<T::Value>> {
|
||||||
// Deserialize each item coming out of the iterator.
|
// Deserialize each item coming out of the iterator.
|
||||||
match self.iter.next() {
|
self.iter.next().map_or(Ok(None), |item| {
|
||||||
Some(item) => seed.deserialize(item.into_deserializer()).map(Some),
|
seed.deserialize(item.into_deserializer()).map(Some)
|
||||||
None => Ok(None),
|
})
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -553,10 +552,10 @@ impl<'de, K: Iterator<Item = &'de str>, V: Iterator<Item = &'de Dynamic>> serde:
|
|||||||
seed: S,
|
seed: S,
|
||||||
) -> RhaiResultOf<Option<S::Value>> {
|
) -> RhaiResultOf<Option<S::Value>> {
|
||||||
// Deserialize each `Identifier` key coming out of the keys iterator.
|
// Deserialize each `Identifier` key coming out of the keys iterator.
|
||||||
match self.keys.next().map(<_>::into_deserializer) {
|
self.keys
|
||||||
Some(d) => seed.deserialize(d).map(Some),
|
.next()
|
||||||
None => Ok(None),
|
.map(<_>::into_deserializer)
|
||||||
}
|
.map_or(Ok(None), |d| seed.deserialize(d).map(Some))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_value_seed<S: serde::de::DeserializeSeed<'de>>(
|
fn next_value_seed<S: serde::de::DeserializeSeed<'de>>(
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
//! Implementations of [`serde::Deserialize`].
|
//! Implementations of [`serde::Deserialize`].
|
||||||
|
|
||||||
use crate::{Dynamic, Identifier, ImmutableString, Scope, INT};
|
use crate::{Dynamic, Identifier, ImmutableString, Scope, INT};
|
||||||
|
use num_traits::FromPrimitive;
|
||||||
use serde::{
|
use serde::{
|
||||||
de::{Error, SeqAccess, Visitor},
|
de::{Error, SeqAccess, Visitor},
|
||||||
Deserialize, Deserializer,
|
Deserialize, Deserializer,
|
||||||
@ -38,14 +39,43 @@ impl<'de> Visitor<'de> for DynamicVisitor {
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn visit_i64<E: Error>(self, v: i64) -> Result<Self::Value, E> {
|
fn visit_i64<E: Error>(self, v: i64) -> Result<Self::Value, E> {
|
||||||
#[cfg(not(feature = "only_i32"))]
|
#[cfg(not(feature = "only_i32"))]
|
||||||
{
|
return Ok(v.into());
|
||||||
Ok(v.into())
|
|
||||||
}
|
|
||||||
#[cfg(feature = "only_i32")]
|
#[cfg(feature = "only_i32")]
|
||||||
if v > i32::MAX as i64 {
|
if v <= INT::MAX as i64 {
|
||||||
Ok(Dynamic::from(v))
|
return Ok(Dynamic::from(v as INT));
|
||||||
} else {
|
}
|
||||||
self.visit_i32(v as i32)
|
|
||||||
|
#[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)]
|
#[inline(always)]
|
||||||
@ -59,57 +89,79 @@ impl<'de> Visitor<'de> for DynamicVisitor {
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn visit_u32<E: Error>(self, v: u32) -> Result<Self::Value, E> {
|
fn visit_u32<E: Error>(self, v: u32) -> Result<Self::Value, E> {
|
||||||
#[cfg(not(feature = "only_i32"))]
|
#[cfg(not(feature = "only_i32"))]
|
||||||
{
|
return Ok(Dynamic::from(v as INT));
|
||||||
Ok(INT::from(v).into())
|
|
||||||
}
|
|
||||||
#[cfg(feature = "only_i32")]
|
#[cfg(feature = "only_i32")]
|
||||||
if v > i32::MAX as u32 {
|
if v <= INT::MAX as i32 {
|
||||||
Ok(Dynamic::from(v))
|
return Ok(Dynamic::from(v as INT));
|
||||||
} else {
|
}
|
||||||
self.visit_i32(v as i32)
|
|
||||||
|
#[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]
|
#[inline]
|
||||||
fn visit_u64<E: Error>(self, v: u64) -> Result<Self::Value, E> {
|
fn visit_u64<E: Error>(self, v: u64) -> Result<Self::Value, E> {
|
||||||
#[cfg(not(feature = "only_i32"))]
|
if v <= INT::MAX as u64 {
|
||||||
if v > i64::MAX as u64 {
|
return Ok(Dynamic::from(v as INT));
|
||||||
Ok(Dynamic::from(v))
|
|
||||||
} else {
|
|
||||||
self.visit_i64(v as i64)
|
|
||||||
}
|
}
|
||||||
#[cfg(feature = "only_i32")]
|
|
||||||
if v > i32::MAX as u64 {
|
#[cfg(feature = "decimal")]
|
||||||
Ok(Dynamic::from(v))
|
if let Some(n) = rust_decimal::Decimal::from_u64(v) {
|
||||||
} else {
|
return Ok(Dynamic::from_decimal(n));
|
||||||
self.visit_i32(v as i32)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn visit_f32<E: Error>(self, v: f32) -> Result<Self::Value, E> {
|
fn visit_f32<E: Error>(self, v: f32) -> Result<Self::Value, E> {
|
||||||
#[cfg(not(feature = "f32_float"))]
|
Ok(crate::FLOAT::from(v).into())
|
||||||
return self.visit_f64(v as f64);
|
|
||||||
#[cfg(feature = "f32_float")]
|
|
||||||
return Ok(v.into());
|
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn visit_f64<E: Error>(self, v: f64) -> Result<Self::Value, E> {
|
fn visit_f64<E: Error>(self, v: f64) -> Result<Self::Value, E> {
|
||||||
#[cfg(not(feature = "f32_float"))]
|
Ok(crate::FLOAT::from(v).into())
|
||||||
return Ok(v.into());
|
|
||||||
#[cfg(feature = "f32_float")]
|
|
||||||
return self.visit_f32(v as f32);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "no_float")]
|
#[cfg(feature = "no_float")]
|
||||||
#[cfg(feature = "decimal")]
|
#[cfg(feature = "decimal")]
|
||||||
#[inline]
|
#[inline]
|
||||||
fn visit_f32<E: Error>(self, v: f32) -> Result<Self::Value, E> {
|
fn visit_f32<E: Error>(self, v: f32) -> Result<Self::Value, E> {
|
||||||
use rust_decimal::Decimal;
|
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
Decimal::try_from(v)
|
rust_decimal::Decimal::try_from(v)
|
||||||
.map(|v| v.into())
|
.map(|v| v.into())
|
||||||
.map_err(Error::custom)
|
.map_err(Error::custom)
|
||||||
}
|
}
|
||||||
@ -117,10 +169,9 @@ impl<'de> Visitor<'de> for DynamicVisitor {
|
|||||||
#[cfg(feature = "decimal")]
|
#[cfg(feature = "decimal")]
|
||||||
#[inline]
|
#[inline]
|
||||||
fn visit_f64<E: Error>(self, v: f64) -> Result<Self::Value, E> {
|
fn visit_f64<E: Error>(self, v: f64) -> Result<Self::Value, E> {
|
||||||
use rust_decimal::Decimal;
|
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
Decimal::try_from(v)
|
rust_decimal::Decimal::try_from(v)
|
||||||
.map(|v| v.into())
|
.map(|v| v.into())
|
||||||
.map_err(Error::custom)
|
.map_err(Error::custom)
|
||||||
}
|
}
|
||||||
@ -216,10 +267,9 @@ impl<'de> Deserialize<'de> for Scope<'de> {
|
|||||||
where
|
where
|
||||||
A: SeqAccess<'de>,
|
A: SeqAccess<'de>,
|
||||||
{
|
{
|
||||||
let mut scope = match access.size_hint() {
|
let mut scope = access
|
||||||
Some(size) => Scope::with_capacity(size),
|
.size_hint()
|
||||||
None => Scope::new(),
|
.map_or_else(Scope::new, Scope::with_capacity);
|
||||||
};
|
|
||||||
|
|
||||||
while let Some(ScopeEntry {
|
while let Some(ScopeEntry {
|
||||||
name,
|
name,
|
||||||
|
198
src/serde/ser.rs
198
src/serde/ser.rs
@ -1,6 +1,7 @@
|
|||||||
//! Implement serialization support of [`Dynamic`][crate::Dynamic] for [`serde`].
|
//! 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::{
|
use serde::ser::{
|
||||||
Error, SerializeMap, SerializeSeq, SerializeStruct, SerializeTuple, SerializeTupleStruct,
|
Error, SerializeMap, SerializeSeq, SerializeStruct, SerializeTuple, SerializeTupleStruct,
|
||||||
};
|
};
|
||||||
@ -112,153 +113,165 @@ impl Serializer for &mut DynamicSerializer {
|
|||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn serialize_i8(self, v: i8) -> RhaiResultOf<Self::Ok> {
|
fn serialize_i8(self, v: i8) -> RhaiResultOf<Self::Ok> {
|
||||||
#[cfg(not(feature = "only_i32"))]
|
Ok(INT::from(v).into())
|
||||||
return self.serialize_i64(i64::from(v));
|
|
||||||
#[cfg(feature = "only_i32")]
|
|
||||||
return self.serialize_i32(i32::from(v));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn serialize_i16(self, v: i16) -> RhaiResultOf<Self::Ok> {
|
fn serialize_i16(self, v: i16) -> RhaiResultOf<Self::Ok> {
|
||||||
#[cfg(not(feature = "only_i32"))]
|
Ok(INT::from(v).into())
|
||||||
return self.serialize_i64(i64::from(v));
|
|
||||||
#[cfg(feature = "only_i32")]
|
|
||||||
return self.serialize_i32(i32::from(v));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn serialize_i32(self, v: i32) -> RhaiResultOf<Self::Ok> {
|
fn serialize_i32(self, v: i32) -> RhaiResultOf<Self::Ok> {
|
||||||
#[cfg(not(feature = "only_i32"))]
|
Ok(INT::from(v).into())
|
||||||
return self.serialize_i64(i64::from(v));
|
|
||||||
#[cfg(feature = "only_i32")]
|
|
||||||
return Ok(v.into());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn serialize_i64(self, v: i64) -> RhaiResultOf<Self::Ok> {
|
fn serialize_i64(self, v: i64) -> RhaiResultOf<Self::Ok> {
|
||||||
#[cfg(not(feature = "only_i32"))]
|
#[cfg(not(feature = "only_i32"))]
|
||||||
{
|
return Ok(v.into());
|
||||||
Ok(v.into())
|
|
||||||
}
|
|
||||||
#[cfg(feature = "only_i32")]
|
#[cfg(feature = "only_i32")]
|
||||||
if v > i32::MAX as i64 {
|
if v <= INT::MAX as i64 {
|
||||||
Ok(Dynamic::from(v))
|
return Ok(Dynamic::from(v as INT));
|
||||||
} else {
|
}
|
||||||
self.serialize_i32(v as i32)
|
|
||||||
|
#[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]
|
#[inline]
|
||||||
fn serialize_i128(self, v: i128) -> RhaiResultOf<Self::Ok> {
|
fn serialize_i128(self, v: i128) -> RhaiResultOf<Self::Ok> {
|
||||||
#[cfg(not(feature = "only_i32"))]
|
if v <= i128::from(INT::MAX) {
|
||||||
if v > i64::MAX as i128 {
|
return Ok(Dynamic::from(v as INT));
|
||||||
Ok(Dynamic::from(v))
|
|
||||||
} else {
|
|
||||||
self.serialize_i64(v as i64)
|
|
||||||
}
|
}
|
||||||
#[cfg(feature = "only_i32")]
|
|
||||||
if v > i32::MAX as i128 {
|
#[allow(unreachable_code)]
|
||||||
Ok(Dynamic::from(v))
|
{
|
||||||
} else {
|
#[cfg(feature = "decimal")]
|
||||||
self.serialize_i32(v as i32)
|
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)]
|
#[inline(always)]
|
||||||
fn serialize_u8(self, v: u8) -> RhaiResultOf<Self::Ok> {
|
fn serialize_u8(self, v: u8) -> RhaiResultOf<Self::Ok> {
|
||||||
#[cfg(not(feature = "only_i32"))]
|
Ok(INT::from(v).into())
|
||||||
return self.serialize_i64(i64::from(v));
|
|
||||||
#[cfg(feature = "only_i32")]
|
|
||||||
return self.serialize_i32(i32::from(v));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn serialize_u16(self, v: u16) -> RhaiResultOf<Self::Ok> {
|
fn serialize_u16(self, v: u16) -> RhaiResultOf<Self::Ok> {
|
||||||
#[cfg(not(feature = "only_i32"))]
|
Ok(INT::from(v).into())
|
||||||
return self.serialize_i64(i64::from(v));
|
|
||||||
#[cfg(feature = "only_i32")]
|
|
||||||
return self.serialize_i32(i32::from(v));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn serialize_u32(self, v: u32) -> RhaiResultOf<Self::Ok> {
|
fn serialize_u32(self, v: u32) -> RhaiResultOf<Self::Ok> {
|
||||||
#[cfg(not(feature = "only_i32"))]
|
#[cfg(not(feature = "only_i32"))]
|
||||||
{
|
return Ok(Dynamic::from(v as INT));
|
||||||
self.serialize_i64(i64::from(v))
|
|
||||||
}
|
|
||||||
#[cfg(feature = "only_i32")]
|
#[cfg(feature = "only_i32")]
|
||||||
if v > i32::MAX as u32 {
|
if v <= INT::MAX as i32 {
|
||||||
Ok(Dynamic::from(v))
|
return Ok(Dynamic::from(v as INT));
|
||||||
} else {
|
}
|
||||||
self.serialize_i32(v as i32)
|
|
||||||
|
#[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]
|
#[inline]
|
||||||
fn serialize_u64(self, v: u64) -> RhaiResultOf<Self::Ok> {
|
fn serialize_u64(self, v: u64) -> RhaiResultOf<Self::Ok> {
|
||||||
#[cfg(not(feature = "only_i32"))]
|
if v <= INT::MAX as u64 {
|
||||||
if v > i64::MAX as u64 {
|
return Ok(Dynamic::from(v as INT));
|
||||||
Ok(Dynamic::from(v))
|
|
||||||
} else {
|
|
||||||
self.serialize_i64(v as i64)
|
|
||||||
}
|
}
|
||||||
#[cfg(feature = "only_i32")]
|
|
||||||
if v > i32::MAX as u64 {
|
#[cfg(feature = "decimal")]
|
||||||
Ok(Dynamic::from(v))
|
if let Some(n) = rust_decimal::Decimal::from_u64(v) {
|
||||||
} else {
|
return Ok(Dynamic::from_decimal(n));
|
||||||
self.serialize_i32(v as i32)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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]
|
#[inline]
|
||||||
fn serialize_u128(self, v: u128) -> RhaiResultOf<Self::Ok> {
|
fn serialize_u128(self, v: u128) -> RhaiResultOf<Self::Ok> {
|
||||||
#[cfg(not(feature = "only_i32"))]
|
if v <= INT::MAX as u128 {
|
||||||
if v > i64::MAX as u128 {
|
return Ok(Dynamic::from(v as INT));
|
||||||
Ok(Dynamic::from(v))
|
|
||||||
} else {
|
|
||||||
self.serialize_i64(v as i64)
|
|
||||||
}
|
|
||||||
#[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]
|
#[inline]
|
||||||
fn serialize_f32(self, v: f32) -> RhaiResultOf<Self::Ok> {
|
fn serialize_f32(self, v: f32) -> RhaiResultOf<Self::Ok> {
|
||||||
#[cfg(any(not(feature = "no_float"), not(feature = "decimal")))]
|
|
||||||
return Ok(Dynamic::from(v));
|
|
||||||
|
|
||||||
#[cfg(feature = "no_float")]
|
|
||||||
#[cfg(feature = "decimal")]
|
|
||||||
{
|
|
||||||
use rust_decimal::Decimal;
|
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
Decimal::try_from(v)
|
rust_decimal::Decimal::try_from(v)
|
||||||
.map(|v| v.into())
|
.map(|v| v.into())
|
||||||
.map_err(Error::custom)
|
.map_err(Error::custom)
|
||||||
}
|
}
|
||||||
}
|
#[cfg(feature = "no_float")]
|
||||||
|
#[cfg(feature = "decimal")]
|
||||||
#[inline]
|
#[inline]
|
||||||
fn serialize_f64(self, v: f64) -> RhaiResultOf<Self::Ok> {
|
fn serialize_f64(self, v: f64) -> RhaiResultOf<Self::Ok> {
|
||||||
#[cfg(any(not(feature = "no_float"), not(feature = "decimal")))]
|
|
||||||
return Ok(Dynamic::from(v));
|
|
||||||
|
|
||||||
#[cfg(feature = "no_float")]
|
|
||||||
#[cfg(feature = "decimal")]
|
|
||||||
{
|
|
||||||
use rust_decimal::Decimal;
|
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
Decimal::try_from(v)
|
rust_decimal::Decimal::try_from(v)
|
||||||
.map(|v| v.into())
|
.map(|v| v.into())
|
||||||
.map_err(Error::custom)
|
.map_err(Error::custom)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn serialize_char(self, v: char) -> RhaiResultOf<Self::Ok> {
|
fn serialize_char(self, v: char) -> RhaiResultOf<Self::Ok> {
|
||||||
@ -332,10 +345,7 @@ impl Serializer for &mut DynamicSerializer {
|
|||||||
_value: &T,
|
_value: &T,
|
||||||
) -> RhaiResultOf<Self::Ok> {
|
) -> RhaiResultOf<Self::Ok> {
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
{
|
return Ok(make_variant(_variant, to_dynamic(_value)?));
|
||||||
let content = to_dynamic(_value)?;
|
|
||||||
make_variant(_variant, content)
|
|
||||||
}
|
|
||||||
#[cfg(feature = "no_object")]
|
#[cfg(feature = "no_object")]
|
||||||
return Err(ERR::ErrorMismatchDataType(
|
return Err(ERR::ErrorMismatchDataType(
|
||||||
"".into(),
|
"".into(),
|
||||||
@ -688,7 +698,7 @@ impl serde::ser::SerializeTupleVariant for TupleVariantSerializer {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn end(self) -> RhaiResultOf<Self::Ok> {
|
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]
|
#[inline]
|
||||||
fn end(self) -> RhaiResultOf<Self::Ok> {
|
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"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
#[inline]
|
#[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();
|
let mut map = crate::Map::new();
|
||||||
map.insert(variant.into(), value);
|
map.insert(variant.into(), value);
|
||||||
Ok(map.into())
|
map.into()
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,7 @@ impl Serialize for Dynamic {
|
|||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Union::Array(ref a, ..) => (**a).serialize(ser),
|
Union::Array(ref a, ..) => (**a).serialize(ser),
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[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"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Union::Map(ref m, ..) => {
|
Union::Map(ref m, ..) => {
|
||||||
let mut map = ser.serialize_map(Some(m.len()))?;
|
let mut map = ser.serialize_map(Some(m.len()))?;
|
||||||
|
@ -13,22 +13,20 @@ use rhai::Array;
|
|||||||
use rhai::Map;
|
use rhai::Map;
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
use rhai::FLOAT;
|
use rhai::FLOAT;
|
||||||
#[cfg(feature = "no_float")]
|
|
||||||
#[cfg(feature = "decimal")]
|
#[cfg(feature = "decimal")]
|
||||||
use rust_decimal::Decimal;
|
use rust_decimal::Decimal;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_serde_ser_primary_types() -> Result<(), Box<EvalAltResult>> {
|
fn test_serde_ser_primary_types() -> Result<(), Box<EvalAltResult>> {
|
||||||
assert!(to_dynamic(42_u64)?.is_int());
|
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(42 as INT)?.is_int());
|
||||||
assert!(to_dynamic(true)?.is_bool());
|
assert!(to_dynamic(true)?.is_bool());
|
||||||
assert!(to_dynamic(())?.is_unit());
|
assert!(to_dynamic(())?.is_unit());
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
{
|
{
|
||||||
assert!(to_dynamic(123.456_f64)?.is::<f64>());
|
assert!(to_dynamic(123.456_f64)?.is::<FLOAT>());
|
||||||
assert!(to_dynamic(123.456_f32)?.is::<f32>());
|
assert!(to_dynamic(123.456_f32)?.is::<FLOAT>());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "no_float")]
|
#[cfg(feature = "no_float")]
|
||||||
@ -749,6 +747,31 @@ fn test_serde_json() -> serde_json::Result<()> {
|
|||||||
Ok(())
|
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]
|
#[test]
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
fn test_serde_optional() -> Result<(), Box<EvalAltResult>> {
|
fn test_serde_optional() -> Result<(), Box<EvalAltResult>> {
|
||||||
|
Loading…
Reference in New Issue
Block a user