rhai/src/packages/array_basic.rs

1040 lines
32 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;
use crate::eval::calc_offset_len;
2020-08-14 12:58:34 +02:00
use crate::plugin::*;
2021-12-15 05:06:17 +01:00
use crate::{
2021-12-27 05:27:31 +01:00
def_package, Array, Dynamic, ExclusiveRange, FnPtr, InclusiveRange, NativeCallContext,
Position, RhaiResultOf, ERR, INT,
2021-12-15 05:06:17 +01:00
};
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
2021-12-20 04:42:39 +01:00
def_package! {
/// Package of basic array utilities.
crate::BasicArrayPackage => |lib| {
lib.standard = true;
2021-12-20 04:42:39 +01:00
combine_with_exported_module!(lib, "array", array_functions);
2020-09-21 10:15:52 +02:00
2021-12-20 04:42:39 +01:00
// Register array iterator
lib.set_iterable::<Array>();
}
}
2020-08-14 12:58:34 +02:00
#[export_module]
2021-12-22 12:59:48 +01:00
pub 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
}
pub fn push(array: &mut Array, item: Dynamic) {
array.push(item);
}
2021-12-22 12:59:48 +01:00
pub fn append(array1: &mut Array, array2: Array) {
if !array2.is_empty() {
if array1.is_empty() {
*array1 = array2;
} else {
2021-12-22 12:59:48 +01:00
array1.extend(array2);
}
}
2020-08-14 12:58:34 +02:00
}
#[rhai_fn(name = "+")]
2021-12-22 12:59:48 +01:00
pub fn concat(array1: Array, array2: Array) -> Array {
if !array2.is_empty() {
if array1.is_empty() {
array2
} else {
2021-12-22 12:59:48 +01:00
let mut array = array1;
array.extend(array2);
array
}
2021-12-22 12:59:48 +01:00
} else {
array1
}
}
pub fn insert(array: &mut Array, index: INT, item: Dynamic) {
if array.is_empty() {
array.push(item);
return;
}
let (index, _) = calc_offset_len(array.len(), index, 0);
if index >= array.len() {
array.push(item);
} else {
array.insert(index, item);
}
}
#[rhai_fn(return_raw)]
pub fn pad(
2021-11-23 11:10:01 +01:00
ctx: NativeCallContext,
array: &mut Array,
len: INT,
item: Dynamic,
2021-12-25 16:49:14 +01:00
) -> RhaiResultOf<()> {
2022-01-06 08:30:17 +01:00
if len <= 0 || (len as usize) <= array.len() {
return Ok(());
}
2021-11-23 11:10:01 +01:00
let _ctx = ctx;
2022-01-06 08:30:17 +01:00
let len = len as usize;
2021-11-23 11:10:01 +01:00
// Check if array will be over max size limit
#[cfg(not(feature = "unchecked"))]
2022-01-06 08:30:17 +01:00
if _ctx.engine().max_array_size() > 0 && len > _ctx.engine().max_array_size() {
2021-12-27 05:27:31 +01:00
return Err(ERR::ErrorDataTooLarge("Size of array".to_string(), Position::NONE).into());
}
2022-01-06 08:30:17 +01:00
#[cfg(not(feature = "unchecked"))]
let check_sizes = match item.0 {
2022-01-06 15:10:16 +01:00
crate::types::dynamic::Union::Array(_, _, _)
| crate::types::dynamic::Union::Str(_, _, _) => true,
2022-01-06 16:29:11 +01:00
#[cfg(not(feature = "no_object"))]
2022-01-06 15:10:16 +01:00
crate::types::dynamic::Union::Map(_, _, _) => true,
2022-01-06 08:30:17 +01:00
_ => false,
};
#[cfg(feature = "unchecked")]
let check_sizes = false;
if check_sizes {
2022-01-13 15:05:07 +01:00
let mut arr_len = array.len();
let mut arr = Dynamic::from_array(mem::take(array));
2022-01-06 08:30:17 +01:00
2022-01-13 15:05:07 +01:00
#[cfg(not(feature = "unchecked"))]
let (mut a1, mut m1, mut s1) = Engine::calc_data_sizes(&arr, true);
#[cfg(not(feature = "unchecked"))]
let (a2, m2, s2) = Engine::calc_data_sizes(&item, true);
2022-01-06 08:30:17 +01:00
2022-01-13 15:05:07 +01:00
{
let mut guard = arr.write_lock::<Array>().unwrap();
while arr_len < len {
#[cfg(not(feature = "unchecked"))]
{
a1 += a2;
m1 += m2;
s1 += s2;
_ctx.engine()
.raise_err_if_over_data_size_limit((a1, m1, s1), Position::NONE)?;
}
guard.push(item.clone());
arr_len += 1;
}
2022-01-06 08:30:17 +01:00
}
*array = arr.into_array().unwrap();
} else {
array.resize(len, item);
}
2021-03-22 04:18:09 +01:00
Ok(())
}
pub fn pop(array: &mut Array) -> Dynamic {
if array.is_empty() {
Dynamic::UNIT
} else {
array.pop().unwrap_or_else(|| Dynamic::UNIT)
}
2020-08-14 12:58:34 +02:00
}
pub fn shift(array: &mut Array) -> Dynamic {
if array.is_empty() {
Dynamic::UNIT
2020-08-14 12:58:34 +02:00
} else {
array.remove(0)
2020-08-14 12:58:34 +02:00
}
}
pub fn remove(array: &mut Array, index: INT) -> Dynamic {
if index < 0 || (index as usize) >= array.len() {
Dynamic::UNIT
2020-08-14 12:58:34 +02:00
} else {
array.remove(index as usize)
2020-08-14 12:58:34 +02:00
}
}
pub fn clear(array: &mut Array) {
if !array.is_empty() {
array.clear();
}
2020-08-14 12:58:34 +02:00
}
pub fn truncate(array: &mut Array, len: INT) {
if !array.is_empty() {
if len >= 0 {
array.truncate(len as usize);
} else {
array.clear();
}
2020-08-14 12:58:34 +02:00
}
}
pub fn chop(array: &mut Array, len: INT) {
if !array.is_empty() && len as usize >= array.len() {
if len >= 0 {
array.drain(0..array.len() - len as usize);
} else {
array.clear();
}
2020-10-13 08:39:49 +02:00
}
}
pub fn reverse(array: &mut Array) {
if !array.is_empty() {
array.reverse();
}
2020-09-24 04:51:21 +02:00
}
2021-12-15 05:06:17 +01:00
#[rhai_fn(name = "splice")]
pub fn splice_range(array: &mut Array, range: ExclusiveRange, replace: Array) {
let start = INT::max(range.start, 0);
let end = INT::max(range.end, start);
splice(array, start, end - start, replace)
}
#[rhai_fn(name = "splice")]
pub fn splice_inclusive_range(array: &mut Array, range: InclusiveRange, replace: Array) {
let start = INT::max(*range.start(), 0);
let end = INT::max(*range.end(), start);
splice(array, start, end - start + 1, replace)
}
pub fn splice(array: &mut Array, start: INT, len: INT, replace: Array) {
if array.is_empty() {
*array = replace;
return;
}
let (start, len) = calc_offset_len(array.len(), start, len);
2020-10-13 04:57:29 +02:00
if start >= array.len() {
array.extend(replace);
2020-10-13 04:57:29 +02:00
} else {
array.splice(start..start + len, replace);
}
2020-10-13 04:57:29 +02:00
}
2021-12-15 05:06:17 +01:00
#[rhai_fn(name = "extract")]
pub fn extract_range(array: &mut Array, range: ExclusiveRange) -> Array {
let start = INT::max(range.start, 0);
let end = INT::max(range.end, start);
extract(array, start, end - start)
}
#[rhai_fn(name = "extract")]
pub fn extract_inclusive_range(array: &mut Array, range: InclusiveRange) -> Array {
let start = INT::max(*range.start(), 0);
let end = INT::max(*range.end(), start);
extract(array, start, end - start + 1)
}
pub fn extract(array: &mut Array, start: INT, len: INT) -> Array {
if array.is_empty() || len <= 0 {
return Array::new();
}
let (start, len) = calc_offset_len(array.len(), start, len);
2020-10-13 08:39:49 +02:00
if len == 0 {
Array::new()
} else {
array[start..start + len].to_vec()
}
2020-10-13 08:39:49 +02:00
}
#[rhai_fn(name = "extract")]
pub fn extract_tail(array: &mut Array, start: INT) -> Array {
2021-12-12 10:26:15 +01:00
extract(array, start, INT::MAX)
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 array.is_empty() {
return Array::new();
}
let (start, len) = calc_offset_len(array.len(), start, INT::MAX);
if start == 0 {
if len >= array.len() {
mem::take(array)
} else {
let mut result = Array::new();
result.extend(array.drain(array.len() - len..));
result
}
} else if start >= array.len() {
Array::new()
2021-02-23 04:57:50 +01:00
} else {
2021-09-11 13:40:40 +02:00
let mut result = Array::new();
2021-02-23 04:57:50 +01:00
result.extend(array.drain(start as usize..));
result
}
}
2021-10-21 13:04:53 +02:00
#[rhai_fn(return_raw, pure)]
2021-12-25 16:49:14 +01:00
pub fn map(ctx: NativeCallContext, array: &mut Array, mapper: FnPtr) -> RhaiResultOf<Array> {
if array.is_empty() {
2021-11-23 15:37:18 +01:00
return Ok(array.clone());
}
2021-03-23 05:13:53 +01:00
let mut ar = Array::with_capacity(array.len());
2021-11-23 15:37:18 +01:00
for (i, item) in array.iter().enumerate() {
ar.push(
mapper
2021-11-29 05:43:59 +01:00
.call_raw(&ctx, None, [item.clone()])
2021-11-23 15:37:18 +01:00
.or_else(|err| match *err {
2021-12-27 05:27:31 +01:00
ERR::ErrorFunctionNotFound(fn_sig, _)
2021-11-23 15:37:18 +01:00
if fn_sig.starts_with(mapper.fn_name()) =>
{
2021-11-29 05:43:59 +01:00
mapper.call_raw(&ctx, None, [item.clone(), (i as INT).into()])
2021-11-23 15:37:18 +01:00
}
_ => Err(err),
})
.map_err(|err| {
2021-12-27 05:27:31 +01:00
Box::new(ERR::ErrorInFunctionCall(
2021-10-21 13:04:53 +02:00
"map".to_string(),
ctx.source().unwrap_or("").to_string(),
err,
Position::NONE,
2021-11-23 15:37:18 +01:00
))
})?,
);
}
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-11-23 15:37:18 +01:00
#[rhai_fn(name = "map", return_raw, pure)]
pub fn map_with_fn_name(
ctx: NativeCallContext,
array: &mut Array,
2021-11-23 15:37:18 +01:00
mapper: &str,
2021-12-25 16:49:14 +01:00
) -> RhaiResultOf<Array> {
2021-11-23 15:37:18 +01:00
map(ctx, array, FnPtr::new(mapper)?)
}
2021-11-23 15:37:18 +01:00
#[rhai_fn(return_raw, pure)]
2021-12-27 04:43:11 +01:00
pub fn filter(ctx: NativeCallContext, array: &mut Array, filter: FnPtr) -> RhaiResultOf<Array> {
if array.is_empty() {
return Ok(array.clone());
}
2021-03-23 05:13:53 +01:00
let mut ar = Array::new();
2021-11-23 15:37:18 +01:00
for (i, item) in array.iter().enumerate() {
if filter
2021-11-29 05:43:59 +01:00
.call_raw(&ctx, None, [item.clone()])
2021-11-23 15:37:18 +01:00
.or_else(|err| match *err {
2021-12-27 05:27:31 +01:00
ERR::ErrorFunctionNotFound(fn_sig, _)
2021-11-23 15:37:18 +01:00
if fn_sig.starts_with(filter.fn_name()) =>
{
2021-11-29 05:43:59 +01:00
filter.call_raw(&ctx, None, [item.clone(), (i as INT).into()])
}
2021-11-23 15:37:18 +01:00
_ => Err(err),
})
.map_err(|err| {
2021-12-27 05:27:31 +01:00
Box::new(ERR::ErrorInFunctionCall(
2021-11-23 15:37:18 +01:00
"filter".to_string(),
ctx.source().unwrap_or("").to_string(),
err,
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-11-23 15:37:18 +01:00
#[rhai_fn(name = "filter", return_raw, pure)]
pub fn filter_with_fn_name(
ctx: NativeCallContext,
array: &mut Array,
filter_func: &str,
2021-12-25 16:49:14 +01:00
) -> RhaiResultOf<Array> {
2021-11-23 15:37:18 +01:00
filter(ctx, array, FnPtr::new(filter_func)?)
}
2021-03-09 06:16:05 +01:00
#[rhai_fn(return_raw, pure)]
pub fn contains(
ctx: NativeCallContext,
array: &mut Array,
value: Dynamic,
2021-12-25 16:49:14 +01:00
) -> RhaiResultOf<bool> {
if array.is_empty() {
return Ok(false);
}
for item in array.iter_mut() {
2021-03-09 06:16:05 +01:00
if ctx
.call_fn_raw(OP_EQUALS, true, false, &mut [item, &mut value.clone()])
2021-03-09 06:16:05 +01:00
.or_else(|err| match *err {
2021-12-27 05:27:31 +01:00
ERR::ErrorFunctionNotFound(ref fn_sig, _) if fn_sig.starts_with(OP_EQUALS) => {
2021-03-09 06:16:05 +01:00
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-12-25 16:49:14 +01:00
) -> RhaiResultOf<INT> {
if array.is_empty() {
Ok(-1)
} else {
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,
2021-12-25 16:49:14 +01:00
) -> RhaiResultOf<INT> {
if array.is_empty() {
return Ok(-1);
}
let (start, _) = calc_offset_len(array.len(), start, 0);
for (i, item) in array.iter_mut().enumerate().skip(start) {
2021-03-09 06:16:05 +01:00
if ctx
.call_fn_raw(OP_EQUALS, true, false, &mut [item, &mut value.clone()])
2021-03-09 06:16:05 +01:00
.or_else(|err| match *err {
2021-12-27 05:27:31 +01:00
ERR::ErrorFunctionNotFound(ref fn_sig, _) if fn_sig.starts_with(OP_EQUALS) => {
2021-03-09 06:16:05 +01:00
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_with_fn_name(
ctx: NativeCallContext,
array: &mut Array,
filter: &str,
2021-12-25 16:49:14 +01:00
) -> RhaiResultOf<INT> {
index_of_filter(ctx, array, FnPtr::new(filter)?)
}
#[rhai_fn(name = "index_of", return_raw, pure)]
2021-03-09 06:16:05 +01:00
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-12-25 16:49:14 +01:00
) -> RhaiResultOf<INT> {
if array.is_empty() {
Ok(-1)
} else {
index_of_filter_starting_from(ctx, array, filter, 0)
}
}
#[rhai_fn(name = "index_of", return_raw, pure)]
2021-10-21 13:04:53 +02:00
pub fn index_of_filter_starting_from(
ctx: NativeCallContext,
array: &mut Array,
2021-10-21 13:04:53 +02:00
filter: FnPtr,
start: INT,
2021-12-25 16:49:14 +01:00
) -> RhaiResultOf<INT> {
if array.is_empty() {
return Ok(-1);
}
let (start, _) = calc_offset_len(array.len(), start, 0);
2021-11-23 15:37:18 +01:00
for (i, item) in array.iter().enumerate().skip(start) {
if filter
2021-11-29 05:43:59 +01:00
.call_raw(&ctx, None, [item.clone()])
2021-11-23 15:37:18 +01:00
.or_else(|err| match *err {
2021-12-27 05:27:31 +01:00
ERR::ErrorFunctionNotFound(fn_sig, _)
2021-11-23 15:37:18 +01:00
if fn_sig.starts_with(filter.fn_name()) =>
2020-11-08 16:00:37 +01:00
{
2021-11-29 05:43:59 +01:00
filter.call_raw(&ctx, None, [item.clone(), (i as INT).into()])
2020-11-08 16:00:37 +01:00
}
2021-11-23 15:37:18 +01:00
_ => Err(err),
})
.map_err(|err| {
2021-12-27 05:27:31 +01:00
Box::new(ERR::ErrorInFunctionCall(
2021-11-23 15:37:18 +01:00
"index_of".to_string(),
ctx.source().unwrap_or("").to_string(),
err,
Position::NONE,
))
})?
.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-11-23 15:37:18 +01:00
#[rhai_fn(name = "index_of", return_raw, pure)]
pub fn index_of_with_fn_name_filter_starting_from(
ctx: NativeCallContext,
array: &mut Array,
2021-11-23 15:37:18 +01:00
filter: &str,
start: INT,
2021-12-25 16:49:14 +01:00
) -> RhaiResultOf<INT> {
2021-11-23 15:37:18 +01:00
index_of_filter_starting_from(ctx, array, FnPtr::new(filter)?, start)
}
2021-11-23 15:37:18 +01:00
#[rhai_fn(return_raw, pure)]
2021-12-25 16:49:14 +01:00
pub fn some(ctx: NativeCallContext, array: &mut Array, filter: FnPtr) -> RhaiResultOf<bool> {
if array.is_empty() {
return Ok(false);
}
2021-11-23 15:37:18 +01:00
for (i, item) in array.iter().enumerate() {
if filter
2021-11-29 05:43:59 +01:00
.call_raw(&ctx, None, [item.clone()])
2021-11-23 15:37:18 +01:00
.or_else(|err| match *err {
2021-12-27 05:27:31 +01:00
ERR::ErrorFunctionNotFound(fn_sig, _)
2021-11-23 15:37:18 +01:00
if fn_sig.starts_with(filter.fn_name()) =>
{
2021-11-29 05:43:59 +01:00
filter.call_raw(&ctx, None, [item.clone(), (i as INT).into()])
}
2021-11-23 15:37:18 +01:00
_ => Err(err),
})
.map_err(|err| {
2021-12-27 05:27:31 +01:00
Box::new(ERR::ErrorInFunctionCall(
2021-11-23 15:37:18 +01:00
"some".to_string(),
ctx.source().unwrap_or("").to_string(),
err,
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-11-23 15:37:18 +01:00
#[rhai_fn(name = "some", return_raw, pure)]
pub fn some_with_fn_name(
ctx: NativeCallContext,
array: &mut Array,
2021-11-23 15:37:18 +01:00
filter: &str,
2021-12-25 16:49:14 +01:00
) -> RhaiResultOf<bool> {
2021-11-23 15:37:18 +01:00
some(ctx, array, FnPtr::new(filter)?)
}
2021-11-23 15:37:18 +01:00
#[rhai_fn(return_raw, pure)]
2021-12-25 16:49:14 +01:00
pub fn all(ctx: NativeCallContext, array: &mut Array, filter: FnPtr) -> RhaiResultOf<bool> {
if array.is_empty() {
return Ok(true);
}
2021-11-23 15:37:18 +01:00
for (i, item) in array.iter().enumerate() {
if !filter
2021-11-29 05:43:59 +01:00
.call_raw(&ctx, None, [item.clone()])
2021-11-23 15:37:18 +01:00
.or_else(|err| match *err {
2021-12-27 05:27:31 +01:00
ERR::ErrorFunctionNotFound(fn_sig, _)
2021-11-23 15:37:18 +01:00
if fn_sig.starts_with(filter.fn_name()) =>
{
2021-11-29 05:43:59 +01:00
filter.call_raw(&ctx, None, [item.clone(), (i as INT).into()])
}
2021-11-23 15:37:18 +01:00
_ => Err(err),
})
.map_err(|err| {
2021-12-27 05:27:31 +01:00
Box::new(ERR::ErrorInFunctionCall(
2021-11-23 15:37:18 +01:00
"all".to_string(),
ctx.source().unwrap_or("").to_string(),
err,
Position::NONE,
))
})?
.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-11-23 15:37:18 +01:00
#[rhai_fn(name = "all", return_raw, pure)]
pub fn all_with_fn_name(
ctx: NativeCallContext,
array: &mut Array,
filter: &str,
2021-12-25 16:49:14 +01:00
) -> RhaiResultOf<bool> {
2021-11-23 15:37:18 +01:00
all(ctx, array, FnPtr::new(filter)?)
}
2021-10-21 11:59:54 +02:00
#[rhai_fn(return_raw)]
2021-12-25 16:49:14 +01:00
pub fn dedup(ctx: NativeCallContext, array: &mut Array) -> RhaiResultOf<()> {
2021-10-21 11:59:54 +02:00
dedup_with_fn_name(ctx, array, OP_EQUALS)
}
#[rhai_fn(name = "dedup", return_raw)]
pub fn dedup_by_comparer(
ctx: NativeCallContext,
array: &mut Array,
comparer: FnPtr,
2021-12-25 16:49:14 +01:00
) -> RhaiResultOf<()> {
2021-10-21 11:59:54 +02:00
if array.is_empty() {
return Ok(());
}
array.dedup_by(|x, y| {
2021-11-23 15:37:18 +01:00
comparer
2021-11-29 05:43:59 +01:00
.call_raw(&ctx, None, [x.clone(), y.clone()])
2021-10-21 11:59:54 +02:00
.unwrap_or_else(|_| Dynamic::FALSE)
.as_bool()
.unwrap_or(false)
});
Ok(())
}
2021-11-23 15:37:18 +01:00
#[rhai_fn(name = "dedup", return_raw)]
fn dedup_with_fn_name(
ctx: NativeCallContext,
array: &mut Array,
comparer: &str,
2021-12-25 16:49:14 +01:00
) -> RhaiResultOf<()> {
2021-11-23 15:37:18 +01:00
dedup_by_comparer(ctx, array, FnPtr::new(comparer)?)
}
2021-03-09 06:16:05 +01:00
#[rhai_fn(return_raw, pure)]
2021-12-25 16:49:14 +01:00
pub fn reduce(ctx: NativeCallContext, array: &mut Array, reducer: FnPtr) -> RhaiResult {
2021-11-23 15:37:18 +01:00
reduce_with_initial(ctx, array, reducer, Dynamic::UNIT)
2020-10-12 16:49:51 +02:00
}
2021-03-09 06:16:05 +01:00
#[rhai_fn(name = "reduce", return_raw, pure)]
2021-10-21 13:04:53 +02:00
pub fn reduce_with_fn_name(
ctx: NativeCallContext,
array: &mut Array,
reducer: &str,
2021-12-25 16:49:14 +01:00
) -> RhaiResult {
2021-11-23 15:37:18 +01:00
reduce(ctx, array, FnPtr::new(reducer)?)
}
#[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,
2021-12-25 16:49:14 +01:00
) -> RhaiResult {
if array.is_empty() {
return Ok(initial);
}
2021-03-22 04:18:09 +01:00
let mut result = initial;
2021-11-23 15:37:18 +01:00
for (i, item) in array.iter().enumerate() {
let item = item.clone();
2021-10-21 13:04:53 +02:00
2021-11-23 15:37:18 +01:00
result = reducer
2021-11-29 05:43:59 +01:00
.call_raw(&ctx, None, [result.clone(), item.clone()])
.or_else(|err| match *err {
2021-12-27 05:27:31 +01:00
ERR::ErrorFunctionNotFound(fn_sig, _)
2021-11-23 15:37:18 +01:00
if fn_sig.starts_with(reducer.fn_name()) =>
{
2021-11-29 05:43:59 +01:00
reducer.call_raw(&ctx, None, [result, item, (i as INT).into()])
}
_ => Err(err),
})
.map_err(|err| {
2021-12-27 05:27:31 +01:00
Box::new(ERR::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-11-23 15:37:18 +01:00
#[rhai_fn(name = "reduce", return_raw, pure)]
pub fn reduce_with_fn_name_with_initial(
ctx: NativeCallContext,
array: &mut Array,
reducer: &str,
initial: Dynamic,
2021-12-25 16:49:14 +01:00
) -> RhaiResult {
2021-11-23 15:37:18 +01:00
reduce_with_initial(ctx, array, FnPtr::new(reducer)?, initial)
}
2021-03-09 06:16:05 +01:00
#[rhai_fn(return_raw, pure)]
2021-12-25 16:49:14 +01:00
pub fn reduce_rev(ctx: NativeCallContext, array: &mut Array, reducer: FnPtr) -> RhaiResult {
2021-11-23 15:37:18 +01:00
reduce_rev_with_initial(ctx, array, reducer, Dynamic::UNIT)
2020-10-14 15:27:31 +02:00
}
2021-10-21 13:04:53 +02:00
#[rhai_fn(name = "reduce_rev", return_raw, pure)]
pub fn reduce_rev_with_fn_name(
ctx: NativeCallContext,
array: &mut Array,
reducer: &str,
2021-12-25 16:49:14 +01:00
) -> RhaiResult {
2021-11-23 15:37:18 +01:00
reduce_rev(ctx, array, FnPtr::new(reducer)?)
}
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,
2021-12-25 16:49:14 +01:00
) -> RhaiResult {
if array.is_empty() {
return Ok(initial);
}
2021-03-22 04:18:09 +01:00
let mut result = initial;
2021-11-28 15:57:28 +01:00
let len = array.len();
2021-10-21 13:04:53 +02:00
2021-11-28 15:57:28 +01:00
for (i, item) in array.iter().rev().enumerate() {
2021-11-23 15:37:18 +01:00
let item = item.clone();
2021-11-23 15:37:18 +01:00
result = reducer
2021-11-29 05:43:59 +01:00
.call_raw(&ctx, None, [result.clone(), item.clone()])
.or_else(|err| match *err {
2021-12-27 05:27:31 +01:00
ERR::ErrorFunctionNotFound(fn_sig, _)
2021-11-23 15:37:18 +01:00
if fn_sig.starts_with(reducer.fn_name()) =>
{
2021-11-29 05:43:59 +01:00
reducer.call_raw(&ctx, None, [result, item, ((len - 1 - i) as INT).into()])
}
_ => Err(err),
})
.map_err(|err| {
2021-12-27 05:27:31 +01:00
Box::new(ERR::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
}
2021-11-23 15:37:18 +01:00
#[rhai_fn(name = "reduce_rev", return_raw, pure)]
pub fn reduce_rev_with_fn_name_with_initial(
ctx: NativeCallContext,
array: &mut Array,
reducer: &str,
initial: Dynamic,
2021-12-25 16:49:14 +01:00
) -> RhaiResult {
2021-11-23 15:37:18 +01:00
reduce_rev_with_initial(ctx, array, FnPtr::new(reducer)?, initial)
}
#[rhai_fn(name = "sort", return_raw)]
pub fn sort_with_fn_name(
ctx: NativeCallContext,
array: &mut Array,
comparer: &str,
2021-12-25 16:49:14 +01:00
) -> RhaiResultOf<()> {
sort(ctx, array, FnPtr::new(comparer)?)
}
#[rhai_fn(return_raw)]
2021-12-25 16:49:14 +01:00
pub fn sort(ctx: NativeCallContext, array: &mut Array, comparer: FnPtr) -> RhaiResultOf<()> {
2021-10-23 05:51:48 +02:00
if array.len() <= 1 {
return Ok(());
}
array.sort_by(|x, y| {
comparer
2021-11-29 05:43:59 +01:00
.call_raw(&ctx, None, [x.clone(), y.clone()])
.ok()
.and_then(|v| v.as_int().ok())
2021-05-25 04:54:48 +02:00
.map(|v| match v {
v if v > 0 => Ordering::Greater,
v if v < 0 => Ordering::Less,
0 => Ordering::Equal,
2021-12-30 05:19:41 +01:00
_ => unreachable!("v is {}", v),
})
2021-05-25 04:54:48 +02:00
.unwrap_or_else(|| x.type_id().cmp(&y.type_id()))
});
2020-10-13 04:57:29 +02:00
2021-03-22 04:18:09 +01:00
Ok(())
}
2021-10-23 05:51:48 +02:00
#[rhai_fn(name = "sort", return_raw)]
2021-12-25 16:49:14 +01:00
pub fn sort_with_builtin(array: &mut Array) -> RhaiResultOf<()> {
2021-10-23 05:51:48 +02:00
if array.len() <= 1 {
return Ok(());
}
let type_id = array[0].type_id();
if array.iter().any(|a| a.type_id() != type_id) {
2021-12-27 05:27:31 +01:00
return Err(ERR::ErrorFunctionNotFound(
2021-10-23 05:51:48 +02:00
"sort() cannot be called with elements of different types".into(),
Position::NONE,
)
.into());
}
if type_id == TypeId::of::<INT>() {
array.sort_by(|a, b| {
2021-11-13 05:23:35 +01:00
let a = a.as_int().expect("`INT`");
let b = b.as_int().expect("`INT`");
2021-10-23 05:51:48 +02:00
a.cmp(&b)
});
return Ok(());
}
if type_id == TypeId::of::<char>() {
array.sort_by(|a, b| {
2021-11-13 05:23:35 +01:00
let a = a.as_char().expect("char");
let b = b.as_char().expect("char");
2021-10-23 05:51:48 +02:00
a.cmp(&b)
});
return Ok(());
}
#[cfg(not(feature = "no_float"))]
if type_id == TypeId::of::<crate::FLOAT>() {
array.sort_by(|a, b| {
2021-11-13 05:23:35 +01:00
let a = a.as_float().expect("`FLOAT`");
let b = b.as_float().expect("`FLOAT`");
2021-10-23 05:51:48 +02:00
a.partial_cmp(&b).unwrap_or(Ordering::Equal)
});
return Ok(());
}
if type_id == TypeId::of::<ImmutableString>() {
array.sort_by(|a, b| {
2021-11-13 05:23:35 +01:00
let a = a.read_lock::<ImmutableString>().expect("`ImmutableString`");
let b = b.read_lock::<ImmutableString>().expect("`ImmutableString`");
2021-10-23 05:51:48 +02:00
a.as_str().cmp(b.as_str())
});
return Ok(());
}
#[cfg(feature = "decimal")]
if type_id == TypeId::of::<rust_decimal::Decimal>() {
array.sort_by(|a, b| {
2021-11-13 05:23:35 +01:00
let a = a.as_decimal().expect("`Decimal`");
let b = b.as_decimal().expect("`Decimal`");
2021-10-23 05:51:48 +02:00
a.cmp(&b)
});
return Ok(());
}
if type_id == TypeId::of::<bool>() {
array.sort_by(|a, b| {
2021-11-13 05:23:35 +01:00
let a = a.as_bool().expect("`bool`");
let b = b.as_bool().expect("`bool`");
2021-10-23 05:51:48 +02:00
a.cmp(&b)
});
return Ok(());
}
if type_id == TypeId::of::<()>() {
return Ok(());
}
Ok(())
}
2021-11-23 15:37:18 +01:00
#[rhai_fn(return_raw)]
2021-12-27 04:43:11 +01:00
pub fn drain(ctx: NativeCallContext, array: &mut Array, filter: FnPtr) -> RhaiResultOf<Array> {
if array.is_empty() {
return Ok(Array::new());
}
2021-11-23 15:37:18 +01:00
let mut drained = Array::with_capacity(array.len());
2020-10-13 04:57:29 +02:00
2021-11-23 15:37:18 +01:00
let mut i = 0;
let mut x = 0;
2020-10-18 07:18:12 +02:00
2021-11-23 15:37:18 +01:00
while x < array.len() {
if filter
2021-11-29 05:43:59 +01:00
.call_raw(&ctx, None, [array[x].clone()])
2021-11-23 15:37:18 +01:00
.or_else(|err| match *err {
2021-12-27 05:27:31 +01:00
ERR::ErrorFunctionNotFound(fn_sig, _)
2021-11-23 15:37:18 +01:00
if fn_sig.starts_with(filter.fn_name()) =>
{
2021-11-29 05:43:59 +01:00
filter.call_raw(&ctx, None, [array[x].clone(), (i as INT).into()])
}
2021-11-23 15:37:18 +01:00
_ => Err(err),
})
.map_err(|err| {
2021-12-27 05:27:31 +01:00
Box::new(ERR::ErrorInFunctionCall(
2021-11-23 15:37:18 +01:00
"drain".to_string(),
ctx.source().unwrap_or("").to_string(),
err,
Position::NONE,
))
})?
.as_bool()
.unwrap_or(false)
{
drained.push(array.remove(x));
} else {
2021-11-23 15:37:18 +01:00
x += 1;
}
2021-11-23 15:37:18 +01:00
i += 1;
}
2021-11-23 15:37:18 +01:00
Ok(drained)
}
#[rhai_fn(name = "drain", return_raw)]
pub fn drain_with_fn_name(
ctx: NativeCallContext,
array: &mut Array,
filter: &str,
2021-12-25 16:49:14 +01:00
) -> RhaiResultOf<Array> {
2021-11-23 15:37:18 +01:00
drain(ctx, array, FnPtr::new(filter)?)
}
#[rhai_fn(name = "drain")]
2021-12-15 05:06:17 +01:00
pub fn drain_exclusive_range(array: &mut Array, range: ExclusiveRange) -> Array {
let start = INT::max(range.start, 0);
let end = INT::max(range.end, start);
drain_range(array, start, end - start)
}
#[rhai_fn(name = "drain")]
pub fn drain_inclusive_range(array: &mut Array, range: InclusiveRange) -> Array {
let start = INT::max(*range.start(), 0);
let end = INT::max(*range.end(), start);
drain_range(array, start, end - start + 1)
}
#[rhai_fn(name = "drain")]
pub fn drain_range(array: &mut Array, start: INT, len: INT) -> Array {
if array.is_empty() || len <= 0 {
return Array::new();
}
let (start, len) = calc_offset_len(array.len(), start, len);
2020-10-18 07:18:12 +02:00
if len == 0 {
Array::new()
} else {
array.drain(start..start + len).collect()
}
2020-10-18 07:18:12 +02:00
}
2021-11-23 15:37:18 +01:00
#[rhai_fn(return_raw)]
2021-12-27 04:43:11 +01:00
pub fn retain(ctx: NativeCallContext, array: &mut Array, filter: FnPtr) -> RhaiResultOf<Array> {
if array.is_empty() {
return Ok(Array::new());
}
2021-11-23 15:37:18 +01:00
let mut drained = Array::new();
2020-10-18 07:18:12 +02:00
2021-11-23 15:37:18 +01:00
let mut i = 0;
let mut x = 0;
2020-10-18 07:18:12 +02:00
2021-11-23 15:37:18 +01:00
while x < array.len() {
if !filter
2021-11-29 05:43:59 +01:00
.call_raw(&ctx, None, [array[x].clone()])
2021-11-23 15:37:18 +01:00
.or_else(|err| match *err {
2021-12-27 05:27:31 +01:00
ERR::ErrorFunctionNotFound(fn_sig, _)
2021-11-23 15:37:18 +01:00
if fn_sig.starts_with(filter.fn_name()) =>
{
2021-11-29 05:43:59 +01:00
filter.call_raw(&ctx, None, [array[x].clone(), (i as INT).into()])
}
2021-11-23 15:37:18 +01:00
_ => Err(err),
})
.map_err(|err| {
2021-12-27 05:27:31 +01:00
Box::new(ERR::ErrorInFunctionCall(
2021-11-23 15:37:18 +01:00
"retain".to_string(),
ctx.source().unwrap_or("").to_string(),
err,
Position::NONE,
))
})?
.as_bool()
.unwrap_or(false)
{
drained.push(array.remove(x));
} else {
2021-11-23 15:37:18 +01:00
x += 1;
}
2021-11-23 15:37:18 +01:00
i += 1;
}
2021-11-23 15:37:18 +01:00
Ok(drained)
}
#[rhai_fn(name = "retain", return_raw)]
pub fn retain_with_fn_name(
ctx: NativeCallContext,
array: &mut Array,
filter: &str,
2021-12-25 16:49:14 +01:00
) -> RhaiResultOf<Array> {
2021-11-23 15:37:18 +01:00
retain(ctx, array, FnPtr::new(filter)?)
}
#[rhai_fn(name = "retain")]
2021-12-15 05:06:17 +01:00
pub fn retain_exclusive_range(array: &mut Array, range: ExclusiveRange) -> Array {
let start = INT::max(range.start, 0);
let end = INT::max(range.end, start);
retain_range(array, start, end - start)
}
#[rhai_fn(name = "retain")]
pub fn retain_inclusive_range(array: &mut Array, range: InclusiveRange) -> Array {
let start = INT::max(*range.start(), 0);
let end = INT::max(*range.end(), start);
retain_range(array, start, end - start + 1)
}
#[rhai_fn(name = "retain")]
pub fn retain_range(array: &mut Array, start: INT, len: INT) -> Array {
if array.is_empty() || len <= 0 {
return Array::new();
}
let (start, len) = calc_offset_len(array.len(), start, len);
2020-10-18 07:18:12 +02:00
if len == 0 {
Array::new()
} else {
let mut drained: Array = array.drain(..start).collect();
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)]
2021-12-27 04:43:11 +01:00
pub fn equals(ctx: NativeCallContext, array1: &mut Array, array2: Array) -> RhaiResultOf<bool> {
2021-08-13 07:42:39 +02:00
if array1.len() != array2.len() {
2021-03-22 04:18:09 +01:00
return Ok(false);
2020-11-08 16:00:37 +01:00
}
2021-08-13 07:42:39 +02:00
if array1.is_empty() {
2021-03-22 04:18:09 +01:00
return Ok(true);
2020-11-08 16:00:37 +01:00
}
2021-08-13 07:42:39 +02:00
let mut array2 = array2;
for (a1, a2) in array1.iter_mut().zip(array2.iter_mut()) {
2021-03-09 06:16:05 +01:00
if !ctx
.call_fn_raw(OP_EQUALS, true, false, &mut [a1, a2])
2021-03-09 06:16:05 +01:00
.or_else(|err| match *err {
2021-12-27 05:27:31 +01:00
ERR::ErrorFunctionNotFound(ref fn_sig, _) if fn_sig.starts_with(OP_EQUALS) => {
2021-03-09 06:16:05 +01:00
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,
2021-08-13 07:42:39 +02:00
array1: &mut Array,
array2: Array,
2021-12-25 16:49:14 +01:00
) -> RhaiResultOf<bool> {
2021-08-13 07:42:39 +02:00
equals(ctx, array1, array2).map(|r| !r)
2020-11-08 16:00:37 +01:00
}
2020-10-18 07:18:12 +02:00
}