Merge branch 'master' into plugins
This commit is contained in:
commit
3b7a7426cf
2
.gitignore
vendored
2
.gitignore
vendored
@ -3,3 +3,5 @@ Cargo.lock
|
|||||||
.vscode/
|
.vscode/
|
||||||
.cargo/
|
.cargo/
|
||||||
doc/book/
|
doc/book/
|
||||||
|
before
|
||||||
|
after
|
||||||
|
@ -12,7 +12,7 @@ Like C, `continue` can be used to skip to the next iteration, by-passing all fol
|
|||||||
let x = 10;
|
let x = 10;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
x = x - 1;
|
x -= 1;
|
||||||
|
|
||||||
if x > 5 { continue; } // skip to the next iteration
|
if x > 5 { continue; } // skip to the next iteration
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ Like C, `continue` can be used to skip to the next iteration, by-passing all fol
|
|||||||
let x = 10;
|
let x = 10;
|
||||||
|
|
||||||
while x > 0 {
|
while x > 0 {
|
||||||
x = x - 1;
|
x -= 1;
|
||||||
if x < 6 { continue; } // skip to the next iteration
|
if x < 6 { continue; } // skip to the next iteration
|
||||||
print(x);
|
print(x);
|
||||||
if x == 5 { break; } // break out of while loop
|
if x == 5 { break; } // break out of while loop
|
||||||
|
@ -1046,8 +1046,8 @@ impl Engine {
|
|||||||
/// let mut scope = Scope::new();
|
/// let mut scope = Scope::new();
|
||||||
/// scope.push("x", 40_i64);
|
/// scope.push("x", 40_i64);
|
||||||
///
|
///
|
||||||
/// assert_eq!(engine.eval_with_scope::<i64>(&mut scope, "x = x + 2; x")?, 42);
|
/// assert_eq!(engine.eval_with_scope::<i64>(&mut scope, "x += 2; x")?, 42);
|
||||||
/// assert_eq!(engine.eval_with_scope::<i64>(&mut scope, "x = x + 2; x")?, 44);
|
/// assert_eq!(engine.eval_with_scope::<i64>(&mut scope, "x += 2; x")?, 44);
|
||||||
///
|
///
|
||||||
/// // The variable in the scope is modified
|
/// // The variable in the scope is modified
|
||||||
/// assert_eq!(scope.get_value::<i64>("x").expect("variable x should exist"), 44);
|
/// assert_eq!(scope.get_value::<i64>("x").expect("variable x should exist"), 44);
|
||||||
@ -1160,7 +1160,7 @@ impl Engine {
|
|||||||
/// scope.push("x", 40_i64);
|
/// scope.push("x", 40_i64);
|
||||||
///
|
///
|
||||||
/// // Compile a script to an AST and store it for later evaluation
|
/// // Compile a script to an AST and store it for later evaluation
|
||||||
/// let ast = engine.compile("x = x + 2; x")?;
|
/// let ast = engine.compile("x += 2; x")?;
|
||||||
///
|
///
|
||||||
/// // Evaluate it
|
/// // Evaluate it
|
||||||
/// assert_eq!(engine.eval_ast_with_scope::<i64>(&mut scope, &ast)?, 42);
|
/// assert_eq!(engine.eval_ast_with_scope::<i64>(&mut scope, &ast)?, 42);
|
||||||
|
@ -11,7 +11,7 @@ use crate::parser::{Expr, FnAccess, ImmutableString, ReturnType, ScriptFnDef, St
|
|||||||
use crate::r#unsafe::unsafe_cast_var_name_to_lifetime;
|
use crate::r#unsafe::unsafe_cast_var_name_to_lifetime;
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::scope::{EntryType as ScopeEntryType, Scope};
|
use crate::scope::{EntryType as ScopeEntryType, Scope};
|
||||||
use crate::token::{is_valid_identifier, Position};
|
use crate::token::Position;
|
||||||
use crate::utils::StaticVec;
|
use crate::utils::StaticVec;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
@ -22,6 +22,7 @@ use crate::stdlib::{
|
|||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
boxed::Box,
|
boxed::Box,
|
||||||
collections::{HashMap, HashSet},
|
collections::{HashMap, HashSet},
|
||||||
|
convert::TryFrom,
|
||||||
format,
|
format,
|
||||||
iter::{empty, once},
|
iter::{empty, once},
|
||||||
mem,
|
mem,
|
||||||
@ -1735,6 +1736,7 @@ impl Engine {
|
|||||||
let expr = args_expr.get(0);
|
let expr = args_expr.get(0);
|
||||||
let arg_value =
|
let arg_value =
|
||||||
self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?;
|
self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?;
|
||||||
|
|
||||||
return arg_value
|
return arg_value
|
||||||
.take_immutable_string()
|
.take_immutable_string()
|
||||||
.map_err(|typ| {
|
.map_err(|typ| {
|
||||||
@ -1744,17 +1746,9 @@ impl Engine {
|
|||||||
expr.position(),
|
expr.position(),
|
||||||
))
|
))
|
||||||
})
|
})
|
||||||
.and_then(|s| {
|
.and_then(|s| FnPtr::try_from(s))
|
||||||
if is_valid_identifier(s.chars()) {
|
.map(Into::<Dynamic>::into)
|
||||||
Ok(s)
|
.map_err(|err| err.new_position(*pos));
|
||||||
} else {
|
|
||||||
Err(Box::new(EvalAltResult::ErrorFunctionNotFound(
|
|
||||||
s.to_string(),
|
|
||||||
expr.position(),
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.map(|s| FnPtr::from(s).into());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,9 +4,10 @@ use crate::module::Module;
|
|||||||
use crate::parser::ScriptFnDef;
|
use crate::parser::ScriptFnDef;
|
||||||
use crate::plugin::PluginFunction;
|
use crate::plugin::PluginFunction;
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
|
use crate::token::{is_valid_identifier, Position};
|
||||||
use crate::utils::ImmutableString;
|
use crate::utils::ImmutableString;
|
||||||
|
|
||||||
use crate::stdlib::{boxed::Box, fmt, rc::Rc, sync::Arc};
|
use crate::stdlib::{boxed::Box, convert::TryFrom, fmt, rc::Rc, sync::Arc};
|
||||||
|
|
||||||
/// Trait that maps to `Send + Sync` only under the `sync` feature.
|
/// Trait that maps to `Send + Sync` only under the `sync` feature.
|
||||||
#[cfg(feature = "sync")]
|
#[cfg(feature = "sync")]
|
||||||
@ -53,6 +54,10 @@ pub type FnCallArgs<'a> = [&'a mut Dynamic];
|
|||||||
pub struct FnPtr(ImmutableString);
|
pub struct FnPtr(ImmutableString);
|
||||||
|
|
||||||
impl FnPtr {
|
impl FnPtr {
|
||||||
|
/// Create a new function pointer.
|
||||||
|
pub(crate) fn new<S: Into<ImmutableString>>(name: S) -> Self {
|
||||||
|
Self(name.into())
|
||||||
|
}
|
||||||
/// Get the name of the function.
|
/// Get the name of the function.
|
||||||
pub fn fn_name(&self) -> &str {
|
pub fn fn_name(&self) -> &str {
|
||||||
self.get_fn_name().as_ref()
|
self.get_fn_name().as_ref()
|
||||||
@ -73,9 +78,36 @@ impl fmt::Display for FnPtr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: Into<ImmutableString>> From<S> for FnPtr {
|
impl TryFrom<ImmutableString> for FnPtr {
|
||||||
fn from(value: S) -> Self {
|
type Error = Box<EvalAltResult>;
|
||||||
Self(value.into())
|
|
||||||
|
fn try_from(value: ImmutableString) -> Result<Self, Self::Error> {
|
||||||
|
if is_valid_identifier(value.chars()) {
|
||||||
|
Ok(Self(value))
|
||||||
|
} else {
|
||||||
|
Err(Box::new(EvalAltResult::ErrorFunctionNotFound(
|
||||||
|
value.to_string(),
|
||||||
|
Position::none(),
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<String> for FnPtr {
|
||||||
|
type Error = Box<EvalAltResult>;
|
||||||
|
|
||||||
|
fn try_from(value: String) -> Result<Self, Self::Error> {
|
||||||
|
let s: ImmutableString = value.into();
|
||||||
|
Self::try_from(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<&str> for FnPtr {
|
||||||
|
type Error = Box<EvalAltResult>;
|
||||||
|
|
||||||
|
fn try_from(value: &str) -> Result<Self, Self::Error> {
|
||||||
|
let s: ImmutableString = value.into();
|
||||||
|
Self::try_from(s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,7 +102,7 @@ mod utils;
|
|||||||
pub use any::Dynamic;
|
pub use any::Dynamic;
|
||||||
pub use engine::Engine;
|
pub use engine::Engine;
|
||||||
pub use error::{ParseError, ParseErrorType};
|
pub use error::{ParseError, ParseErrorType};
|
||||||
pub use fn_native::IteratorFn;
|
pub use fn_native::{FnPtr, IteratorFn};
|
||||||
pub use fn_register::{RegisterFn, RegisterPlugin, RegisterResultFn};
|
pub use fn_register::{RegisterFn, RegisterPlugin, RegisterResultFn};
|
||||||
pub use module::Module;
|
pub use module::Module;
|
||||||
pub use parser::{ImmutableString, AST, INT};
|
pub use parser::{ImmutableString, AST, INT};
|
||||||
|
132
src/serde/de.rs
132
src/serde/de.rs
@ -7,7 +7,10 @@ use crate::result::EvalAltResult;
|
|||||||
use crate::token::Position;
|
use crate::token::Position;
|
||||||
use crate::utils::ImmutableString;
|
use crate::utils::ImmutableString;
|
||||||
|
|
||||||
use serde::de::{DeserializeSeed, Deserializer, Error, MapAccess, SeqAccess, Visitor};
|
use serde::de::{
|
||||||
|
DeserializeSeed, Deserializer, EnumAccess, Error, IntoDeserializer, MapAccess, SeqAccess,
|
||||||
|
VariantAccess, Visitor,
|
||||||
|
};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
@ -49,6 +52,20 @@ impl<'de> DynamicDeserializer<'de> {
|
|||||||
Position::none(),
|
Position::none(),
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
fn deserialize_int<V: Visitor<'de>>(
|
||||||
|
&mut self,
|
||||||
|
v: crate::INT,
|
||||||
|
visitor: V,
|
||||||
|
) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
|
#[cfg(not(feature = "only_i32"))]
|
||||||
|
{
|
||||||
|
visitor.visit_i64(v)
|
||||||
|
}
|
||||||
|
#[cfg(feature = "only_i32")]
|
||||||
|
{
|
||||||
|
visitor.visit_i32(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deserialize a `Dynamic` value into a Rust type that implements `serde::Deserialize`.
|
/// Deserialize a `Dynamic` value into a Rust type that implements `serde::Deserialize`.
|
||||||
@ -159,52 +176,88 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_i8<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_i8<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
|
if let Ok(v) = self.value.as_int() {
|
||||||
|
self.deserialize_int(v, visitor)
|
||||||
|
} else {
|
||||||
self.value
|
self.value
|
||||||
.downcast_ref::<i8>()
|
.downcast_ref::<i8>()
|
||||||
.map_or_else(|| self.type_error(), |&x| visitor.visit_i8(x))
|
.map_or_else(|| self.type_error(), |&x| visitor.visit_i8(x))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn deserialize_i16<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_i16<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
|
if let Ok(v) = self.value.as_int() {
|
||||||
|
self.deserialize_int(v, visitor)
|
||||||
|
} else {
|
||||||
self.value
|
self.value
|
||||||
.downcast_ref::<i16>()
|
.downcast_ref::<i16>()
|
||||||
.map_or_else(|| self.type_error(), |&x| visitor.visit_i16(x))
|
.map_or_else(|| self.type_error(), |&x| visitor.visit_i16(x))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn deserialize_i32<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_i32<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
|
if let Ok(v) = self.value.as_int() {
|
||||||
|
self.deserialize_int(v, visitor)
|
||||||
|
} else if cfg!(feature = "only_i32") {
|
||||||
|
self.type_error()
|
||||||
|
} else {
|
||||||
self.value
|
self.value
|
||||||
.downcast_ref::<i32>()
|
.downcast_ref::<i32>()
|
||||||
.map_or_else(|| self.type_error(), |&x| visitor.visit_i32(x))
|
.map_or_else(|| self.type_error(), |&x| visitor.visit_i32(x))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn deserialize_i64<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_i64<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
|
if let Ok(v) = self.value.as_int() {
|
||||||
|
self.deserialize_int(v, visitor)
|
||||||
|
} else if cfg!(not(feature = "only_i32")) {
|
||||||
|
self.type_error()
|
||||||
|
} else {
|
||||||
self.value
|
self.value
|
||||||
.downcast_ref::<i64>()
|
.downcast_ref::<i64>()
|
||||||
.map_or_else(|| self.type_error(), |&x| visitor.visit_i64(x))
|
.map_or_else(|| self.type_error(), |&x| visitor.visit_i64(x))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn deserialize_u8<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_u8<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
|
if let Ok(v) = self.value.as_int() {
|
||||||
|
self.deserialize_int(v, visitor)
|
||||||
|
} else {
|
||||||
self.value
|
self.value
|
||||||
.downcast_ref::<u8>()
|
.downcast_ref::<u8>()
|
||||||
.map_or_else(|| self.type_error(), |&x| visitor.visit_u8(x))
|
.map_or_else(|| self.type_error(), |&x| visitor.visit_u8(x))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn deserialize_u16<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_u16<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
|
if let Ok(v) = self.value.as_int() {
|
||||||
|
self.deserialize_int(v, visitor)
|
||||||
|
} else {
|
||||||
self.value
|
self.value
|
||||||
.downcast_ref::<u16>()
|
.downcast_ref::<u16>()
|
||||||
.map_or_else(|| self.type_error(), |&x| visitor.visit_u16(x))
|
.map_or_else(|| self.type_error(), |&x| visitor.visit_u16(x))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn deserialize_u32<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_u32<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
|
if let Ok(v) = self.value.as_int() {
|
||||||
|
self.deserialize_int(v, visitor)
|
||||||
|
} else {
|
||||||
self.value
|
self.value
|
||||||
.downcast_ref::<u32>()
|
.downcast_ref::<u32>()
|
||||||
.map_or_else(|| self.type_error(), |&x| visitor.visit_u32(x))
|
.map_or_else(|| self.type_error(), |&x| visitor.visit_u32(x))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn deserialize_u64<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_u64<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
|
if let Ok(v) = self.value.as_int() {
|
||||||
|
self.deserialize_int(v, visitor)
|
||||||
|
} else {
|
||||||
self.value
|
self.value
|
||||||
.downcast_ref::<u64>()
|
.downcast_ref::<u64>()
|
||||||
.map_or_else(|| self.type_error(), |&x| visitor.visit_u64(x))
|
.map_or_else(|| self.type_error(), |&x| visitor.visit_u64(x))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn deserialize_f32<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_f32<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
@ -334,10 +387,31 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
|
|||||||
self,
|
self,
|
||||||
_name: &'static str,
|
_name: &'static str,
|
||||||
_variants: &'static [&'static str],
|
_variants: &'static [&'static str],
|
||||||
_: V,
|
visitor: V,
|
||||||
) -> Result<V::Value, Box<EvalAltResult>> {
|
) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
|
if let Ok(s) = self.value.as_str() {
|
||||||
|
visitor.visit_enum(s.into_deserializer())
|
||||||
|
} else {
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
if let Some(map) = self.value.downcast_ref::<Map>() {
|
||||||
|
let mut iter = map.iter();
|
||||||
|
let first = iter.next();
|
||||||
|
let second = iter.next();
|
||||||
|
if let (Some((key, value)), None) = (first, second) {
|
||||||
|
visitor.visit_enum(EnumDeserializer {
|
||||||
|
tag: &key,
|
||||||
|
content: DynamicDeserializer::from_dynamic(value),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
self.type_error()
|
self.type_error()
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
self.type_error()
|
||||||
|
}
|
||||||
|
#[cfg(feature = "no_object")]
|
||||||
|
return self.type_error();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn deserialize_identifier<V: Visitor<'de>>(
|
fn deserialize_identifier<V: Visitor<'de>>(
|
||||||
self,
|
self,
|
||||||
@ -444,3 +518,57 @@ where
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
struct EnumDeserializer<'t, 'de: 't> {
|
||||||
|
tag: &'t str,
|
||||||
|
content: DynamicDeserializer<'de>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
impl<'t, 'de> EnumAccess<'de> for EnumDeserializer<'t, 'de> {
|
||||||
|
type Error = Box<EvalAltResult>;
|
||||||
|
type Variant = Self;
|
||||||
|
|
||||||
|
fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error>
|
||||||
|
where
|
||||||
|
V: DeserializeSeed<'de>,
|
||||||
|
{
|
||||||
|
seed.deserialize(self.tag.into_deserializer())
|
||||||
|
.map(|v| (v, self))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
impl<'t, 'de> VariantAccess<'de> for EnumDeserializer<'t, 'de> {
|
||||||
|
type Error = Box<EvalAltResult>;
|
||||||
|
|
||||||
|
fn unit_variant(mut self) -> Result<(), Self::Error> {
|
||||||
|
Deserialize::deserialize(&mut self.content)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn newtype_variant_seed<T>(mut self, seed: T) -> Result<T::Value, Self::Error>
|
||||||
|
where
|
||||||
|
T: DeserializeSeed<'de>,
|
||||||
|
{
|
||||||
|
seed.deserialize(&mut self.content)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tuple_variant<V>(mut self, len: usize, visitor: V) -> Result<V::Value, Self::Error>
|
||||||
|
where
|
||||||
|
V: Visitor<'de>,
|
||||||
|
{
|
||||||
|
self.content.deserialize_tuple(len, visitor)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn struct_variant<V>(
|
||||||
|
mut self,
|
||||||
|
fields: &'static [&'static str],
|
||||||
|
visitor: V,
|
||||||
|
) -> Result<V::Value, Self::Error>
|
||||||
|
where
|
||||||
|
V: Visitor<'de>,
|
||||||
|
{
|
||||||
|
self.content.deserialize_struct("", fields, visitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
143
src/serde/ser.rs
143
src/serde/ser.rs
@ -103,10 +103,16 @@ impl Serializer for &mut DynamicSerializer {
|
|||||||
type SerializeSeq = DynamicSerializer;
|
type SerializeSeq = DynamicSerializer;
|
||||||
type SerializeTuple = DynamicSerializer;
|
type SerializeTuple = DynamicSerializer;
|
||||||
type SerializeTupleStruct = DynamicSerializer;
|
type SerializeTupleStruct = DynamicSerializer;
|
||||||
type SerializeTupleVariant = DynamicSerializer;
|
#[cfg(not(any(feature = "no_object", feature = "no_index")))]
|
||||||
|
type SerializeTupleVariant = TupleVariantSerializer;
|
||||||
|
#[cfg(any(feature = "no_object", feature = "no_index"))]
|
||||||
|
type SerializeTupleVariant = serde::ser::Impossible<Dynamic, Box<EvalAltResult>>;
|
||||||
type SerializeMap = DynamicSerializer;
|
type SerializeMap = DynamicSerializer;
|
||||||
type SerializeStruct = DynamicSerializer;
|
type SerializeStruct = DynamicSerializer;
|
||||||
type SerializeStructVariant = DynamicSerializer;
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
type SerializeStructVariant = StructVariantSerializer;
|
||||||
|
#[cfg(feature = "no_object")]
|
||||||
|
type SerializeStructVariant = serde::ser::Impossible<Dynamic, Box<EvalAltResult>>;
|
||||||
|
|
||||||
fn serialize_bool(self, v: bool) -> Result<Self::Ok, Box<EvalAltResult>> {
|
fn serialize_bool(self, v: bool) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||||
Ok(v.into())
|
Ok(v.into())
|
||||||
@ -162,7 +168,7 @@ impl Serializer for &mut DynamicSerializer {
|
|||||||
#[cfg(not(feature = "only_i32"))]
|
#[cfg(not(feature = "only_i32"))]
|
||||||
return self.serialize_i64(i64::from(v));
|
return self.serialize_i64(i64::from(v));
|
||||||
#[cfg(feature = "only_i32")]
|
#[cfg(feature = "only_i32")]
|
||||||
if v > i32::MAX as u64 {
|
if v > i32::MAX as u32 {
|
||||||
return Ok(Dynamic::from(v));
|
return Ok(Dynamic::from(v));
|
||||||
} else {
|
} else {
|
||||||
return self.serialize_i32(v as i32);
|
return self.serialize_i32(v as i32);
|
||||||
@ -244,10 +250,20 @@ impl Serializer for &mut DynamicSerializer {
|
|||||||
self,
|
self,
|
||||||
_name: &'static str,
|
_name: &'static str,
|
||||||
_variant_index: u32,
|
_variant_index: u32,
|
||||||
_variant: &'static str,
|
variant: &'static str,
|
||||||
value: &T,
|
value: &T,
|
||||||
) -> Result<Self::Ok, Box<EvalAltResult>> {
|
) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||||
value.serialize(&mut *self)
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
{
|
||||||
|
let content = to_dynamic(value)?;
|
||||||
|
make_variant(variant, content)
|
||||||
|
}
|
||||||
|
#[cfg(feature = "no_object")]
|
||||||
|
return Err(Box::new(EvalAltResult::ErrorMismatchOutputType(
|
||||||
|
"Dynamic".into(),
|
||||||
|
"map".into(),
|
||||||
|
Position::none(),
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Box<EvalAltResult>> {
|
fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Box<EvalAltResult>> {
|
||||||
@ -277,10 +293,26 @@ impl Serializer for &mut DynamicSerializer {
|
|||||||
self,
|
self,
|
||||||
_name: &'static str,
|
_name: &'static str,
|
||||||
_variant_index: u32,
|
_variant_index: u32,
|
||||||
_variant: &'static str,
|
variant: &'static str,
|
||||||
len: usize,
|
len: usize,
|
||||||
) -> Result<Self::SerializeTupleVariant, Box<EvalAltResult>> {
|
) -> Result<Self::SerializeTupleVariant, Box<EvalAltResult>> {
|
||||||
self.serialize_seq(Some(len))
|
#[cfg(not(any(feature = "no_object", feature = "no_index")))]
|
||||||
|
return Ok(TupleVariantSerializer {
|
||||||
|
variant,
|
||||||
|
array: Array::with_capacity(len),
|
||||||
|
});
|
||||||
|
#[cfg(any(feature = "no_object", feature = "no_index"))]
|
||||||
|
{
|
||||||
|
#[cfg(feature = "no_object")]
|
||||||
|
let err_type = "map";
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
let err_type = "array";
|
||||||
|
Err(Box::new(EvalAltResult::ErrorMismatchOutputType(
|
||||||
|
"Dynamic".into(),
|
||||||
|
err_type.into(),
|
||||||
|
Position::none(),
|
||||||
|
)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Box<EvalAltResult>> {
|
fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Box<EvalAltResult>> {
|
||||||
@ -306,10 +338,20 @@ impl Serializer for &mut DynamicSerializer {
|
|||||||
self,
|
self,
|
||||||
_name: &'static str,
|
_name: &'static str,
|
||||||
_variant_index: u32,
|
_variant_index: u32,
|
||||||
_variant: &'static str,
|
variant: &'static str,
|
||||||
len: usize,
|
len: usize,
|
||||||
) -> Result<Self::SerializeStructVariant, Box<EvalAltResult>> {
|
) -> Result<Self::SerializeStructVariant, Box<EvalAltResult>> {
|
||||||
self.serialize_map(Some(len))
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
return Ok(StructVariantSerializer {
|
||||||
|
variant,
|
||||||
|
map: Map::with_capacity(len),
|
||||||
|
});
|
||||||
|
#[cfg(feature = "no_object")]
|
||||||
|
return Err(Box::new(EvalAltResult::ErrorMismatchOutputType(
|
||||||
|
"Dynamic".into(),
|
||||||
|
"map".into(),
|
||||||
|
Position::none(),
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -395,33 +437,6 @@ impl SerializeTupleStruct for DynamicSerializer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SerializeTupleVariant for DynamicSerializer {
|
|
||||||
type Ok = Dynamic;
|
|
||||||
type Error = Box<EvalAltResult>;
|
|
||||||
|
|
||||||
fn serialize_field<T: ?Sized + Serialize>(
|
|
||||||
&mut self,
|
|
||||||
value: &T,
|
|
||||||
) -> Result<(), Box<EvalAltResult>> {
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
|
||||||
{
|
|
||||||
let value = value.serialize(&mut *self)?;
|
|
||||||
let arr = self.value.downcast_mut::<Array>().unwrap();
|
|
||||||
arr.push(value);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
#[cfg(feature = "no_index")]
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> {
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
|
||||||
return Ok(self.value);
|
|
||||||
#[cfg(feature = "no_index")]
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SerializeMap for DynamicSerializer {
|
impl SerializeMap for DynamicSerializer {
|
||||||
type Ok = Dynamic;
|
type Ok = Dynamic;
|
||||||
type Error = Box<EvalAltResult>;
|
type Error = Box<EvalAltResult>;
|
||||||
@ -520,7 +535,39 @@ impl SerializeStruct for DynamicSerializer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SerializeStructVariant for DynamicSerializer {
|
#[cfg(not(any(feature = "no_object", feature = "no_index")))]
|
||||||
|
pub struct TupleVariantSerializer {
|
||||||
|
variant: &'static str,
|
||||||
|
array: Array,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(any(feature = "no_object", feature = "no_index")))]
|
||||||
|
impl SerializeTupleVariant for TupleVariantSerializer {
|
||||||
|
type Ok = Dynamic;
|
||||||
|
type Error = Box<EvalAltResult>;
|
||||||
|
|
||||||
|
fn serialize_field<T: ?Sized + Serialize>(
|
||||||
|
&mut self,
|
||||||
|
value: &T,
|
||||||
|
) -> Result<(), Box<EvalAltResult>> {
|
||||||
|
let value = to_dynamic(value)?;
|
||||||
|
self.array.push(value);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||||
|
make_variant(self.variant, self.array.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
pub struct StructVariantSerializer {
|
||||||
|
variant: &'static str,
|
||||||
|
map: Map,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
impl SerializeStructVariant for StructVariantSerializer {
|
||||||
type Ok = Dynamic;
|
type Ok = Dynamic;
|
||||||
type Error = Box<EvalAltResult>;
|
type Error = Box<EvalAltResult>;
|
||||||
|
|
||||||
@ -529,21 +576,19 @@ impl SerializeStructVariant for DynamicSerializer {
|
|||||||
key: &'static str,
|
key: &'static str,
|
||||||
value: &T,
|
value: &T,
|
||||||
) -> Result<(), Box<EvalAltResult>> {
|
) -> Result<(), Box<EvalAltResult>> {
|
||||||
#[cfg(not(feature = "no_object"))]
|
let value = to_dynamic(value)?;
|
||||||
{
|
self.map.insert(key.into(), value);
|
||||||
let value = value.serialize(&mut *self)?;
|
|
||||||
let map = self.value.downcast_mut::<Map>().unwrap();
|
|
||||||
map.insert(key.into(), value);
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
#[cfg(feature = "no_object")]
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> {
|
fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||||
#[cfg(not(feature = "no_object"))]
|
make_variant(self.variant, self.map.into())
|
||||||
return Ok(self.value);
|
|
||||||
#[cfg(feature = "no_object")]
|
|
||||||
unreachable!()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
fn make_variant(variant: &'static str, value: Dynamic) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||||
|
let mut map = Map::with_capacity(1);
|
||||||
|
map.insert(variant.into(), value);
|
||||||
|
Ok(map.into())
|
||||||
|
}
|
||||||
|
@ -32,7 +32,7 @@ fn test_call_fn() -> Result<(), Box<EvalAltResult>> {
|
|||||||
x + y
|
x + y
|
||||||
}
|
}
|
||||||
fn hello(x) {
|
fn hello(x) {
|
||||||
x = x * foo;
|
x *= foo;
|
||||||
foo = 1;
|
foo = 1;
|
||||||
x
|
x
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ fn test_loop() -> Result<(), Box<EvalAltResult>> {
|
|||||||
if i < 10 {
|
if i < 10 {
|
||||||
i += 1;
|
i += 1;
|
||||||
if x > 20 { continue; }
|
if x > 20 { continue; }
|
||||||
x = x + i;
|
x += i;
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
534
tests/serde.rs
534
tests/serde.rs
@ -10,25 +10,33 @@ use rhai::Map;
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_serde_ser_primary_types() -> Result<(), Box<EvalAltResult>> {
|
fn test_serde_ser_primary_types() -> Result<(), Box<EvalAltResult>> {
|
||||||
assert_eq!(
|
assert!(to_dynamic(42_u64)?.is::<INT>());
|
||||||
to_dynamic(42_u64)?.type_name(),
|
assert!(to_dynamic(u64::MAX)?.is::<u64>());
|
||||||
std::any::type_name::<INT>()
|
assert!(to_dynamic(42 as INT)?.is::<INT>());
|
||||||
);
|
assert!(to_dynamic(true)?.is::<bool>());
|
||||||
assert_eq!(to_dynamic(u64::MAX)?.type_name(), "u64");
|
assert!(to_dynamic(())?.is::<()>());
|
||||||
assert_eq!(
|
|
||||||
to_dynamic(42 as INT)?.type_name(),
|
|
||||||
std::any::type_name::<INT>()
|
|
||||||
);
|
|
||||||
assert_eq!(to_dynamic(true)?.type_name(), "bool");
|
|
||||||
assert_eq!(to_dynamic(())?.type_name(), "()");
|
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
{
|
{
|
||||||
assert_eq!(to_dynamic(123.456_f64)?.type_name(), "f64");
|
assert!(to_dynamic(123.456_f64)?.is::<f64>());
|
||||||
assert_eq!(to_dynamic(123.456_f32)?.type_name(), "f32");
|
assert!(to_dynamic(123.456_f32)?.is::<f32>());
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_eq!(to_dynamic("hello".to_string())?.type_name(), "string");
|
assert!(to_dynamic("hello".to_string())?.is::<String>());
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_serde_ser_integer_types() -> Result<(), Box<EvalAltResult>> {
|
||||||
|
assert!(to_dynamic(42_i8)?.is::<INT>());
|
||||||
|
assert!(to_dynamic(42_i16)?.is::<INT>());
|
||||||
|
assert!(to_dynamic(42_i32)?.is::<INT>());
|
||||||
|
assert!(to_dynamic(42_i64)?.is::<INT>());
|
||||||
|
assert!(to_dynamic(42_u8)?.is::<INT>());
|
||||||
|
assert!(to_dynamic(42_u16)?.is::<INT>());
|
||||||
|
assert!(to_dynamic(42_u32)?.is::<INT>());
|
||||||
|
assert!(to_dynamic(42_u64)?.is::<INT>());
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -40,7 +48,7 @@ fn test_serde_ser_array() -> Result<(), Box<EvalAltResult>> {
|
|||||||
|
|
||||||
let d = to_dynamic(arr)?;
|
let d = to_dynamic(arr)?;
|
||||||
assert!(d.is::<Array>());
|
assert!(d.is::<Array>());
|
||||||
assert_eq!(d.cast::<Array>().len(), 4);
|
assert_eq!(4, d.cast::<Array>().len());
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -73,14 +81,226 @@ fn test_serde_ser_struct() -> Result<(), Box<EvalAltResult>> {
|
|||||||
assert!(d.is::<Map>());
|
assert!(d.is::<Map>());
|
||||||
|
|
||||||
let mut map = d.cast::<Map>();
|
let mut map = d.cast::<Map>();
|
||||||
let mut obj = map.remove("obj").unwrap().cast::<Map>();
|
let obj = map.remove("obj").unwrap().cast::<Map>();
|
||||||
let mut seq = map.remove("seq").unwrap().cast::<Array>();
|
let seq = map.remove("seq").unwrap().cast::<Array>();
|
||||||
|
|
||||||
assert_eq!(obj.remove("a").unwrap().cast::<INT>(), 123);
|
assert_eq!(Ok(123), obj["a"].as_int());
|
||||||
assert!(obj.remove("b").unwrap().cast::<bool>());
|
assert!(obj["b"].as_bool().unwrap());
|
||||||
assert_eq!(map.remove("int").unwrap().cast::<INT>(), 42);
|
assert_eq!(Ok(42), map["int"].as_int());
|
||||||
assert_eq!(seq.len(), 3);
|
assert_eq!(seq.len(), 3);
|
||||||
assert_eq!(seq.remove(1).cast::<String>(), "kitty");
|
assert_eq!(Ok("kitty"), seq[1].as_str());
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_serde_ser_unit_enum() -> Result<(), Box<EvalAltResult>> {
|
||||||
|
#[derive(Serialize)]
|
||||||
|
enum MyEnum {
|
||||||
|
VariantFoo,
|
||||||
|
VariantBar,
|
||||||
|
}
|
||||||
|
|
||||||
|
let d = to_dynamic(MyEnum::VariantFoo)?;
|
||||||
|
assert_eq!(Ok("VariantFoo"), d.as_str());
|
||||||
|
|
||||||
|
let d = to_dynamic(MyEnum::VariantBar)?;
|
||||||
|
assert_eq!(Ok("VariantBar"), d.as_str());
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
fn test_serde_ser_externally_tagged_enum() -> Result<(), Box<EvalAltResult>> {
|
||||||
|
#[derive(Serialize)]
|
||||||
|
enum MyEnum {
|
||||||
|
VariantUnit,
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
VariantUnitTuple(),
|
||||||
|
VariantNewtype(i32),
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
VariantTuple(i32, i32),
|
||||||
|
VariantEmptyStruct {},
|
||||||
|
VariantStruct {
|
||||||
|
a: i32,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
assert_eq!(Ok("VariantUnit"), to_dynamic(MyEnum::VariantUnit)?.as_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
{
|
||||||
|
let mut map = to_dynamic(MyEnum::VariantUnitTuple())?.cast::<Map>();
|
||||||
|
let content = map.remove("VariantUnitTuple").unwrap().cast::<Array>();
|
||||||
|
assert!(map.is_empty());
|
||||||
|
assert!(content.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut map = to_dynamic(MyEnum::VariantNewtype(123))?.cast::<Map>();
|
||||||
|
let content = map.remove("VariantNewtype").unwrap();
|
||||||
|
assert!(map.is_empty());
|
||||||
|
assert_eq!(Ok(123), content.as_int());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
{
|
||||||
|
let mut map = to_dynamic(MyEnum::VariantTuple(123, 456))?.cast::<Map>();
|
||||||
|
let content = map.remove("VariantTuple").unwrap().cast::<Array>();
|
||||||
|
assert!(map.is_empty());
|
||||||
|
assert_eq!(2, content.len());
|
||||||
|
assert_eq!(Ok(123), content[0].as_int());
|
||||||
|
assert_eq!(Ok(456), content[1].as_int());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut map = to_dynamic(MyEnum::VariantEmptyStruct {})?.cast::<Map>();
|
||||||
|
let map_inner = map.remove("VariantEmptyStruct").unwrap().cast::<Map>();
|
||||||
|
assert!(map.is_empty());
|
||||||
|
assert!(map_inner.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut map = to_dynamic(MyEnum::VariantStruct { a: 123 })?.cast::<Map>();
|
||||||
|
let mut map_inner = map.remove("VariantStruct").unwrap().cast::<Map>();
|
||||||
|
assert!(map.is_empty());
|
||||||
|
assert_eq!(Ok(123), map_inner.remove("a").unwrap().as_int());
|
||||||
|
assert!(map_inner.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
fn test_serde_ser_internally_tagged_enum() -> Result<(), Box<EvalAltResult>> {
|
||||||
|
#[derive(Serialize)]
|
||||||
|
#[serde(tag = "tag")]
|
||||||
|
enum MyEnum {
|
||||||
|
VariantEmptyStruct {},
|
||||||
|
VariantStruct { a: i32 },
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut map = to_dynamic(MyEnum::VariantEmptyStruct {})?.cast::<Map>();
|
||||||
|
assert_eq!(
|
||||||
|
Ok("VariantEmptyStruct"),
|
||||||
|
map.remove("tag").unwrap().as_str()
|
||||||
|
);
|
||||||
|
assert!(map.is_empty());
|
||||||
|
|
||||||
|
let mut map = to_dynamic(MyEnum::VariantStruct { a: 123 })?.cast::<Map>();
|
||||||
|
assert_eq!(Ok("VariantStruct"), map.remove("tag").unwrap().as_str());
|
||||||
|
assert_eq!(Ok(123), map.remove("a").unwrap().as_int());
|
||||||
|
assert!(map.is_empty());
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
fn test_serde_ser_adjacently_tagged_enum() -> Result<(), Box<EvalAltResult>> {
|
||||||
|
#[derive(Serialize)]
|
||||||
|
#[serde(tag = "tag", content = "content")]
|
||||||
|
enum MyEnum {
|
||||||
|
VariantUnit,
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
VariantUnitTuple(),
|
||||||
|
VariantNewtype(i32),
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
VariantTuple(i32, i32),
|
||||||
|
VariantEmptyStruct {},
|
||||||
|
VariantStruct {
|
||||||
|
a: i32,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut map = to_dynamic(MyEnum::VariantUnit)?.cast::<Map>();
|
||||||
|
assert_eq!(Ok("VariantUnit"), map.remove("tag").unwrap().as_str());
|
||||||
|
assert!(map.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
{
|
||||||
|
let mut map = to_dynamic(MyEnum::VariantUnitTuple())?.cast::<Map>();
|
||||||
|
assert_eq!(Ok("VariantUnitTuple"), map.remove("tag").unwrap().as_str());
|
||||||
|
let content = map.remove("content").unwrap().cast::<Array>();
|
||||||
|
assert!(map.is_empty());
|
||||||
|
assert!(content.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut map = to_dynamic(MyEnum::VariantNewtype(123))?.cast::<Map>();
|
||||||
|
assert_eq!(Ok("VariantNewtype"), map.remove("tag").unwrap().as_str());
|
||||||
|
let content = map.remove("content").unwrap();
|
||||||
|
assert!(map.is_empty());
|
||||||
|
assert_eq!(Ok(123), content.as_int());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
{
|
||||||
|
let mut map = to_dynamic(MyEnum::VariantTuple(123, 456))?.cast::<Map>();
|
||||||
|
assert_eq!(Ok("VariantTuple"), map.remove("tag").unwrap().as_str());
|
||||||
|
let content = map.remove("content").unwrap().cast::<Array>();
|
||||||
|
assert!(map.is_empty());
|
||||||
|
assert_eq!(2, content.len());
|
||||||
|
assert_eq!(Ok(123), content[0].as_int());
|
||||||
|
assert_eq!(Ok(456), content[1].as_int());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut map = to_dynamic(MyEnum::VariantEmptyStruct {})?.cast::<Map>();
|
||||||
|
assert_eq!(
|
||||||
|
Ok("VariantEmptyStruct"),
|
||||||
|
map.remove("tag").unwrap().as_str()
|
||||||
|
);
|
||||||
|
let map_inner = map.remove("content").unwrap().cast::<Map>();
|
||||||
|
assert!(map.is_empty());
|
||||||
|
assert!(map_inner.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut map = to_dynamic(MyEnum::VariantStruct { a: 123 })?.cast::<Map>();
|
||||||
|
assert_eq!(Ok("VariantStruct"), map.remove("tag").unwrap().as_str());
|
||||||
|
let mut map_inner = map.remove("content").unwrap().cast::<Map>();
|
||||||
|
assert!(map.is_empty());
|
||||||
|
assert_eq!(Ok(123), map_inner.remove("a").unwrap().as_int());
|
||||||
|
assert!(map_inner.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
fn test_serde_ser_untagged_enum() -> Result<(), Box<EvalAltResult>> {
|
||||||
|
#[derive(Serialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
enum MyEnum {
|
||||||
|
VariantEmptyStruct {},
|
||||||
|
VariantStruct1 { a: i32 },
|
||||||
|
VariantStruct2 { b: i32 },
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let map = to_dynamic(MyEnum::VariantEmptyStruct {})?.cast::<Map>();
|
||||||
|
assert!(map.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut map = to_dynamic(MyEnum::VariantStruct1 { a: 123 })?.cast::<Map>();
|
||||||
|
assert_eq!(Ok(123), map.remove("a").unwrap().as_int());
|
||||||
|
assert!(map.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut map = to_dynamic(MyEnum::VariantStruct2 { b: 123 })?.cast::<Map>();
|
||||||
|
assert_eq!(Ok(123), map.remove("b").unwrap().as_int());
|
||||||
|
assert!(map.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -106,6 +326,20 @@ fn test_serde_de_primary_types() -> Result<(), Box<EvalAltResult>> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_serde_de_integer_types() -> Result<(), Box<EvalAltResult>> {
|
||||||
|
assert_eq!(42_i8, from_dynamic(&Dynamic::from(42 as INT))?);
|
||||||
|
assert_eq!(42_i16, from_dynamic(&Dynamic::from(42 as INT))?);
|
||||||
|
assert_eq!(42_i32, from_dynamic(&Dynamic::from(42 as INT))?);
|
||||||
|
assert_eq!(42_i64, from_dynamic(&Dynamic::from(42 as INT))?);
|
||||||
|
assert_eq!(42_u8, from_dynamic(&Dynamic::from(42 as INT))?);
|
||||||
|
assert_eq!(42_u16, from_dynamic(&Dynamic::from(42 as INT))?);
|
||||||
|
assert_eq!(42_u32, from_dynamic(&Dynamic::from(42 as INT))?);
|
||||||
|
assert_eq!(42_u64, from_dynamic(&Dynamic::from(42 as INT))?);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
fn test_serde_de_array() -> Result<(), Box<EvalAltResult>> {
|
fn test_serde_de_array() -> Result<(), Box<EvalAltResult>> {
|
||||||
@ -190,3 +424,261 @@ fn test_serde_de_script() -> Result<(), Box<EvalAltResult>> {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_serde_de_unit_enum() -> Result<(), Box<EvalAltResult>> {
|
||||||
|
#[derive(Debug, PartialEq, Deserialize)]
|
||||||
|
enum MyEnum {
|
||||||
|
VariantFoo,
|
||||||
|
VariantBar,
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let d = Dynamic::from("VariantFoo".to_string());
|
||||||
|
assert_eq!(MyEnum::VariantFoo, from_dynamic(&d)?);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let d = Dynamic::from("VariantBar".to_string());
|
||||||
|
assert_eq!(MyEnum::VariantBar, from_dynamic(&d)?);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
fn test_serde_de_externally_tagged_enum() -> Result<(), Box<EvalAltResult>> {
|
||||||
|
#[derive(Debug, PartialEq, Deserialize)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
enum MyEnum {
|
||||||
|
VariantUnit,
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
VariantUnitTuple(),
|
||||||
|
VariantNewtype(i32),
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
VariantTuple(i32, i32),
|
||||||
|
VariantEmptyStruct {},
|
||||||
|
VariantStruct {
|
||||||
|
a: i32,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let d = Dynamic::from("VariantUnit".to_string());
|
||||||
|
assert_eq!(MyEnum::VariantUnit, from_dynamic(&d).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
{
|
||||||
|
let array: Array = vec![];
|
||||||
|
let mut map_outer = Map::new();
|
||||||
|
map_outer.insert("VariantUnitTuple".into(), array.into());
|
||||||
|
assert_eq!(
|
||||||
|
MyEnum::VariantUnitTuple(),
|
||||||
|
from_dynamic(&map_outer.into()).unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut map_outer = Map::new();
|
||||||
|
map_outer.insert("VariantNewtype".into(), (123 as INT).into());
|
||||||
|
assert_eq!(
|
||||||
|
MyEnum::VariantNewtype(123),
|
||||||
|
from_dynamic(&map_outer.into()).unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
{
|
||||||
|
let array: Array = vec![(123 as INT).into(), (456 as INT).into()];
|
||||||
|
let mut map_outer = Map::new();
|
||||||
|
map_outer.insert("VariantTuple".into(), array.into());
|
||||||
|
assert_eq!(
|
||||||
|
MyEnum::VariantTuple(123, 456),
|
||||||
|
from_dynamic(&map_outer.into()).unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let map_inner = Map::new();
|
||||||
|
let mut map_outer = Map::new();
|
||||||
|
map_outer.insert("VariantEmptyStruct".into(), map_inner.into());
|
||||||
|
assert_eq!(
|
||||||
|
MyEnum::VariantEmptyStruct {},
|
||||||
|
from_dynamic(&map_outer.into()).unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut map_inner = Map::new();
|
||||||
|
map_inner.insert("a".into(), (123 as INT).into());
|
||||||
|
let mut map_outer = Map::new();
|
||||||
|
map_outer.insert("VariantStruct".into(), map_inner.into());
|
||||||
|
assert_eq!(
|
||||||
|
MyEnum::VariantStruct { a: 123 },
|
||||||
|
from_dynamic(&map_outer.into()).unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
fn test_serde_de_internally_tagged_enum() -> Result<(), Box<EvalAltResult>> {
|
||||||
|
#[derive(Debug, PartialEq, Deserialize)]
|
||||||
|
#[serde(tag = "tag", deny_unknown_fields)]
|
||||||
|
enum MyEnum {
|
||||||
|
VariantEmptyStruct {},
|
||||||
|
VariantStruct { a: i32 },
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut map = Map::new();
|
||||||
|
map.insert("tag".into(), "VariantStruct".into());
|
||||||
|
map.insert("a".into(), (123 as INT).into());
|
||||||
|
assert_eq!(
|
||||||
|
MyEnum::VariantStruct { a: 123 },
|
||||||
|
from_dynamic(&map.into()).unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut map = Map::new();
|
||||||
|
map.insert("tag".into(), "VariantEmptyStruct".into());
|
||||||
|
assert_eq!(
|
||||||
|
MyEnum::VariantEmptyStruct {},
|
||||||
|
from_dynamic(&map.into()).unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
fn test_serde_de_adjacently_tagged_enum() -> Result<(), Box<EvalAltResult>> {
|
||||||
|
#[derive(Debug, PartialEq, Deserialize)]
|
||||||
|
#[serde(tag = "tag", content = "content", deny_unknown_fields)]
|
||||||
|
enum MyEnum {
|
||||||
|
VariantUnit,
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
VariantUnitTuple(),
|
||||||
|
VariantNewtype(i32),
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
VariantTuple(i32, i32),
|
||||||
|
VariantEmptyStruct {},
|
||||||
|
VariantStruct {
|
||||||
|
a: i32,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut map_outer = Map::new();
|
||||||
|
map_outer.insert("tag".into(), "VariantUnit".into());
|
||||||
|
assert_eq!(
|
||||||
|
MyEnum::VariantUnit,
|
||||||
|
from_dynamic(&map_outer.into()).unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
{
|
||||||
|
let array: Array = vec![];
|
||||||
|
let mut map_outer = Map::new();
|
||||||
|
map_outer.insert("tag".into(), "VariantUnitTuple".into());
|
||||||
|
map_outer.insert("content".into(), array.into());
|
||||||
|
assert_eq!(
|
||||||
|
MyEnum::VariantUnitTuple(),
|
||||||
|
from_dynamic(&map_outer.into()).unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut map_outer = Map::new();
|
||||||
|
map_outer.insert("tag".into(), "VariantNewtype".into());
|
||||||
|
map_outer.insert("content".into(), (123 as INT).into());
|
||||||
|
assert_eq!(
|
||||||
|
MyEnum::VariantNewtype(123),
|
||||||
|
from_dynamic(&map_outer.into()).unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
{
|
||||||
|
let array: Array = vec![(123 as INT).into(), (456 as INT).into()];
|
||||||
|
let mut map_outer = Map::new();
|
||||||
|
map_outer.insert("tag".into(), "VariantTuple".into());
|
||||||
|
map_outer.insert("content".into(), array.into());
|
||||||
|
assert_eq!(
|
||||||
|
MyEnum::VariantTuple(123, 456),
|
||||||
|
from_dynamic(&map_outer.into()).unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let map_inner = Map::new();
|
||||||
|
let mut map_outer = Map::new();
|
||||||
|
map_outer.insert("tag".into(), "VariantEmptyStruct".into());
|
||||||
|
map_outer.insert("content".into(), map_inner.into());
|
||||||
|
assert_eq!(
|
||||||
|
MyEnum::VariantEmptyStruct {},
|
||||||
|
from_dynamic(&map_outer.into()).unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut map_inner = Map::new();
|
||||||
|
map_inner.insert("a".into(), (123 as INT).into());
|
||||||
|
let mut map_outer = Map::new();
|
||||||
|
map_outer.insert("tag".into(), "VariantStruct".into());
|
||||||
|
map_outer.insert("content".into(), map_inner.into());
|
||||||
|
assert_eq!(
|
||||||
|
MyEnum::VariantStruct { a: 123 },
|
||||||
|
from_dynamic(&map_outer.into()).unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
fn test_serde_de_untagged_enum() -> Result<(), Box<EvalAltResult>> {
|
||||||
|
#[derive(Debug, PartialEq, Deserialize)]
|
||||||
|
#[serde(untagged, deny_unknown_fields)]
|
||||||
|
enum MyEnum {
|
||||||
|
VariantEmptyStruct {},
|
||||||
|
VariantStruct1 { a: i32 },
|
||||||
|
VariantStruct2 { b: i32 },
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let map = Map::new();
|
||||||
|
assert_eq!(
|
||||||
|
MyEnum::VariantEmptyStruct {},
|
||||||
|
from_dynamic(&map.into()).unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut map = Map::new();
|
||||||
|
map.insert("a".into(), (123 as INT).into());
|
||||||
|
assert_eq!(
|
||||||
|
MyEnum::VariantStruct1 { a: 123 },
|
||||||
|
from_dynamic(&map.into()).unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut map = Map::new();
|
||||||
|
map.insert("b".into(), (123 as INT).into());
|
||||||
|
assert_eq!(
|
||||||
|
MyEnum::VariantStruct2 { b: 123 },
|
||||||
|
from_dynamic(&map.into()).unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
@ -7,7 +7,7 @@ fn test_var_scope() -> Result<(), Box<EvalAltResult>> {
|
|||||||
|
|
||||||
engine.eval_with_scope::<()>(&mut scope, "let x = 4 + 5")?;
|
engine.eval_with_scope::<()>(&mut scope, "let x = 4 + 5")?;
|
||||||
assert_eq!(engine.eval_with_scope::<INT>(&mut scope, "x")?, 9);
|
assert_eq!(engine.eval_with_scope::<INT>(&mut scope, "x")?, 9);
|
||||||
engine.eval_with_scope::<()>(&mut scope, "x = x + 1; x = x + 2;")?;
|
engine.eval_with_scope::<()>(&mut scope, "x += 1; x += 2;")?;
|
||||||
assert_eq!(engine.eval_with_scope::<INT>(&mut scope, "x")?, 12);
|
assert_eq!(engine.eval_with_scope::<INT>(&mut scope, "x")?, 12);
|
||||||
|
|
||||||
scope.set_value("x", 42 as INT);
|
scope.set_value("x", 42 as INT);
|
||||||
|
@ -10,10 +10,10 @@ fn test_while() -> Result<(), Box<EvalAltResult>> {
|
|||||||
let x = 0;
|
let x = 0;
|
||||||
|
|
||||||
while x < 10 {
|
while x < 10 {
|
||||||
x = x + 1;
|
x += 1;
|
||||||
if x > 5 { break; }
|
if x > 5 { break; }
|
||||||
if x > 3 { continue; }
|
if x > 3 { continue; }
|
||||||
x = x + 3;
|
x += 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
x
|
x
|
||||||
|
Loading…
Reference in New Issue
Block a user