Allow NativeCallContext in function arguments.
This commit is contained in:
@@ -1561,7 +1561,7 @@ impl Engine {
|
||||
|
||||
// Overriding exact implementation
|
||||
if func.is_plugin_fn() {
|
||||
func.get_plugin_fn().call(args)?;
|
||||
func.get_plugin_fn().call((self, lib).into(), args)?;
|
||||
} else {
|
||||
func.get_native_fn()((self, lib).into(), args)?;
|
||||
}
|
||||
|
@@ -206,7 +206,7 @@ impl Engine {
|
||||
|
||||
// Run external function
|
||||
let result = if func.is_plugin_fn() {
|
||||
func.get_plugin_fn().call(args)
|
||||
func.get_plugin_fn().call((self, lib).into(), args)
|
||||
} else {
|
||||
func.get_native_fn()((self, lib).into(), args)
|
||||
};
|
||||
@@ -1185,7 +1185,9 @@ impl Engine {
|
||||
|
||||
self.call_script_fn(new_scope, mods, state, lib, &mut None, fn_def, args, level)
|
||||
}
|
||||
Some(f) if f.is_plugin_fn() => f.get_plugin_fn().call(args.as_mut()),
|
||||
Some(f) if f.is_plugin_fn() => {
|
||||
f.get_plugin_fn().call((self, lib).into(), args.as_mut())
|
||||
}
|
||||
Some(f) if f.is_native() => {
|
||||
if !f.is_method() {
|
||||
// Clone first argument
|
||||
|
@@ -1,7 +1,6 @@
|
||||
//! Module defining external-loaded modules for Rhai.
|
||||
|
||||
use crate::any::{Dynamic, Variant};
|
||||
use crate::engine::Engine;
|
||||
use crate::fn_native::{CallableFunction, FnCallArgs, IteratorFn, NativeCallContext, SendSync};
|
||||
use crate::fn_register::by_value as cast_arg;
|
||||
use crate::parser::FnAccess;
|
||||
@@ -15,7 +14,7 @@ use crate::{fn_native::Shared, parser::ScriptFnDef};
|
||||
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
use crate::{
|
||||
engine::Imports,
|
||||
engine::{Engine, Imports},
|
||||
parser::AST,
|
||||
scope::{Entry as ScopeEntry, Scope},
|
||||
};
|
||||
|
@@ -1,7 +1,7 @@
|
||||
#![cfg(not(feature = "no_index"))]
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use crate::any::{Dynamic, Variant};
|
||||
use crate::any::Dynamic;
|
||||
use crate::def_package;
|
||||
use crate::engine::Array;
|
||||
use crate::fn_native::{FnPtr, NativeCallContext};
|
||||
@@ -38,6 +38,23 @@ macro_rules! gen_array_functions {
|
||||
list.insert(position as usize, Dynamic::from(item));
|
||||
}
|
||||
}
|
||||
|
||||
#[rhai_fn(return_raw)]
|
||||
pub fn pad(context: NativeCallContext, list: &mut Array, len: INT, item: $arg_type) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
// Check if array will be over max size limit
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
if context.engine().max_array_size() > 0 && len > 0 && (len as usize) > context.engine().max_array_size() {
|
||||
return EvalAltResult::ErrorDataTooLarge(
|
||||
"Size of array".to_string(), context.engine().max_array_size(), len as usize, Position::none(),
|
||||
).into();
|
||||
}
|
||||
|
||||
if len > 0 && len as usize > list.len() {
|
||||
list.resize(len as usize, Dynamic::from(item));
|
||||
}
|
||||
|
||||
Ok(().into())
|
||||
}
|
||||
}
|
||||
})* }
|
||||
}
|
||||
@@ -46,10 +63,6 @@ macro_rules! gen_array_functions {
|
||||
macro_rules! reg_functions {
|
||||
($mod_name:ident += $root:ident ; $($arg_type:ident),+) => { $(
|
||||
combine_with_exported_module!($mod_name, "array_functions", $root::$arg_type::functions);
|
||||
|
||||
$mod_name.set_raw_fn("pad",
|
||||
&[TypeId::of::<Array>(), TypeId::of::<INT>(), TypeId::of::<$arg_type>()],
|
||||
pad::<$arg_type>);
|
||||
)* }
|
||||
}
|
||||
|
||||
@@ -71,18 +84,6 @@ def_package!(crate:BasicArrayPackage:"Basic array utilities.", lib, {
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
reg_functions!(lib += map; Map);
|
||||
|
||||
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("drain", &[TypeId::of::<Array>(), TypeId::of::<FnPtr>()], drain);
|
||||
lib.set_raw_fn("retain", &[TypeId::of::<Array>(), TypeId::of::<FnPtr>()], retain);
|
||||
lib.set_raw_fn("reduce", &[TypeId::of::<Array>(), TypeId::of::<FnPtr>()], reduce);
|
||||
lib.set_raw_fn("reduce", &[TypeId::of::<Array>(), TypeId::of::<FnPtr>(), TypeId::of::<FnPtr>()], reduce_with_initial);
|
||||
lib.set_raw_fn("reduce_rev", &[TypeId::of::<Array>(), TypeId::of::<FnPtr>()], reduce_rev);
|
||||
lib.set_raw_fn("reduce_rev", &[TypeId::of::<Array>(), TypeId::of::<FnPtr>(), TypeId::of::<FnPtr>()], reduce_rev_with_initial);
|
||||
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);
|
||||
|
||||
// Merge in the module at the end to override `+=` for arrays
|
||||
combine_with_exported_module!(lib, "array", array_functions);
|
||||
|
||||
@@ -193,6 +194,364 @@ mod array_functions {
|
||||
|
||||
list[start..].iter().cloned().collect()
|
||||
}
|
||||
#[rhai_fn(return_raw)]
|
||||
pub fn map(
|
||||
context: NativeCallContext,
|
||||
list: &mut Array,
|
||||
mapper: FnPtr,
|
||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
let mut array = Array::with_capacity(list.len());
|
||||
|
||||
for (i, item) in list.iter().enumerate() {
|
||||
array.push(
|
||||
mapper
|
||||
.call_dynamic(context, None, [item.clone()])
|
||||
.or_else(|err| match *err {
|
||||
EvalAltResult::ErrorFunctionNotFound(fn_sig, _)
|
||||
if fn_sig.starts_with(mapper.fn_name()) =>
|
||||
{
|
||||
mapper.call_dynamic(context, None, [item.clone(), (i as INT).into()])
|
||||
}
|
||||
_ => Err(err),
|
||||
})
|
||||
.map_err(|err| {
|
||||
Box::new(EvalAltResult::ErrorInFunctionCall(
|
||||
"map".to_string(),
|
||||
err,
|
||||
Position::none(),
|
||||
))
|
||||
})?,
|
||||
);
|
||||
}
|
||||
|
||||
Ok(array.into())
|
||||
}
|
||||
#[rhai_fn(return_raw)]
|
||||
pub fn filter(
|
||||
context: NativeCallContext,
|
||||
list: &mut Array,
|
||||
filter: FnPtr,
|
||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
let mut array = Array::with_capacity(list.len());
|
||||
|
||||
for (i, item) in list.iter().enumerate() {
|
||||
if filter
|
||||
.call_dynamic(context, None, [item.clone()])
|
||||
.or_else(|err| match *err {
|
||||
EvalAltResult::ErrorFunctionNotFound(fn_sig, _)
|
||||
if fn_sig.starts_with(filter.fn_name()) =>
|
||||
{
|
||||
filter.call_dynamic(context, 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.into())
|
||||
}
|
||||
#[rhai_fn(return_raw)]
|
||||
pub fn some(
|
||||
context: NativeCallContext,
|
||||
list: &mut Array,
|
||||
filter: FnPtr,
|
||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
for (i, item) in list.iter().enumerate() {
|
||||
if filter
|
||||
.call_dynamic(context, None, [item.clone()])
|
||||
.or_else(|err| match *err {
|
||||
EvalAltResult::ErrorFunctionNotFound(fn_sig, _)
|
||||
if fn_sig.starts_with(filter.fn_name()) =>
|
||||
{
|
||||
filter.call_dynamic(context, 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())
|
||||
}
|
||||
#[rhai_fn(return_raw)]
|
||||
pub fn all(
|
||||
context: NativeCallContext,
|
||||
list: &mut Array,
|
||||
filter: FnPtr,
|
||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
for (i, item) in list.iter().enumerate() {
|
||||
if !filter
|
||||
.call_dynamic(context, None, [item.clone()])
|
||||
.or_else(|err| match *err {
|
||||
EvalAltResult::ErrorFunctionNotFound(fn_sig, _)
|
||||
if fn_sig.starts_with(filter.fn_name()) =>
|
||||
{
|
||||
filter.call_dynamic(context, 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())
|
||||
}
|
||||
#[rhai_fn(return_raw)]
|
||||
pub fn reduce(
|
||||
context: NativeCallContext,
|
||||
list: &mut Array,
|
||||
reducer: FnPtr,
|
||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
let mut result: Dynamic = ().into();
|
||||
|
||||
for (i, item) in list.iter().enumerate() {
|
||||
result = reducer
|
||||
.call_dynamic(context, 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(
|
||||
context,
|
||||
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)
|
||||
}
|
||||
#[rhai_fn(name = "reduce", return_raw)]
|
||||
pub fn reduce_with_initial(
|
||||
context: NativeCallContext,
|
||||
list: &mut Array,
|
||||
reducer: FnPtr,
|
||||
initial: FnPtr,
|
||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
let mut result = initial.call_dynamic(context, None, []).map_err(|err| {
|
||||
Box::new(EvalAltResult::ErrorInFunctionCall(
|
||||
"reduce".to_string(),
|
||||
err,
|
||||
Position::none(),
|
||||
))
|
||||
})?;
|
||||
|
||||
for (i, item) in list.iter().enumerate() {
|
||||
result = reducer
|
||||
.call_dynamic(context, 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(
|
||||
context,
|
||||
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)
|
||||
}
|
||||
#[rhai_fn(return_raw)]
|
||||
pub fn reduce_rev(
|
||||
context: NativeCallContext,
|
||||
list: &mut Array,
|
||||
reducer: FnPtr,
|
||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
let mut result: Dynamic = ().into();
|
||||
|
||||
for (i, item) in list.iter().enumerate().rev() {
|
||||
result = reducer
|
||||
.call_dynamic(context, 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(
|
||||
context,
|
||||
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)
|
||||
}
|
||||
#[rhai_fn(name = "reduce_rev", return_raw)]
|
||||
pub fn reduce_rev_with_initial(
|
||||
context: NativeCallContext,
|
||||
list: &mut Array,
|
||||
reducer: FnPtr,
|
||||
initial: FnPtr,
|
||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
let mut result = initial.call_dynamic(context, None, []).map_err(|err| {
|
||||
Box::new(EvalAltResult::ErrorInFunctionCall(
|
||||
"reduce".to_string(),
|
||||
err,
|
||||
Position::none(),
|
||||
))
|
||||
})?;
|
||||
|
||||
for (i, item) in list.iter().enumerate().rev() {
|
||||
result = reducer
|
||||
.call_dynamic(context, 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(
|
||||
context,
|
||||
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)
|
||||
}
|
||||
#[rhai_fn(return_raw)]
|
||||
pub fn sort(
|
||||
context: NativeCallContext,
|
||||
list: &mut Array,
|
||||
comparer: FnPtr,
|
||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
list.sort_by(|x, y| {
|
||||
comparer
|
||||
.call_dynamic(context, 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())
|
||||
}
|
||||
#[rhai_fn(return_raw)]
|
||||
pub fn drain(
|
||||
context: NativeCallContext,
|
||||
list: &mut Array,
|
||||
filter: FnPtr,
|
||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
let mut drained = Array::with_capacity(list.len());
|
||||
|
||||
let mut i = list.len();
|
||||
|
||||
while i > 0 {
|
||||
i -= 1;
|
||||
|
||||
if filter
|
||||
.call_dynamic(context, None, [list[i].clone()])
|
||||
.or_else(|err| match *err {
|
||||
EvalAltResult::ErrorFunctionNotFound(fn_sig, _)
|
||||
if fn_sig.starts_with(filter.fn_name()) =>
|
||||
{
|
||||
filter.call_dynamic(context, None, [list[i].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)
|
||||
{
|
||||
drained.push(list.remove(i));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(drained.into())
|
||||
}
|
||||
#[rhai_fn(name = "drain")]
|
||||
pub fn drain_range(list: &mut Array, start: INT, len: INT) -> Array {
|
||||
let start = if start < 0 {
|
||||
@@ -213,6 +572,45 @@ mod array_functions {
|
||||
|
||||
list.drain(start..start + len - 1).collect()
|
||||
}
|
||||
#[rhai_fn(return_raw)]
|
||||
pub fn retain(
|
||||
context: NativeCallContext,
|
||||
list: &mut Array,
|
||||
filter: FnPtr,
|
||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
let mut drained = Array::with_capacity(list.len());
|
||||
|
||||
let mut i = list.len();
|
||||
|
||||
while i > 0 {
|
||||
i -= 1;
|
||||
|
||||
if !filter
|
||||
.call_dynamic(context, None, [list[i].clone()])
|
||||
.or_else(|err| match *err {
|
||||
EvalAltResult::ErrorFunctionNotFound(fn_sig, _)
|
||||
if fn_sig.starts_with(filter.fn_name()) =>
|
||||
{
|
||||
filter.call_dynamic(context, None, [list[i].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)
|
||||
{
|
||||
drained.push(list.remove(i));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(drained.into())
|
||||
}
|
||||
#[rhai_fn(name = "retain")]
|
||||
pub fn retain_range(list: &mut Array, start: INT, len: INT) -> Array {
|
||||
let start = if start < 0 {
|
||||
@@ -238,412 +636,6 @@ mod array_functions {
|
||||
}
|
||||
}
|
||||
|
||||
fn pad<T: Variant + Clone>(
|
||||
_context: NativeCallContext,
|
||||
args: &mut [&mut Dynamic],
|
||||
) -> Result<(), Box<EvalAltResult>> {
|
||||
let len = *args[1].read_lock::<INT>().unwrap();
|
||||
|
||||
// Check if array will be over max size limit
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
if _context.engine().max_array_size() > 0
|
||||
&& len > 0
|
||||
&& (len as usize) > _context.engine().max_array_size()
|
||||
{
|
||||
return EvalAltResult::ErrorDataTooLarge(
|
||||
"Size of array".to_string(),
|
||||
_context.engine().max_array_size(),
|
||||
len as usize,
|
||||
Position::none(),
|
||||
)
|
||||
.into();
|
||||
}
|
||||
|
||||
if len > 0 {
|
||||
let item = args[2].clone();
|
||||
let mut list = args[0].write_lock::<Array>().unwrap();
|
||||
|
||||
if len as usize > list.len() {
|
||||
list.resize(len as usize, item);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn map(context: NativeCallContext, 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(context, None, [item.clone()])
|
||||
.or_else(|err| match *err {
|
||||
EvalAltResult::ErrorFunctionNotFound(_, _) => {
|
||||
mapper.call_dynamic(context, 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(
|
||||
context: NativeCallContext,
|
||||
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(context, None, [item.clone()])
|
||||
.or_else(|err| match *err {
|
||||
EvalAltResult::ErrorFunctionNotFound(_, _) => {
|
||||
filter.call_dynamic(context, 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)
|
||||
}
|
||||
|
||||
fn some(context: NativeCallContext, 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(context, None, [item.clone()])
|
||||
.or_else(|err| match *err {
|
||||
EvalAltResult::ErrorFunctionNotFound(_, _) => {
|
||||
filter.call_dynamic(context, 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(context: NativeCallContext, 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(context, None, [item.clone()])
|
||||
.or_else(|err| match *err {
|
||||
EvalAltResult::ErrorFunctionNotFound(_, _) => {
|
||||
filter.call_dynamic(context, 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())
|
||||
}
|
||||
|
||||
fn reduce(
|
||||
context: NativeCallContext,
|
||||
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(context, None, [result.clone(), item.clone()])
|
||||
.or_else(|err| match *err {
|
||||
EvalAltResult::ErrorFunctionNotFound(_, _) => {
|
||||
reducer.call_dynamic(context, 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 reduce_with_initial(
|
||||
context: NativeCallContext,
|
||||
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 initial = args[2].read_lock::<FnPtr>().unwrap();
|
||||
|
||||
let mut result = initial.call_dynamic(context, None, []).map_err(|err| {
|
||||
Box::new(EvalAltResult::ErrorInFunctionCall(
|
||||
"reduce".to_string(),
|
||||
err,
|
||||
Position::none(),
|
||||
))
|
||||
})?;
|
||||
|
||||
for (i, item) in list.iter().enumerate() {
|
||||
result = reducer
|
||||
.call_dynamic(context, None, [result.clone(), item.clone()])
|
||||
.or_else(|err| match *err {
|
||||
EvalAltResult::ErrorFunctionNotFound(_, _) => {
|
||||
reducer.call_dynamic(context, 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 reduce_rev(
|
||||
context: NativeCallContext,
|
||||
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(context, None, [result.clone(), item.clone()])
|
||||
.or_else(|err| match *err {
|
||||
EvalAltResult::ErrorFunctionNotFound(_, _) => {
|
||||
reducer.call_dynamic(context, 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 reduce_rev_with_initial(
|
||||
context: NativeCallContext,
|
||||
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 initial = args[2].read_lock::<FnPtr>().unwrap();
|
||||
|
||||
let mut result = initial.call_dynamic(context, None, []).map_err(|err| {
|
||||
Box::new(EvalAltResult::ErrorInFunctionCall(
|
||||
"reduce".to_string(),
|
||||
err,
|
||||
Position::none(),
|
||||
))
|
||||
})?;
|
||||
|
||||
for (i, item) in list.iter().enumerate().rev() {
|
||||
result = reducer
|
||||
.call_dynamic(context, None, [result.clone(), item.clone()])
|
||||
.or_else(|err| match *err {
|
||||
EvalAltResult::ErrorFunctionNotFound(_, _) => {
|
||||
reducer.call_dynamic(context, 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(
|
||||
context: NativeCallContext,
|
||||
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(context, 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())
|
||||
}
|
||||
|
||||
fn drain(
|
||||
context: NativeCallContext,
|
||||
args: &mut [&mut Dynamic],
|
||||
) -> Result<Array, Box<EvalAltResult>> {
|
||||
let filter = args[1].read_lock::<FnPtr>().unwrap().clone();
|
||||
let mut list = args[0].write_lock::<Array>().unwrap();
|
||||
|
||||
let mut drained = Array::with_capacity(list.len());
|
||||
|
||||
let mut i = list.len();
|
||||
|
||||
while i > 0 {
|
||||
i -= 1;
|
||||
|
||||
if filter
|
||||
.call_dynamic(context, None, [list[i].clone()])
|
||||
.or_else(|err| match *err {
|
||||
EvalAltResult::ErrorFunctionNotFound(_, _) => {
|
||||
filter.call_dynamic(context, None, [list[i].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)
|
||||
{
|
||||
drained.push(list.remove(i));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(drained)
|
||||
}
|
||||
|
||||
fn retain(
|
||||
context: NativeCallContext,
|
||||
args: &mut [&mut Dynamic],
|
||||
) -> Result<Array, Box<EvalAltResult>> {
|
||||
let filter = args[1].read_lock::<FnPtr>().unwrap().clone();
|
||||
let mut list = args[0].write_lock::<Array>().unwrap();
|
||||
|
||||
let mut drained = Array::with_capacity(list.len());
|
||||
|
||||
let mut i = list.len();
|
||||
|
||||
while i > 0 {
|
||||
i -= 1;
|
||||
|
||||
if !filter
|
||||
.call_dynamic(context, None, [list[i].clone()])
|
||||
.or_else(|err| match *err {
|
||||
EvalAltResult::ErrorFunctionNotFound(_, _) => {
|
||||
filter.call_dynamic(context, None, [list[i].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)
|
||||
{
|
||||
drained.push(list.remove(i));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(drained)
|
||||
}
|
||||
|
||||
gen_array_functions!(basic => INT, bool, char, ImmutableString, FnPtr, Array, Unit);
|
||||
|
||||
#[cfg(not(feature = "only_i32"))]
|
||||
|
@@ -3,7 +3,10 @@ use crate::def_package;
|
||||
use crate::parser::INT;
|
||||
use crate::result::EvalAltResult;
|
||||
|
||||
use crate::stdlib::ops::{Add, Range};
|
||||
use crate::stdlib::{
|
||||
boxed::Box,
|
||||
ops::{Add, Range},
|
||||
};
|
||||
|
||||
fn get_range<T: Variant + Clone>(from: T, to: T) -> Result<Range<T>, Box<EvalAltResult>> {
|
||||
Ok(from..to)
|
||||
|
@@ -2,7 +2,7 @@
|
||||
|
||||
pub use crate::any::Dynamic;
|
||||
pub use crate::engine::Engine;
|
||||
pub use crate::fn_native::CallableFunction;
|
||||
pub use crate::fn_native::{CallableFunction, NativeCallContext};
|
||||
pub use crate::fn_register::{RegisterFn, RegisterResultFn};
|
||||
pub use crate::module::Module;
|
||||
pub use crate::parser::FnAccess;
|
||||
@@ -22,7 +22,11 @@ pub use rhai_codegen::{export_fn, register_exported_fn};
|
||||
/// Use the `#[export_module]` and `#[export_fn]` procedural attributes instead.
|
||||
pub trait PluginFunction {
|
||||
/// Call the plugin function with the arguments provided.
|
||||
fn call(&self, args: &mut [&mut Dynamic]) -> Result<Dynamic, Box<EvalAltResult>>;
|
||||
fn call(
|
||||
&self,
|
||||
context: NativeCallContext,
|
||||
args: &mut [&mut Dynamic],
|
||||
) -> Result<Dynamic, Box<EvalAltResult>>;
|
||||
|
||||
/// Is this plugin function a method?
|
||||
fn is_method_call(&self) -> bool;
|
||||
|
Reference in New Issue
Block a user