rhai/src/packages/array_basic.rs

451 lines
13 KiB
Rust
Raw Normal View History

#![cfg(not(feature = "no_index"))]
2020-08-14 12:58:34 +02:00
#![allow(non_snake_case)]
use crate::any::{Dynamic, Variant};
use crate::def_package;
2020-08-15 02:37:16 +02:00
use crate::engine::{Array, Engine};
2020-08-03 17:11:08 +02:00
use crate::fn_native::FnPtr;
2020-05-25 07:44:28 +02:00
use crate::parser::{ImmutableString, INT};
2020-08-14 12:58:34 +02:00
use crate::plugin::*;
2020-10-12 17:17:16 +02:00
use crate::result::EvalAltResult;
use crate::token::Position;
2020-07-26 09:53:22 +02:00
2020-08-24 16:37:44 +02:00
#[cfg(not(feature = "no_object"))]
use crate::engine::Map;
2020-10-13 04:57:29 +02:00
use crate::stdlib::{any::TypeId, boxed::Box, cmp::Ordering, string::ToString};
2020-08-14 12:58:34 +02:00
pub type Unit = ();
macro_rules! gen_array_functions {
($root:ident => $($arg_type:ident),+ ) => {
2020-09-22 13:17:50 +02:00
pub mod $root { $( pub mod $arg_type {
use super::super::*;
2020-09-22 13:17:50 +02:00
#[export_module]
pub mod functions {
#[rhai_fn(name = "push", name = "+=")]
pub fn push(list: &mut Array, item: $arg_type) {
list.push(Dynamic::from(item));
}
2020-08-14 12:58:34 +02:00
2020-09-22 13:17:50 +02:00
pub fn insert(list: &mut Array, position: INT, item: $arg_type) {
if position <= 0 {
list.insert(0, Dynamic::from(item));
} else if (position as usize) >= list.len() - 1 {
push(list, item);
} else {
list.insert(position as usize, Dynamic::from(item));
}
2020-08-14 12:58:34 +02:00
}
}
})* }
2020-08-14 12:58:34 +02:00
}
}
macro_rules! reg_functions {
2020-08-24 16:37:44 +02:00
($mod_name:ident += $root:ident ; $($arg_type:ident),+) => { $(
2020-09-22 13:17:50 +02:00
combine_with_exported_module!($mod_name, "array_functions", $root::$arg_type::functions);
2020-08-24 16:37:44 +02:00
$mod_name.set_raw_fn("pad",
&[TypeId::of::<Array>(), TypeId::of::<INT>(), TypeId::of::<$arg_type>()],
pad::<$arg_type>);
)* }
2020-08-14 12:58:34 +02:00
}
def_package!(crate:BasicArrayPackage:"Basic array utilities.", lib, {
reg_functions!(lib += basic; INT, bool, char, ImmutableString, FnPtr, Array, Unit);
#[cfg(not(feature = "only_i32"))]
#[cfg(not(feature = "only_i64"))]
{
reg_functions!(lib += numbers; i8, u8, i16, u16, i32, i64, u32, u64);
#[cfg(not(target_arch = "wasm32"))]
2020-08-24 16:37:44 +02:00
reg_functions!(lib += num_128; i128, u128);
2020-08-14 12:58:34 +02:00
}
#[cfg(not(feature = "no_float"))]
2020-08-24 16:37:44 +02:00
reg_functions!(lib += float; f32, f64);
#[cfg(not(feature = "no_object"))]
reg_functions!(lib += map; Map);
2020-08-14 12:58:34 +02:00
2020-10-12 16:49:51 +02:00
lib.set_raw_fn("map", &[TypeId::of::<Array>(), TypeId::of::<FnPtr>()], map);
lib.set_raw_fn("filter", &[TypeId::of::<Array>(), TypeId::of::<FnPtr>()], filter);
lib.set_raw_fn("reduce", &[TypeId::of::<Array>(), TypeId::of::<FnPtr>()], reduce);
2020-10-13 04:57:29 +02:00
lib.set_raw_fn("reduce_rev", &[TypeId::of::<Array>(), TypeId::of::<FnPtr>()], reduce_rev);
lib.set_raw_fn("some", &[TypeId::of::<Array>(), TypeId::of::<FnPtr>()], some);
lib.set_raw_fn("all", &[TypeId::of::<Array>(), TypeId::of::<FnPtr>()], all);
lib.set_raw_fn("sort", &[TypeId::of::<Array>(), TypeId::of::<FnPtr>()], sort);
2020-10-12 16:49:51 +02:00
2020-09-21 10:15:52 +02:00
// Merge in the module at the end to override `+=` for arrays
combine_with_exported_module!(lib, "array", array_functions);
2020-08-14 12:58:34 +02:00
// Register array iterator
lib.set_iter(
TypeId::of::<Array>(),
|arr| Box::new(arr.cast::<Array>().into_iter()) as Box<dyn Iterator<Item = Dynamic>>,
);
});
#[export_module]
mod array_functions {
#[rhai_fn(name = "len", get = "len")]
2020-08-14 12:58:34 +02:00
pub fn len(list: &mut Array) -> INT {
list.len() as INT
2020-08-14 12:58:34 +02:00
}
#[rhai_fn(name = "append", name = "+=")]
2020-08-14 12:58:34 +02:00
pub fn append(x: &mut Array, y: Array) {
x.extend(y);
}
#[rhai_fn(name = "+")]
pub fn concat(mut x: Array, y: Array) -> Array {
x.extend(y);
x
}
2020-08-14 12:58:34 +02:00
pub fn pop(list: &mut Array) -> Dynamic {
list.pop().unwrap_or_else(|| ().into())
}
pub fn shift(list: &mut Array) -> Dynamic {
if list.is_empty() {
().into()
} else {
list.remove(0)
}
}
pub fn remove(list: &mut Array, len: INT) -> Dynamic {
if len < 0 || (len as usize) >= list.len() {
().into()
} else {
list.remove(len as usize)
}
}
pub fn clear(list: &mut Array) {
list.clear();
}
pub fn truncate(list: &mut Array, len: INT) {
if len >= 0 {
list.truncate(len as usize);
} else {
list.clear();
}
}
2020-09-24 04:51:21 +02:00
pub fn reverse(list: &mut Array) {
list.reverse();
}
2020-10-13 04:57:29 +02:00
pub fn splice(list: &mut Array, start: INT, len: INT, replace: Array) {
let start = if start < 0 {
0
} else if start as usize >= list.len() {
list.len() - 1
} else {
start as usize
};
let len = if len < 0 {
0
} else if len as usize > list.len() - start {
list.len() - start
} else {
len as usize
};
list.splice(start..start + len, replace.into_iter());
}
2020-08-14 12:58:34 +02:00
}
fn pad<T: Variant + Clone>(
2020-07-26 09:53:22 +02:00
_engine: &Engine,
_: &Module,
args: &mut [&mut Dynamic],
2020-08-14 12:58:34 +02:00
) -> Result<(), Box<EvalAltResult>> {
let len = *args[1].read_lock::<INT>().unwrap();
// Check if array will be over max size limit
#[cfg(not(feature = "unchecked"))]
2020-07-26 09:53:22 +02:00
if _engine.limits.max_array_size > 0
&& len > 0
&& (len as usize) > _engine.limits.max_array_size
{
2020-08-06 04:17:32 +02:00
return EvalAltResult::ErrorDataTooLarge(
2020-07-04 16:53:00 +02:00
"Size of array".to_string(),
2020-07-26 09:53:22 +02:00
_engine.limits.max_array_size,
2020-07-04 16:53:00 +02:00
len as usize,
Position::none(),
2020-08-06 04:17:32 +02:00
)
.into();
}
2020-06-30 12:34:32 +02:00
if len > 0 {
2020-06-29 17:55:28 +02:00
let item = args[2].clone();
let mut list = args[0].write_lock::<Array>().unwrap();
2020-06-30 12:34:32 +02:00
if len as usize > list.len() {
list.resize(len as usize, item);
}
}
Ok(())
}
2020-10-12 16:49:51 +02:00
fn map(
engine: &Engine,
lib: &Module,
args: &mut [&mut Dynamic],
) -> Result<Array, Box<EvalAltResult>> {
let list = args[0].read_lock::<Array>().unwrap();
let mapper = args[1].read_lock::<FnPtr>().unwrap();
let mut array = Array::with_capacity(list.len());
for (i, item) in list.iter().enumerate() {
array.push(
mapper
.call_dynamic(engine, lib, None, [item.clone()])
.or_else(|err| match *err {
EvalAltResult::ErrorFunctionNotFound(_, _) => {
mapper.call_dynamic(engine, lib, None, [item.clone(), (i as INT).into()])
}
_ => Err(err),
})
.map_err(|err| {
Box::new(EvalAltResult::ErrorInFunctionCall(
"map".to_string(),
err,
Position::none(),
))
})?,
);
}
Ok(array)
}
fn filter(
engine: &Engine,
lib: &Module,
args: &mut [&mut Dynamic],
) -> Result<Array, Box<EvalAltResult>> {
let list = args[0].read_lock::<Array>().unwrap();
let filter = args[1].read_lock::<FnPtr>().unwrap();
let mut array = Array::with_capacity(list.len());
for (i, item) in list.iter().enumerate() {
if filter
.call_dynamic(engine, lib, None, [item.clone()])
.or_else(|err| match *err {
EvalAltResult::ErrorFunctionNotFound(_, _) => {
filter.call_dynamic(engine, lib, None, [item.clone(), (i as INT).into()])
}
_ => Err(err),
})
.map_err(|err| {
Box::new(EvalAltResult::ErrorInFunctionCall(
"filter".to_string(),
err,
Position::none(),
))
})?
.as_bool()
.unwrap_or(false)
{
array.push(item.clone());
}
}
Ok(array)
}
2020-10-13 04:57:29 +02:00
fn some(
engine: &Engine,
lib: &Module,
args: &mut [&mut Dynamic],
) -> Result<bool, Box<EvalAltResult>> {
let list = args[0].read_lock::<Array>().unwrap();
let filter = args[1].read_lock::<FnPtr>().unwrap();
for (i, item) in list.iter().enumerate() {
if filter
.call_dynamic(engine, lib, None, [item.clone()])
.or_else(|err| match *err {
EvalAltResult::ErrorFunctionNotFound(_, _) => {
filter.call_dynamic(engine, lib, None, [item.clone(), (i as INT).into()])
}
_ => Err(err),
})
.map_err(|err| {
Box::new(EvalAltResult::ErrorInFunctionCall(
"filter".to_string(),
err,
Position::none(),
))
})?
.as_bool()
.unwrap_or(false)
{
return Ok(true.into());
}
}
Ok(false.into())
}
fn all(
engine: &Engine,
lib: &Module,
args: &mut [&mut Dynamic],
) -> Result<bool, Box<EvalAltResult>> {
let list = args[0].read_lock::<Array>().unwrap();
let filter = args[1].read_lock::<FnPtr>().unwrap();
for (i, item) in list.iter().enumerate() {
if !filter
.call_dynamic(engine, lib, None, [item.clone()])
.or_else(|err| match *err {
EvalAltResult::ErrorFunctionNotFound(_, _) => {
filter.call_dynamic(engine, lib, None, [item.clone(), (i as INT).into()])
}
_ => Err(err),
})
.map_err(|err| {
Box::new(EvalAltResult::ErrorInFunctionCall(
"filter".to_string(),
err,
Position::none(),
))
})?
.as_bool()
.unwrap_or(false)
{
return Ok(false.into());
}
}
Ok(true.into())
}
2020-10-12 16:49:51 +02:00
fn reduce(
engine: &Engine,
lib: &Module,
args: &mut [&mut Dynamic],
) -> Result<Dynamic, Box<EvalAltResult>> {
let list = args[0].read_lock::<Array>().unwrap();
let reducer = args[1].read_lock::<FnPtr>().unwrap();
let mut result: Dynamic = ().into();
for (i, item) in list.iter().enumerate() {
result = reducer
.call_dynamic(engine, lib, None, [result.clone(), item.clone()])
.or_else(|err| match *err {
EvalAltResult::ErrorFunctionNotFound(_, _) => reducer.call_dynamic(
engine,
lib,
None,
[result, item.clone(), (i as INT).into()],
),
_ => Err(err),
})
.map_err(|err| {
Box::new(EvalAltResult::ErrorInFunctionCall(
"reduce".to_string(),
err,
Position::none(),
))
})?;
}
Ok(result)
}
2020-10-13 04:57:29 +02:00
fn reduce_rev(
engine: &Engine,
lib: &Module,
args: &mut [&mut Dynamic],
) -> Result<Dynamic, Box<EvalAltResult>> {
let list = args[0].read_lock::<Array>().unwrap();
let reducer = args[1].read_lock::<FnPtr>().unwrap();
let mut result: Dynamic = ().into();
for (i, item) in list.iter().enumerate().rev() {
result = reducer
.call_dynamic(engine, lib, None, [result.clone(), item.clone()])
.or_else(|err| match *err {
EvalAltResult::ErrorFunctionNotFound(_, _) => reducer.call_dynamic(
engine,
lib,
None,
[result, item.clone(), (i as INT).into()],
),
_ => Err(err),
})
.map_err(|err| {
Box::new(EvalAltResult::ErrorInFunctionCall(
"reduce".to_string(),
err,
Position::none(),
))
})?;
}
Ok(result)
}
fn sort(
engine: &Engine,
lib: &Module,
args: &mut [&mut Dynamic],
) -> Result<Dynamic, Box<EvalAltResult>> {
let comparer = args[1].read_lock::<FnPtr>().unwrap().clone();
let mut list = args[0].write_lock::<Array>().unwrap();
list.sort_by(|x, y| {
comparer
.call_dynamic(engine, lib, None, [x.clone(), y.clone()])
.ok()
.and_then(|v| v.as_int().ok())
.map(|v| {
if v > 0 {
Ordering::Greater
} else if v < 0 {
Ordering::Less
} else {
Ordering::Equal
}
})
.unwrap_or_else(|| {
let x_type_id = x.type_id();
let y_type_id = y.type_id();
if x_type_id > y_type_id {
Ordering::Greater
} else if x_type_id < y_type_id {
Ordering::Less
} else {
Ordering::Equal
}
})
});
Ok(().into())
}
2020-08-14 12:58:34 +02:00
gen_array_functions!(basic => INT, bool, char, ImmutableString, FnPtr, Array, Unit);
2020-08-14 12:58:34 +02:00
#[cfg(not(feature = "only_i32"))]
#[cfg(not(feature = "only_i64"))]
gen_array_functions!(numbers => i8, u8, i16, u16, i32, i64, u32, u64);
2020-08-14 12:58:34 +02:00
#[cfg(not(feature = "only_i32"))]
#[cfg(not(feature = "only_i64"))]
#[cfg(not(target_arch = "wasm32"))]
gen_array_functions!(num_128 => i128, u128);
2020-06-17 10:50:46 +02:00
2020-08-14 12:58:34 +02:00
#[cfg(not(feature = "no_float"))]
gen_array_functions!(float => f32, f64);
2020-08-24 16:37:44 +02:00
#[cfg(not(feature = "no_object"))]
gen_array_functions!(map => Map);