rhai/src/packages/array_basic.rs

814 lines
26 KiB
Rust
Raw Normal View History

#![cfg(not(feature = "no_index"))]
2020-08-14 12:58:34 +02:00
#![allow(non_snake_case)]
2021-03-23 05:13:53 +01:00
use crate::engine::OP_EQUALS;
2020-08-14 12:58:34 +02:00
use crate::plugin::*;
use crate::{def_package, Array, Dynamic, EvalAltResult, FnPtr, NativeCallContext, Position, INT};
2021-04-17 09:15:54 +02:00
#[cfg(feature = "no_std")]
use std::prelude::v1::*;
use std::{any::TypeId, cmp::Ordering, mem};
2020-08-14 12:58:34 +02:00
def_package!(crate:BasicArrayPackage:"Basic array utilities.", lib, {
2020-09-21 10:15:52 +02:00
combine_with_exported_module!(lib, "array", array_functions);
2020-08-14 12:58:34 +02:00
// Register array iterator
2020-10-15 16:11:18 +02:00
lib.set_iterable::<Array>();
2020-08-14 12:58:34 +02:00
});
#[export_module]
mod array_functions {
#[rhai_fn(name = "len", get = "len", pure)]
pub fn len(array: &mut Array) -> INT {
array.len() as INT
2020-08-14 12:58:34 +02:00
}
#[rhai_fn(name = "push", name = "+=")]
pub fn push(array: &mut Array, item: Dynamic) {
array.push(item);
}
#[rhai_fn(name = "append", name = "+=")]
pub fn append(array: &mut Array, y: Array) {
array.extend(y);
2020-08-14 12:58:34 +02:00
}
#[rhai_fn(name = "+")]
pub fn concat(mut array: Array, y: Array) -> Array {
array.extend(y);
array
}
pub fn insert(array: &mut Array, position: INT, item: Dynamic) {
if position <= 0 {
if let Some(n) = position.checked_abs() {
if n as usize > array.len() {
array.insert(0, item);
} else {
array.insert(array.len() - n as usize, item);
}
} else {
array.insert(0, item);
}
} else if (position as usize) >= array.len() {
push(array, item);
} else {
array.insert(position as usize, item);
}
}
#[rhai_fn(return_raw)]
pub fn pad(
_ctx: NativeCallContext,
array: &mut Array,
len: INT,
item: Dynamic,
2021-03-22 04:18:09 +01:00
) -> Result<(), Box<EvalAltResult>> {
// Check if array will be over max size limit
#[cfg(not(feature = "unchecked"))]
if _ctx.engine().max_array_size() > 0
&& len > 0
&& (len as usize) > _ctx.engine().max_array_size()
{
return EvalAltResult::ErrorDataTooLarge("Size of array".to_string(), Position::NONE)
.into();
}
if len > 0 && len as usize > array.len() {
array.resize(len as usize, item);
}
2021-03-22 04:18:09 +01:00
Ok(())
}
pub fn pop(array: &mut Array) -> Dynamic {
array.pop().unwrap_or_else(|| ().into())
2020-08-14 12:58:34 +02:00
}
pub fn shift(array: &mut Array) -> Dynamic {
if array.is_empty() {
2020-08-14 12:58:34 +02:00
().into()
} else {
array.remove(0)
2020-08-14 12:58:34 +02:00
}
}
pub fn remove(array: &mut Array, len: INT) -> Dynamic {
if len < 0 || (len as usize) >= array.len() {
2020-08-14 12:58:34 +02:00
().into()
} else {
array.remove(len as usize)
2020-08-14 12:58:34 +02:00
}
}
pub fn clear(array: &mut Array) {
array.clear();
2020-08-14 12:58:34 +02:00
}
pub fn truncate(array: &mut Array, len: INT) {
2020-08-14 12:58:34 +02:00
if len >= 0 {
array.truncate(len as usize);
2020-08-14 12:58:34 +02:00
} else {
array.clear();
2020-08-14 12:58:34 +02:00
}
}
pub fn chop(array: &mut Array, len: INT) {
if len as usize >= array.len() {
2020-10-13 08:39:49 +02:00
} else if len >= 0 {
array.drain(0..array.len() - len as usize);
2020-10-13 08:39:49 +02:00
} else {
array.clear();
2020-10-13 08:39:49 +02:00
}
}
pub fn reverse(array: &mut Array) {
array.reverse();
2020-09-24 04:51:21 +02:00
}
pub fn splice(array: &mut Array, start: INT, len: INT, replace: Array) {
2020-10-13 04:57:29 +02:00
let start = if start < 0 {
let arr_len = array.len();
start
.checked_abs()
.map_or(0, |n| arr_len - (n as usize).min(arr_len))
} else if start as usize >= array.len() {
array.extend(replace.into_iter());
return;
2020-10-13 04:57:29 +02:00
} else {
start as usize
};
let len = if len < 0 {
0
} else if len as usize > array.len() - start {
array.len() - start
2020-10-13 04:57:29 +02:00
} else {
len as usize
};
array.splice(start..start + len, replace.into_iter());
2020-10-13 04:57:29 +02:00
}
pub fn extract(array: &mut Array, start: INT, len: INT) -> Array {
2020-10-13 08:39:49 +02:00
let start = if start < 0 {
let arr_len = array.len();
start
.checked_abs()
.map_or(0, |n| arr_len - (n as usize).min(arr_len))
} else if start as usize >= array.len() {
return Default::default();
2020-10-13 08:39:49 +02:00
} else {
start as usize
};
let len = if len < 0 {
0
} else if len as usize > array.len() - start {
array.len() - start
2020-10-13 08:39:49 +02:00
} else {
len as usize
};
array[start..start + len].iter().cloned().collect()
2020-10-13 08:39:49 +02:00
}
#[rhai_fn(name = "extract")]
pub fn extract_tail(array: &mut Array, start: INT) -> Array {
2020-10-13 08:39:49 +02:00
let start = if start < 0 {
let arr_len = array.len();
start
.checked_abs()
.map_or(0, |n| arr_len - (n as usize).min(arr_len))
} else if start as usize >= array.len() {
return Default::default();
2020-10-13 08:39:49 +02:00
} else {
start as usize
};
array[start..].iter().cloned().collect()
2020-10-13 08:39:49 +02:00
}
2021-02-23 04:57:50 +01:00
#[rhai_fn(name = "split")]
pub fn split_at(array: &mut Array, start: INT) -> Array {
if start <= 0 {
if let Some(n) = start.checked_abs() {
if n as usize > array.len() {
mem::take(array)
} else {
let mut result: Array = Default::default();
result.extend(array.drain(array.len() - n as usize..));
result
}
} else {
mem::take(array)
}
2021-02-23 04:57:50 +01:00
} else if start as usize >= array.len() {
Default::default()
} else {
let mut result: Array = Default::default();
result.extend(array.drain(start as usize..));
result
}
}
2021-03-09 06:16:05 +01:00
#[rhai_fn(return_raw, pure)]
pub fn map(
2020-11-02 04:04:45 +01:00
ctx: NativeCallContext,
array: &mut Array,
mapper: FnPtr,
2021-03-22 04:18:09 +01:00
) -> Result<Array, Box<EvalAltResult>> {
2021-03-23 05:13:53 +01:00
let mut ar = Array::with_capacity(array.len());
for (i, item) in array.iter().enumerate() {
ar.push(
mapper
.call_dynamic(&ctx, None, [item.clone()])
.or_else(|err| match *err {
EvalAltResult::ErrorFunctionNotFound(fn_sig, _)
if fn_sig.starts_with(mapper.fn_name()) =>
{
mapper.call_dynamic(&ctx, None, [item.clone(), (i as INT).into()])
}
_ => Err(err),
})
.map_err(|err| {
Box::new(EvalAltResult::ErrorInFunctionCall(
"map".to_string(),
2020-12-30 14:12:51 +01:00
ctx.source().unwrap_or("").to_string(),
err,
2020-11-20 09:52:28 +01:00
Position::NONE,
))
})?,
);
}
2020-10-18 07:18:12 +02:00
2021-03-22 04:18:09 +01:00
Ok(ar)
2020-10-18 07:18:12 +02:00
}
2021-03-09 06:16:05 +01:00
#[rhai_fn(return_raw, pure)]
pub fn filter(
2020-11-02 04:04:45 +01:00
ctx: NativeCallContext,
array: &mut Array,
filter: FnPtr,
2021-03-22 04:18:09 +01:00
) -> Result<Array, Box<EvalAltResult>> {
2021-03-23 05:13:53 +01:00
let mut ar = Array::new();
for (i, item) in array.iter().enumerate() {
if filter
.call_dynamic(&ctx, None, [item.clone()])
.or_else(|err| match *err {
EvalAltResult::ErrorFunctionNotFound(fn_sig, _)
if fn_sig.starts_with(filter.fn_name()) =>
{
filter.call_dynamic(&ctx, None, [item.clone(), (i as INT).into()])
}
_ => Err(err),
})
.map_err(|err| {
Box::new(EvalAltResult::ErrorInFunctionCall(
"filter".to_string(),
2020-12-30 14:12:51 +01:00
ctx.source().unwrap_or("").to_string(),
err,
2020-11-20 09:52:28 +01:00
Position::NONE,
))
})?
.as_bool()
.unwrap_or(false)
{
ar.push(item.clone());
}
}
2020-08-14 12:58:34 +02:00
2021-03-22 04:18:09 +01:00
Ok(ar)
}
2021-03-09 06:16:05 +01:00
#[rhai_fn(return_raw, pure)]
pub fn contains(
ctx: NativeCallContext,
array: &mut Array,
value: Dynamic,
2021-03-22 04:18:09 +01:00
) -> Result<bool, Box<EvalAltResult>> {
for item in array.iter_mut() {
2021-03-09 06:16:05 +01:00
if ctx
.call_fn_dynamic_raw(OP_EQUALS, true, &mut [item, &mut value.clone()])
2021-03-09 06:16:05 +01:00
.or_else(|err| match *err {
EvalAltResult::ErrorFunctionNotFound(ref fn_sig, _)
if fn_sig.starts_with(OP_EQUALS) =>
{
if item.type_id() == value.type_id() {
// No default when comparing same type
Err(err)
} else {
Ok(Dynamic::FALSE)
}
}
_ => Err(err),
})?
.as_bool()
.unwrap_or(false)
{
2021-03-22 04:18:09 +01:00
return Ok(true);
2021-03-09 06:16:05 +01:00
}
}
2021-03-22 04:18:09 +01:00
Ok(false)
2021-03-09 06:16:05 +01:00
}
#[rhai_fn(return_raw, pure)]
2020-11-08 16:00:37 +01:00
pub fn index_of(
2021-03-09 06:16:05 +01:00
ctx: NativeCallContext,
array: &mut Array,
value: Dynamic,
2021-03-22 04:18:09 +01:00
) -> Result<INT, Box<EvalAltResult>> {
index_of_starting_from(ctx, array, value, 0)
}
#[rhai_fn(name = "index_of", return_raw, pure)]
pub fn index_of_starting_from(
ctx: NativeCallContext,
array: &mut Array,
value: Dynamic,
start: INT,
) -> Result<INT, Box<EvalAltResult>> {
let start = if start < 0 {
let arr_len = array.len();
start
.checked_abs()
.map_or(0, |n| arr_len - (n as usize).min(arr_len))
} else if start as usize >= array.len() {
return Ok(-1);
} else {
start as usize
};
for (i, item) in array.iter_mut().enumerate().skip(start) {
2021-03-09 06:16:05 +01:00
if ctx
.call_fn_dynamic_raw(OP_EQUALS, true, &mut [item, &mut value.clone()])
2021-03-09 06:16:05 +01:00
.or_else(|err| match *err {
EvalAltResult::ErrorFunctionNotFound(ref fn_sig, _)
if fn_sig.starts_with(OP_EQUALS) =>
{
if item.type_id() == value.type_id() {
// No default when comparing same type
Err(err)
} else {
Ok(Dynamic::FALSE)
}
}
_ => Err(err),
})?
.as_bool()
.unwrap_or(false)
{
2021-03-22 04:18:09 +01:00
return Ok(i as INT);
2021-03-09 06:16:05 +01:00
}
}
2021-03-22 04:18:09 +01:00
Ok(-1 as INT)
2021-03-09 06:16:05 +01:00
}
#[rhai_fn(name = "index_of", return_raw, pure)]
pub fn index_of_filter(
2020-11-08 16:00:37 +01:00
ctx: NativeCallContext,
array: &mut Array,
2020-11-08 16:00:37 +01:00
filter: FnPtr,
2021-03-22 04:18:09 +01:00
) -> Result<INT, Box<EvalAltResult>> {
index_of_filter_starting_from(ctx, array, filter, 0)
}
#[rhai_fn(name = "index_of", return_raw, pure)]
pub fn index_of_filter_starting_from(
ctx: NativeCallContext,
array: &mut Array,
filter: FnPtr,
start: INT,
) -> Result<INT, Box<EvalAltResult>> {
let start = if start < 0 {
let arr_len = array.len();
start
.checked_abs()
.map_or(0, |n| arr_len - (n as usize).min(arr_len))
} else if start as usize >= array.len() {
return Ok(-1);
} else {
start as usize
};
for (i, item) in array.iter().enumerate().skip(start) {
2020-11-08 16:00:37 +01:00
if filter
.call_dynamic(&ctx, None, [item.clone()])
2020-11-08 16:00:37 +01:00
.or_else(|err| match *err {
EvalAltResult::ErrorFunctionNotFound(fn_sig, _)
if fn_sig.starts_with(filter.fn_name()) =>
{
filter.call_dynamic(&ctx, None, [item.clone(), (i as INT).into()])
2020-11-08 16:00:37 +01:00
}
_ => Err(err),
})
.map_err(|err| {
Box::new(EvalAltResult::ErrorInFunctionCall(
2020-11-11 06:25:45 +01:00
"index_of".to_string(),
2020-12-30 14:12:51 +01:00
ctx.source().unwrap_or("").to_string(),
2020-11-08 16:00:37 +01:00
err,
2020-11-20 09:52:28 +01:00
Position::NONE,
2020-11-08 16:00:37 +01:00
))
})?
.as_bool()
.unwrap_or(false)
{
2021-03-22 04:18:09 +01:00
return Ok(i as INT);
2020-11-08 16:00:37 +01:00
}
}
2021-03-22 04:18:09 +01:00
Ok(-1 as INT)
2020-11-08 16:00:37 +01:00
}
2021-03-09 06:16:05 +01:00
#[rhai_fn(return_raw, pure)]
pub fn some(
2020-11-02 04:04:45 +01:00
ctx: NativeCallContext,
array: &mut Array,
filter: FnPtr,
2021-03-22 04:18:09 +01:00
) -> Result<bool, Box<EvalAltResult>> {
for (i, item) in array.iter().enumerate() {
if filter
.call_dynamic(&ctx, None, [item.clone()])
.or_else(|err| match *err {
EvalAltResult::ErrorFunctionNotFound(fn_sig, _)
if fn_sig.starts_with(filter.fn_name()) =>
{
filter.call_dynamic(&ctx, None, [item.clone(), (i as INT).into()])
}
_ => Err(err),
})
.map_err(|err| {
Box::new(EvalAltResult::ErrorInFunctionCall(
2020-11-11 06:25:45 +01:00
"some".to_string(),
2020-12-30 14:12:51 +01:00
ctx.source().unwrap_or("").to_string(),
err,
2020-11-20 09:52:28 +01:00
Position::NONE,
))
})?
.as_bool()
.unwrap_or(false)
{
2021-03-22 04:18:09 +01:00
return Ok(true);
}
2020-06-30 12:34:32 +02:00
}
2020-10-12 16:49:51 +02:00
2021-03-22 04:18:09 +01:00
Ok(false)
}
2021-03-09 06:16:05 +01:00
#[rhai_fn(return_raw, pure)]
pub fn all(
2020-11-02 04:04:45 +01:00
ctx: NativeCallContext,
array: &mut Array,
filter: FnPtr,
2021-03-22 04:18:09 +01:00
) -> Result<bool, Box<EvalAltResult>> {
for (i, item) in array.iter().enumerate() {
if !filter
.call_dynamic(&ctx, None, [item.clone()])
2020-10-12 16:49:51 +02:00
.or_else(|err| match *err {
EvalAltResult::ErrorFunctionNotFound(fn_sig, _)
if fn_sig.starts_with(filter.fn_name()) =>
{
filter.call_dynamic(&ctx, None, [item.clone(), (i as INT).into()])
2020-10-12 16:49:51 +02:00
}
_ => Err(err),
})
.map_err(|err| {
Box::new(EvalAltResult::ErrorInFunctionCall(
2020-11-11 06:25:45 +01:00
"all".to_string(),
2020-12-30 14:12:51 +01:00
ctx.source().unwrap_or("").to_string(),
2020-10-12 16:49:51 +02:00
err,
2020-11-20 09:52:28 +01:00
Position::NONE,
2020-10-12 16:49:51 +02:00
))
})?
.as_bool()
.unwrap_or(false)
{
2021-03-22 04:18:09 +01:00
return Ok(false);
}
2020-10-12 16:49:51 +02:00
}
2021-03-22 04:18:09 +01:00
Ok(true)
2020-10-13 04:57:29 +02:00
}
2021-03-09 06:16:05 +01:00
#[rhai_fn(return_raw, pure)]
pub fn reduce(
2020-11-02 04:04:45 +01:00
ctx: NativeCallContext,
array: &mut Array,
reducer: FnPtr,
) -> Result<Dynamic, Box<EvalAltResult>> {
2021-03-22 04:18:09 +01:00
let mut result = Dynamic::UNIT;
for (i, item) in array.iter().enumerate() {
result = reducer
.call_dynamic(&ctx, None, [result.clone(), item.clone()])
.or_else(|err| match *err {
EvalAltResult::ErrorFunctionNotFound(fn_sig, _)
if fn_sig.starts_with(reducer.fn_name()) =>
{
reducer.call_dynamic(&ctx, None, [result, item.clone(), (i as INT).into()])
}
_ => Err(err),
})
.map_err(|err| {
Box::new(EvalAltResult::ErrorInFunctionCall(
"reduce".to_string(),
2020-12-30 14:12:51 +01:00
ctx.source().unwrap_or("").to_string(),
err,
2020-11-20 09:52:28 +01:00
Position::NONE,
))
})?;
2020-10-13 04:57:29 +02:00
}
Ok(result)
2020-10-12 16:49:51 +02:00
}
2021-03-09 06:16:05 +01:00
#[rhai_fn(name = "reduce", return_raw, pure)]
pub fn reduce_with_initial(
2020-11-02 04:04:45 +01:00
ctx: NativeCallContext,
array: &mut Array,
reducer: FnPtr,
2021-03-22 04:18:09 +01:00
initial: Dynamic,
) -> Result<Dynamic, Box<EvalAltResult>> {
2021-03-22 04:18:09 +01:00
let mut result = initial;
for (i, item) in array.iter().enumerate() {
result = reducer
.call_dynamic(&ctx, None, [result.clone(), item.clone()])
.or_else(|err| match *err {
EvalAltResult::ErrorFunctionNotFound(fn_sig, _)
if fn_sig.starts_with(reducer.fn_name()) =>
{
reducer.call_dynamic(&ctx, None, [result, item.clone(), (i as INT).into()])
}
_ => Err(err),
})
.map_err(|err| {
Box::new(EvalAltResult::ErrorInFunctionCall(
"reduce".to_string(),
2020-12-30 14:12:51 +01:00
ctx.source().unwrap_or("").to_string(),
err,
2020-11-20 09:52:28 +01:00
Position::NONE,
))
})?;
}
2020-10-12 16:49:51 +02:00
Ok(result)
2020-10-14 15:27:31 +02:00
}
2021-03-09 06:16:05 +01:00
#[rhai_fn(return_raw, pure)]
pub fn reduce_rev(
2020-11-02 04:04:45 +01:00
ctx: NativeCallContext,
array: &mut Array,
reducer: FnPtr,
) -> Result<Dynamic, Box<EvalAltResult>> {
2021-03-22 04:18:09 +01:00
let mut result = Dynamic::UNIT;
for (i, item) in array.iter().enumerate().rev() {
result = reducer
.call_dynamic(&ctx, None, [result.clone(), item.clone()])
.or_else(|err| match *err {
EvalAltResult::ErrorFunctionNotFound(fn_sig, _)
if fn_sig.starts_with(reducer.fn_name()) =>
{
reducer.call_dynamic(&ctx, None, [result, item.clone(), (i as INT).into()])
}
_ => Err(err),
})
.map_err(|err| {
Box::new(EvalAltResult::ErrorInFunctionCall(
2020-11-11 06:25:45 +01:00
"reduce_rev".to_string(),
2020-12-30 14:12:51 +01:00
ctx.source().unwrap_or("").to_string(),
err,
2020-11-20 09:52:28 +01:00
Position::NONE,
))
})?;
}
2020-10-14 15:27:31 +02:00
Ok(result)
2020-10-14 15:27:31 +02:00
}
2021-03-09 06:16:05 +01:00
#[rhai_fn(name = "reduce_rev", return_raw, pure)]
pub fn reduce_rev_with_initial(
2020-11-02 04:04:45 +01:00
ctx: NativeCallContext,
array: &mut Array,
reducer: FnPtr,
2021-03-22 04:18:09 +01:00
initial: Dynamic,
) -> Result<Dynamic, Box<EvalAltResult>> {
2021-03-22 04:18:09 +01:00
let mut result = initial;
for (i, item) in array.iter().enumerate().rev() {
result = reducer
.call_dynamic(&ctx, None, [result.clone(), item.clone()])
.or_else(|err| match *err {
EvalAltResult::ErrorFunctionNotFound(fn_sig, _)
if fn_sig.starts_with(reducer.fn_name()) =>
{
reducer.call_dynamic(&ctx, None, [result, item.clone(), (i as INT).into()])
}
_ => Err(err),
})
.map_err(|err| {
Box::new(EvalAltResult::ErrorInFunctionCall(
2020-11-11 06:25:45 +01:00
"reduce_rev".to_string(),
2020-12-30 14:12:51 +01:00
ctx.source().unwrap_or("").to_string(),
err,
2020-11-20 09:52:28 +01:00
Position::NONE,
))
})?;
}
2020-10-14 15:27:31 +02:00
Ok(result)
2020-10-13 04:57:29 +02:00
}
#[rhai_fn(return_raw)]
pub fn sort(
2020-11-02 04:04:45 +01:00
ctx: NativeCallContext,
array: &mut Array,
comparer: FnPtr,
2021-03-22 04:18:09 +01:00
) -> Result<(), Box<EvalAltResult>> {
array.sort_by(|x, y| {
comparer
.call_dynamic(&ctx, 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
}
})
});
2020-10-13 04:57:29 +02:00
2021-03-22 04:18:09 +01:00
Ok(())
}
#[rhai_fn(return_raw)]
pub fn drain(
2020-11-02 04:04:45 +01:00
ctx: NativeCallContext,
array: &mut Array,
filter: FnPtr,
2021-03-22 04:18:09 +01:00
) -> Result<Array, Box<EvalAltResult>> {
2021-03-23 05:13:53 +01:00
let mut drained = Array::with_capacity(array.len());
2020-10-13 04:57:29 +02:00
let mut i = 0;
let mut x = 0;
2020-10-18 07:18:12 +02:00
while x < array.len() {
if filter
.call_dynamic(&ctx, None, [array[x].clone()])
.or_else(|err| match *err {
EvalAltResult::ErrorFunctionNotFound(fn_sig, _)
if fn_sig.starts_with(filter.fn_name()) =>
{
filter.call_dynamic(&ctx, None, [array[x].clone(), (i as INT).into()])
}
_ => Err(err),
})
.map_err(|err| {
Box::new(EvalAltResult::ErrorInFunctionCall(
2020-11-11 06:25:45 +01:00
"drain".to_string(),
2020-12-30 14:12:51 +01:00
ctx.source().unwrap_or("").to_string(),
err,
2020-11-20 09:52:28 +01:00
Position::NONE,
))
})?
.as_bool()
.unwrap_or(false)
{
drained.push(array.remove(x));
} else {
x += 1;
}
i += 1;
}
2020-10-18 07:18:12 +02:00
2021-03-22 04:18:09 +01:00
Ok(drained)
}
#[rhai_fn(name = "drain")]
pub fn drain_range(array: &mut Array, start: INT, len: INT) -> Array {
let start = if start < 0 {
let arr_len = array.len();
start
.checked_abs()
.map_or(0, |n| arr_len - (n as usize).min(arr_len))
} else if start as usize >= array.len() {
return Default::default();
} else {
start as usize
};
2020-10-18 07:18:12 +02:00
let len = if len < 0 {
0
} else if len as usize > array.len() - start {
array.len() - start
} else {
len as usize
};
2020-10-18 07:18:12 +02:00
array.drain(start..start + len).collect()
2020-10-18 07:18:12 +02:00
}
#[rhai_fn(return_raw)]
pub fn retain(
2020-11-02 04:04:45 +01:00
ctx: NativeCallContext,
array: &mut Array,
filter: FnPtr,
2021-03-22 04:18:09 +01:00
) -> Result<Array, Box<EvalAltResult>> {
2021-03-23 05:13:53 +01:00
let mut drained = Array::new();
2020-10-18 07:18:12 +02:00
let mut i = 0;
let mut x = 0;
2020-10-18 07:18:12 +02:00
while x < array.len() {
if !filter
.call_dynamic(&ctx, None, [array[x].clone()])
.or_else(|err| match *err {
EvalAltResult::ErrorFunctionNotFound(fn_sig, _)
if fn_sig.starts_with(filter.fn_name()) =>
{
filter.call_dynamic(&ctx, None, [array[x].clone(), (i as INT).into()])
}
_ => Err(err),
})
.map_err(|err| {
Box::new(EvalAltResult::ErrorInFunctionCall(
2020-11-11 06:25:45 +01:00
"retain".to_string(),
2020-12-30 14:12:51 +01:00
ctx.source().unwrap_or("").to_string(),
err,
2020-11-20 09:52:28 +01:00
Position::NONE,
))
})?
.as_bool()
.unwrap_or(false)
{
drained.push(array.remove(x));
} else {
x += 1;
}
i += 1;
}
2021-03-22 04:18:09 +01:00
Ok(drained)
}
#[rhai_fn(name = "retain")]
pub fn retain_range(array: &mut Array, start: INT, len: INT) -> Array {
let start = if start < 0 {
let arr_len = array.len();
start
.checked_abs()
.map_or(0, |n| arr_len - (n as usize).min(arr_len))
} else if start as usize >= array.len() {
return mem::take(array);
} else {
start as usize
};
2020-10-18 07:18:12 +02:00
let len = if len < 0 {
0
} else if len as usize > array.len() - start {
array.len() - start
} else {
len as usize
};
2020-10-18 07:18:12 +02:00
let mut drained = array.drain(..start).collect::<Array>();
drained.extend(array.drain(len..));
2020-10-18 07:18:12 +02:00
drained
2020-10-18 07:18:12 +02:00
}
2021-03-09 06:16:05 +01:00
#[rhai_fn(name = "==", return_raw, pure)]
2020-11-08 16:00:37 +01:00
pub fn equals(
2020-11-30 04:20:51 +01:00
ctx: NativeCallContext,
array: &mut Array,
mut array2: Array,
2021-03-22 04:18:09 +01:00
) -> Result<bool, Box<EvalAltResult>> {
if array.len() != array2.len() {
2021-03-22 04:18:09 +01:00
return Ok(false);
2020-11-08 16:00:37 +01:00
}
if array.is_empty() {
2021-03-22 04:18:09 +01:00
return Ok(true);
2020-11-08 16:00:37 +01:00
}
for (a1, a2) in array.iter_mut().zip(array2.iter_mut()) {
2021-03-09 06:16:05 +01:00
if !ctx
2021-03-01 08:39:49 +01:00
.call_fn_dynamic_raw(OP_EQUALS, true, &mut [a1, a2])
2021-03-09 06:16:05 +01:00
.or_else(|err| match *err {
EvalAltResult::ErrorFunctionNotFound(ref fn_sig, _)
if fn_sig.starts_with(OP_EQUALS) =>
{
if a1.type_id() == a2.type_id() {
// No default when comparing same type
Err(err)
} else {
Ok(Dynamic::FALSE)
}
}
_ => Err(err),
})?
.as_bool()
.unwrap_or(false)
{
2021-03-22 04:18:09 +01:00
return Ok(false);
2020-11-08 16:00:37 +01:00
}
}
2021-03-22 04:18:09 +01:00
Ok(true)
2020-11-08 16:00:37 +01:00
}
2021-03-09 06:16:05 +01:00
#[rhai_fn(name = "!=", return_raw, pure)]
2020-11-08 16:00:37 +01:00
pub fn not_equals(
ctx: NativeCallContext,
array: &mut Array,
array2: Array,
2021-03-22 04:18:09 +01:00
) -> Result<bool, Box<EvalAltResult>> {
equals(ctx, array, array2).map(|r| !r)
2020-11-08 16:00:37 +01:00
}
2020-10-18 07:18:12 +02:00
}