commit
b73d7f21a4
@ -6,6 +6,11 @@ Version 0.20.1
|
||||
|
||||
This version enables functions to access constants declared at global level via the special `global` module.
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
|
||||
* Fixed bug when position is zero in `insert` and `split_at` methods for arrays.
|
||||
|
||||
Breaking changes
|
||||
----------------
|
||||
|
||||
|
@ -88,7 +88,7 @@ default_features = false
|
||||
optional = true
|
||||
|
||||
[dependencies.rust_decimal]
|
||||
version = "1.10"
|
||||
version = "1.11"
|
||||
default_features = false
|
||||
optional = true
|
||||
|
||||
|
@ -15,8 +15,6 @@ help: consider importing one of these items
|
||||
|
|
||||
11 | use core::fmt::Pointer;
|
||||
|
|
||||
11 | use crate::mem::fmt::Pointer;
|
||||
|
|
||||
11 | use std::fmt::Pointer;
|
||||
|
|
||||
11 | use syn::__private::fmt::Pointer;
|
||||
|
@ -21,7 +21,6 @@ for p in range(2, MAX_NUMBER_TO_CHECK) {
|
||||
|
||||
for i in range(2 * p, MAX_NUMBER_TO_CHECK, p) {
|
||||
prime_mask[i] = false;
|
||||
i += p;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -188,11 +188,11 @@ pub enum Union {
|
||||
/// This data structure provides transparent interoperability between
|
||||
/// normal [`Dynamic`] and shared [`Dynamic`] values.
|
||||
#[derive(Debug)]
|
||||
pub struct DynamicReadLock<'d, T: Variant + Clone>(DynamicReadLockInner<'d, T>);
|
||||
pub struct DynamicReadLock<'d, T: Clone>(DynamicReadLockInner<'d, T>);
|
||||
|
||||
/// Different types of read guards for [`DynamicReadLock`].
|
||||
#[derive(Debug)]
|
||||
enum DynamicReadLockInner<'d, T: Variant + Clone> {
|
||||
enum DynamicReadLockInner<'d, T: Clone> {
|
||||
/// A simple reference to a non-shared value.
|
||||
Reference(&'d T),
|
||||
|
||||
@ -206,7 +206,7 @@ enum DynamicReadLockInner<'d, T: Variant + Clone> {
|
||||
Guard(std::sync::RwLockReadGuard<'d, Dynamic>),
|
||||
}
|
||||
|
||||
impl<'d, T: Variant + Clone> Deref for DynamicReadLock<'d, T> {
|
||||
impl<'d, T: Any + Clone> Deref for DynamicReadLock<'d, T> {
|
||||
type Target = T;
|
||||
|
||||
#[inline(always)]
|
||||
@ -225,11 +225,11 @@ impl<'d, T: Variant + Clone> Deref for DynamicReadLock<'d, T> {
|
||||
/// This data structure provides transparent interoperability between
|
||||
/// normal [`Dynamic`] and shared [`Dynamic`] values.
|
||||
#[derive(Debug)]
|
||||
pub struct DynamicWriteLock<'d, T: Variant + Clone>(DynamicWriteLockInner<'d, T>);
|
||||
pub struct DynamicWriteLock<'d, T: Clone>(DynamicWriteLockInner<'d, T>);
|
||||
|
||||
/// Different types of write guards for [`DynamicReadLock`].
|
||||
#[derive(Debug)]
|
||||
enum DynamicWriteLockInner<'d, T: Variant + Clone> {
|
||||
enum DynamicWriteLockInner<'d, T: Clone> {
|
||||
/// A simple mutable reference to a non-shared value.
|
||||
Reference(&'d mut T),
|
||||
|
||||
@ -243,7 +243,7 @@ enum DynamicWriteLockInner<'d, T: Variant + Clone> {
|
||||
Guard(std::sync::RwLockWriteGuard<'d, Dynamic>),
|
||||
}
|
||||
|
||||
impl<'d, T: Variant + Clone> Deref for DynamicWriteLock<'d, T> {
|
||||
impl<'d, T: Any + Clone> Deref for DynamicWriteLock<'d, T> {
|
||||
type Target = T;
|
||||
|
||||
#[inline(always)]
|
||||
@ -257,7 +257,7 @@ impl<'d, T: Variant + Clone> Deref for DynamicWriteLock<'d, T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Variant + Clone> DerefMut for DynamicWriteLock<'d, T> {
|
||||
impl<'d, T: Any + Clone> DerefMut for DynamicWriteLock<'d, T> {
|
||||
#[inline(always)]
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
match &mut self.0 {
|
||||
@ -298,7 +298,7 @@ impl Dynamic {
|
||||
/// If the [`Dynamic`] is a shared variant checking is performed on
|
||||
/// top of its internal value.
|
||||
#[inline(always)]
|
||||
pub fn is<T: Variant + Clone>(&self) -> bool {
|
||||
pub fn is<T: Any + Clone>(&self) -> bool {
|
||||
let mut target_type_id = TypeId::of::<T>();
|
||||
|
||||
if target_type_id == TypeId::of::<String>() {
|
||||
@ -983,7 +983,7 @@ impl Dynamic {
|
||||
/// assert_eq!(x.try_cast::<u32>().unwrap(), 42);
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn try_cast<T: Variant>(self) -> Option<T> {
|
||||
pub fn try_cast<T: Any>(self) -> Option<T> {
|
||||
// Coded this way in order to maximally leverage potentials for dead-code removal.
|
||||
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
@ -1118,7 +1118,7 @@ impl Dynamic {
|
||||
/// assert_eq!(x.cast::<u32>(), 42);
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn cast<T: Variant + Clone>(self) -> T {
|
||||
pub fn cast<T: Any + Clone>(self) -> T {
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
let self_type_name = if self.is_shared() {
|
||||
// Avoid panics/deadlocks with shared values
|
||||
@ -1165,7 +1165,7 @@ impl Dynamic {
|
||||
/// assert_eq!(y.clone_cast::<u32>(), 42);
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn clone_cast<T: Variant + Clone>(&self) -> T {
|
||||
pub fn clone_cast<T: Any + Clone>(&self) -> T {
|
||||
self.read_lock::<T>().unwrap().clone()
|
||||
}
|
||||
/// Flatten the [`Dynamic`] and clone it.
|
||||
@ -1293,7 +1293,7 @@ impl Dynamic {
|
||||
/// Under the `sync` feature, this call may deadlock, or [panic](https://doc.rust-lang.org/std/sync/struct.RwLock.html#panics-1).
|
||||
/// Otherwise, this call panics if the data is currently borrowed for write.
|
||||
#[inline(always)]
|
||||
pub fn read_lock<T: Variant + Clone>(&self) -> Option<DynamicReadLock<T>> {
|
||||
pub fn read_lock<T: Any + Clone>(&self) -> Option<DynamicReadLock<T>> {
|
||||
match self.0 {
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
Union::Shared(ref cell, _) => {
|
||||
@ -1326,7 +1326,7 @@ impl Dynamic {
|
||||
/// Under the `sync` feature, this call may deadlock, or [panic](https://doc.rust-lang.org/std/sync/struct.RwLock.html#panics-1).
|
||||
/// Otherwise, this call panics if the data is currently borrowed for write.
|
||||
#[inline(always)]
|
||||
pub fn write_lock<T: Variant + Clone>(&mut self) -> Option<DynamicWriteLock<T>> {
|
||||
pub fn write_lock<T: Any + Clone>(&mut self) -> Option<DynamicWriteLock<T>> {
|
||||
match self.0 {
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
Union::Shared(ref cell, _) => {
|
||||
@ -1354,7 +1354,7 @@ impl Dynamic {
|
||||
///
|
||||
/// Returns [`None`] if the cast fails, or if the value is shared.
|
||||
#[inline(always)]
|
||||
pub(crate) fn downcast_ref<T: Variant + Clone>(&self) -> Option<&T> {
|
||||
pub(crate) fn downcast_ref<T: Any + Clone>(&self) -> Option<&T> {
|
||||
// Coded this way in order to maximally leverage potentials for dead-code removal.
|
||||
|
||||
if TypeId::of::<T>() == TypeId::of::<INT>() {
|
||||
@ -1450,7 +1450,7 @@ impl Dynamic {
|
||||
///
|
||||
/// Returns [`None`] if the cast fails, or if the value is shared.
|
||||
#[inline(always)]
|
||||
pub(crate) fn downcast_mut<T: Variant + Clone>(&mut self) -> Option<&mut T> {
|
||||
pub(crate) fn downcast_mut<T: Any + Clone>(&mut self) -> Option<&mut T> {
|
||||
// Coded this way in order to maximally leverage potentials for dead-code removal.
|
||||
|
||||
if TypeId::of::<T>() == TypeId::of::<INT>() {
|
||||
|
@ -2538,7 +2538,6 @@ impl Engine {
|
||||
if let Some(global) = global {
|
||||
let global = Shared::get_mut(global).unwrap();
|
||||
global.set_var(name.clone(), value.clone());
|
||||
global.build_index();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1696,6 +1696,11 @@ impl Engine {
|
||||
}
|
||||
|
||||
let statements = ast.statements();
|
||||
|
||||
if statements.is_empty() {
|
||||
return Ok(Dynamic::UNIT);
|
||||
}
|
||||
|
||||
let lib = &[ast.lib()];
|
||||
self.eval_global_statements(scope, mods, &mut state, statements, lib, level)
|
||||
}
|
||||
@ -1771,9 +1776,12 @@ impl Engine {
|
||||
{
|
||||
state.resolver = ast.resolver();
|
||||
}
|
||||
|
||||
let statements = ast.statements();
|
||||
let lib = &[ast.lib()];
|
||||
self.eval_global_statements(scope, mods, &mut state, statements, lib, 0)?;
|
||||
if !statements.is_empty() {
|
||||
let lib = &[ast.lib()];
|
||||
self.eval_global_statements(scope, mods, &mut state, statements, lib, 0)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
/// Call a script function defined in an [`AST`] with multiple arguments.
|
||||
@ -1931,21 +1939,21 @@ impl Engine {
|
||||
let state = &mut Default::default();
|
||||
let mods = &mut Default::default();
|
||||
let lib = &[ast.lib()];
|
||||
let statements = ast.statements();
|
||||
let name = name.as_ref();
|
||||
|
||||
if eval_ast {
|
||||
self.eval_global_statements(scope, mods, state, ast.statements(), lib, 0)?;
|
||||
if eval_ast && !statements.is_empty() {
|
||||
self.eval_global_statements(scope, mods, state, statements, lib, 0)?;
|
||||
}
|
||||
|
||||
let fn_def = ast
|
||||
.lib()
|
||||
.get_script_fn(name.as_ref(), args.len())
|
||||
.ok_or_else(|| {
|
||||
EvalAltResult::ErrorFunctionNotFound(name.as_ref().into(), Position::NONE)
|
||||
})?;
|
||||
.get_script_fn(name, args.len())
|
||||
.ok_or_else(|| EvalAltResult::ErrorFunctionNotFound(name.into(), Position::NONE))?;
|
||||
|
||||
// Check for data race.
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
crate::fn_call::ensure_no_data_race(name.as_ref(), args, false)?;
|
||||
crate::fn_call::ensure_no_data_race(name, args, false)?;
|
||||
|
||||
self.call_script_fn(
|
||||
scope,
|
||||
|
@ -867,13 +867,18 @@ impl Engine {
|
||||
return Err(ParseErrorType::WrongFnDefinition.into());
|
||||
}
|
||||
|
||||
let statements = ast.statements();
|
||||
if statements.is_empty() {
|
||||
return Ok(Dynamic::UNIT);
|
||||
}
|
||||
|
||||
// Evaluate the AST
|
||||
let mut new_state: State = Default::default();
|
||||
new_state.source = state.source.clone();
|
||||
new_state.operations = state.operations;
|
||||
|
||||
let result =
|
||||
self.eval_global_statements(scope, mods, &mut new_state, ast.statements(), lib, level);
|
||||
self.eval_global_statements(scope, mods, &mut new_state, statements, lib, level);
|
||||
|
||||
state.operations = new_state.operations;
|
||||
|
||||
|
@ -16,7 +16,7 @@ use std::{
|
||||
any::TypeId,
|
||||
collections::{BTreeMap, BTreeSet},
|
||||
fmt,
|
||||
iter::empty,
|
||||
iter::{empty, once},
|
||||
num::NonZeroUsize,
|
||||
ops::{Add, AddAssign, Deref, DerefMut},
|
||||
};
|
||||
@ -166,7 +166,7 @@ impl Default for Module {
|
||||
all_functions: Default::default(),
|
||||
type_iterators: Default::default(),
|
||||
all_type_iterators: Default::default(),
|
||||
indexed: false,
|
||||
indexed: true,
|
||||
contains_indexed_global_functions: false,
|
||||
identifiers: Default::default(),
|
||||
}
|
||||
@ -316,7 +316,7 @@ impl Module {
|
||||
self.internal
|
||||
}
|
||||
|
||||
/// Set the interal status of the [`Module`].
|
||||
/// Set the internal status of the [`Module`].
|
||||
#[inline(always)]
|
||||
pub(crate) fn set_internal(&mut self, value: bool) -> &mut Self {
|
||||
self.internal = value;
|
||||
@ -346,12 +346,17 @@ impl Module {
|
||||
|
||||
/// Is the [`Module`] indexed?
|
||||
///
|
||||
/// A module must be indexed before it can be used in an `import` statement.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use rhai::Module;
|
||||
///
|
||||
/// let mut module = Module::new();
|
||||
/// assert!(module.is_indexed());
|
||||
///
|
||||
/// module.set_native_fn("foo", |x: &mut i64, y: i64| { *x = y; Ok(()) });
|
||||
/// assert!(!module.is_indexed());
|
||||
///
|
||||
/// # #[cfg(not(feature = "no_module"))]
|
||||
@ -446,8 +451,14 @@ impl Module {
|
||||
name: impl Into<Identifier>,
|
||||
value: impl Variant + Clone,
|
||||
) -> &mut Self {
|
||||
self.variables.insert(name.into(), Dynamic::from(value));
|
||||
self.indexed = false;
|
||||
let ident = name.into();
|
||||
let value = Dynamic::from(value);
|
||||
|
||||
if self.indexed {
|
||||
let hash_var = crate::calc_fn_hash(once(""), &ident, 0);
|
||||
self.all_variables.insert(hash_var, value.clone());
|
||||
}
|
||||
self.variables.insert(ident, value);
|
||||
self
|
||||
}
|
||||
|
||||
@ -1015,8 +1026,7 @@ impl Module {
|
||||
///
|
||||
/// let mut module = Module::new();
|
||||
/// let hash = module.set_indexer_set_fn(|x: &mut i64, y: ImmutableString, value: i64| {
|
||||
/// *x = y.len() as i64 + value;
|
||||
/// Ok(())
|
||||
/// *x = y.len() as i64 + value; Ok(())
|
||||
/// });
|
||||
/// assert!(module.contains_fn(hash));
|
||||
/// ```
|
||||
@ -1080,8 +1090,7 @@ impl Module {
|
||||
/// Ok(*x + y.len() as i64)
|
||||
/// },
|
||||
/// |x: &mut i64, y: ImmutableString, value: i64| {
|
||||
/// *x = y.len() as i64 + value;
|
||||
/// Ok(())
|
||||
/// *x = y.len() as i64 + value; Ok(())
|
||||
/// }
|
||||
/// );
|
||||
/// assert!(module.contains_fn(hash_get));
|
||||
@ -1417,10 +1426,10 @@ impl Module {
|
||||
match aliases.len() {
|
||||
0 => (),
|
||||
1 => {
|
||||
module.variables.insert(aliases.pop().unwrap(), value);
|
||||
module.set_var(aliases.pop().unwrap(), value);
|
||||
}
|
||||
_ => aliases.into_iter().for_each(|alias| {
|
||||
module.variables.insert(alias, value.clone());
|
||||
module.set_var(alias, value.clone());
|
||||
}),
|
||||
}
|
||||
});
|
||||
@ -1538,7 +1547,7 @@ impl Module {
|
||||
let mut functions = Default::default();
|
||||
let mut type_iterators = Default::default();
|
||||
|
||||
path.push("root");
|
||||
path.push("");
|
||||
|
||||
self.contains_indexed_global_functions = index_module(
|
||||
self,
|
||||
@ -1571,10 +1580,12 @@ impl Module {
|
||||
|
||||
/// Set a type iterator into the [`Module`].
|
||||
#[inline(always)]
|
||||
pub fn set_iter(&mut self, typ: TypeId, func: IteratorFn) -> &mut Self {
|
||||
self.type_iterators.insert(typ, func);
|
||||
self.indexed = false;
|
||||
self.contains_indexed_global_functions = false;
|
||||
pub fn set_iter(&mut self, type_id: TypeId, func: IteratorFn) -> &mut Self {
|
||||
if self.indexed {
|
||||
self.all_type_iterators.insert(type_id, func.clone());
|
||||
self.contains_indexed_global_functions = true;
|
||||
}
|
||||
self.type_iterators.insert(type_id, func);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,7 @@ mod array_functions {
|
||||
array
|
||||
}
|
||||
pub fn insert(array: &mut Array, position: INT, item: Dynamic) {
|
||||
if position <= 0 {
|
||||
if position < 0 {
|
||||
if let Some(n) = position.checked_abs() {
|
||||
if n as usize > array.len() {
|
||||
array.insert(0, item);
|
||||
@ -174,7 +174,7 @@ mod array_functions {
|
||||
}
|
||||
#[rhai_fn(name = "split")]
|
||||
pub fn split_at(array: &mut Array, start: INT) -> Array {
|
||||
if start <= 0 {
|
||||
if start < 0 {
|
||||
if let Some(n) = start.checked_abs() {
|
||||
if n as usize > array.len() {
|
||||
mem::take(array)
|
||||
|
@ -351,7 +351,7 @@ mod decimal_functions {
|
||||
}
|
||||
}
|
||||
|
||||
Ok(x.round_dp_with_strategy(dp as u32, RoundingStrategy::RoundUp))
|
||||
Ok(x.round_dp_with_strategy(dp as u32, RoundingStrategy::AwayFromZero))
|
||||
}
|
||||
#[rhai_fn(return_raw)]
|
||||
pub fn round_down(x: Decimal, dp: INT) -> Result<Decimal, Box<EvalAltResult>> {
|
||||
@ -367,7 +367,7 @@ mod decimal_functions {
|
||||
}
|
||||
}
|
||||
|
||||
Ok(x.round_dp_with_strategy(dp as u32, RoundingStrategy::RoundDown))
|
||||
Ok(x.round_dp_with_strategy(dp as u32, RoundingStrategy::ToZero))
|
||||
}
|
||||
#[rhai_fn(return_raw)]
|
||||
pub fn round_half_up(x: Decimal, dp: INT) -> Result<Decimal, Box<EvalAltResult>> {
|
||||
@ -383,7 +383,7 @@ mod decimal_functions {
|
||||
}
|
||||
}
|
||||
|
||||
Ok(x.round_dp_with_strategy(dp as u32, RoundingStrategy::RoundHalfUp))
|
||||
Ok(x.round_dp_with_strategy(dp as u32, RoundingStrategy::MidpointAwayFromZero))
|
||||
}
|
||||
#[rhai_fn(return_raw)]
|
||||
pub fn round_half_down(x: Decimal, dp: INT) -> Result<Decimal, Box<EvalAltResult>> {
|
||||
@ -399,7 +399,7 @@ mod decimal_functions {
|
||||
}
|
||||
}
|
||||
|
||||
Ok(x.round_dp_with_strategy(dp as u32, RoundingStrategy::RoundHalfDown))
|
||||
Ok(x.round_dp_with_strategy(dp as u32, RoundingStrategy::MidpointTowardZero))
|
||||
}
|
||||
#[rhai_fn(name = "int", get = "int")]
|
||||
pub fn int(x: Decimal) -> Decimal {
|
||||
|
@ -1,6 +1,5 @@
|
||||
//! A helper module containing unsafe utility functions.
|
||||
|
||||
use crate::dynamic::Variant;
|
||||
#[cfg(feature = "no_std")]
|
||||
use std::prelude::v1::*;
|
||||
use std::{
|
||||
@ -27,7 +26,7 @@ pub fn unsafe_try_cast<A: Any, B: Any>(a: A) -> Result<B, A> {
|
||||
|
||||
/// Cast a Boxed type into another type.
|
||||
#[inline(always)]
|
||||
pub fn unsafe_cast_box<X: Variant, T: Variant>(item: Box<X>) -> Result<Box<T>, Box<X>> {
|
||||
pub fn unsafe_cast_box<X: Any, T: Any>(item: Box<X>) -> Result<Box<T>, Box<X>> {
|
||||
// Only allow casting to the exact same type
|
||||
if TypeId::of::<X>() == TypeId::of::<T>() {
|
||||
// SAFETY: just checked whether we are pointing to the correct type
|
||||
|
143
tests/arrays.rs
143
tests/arrays.rs
@ -1,8 +1,17 @@
|
||||
#![cfg(not(feature = "no_index"))]
|
||||
use rhai::{Array, Engine, EvalAltResult, INT};
|
||||
|
||||
fn convert_to_vec<T: Clone + 'static>(array: Array) -> Vec<T> {
|
||||
array.into_iter().map(|v| v.clone_cast::<T>()).collect()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_arrays() -> Result<(), Box<EvalAltResult>> {
|
||||
let mut a = Array::new();
|
||||
a.push((42 as INT).into());
|
||||
|
||||
assert_eq!(a[0].clone_cast::<INT>(), 42);
|
||||
|
||||
let engine = Engine::new();
|
||||
|
||||
assert_eq!(engine.eval::<INT>("let x = [1, 2, 3]; x[1]")?, 2);
|
||||
@ -14,58 +23,78 @@ fn test_arrays() -> Result<(), Box<EvalAltResult>> {
|
||||
);
|
||||
assert_eq!(engine.eval::<INT>("let y = [1, 2, 3]; y[0]")?, 1);
|
||||
assert_eq!(engine.eval::<INT>("let y = [1, 2, 3]; y[-1]")?, 3);
|
||||
assert_eq!(engine.eval::<INT>("let y = [1, 2, 3]; y[-3]")?, 1);
|
||||
assert!(engine.eval::<bool>("let y = [1, 2, 3]; 2 in y")?);
|
||||
assert_eq!(engine.eval::<INT>("let y = [1, 2, 3]; y += 4; y[3]")?, 4);
|
||||
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
assert_eq!(engine.eval::<INT>("let y = [1, 2, 3]; y.push(4); y[3]")?, 4);
|
||||
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
assert_eq!(
|
||||
engine.eval::<INT>(
|
||||
r"
|
||||
let x = [2, 9];
|
||||
x.insert(-1, 1);
|
||||
x.insert(999, 3);
|
||||
|
||||
let r = x.remove(2);
|
||||
|
||||
let y = [4, 5];
|
||||
x.append(y);
|
||||
|
||||
x.len + r
|
||||
"
|
||||
)?,
|
||||
14
|
||||
convert_to_vec::<INT>(engine.eval("let y = [1, 2, 3]; y[1] += 4; y")?),
|
||||
[1, 6, 3]
|
||||
);
|
||||
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
{
|
||||
assert_eq!(
|
||||
convert_to_vec::<INT>(engine.eval("let y = [1, 2, 3]; y.push(4); y")?),
|
||||
[1, 2, 3, 4]
|
||||
);
|
||||
assert_eq!(
|
||||
convert_to_vec::<INT>(engine.eval("let y = [1, 2, 3]; y.insert(0, 4); y")?),
|
||||
[4, 1, 2, 3]
|
||||
);
|
||||
assert_eq!(
|
||||
convert_to_vec::<INT>(engine.eval("let y = [1, 2, 3]; y.insert(999, 4); y")?),
|
||||
[1, 2, 3, 4]
|
||||
);
|
||||
assert_eq!(
|
||||
convert_to_vec::<INT>(engine.eval("let y = [1, 2, 3]; y.insert(-2, 4); y")?),
|
||||
[1, 4, 2, 3]
|
||||
);
|
||||
assert_eq!(
|
||||
convert_to_vec::<INT>(engine.eval("let y = [1, 2, 3]; y.insert(-999, 4); y")?),
|
||||
[4, 1, 2, 3]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
convert_to_vec::<INT>(engine.eval(
|
||||
r"
|
||||
let x = [2, 9];
|
||||
x.insert(-1, 1);
|
||||
x.insert(999, 3);
|
||||
x.insert(-9, 99);
|
||||
|
||||
let r = x.remove(2);
|
||||
|
||||
let y = [4, 5];
|
||||
x.append(y);
|
||||
|
||||
x
|
||||
"
|
||||
)?),
|
||||
[99, 2, 9, 3, 4, 5]
|
||||
);
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
engine.eval::<INT>(
|
||||
convert_to_vec::<INT>(engine.eval(
|
||||
r"
|
||||
let x = [1, 2, 3];
|
||||
x += [4, 5];
|
||||
len(x)
|
||||
x
|
||||
"
|
||||
)?,
|
||||
5
|
||||
)?),
|
||||
[1, 2, 3, 4, 5]
|
||||
);
|
||||
assert_eq!(
|
||||
engine
|
||||
.eval::<Array>(
|
||||
r"
|
||||
let x = [1, 2, 3];
|
||||
let y = [4, 5];
|
||||
x + y
|
||||
"
|
||||
)?
|
||||
.len(),
|
||||
5
|
||||
convert_to_vec::<INT>(engine.eval(
|
||||
r"
|
||||
let x = [1, 2, 3];
|
||||
let y = [4, 5];
|
||||
x + y
|
||||
"
|
||||
)?),
|
||||
[1, 2, 3, 4, 5]
|
||||
);
|
||||
|
||||
let mut a = Array::new();
|
||||
a.push((42 as INT).into());
|
||||
|
||||
assert_eq!(a[0].clone_cast::<INT>(), 42);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -128,47 +157,43 @@ fn test_arrays_map_reduce() -> Result<(), Box<EvalAltResult>> {
|
||||
let engine = Engine::new();
|
||||
|
||||
assert_eq!(
|
||||
engine.eval::<INT>(
|
||||
convert_to_vec::<INT>(engine.eval(
|
||||
r"
|
||||
let x = [1, 2, 3];
|
||||
let y = x.filter(|v| v > 2);
|
||||
y[0]
|
||||
x.filter(|v| v > 2)
|
||||
"
|
||||
)?,
|
||||
3
|
||||
)?),
|
||||
[3]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
engine.eval::<INT>(
|
||||
convert_to_vec::<INT>(engine.eval(
|
||||
r"
|
||||
let x = [1, 2, 3];
|
||||
let y = x.filter(|v, i| v > i);
|
||||
y.len()
|
||||
x.filter(|v, i| v > i)
|
||||
"
|
||||
)?,
|
||||
3
|
||||
)?),
|
||||
[1, 2, 3]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
engine.eval::<INT>(
|
||||
convert_to_vec::<INT>(engine.eval(
|
||||
r"
|
||||
let x = [1, 2, 3];
|
||||
let y = x.map(|v| v * 2);
|
||||
y[2]
|
||||
x.map(|v| v * 2)
|
||||
"
|
||||
)?,
|
||||
6
|
||||
)?),
|
||||
[2, 4, 6]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
engine.eval::<INT>(
|
||||
convert_to_vec::<INT>(engine.eval(
|
||||
r"
|
||||
let x = [1, 2, 3];
|
||||
let y = x.map(|v, i| v * i);
|
||||
y[2]
|
||||
x.map(|v, i| v * i)
|
||||
"
|
||||
)?,
|
||||
6
|
||||
)?),
|
||||
[0, 2, 6]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
|
Loading…
x
Reference in New Issue
Block a user