Fix bug in array methods.

This commit is contained in:
Stephen Chung 2021-11-23 22:37:18 +08:00
parent 20915572e8
commit 2b0b79870e
2 changed files with 285 additions and 354 deletions

View File

@ -4,6 +4,11 @@ Rhai Release Notes
Version 1.2.1 Version 1.2.1
============= =============
Bug fixes
---------
* Array methods (such as `map`) taking a closure with captures as argument now works properly.
Version 1.2.0 Version 1.2.0
============= =============

View File

@ -250,7 +250,36 @@ mod array_functions {
array: &mut Array, array: &mut Array,
mapper: FnPtr, mapper: FnPtr,
) -> Result<Array, Box<EvalAltResult>> { ) -> Result<Array, Box<EvalAltResult>> {
map_with_fn_name(ctx, array, mapper.fn_name()) if array.is_empty() {
return Ok(array.clone());
}
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(),
ctx.source().unwrap_or("").to_string(),
err,
Position::NONE,
))
})?,
);
}
Ok(ar)
} }
#[rhai_fn(name = "map", return_raw, pure)] #[rhai_fn(name = "map", return_raw, pure)]
pub fn map_with_fn_name( pub fn map_with_fn_name(
@ -258,94 +287,57 @@ mod array_functions {
array: &mut Array, array: &mut Array,
mapper: &str, mapper: &str,
) -> Result<Array, Box<EvalAltResult>> { ) -> Result<Array, Box<EvalAltResult>> {
if array.is_empty() { map(ctx, array, FnPtr::new(mapper)?)
return Ok(Array::new());
}
let mut ar = Array::with_capacity(array.len());
let mut index_val = Dynamic::UNIT;
for (i, item) in array.iter_mut().enumerate() {
let mut args = [item, &mut index_val];
ar.push(match ctx.call_fn_raw(mapper, true, false, &mut args[..1]) {
Ok(r) => r,
Err(err) => match *err {
EvalAltResult::ErrorFunctionNotFound(fn_sig, _)
if fn_sig.starts_with(mapper) =>
{
*args[1] = Dynamic::from(i as INT);
ctx.call_fn_raw(mapper, true, false, &mut args)?
}
_ => {
return Err(EvalAltResult::ErrorInFunctionCall(
"map".to_string(),
ctx.source().unwrap_or("").to_string(),
err,
Position::NONE,
)
.into())
}
},
});
}
Ok(ar)
} }
#[rhai_fn(return_raw, pure)] #[rhai_fn(return_raw, pure)]
pub fn filter( pub fn filter(
ctx: NativeCallContext, ctx: NativeCallContext,
array: &mut Array, array: &mut Array,
filter: FnPtr, filter: FnPtr,
) -> Result<Array, Box<EvalAltResult>> {
filter_with_fn_name(ctx, array, filter.fn_name())
}
#[rhai_fn(name = "filter", return_raw, pure)]
pub fn filter_with_fn_name(
ctx: NativeCallContext,
array: &mut Array,
filter: &str,
) -> Result<Array, Box<EvalAltResult>> { ) -> Result<Array, Box<EvalAltResult>> {
if array.is_empty() { if array.is_empty() {
return Ok(array.clone()); return Ok(array.clone());
} }
let mut ar = Array::new(); let mut ar = Array::new();
let mut index_val = Dynamic::UNIT;
for (i, item) in array.iter_mut().enumerate() { for (i, item) in array.iter().enumerate() {
let mut args = [item, &mut index_val]; if filter
.call_dynamic(&ctx, None, [item.clone()])
let keep = match ctx.call_fn_raw(filter, true, false, &mut args[..1]) { .or_else(|err| match *err {
Ok(r) => r,
Err(err) => match *err {
EvalAltResult::ErrorFunctionNotFound(fn_sig, _) EvalAltResult::ErrorFunctionNotFound(fn_sig, _)
if fn_sig.starts_with(filter) => if fn_sig.starts_with(filter.fn_name()) =>
{ {
*args[1] = Dynamic::from(i as INT); filter.call_dynamic(&ctx, None, [item.clone(), (i as INT).into()])
ctx.call_fn_raw(filter, true, false, &mut args)?
} }
_ => { _ => Err(err),
return Err(EvalAltResult::ErrorInFunctionCall( })
"filter".to_string(), .map_err(|err| {
ctx.source().unwrap_or("").to_string(), Box::new(EvalAltResult::ErrorInFunctionCall(
err, "filter".to_string(),
Position::NONE, ctx.source().unwrap_or("").to_string(),
) err,
.into()) Position::NONE,
} ))
}, })?
} .as_bool()
.as_bool() .unwrap_or(false)
.unwrap_or(false); {
ar.push(item.clone());
if keep {
ar.push(args[0].clone());
} }
} }
Ok(ar) Ok(ar)
} }
#[rhai_fn(name = "filter", return_raw, pure)]
pub fn filter_with_fn_name(
ctx: NativeCallContext,
array: &mut Array,
filter_func: &str,
) -> Result<Array, Box<EvalAltResult>> {
filter(ctx, array, FnPtr::new(filter_func)?)
}
#[rhai_fn(return_raw, pure)] #[rhai_fn(return_raw, pure)]
pub fn contains( pub fn contains(
ctx: NativeCallContext, ctx: NativeCallContext,
@ -466,15 +458,6 @@ mod array_functions {
array: &mut Array, array: &mut Array,
filter: FnPtr, filter: FnPtr,
start: INT, start: INT,
) -> Result<INT, Box<EvalAltResult>> {
index_of_with_fn_name_filter_starting_from(ctx, array, filter.fn_name(), start)
}
#[rhai_fn(name = "index_of", return_raw, pure)]
pub fn index_of_with_fn_name_filter_starting_from(
ctx: NativeCallContext,
array: &mut Array,
filter: &str,
start: INT,
) -> Result<INT, Box<EvalAltResult>> { ) -> Result<INT, Box<EvalAltResult>> {
if array.is_empty() { if array.is_empty() {
return Ok(-1); return Ok(-1);
@ -491,48 +474,80 @@ mod array_functions {
start as usize start as usize
}; };
let mut index_val = Dynamic::UNIT; for (i, item) in array.iter().enumerate().skip(start) {
if filter
for (i, item) in array.iter_mut().enumerate().skip(start) { .call_dynamic(&ctx, None, [item.clone()])
let mut args = [item, &mut index_val]; .or_else(|err| match *err {
let found = match ctx.call_fn_raw(filter, true, false, &mut args[..1]) {
Ok(r) => r,
Err(err) => match *err {
EvalAltResult::ErrorFunctionNotFound(fn_sig, _) EvalAltResult::ErrorFunctionNotFound(fn_sig, _)
if fn_sig.starts_with(filter) => if fn_sig.starts_with(filter.fn_name()) =>
{ {
*args[1] = Dynamic::from(i as INT); filter.call_dynamic(&ctx, None, [item.clone(), (i as INT).into()])
ctx.call_fn_raw(filter, true, false, &mut args)?
} }
_ => { _ => Err(err),
return Err(EvalAltResult::ErrorInFunctionCall( })
"index_of".to_string(), .map_err(|err| {
ctx.source().unwrap_or("").to_string(), Box::new(EvalAltResult::ErrorInFunctionCall(
err, "index_of".to_string(),
Position::NONE, ctx.source().unwrap_or("").to_string(),
) err,
.into()) Position::NONE,
} ))
}, })?
} .as_bool()
.as_bool() .unwrap_or(false)
.unwrap_or(false); {
if found {
return Ok(i as INT); return Ok(i as INT);
} }
} }
Ok(-1 as INT) Ok(-1 as INT)
} }
#[rhai_fn(name = "index_of", return_raw, pure)]
pub fn index_of_with_fn_name_filter_starting_from(
ctx: NativeCallContext,
array: &mut Array,
filter: &str,
start: INT,
) -> Result<INT, Box<EvalAltResult>> {
index_of_filter_starting_from(ctx, array, FnPtr::new(filter)?, start)
}
#[rhai_fn(return_raw, pure)] #[rhai_fn(return_raw, pure)]
pub fn some( pub fn some(
ctx: NativeCallContext, ctx: NativeCallContext,
array: &mut Array, array: &mut Array,
filter: FnPtr, filter: FnPtr,
) -> Result<bool, Box<EvalAltResult>> { ) -> Result<bool, Box<EvalAltResult>> {
some_with_fn_name(ctx, array, filter.fn_name()) if array.is_empty() {
return Ok(false);
}
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(
"some".to_string(),
ctx.source().unwrap_or("").to_string(),
err,
Position::NONE,
))
})?
.as_bool()
.unwrap_or(false)
{
return Ok(true);
}
}
Ok(false)
} }
#[rhai_fn(name = "some", return_raw, pure)] #[rhai_fn(name = "some", return_raw, pure)]
pub fn some_with_fn_name( pub fn some_with_fn_name(
@ -540,44 +555,7 @@ mod array_functions {
array: &mut Array, array: &mut Array,
filter: &str, filter: &str,
) -> Result<bool, Box<EvalAltResult>> { ) -> Result<bool, Box<EvalAltResult>> {
if array.is_empty() { some(ctx, array, FnPtr::new(filter)?)
return Ok(false);
}
let mut index_val = Dynamic::UNIT;
for (i, item) in array.iter_mut().enumerate() {
let mut args = [item, &mut index_val];
let found = match ctx.call_fn_raw(filter, true, false, &mut args[..1]) {
Ok(r) => r,
Err(err) => match *err {
EvalAltResult::ErrorFunctionNotFound(fn_sig, _)
if fn_sig.starts_with(filter) =>
{
*args[1] = Dynamic::from(i as INT);
ctx.call_fn_raw(filter, true, false, &mut args)?
}
_ => {
return Err(EvalAltResult::ErrorInFunctionCall(
"some".to_string(),
ctx.source().unwrap_or("").to_string(),
err,
Position::NONE,
)
.into())
}
},
}
.as_bool()
.unwrap_or(false);
if found {
return Ok(true);
}
}
Ok(false)
} }
#[rhai_fn(return_raw, pure)] #[rhai_fn(return_raw, pure)]
pub fn all( pub fn all(
@ -585,7 +563,37 @@ mod array_functions {
array: &mut Array, array: &mut Array,
filter: FnPtr, filter: FnPtr,
) -> Result<bool, Box<EvalAltResult>> { ) -> Result<bool, Box<EvalAltResult>> {
all_with_fn_name(ctx, array, filter.fn_name()) if array.is_empty() {
return Ok(true);
}
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(
"all".to_string(),
ctx.source().unwrap_or("").to_string(),
err,
Position::NONE,
))
})?
.as_bool()
.unwrap_or(false)
{
return Ok(false);
}
}
Ok(true)
} }
#[rhai_fn(name = "all", return_raw, pure)] #[rhai_fn(name = "all", return_raw, pure)]
pub fn all_with_fn_name( pub fn all_with_fn_name(
@ -593,44 +601,7 @@ mod array_functions {
array: &mut Array, array: &mut Array,
filter: &str, filter: &str,
) -> Result<bool, Box<EvalAltResult>> { ) -> Result<bool, Box<EvalAltResult>> {
if array.is_empty() { all(ctx, array, FnPtr::new(filter)?)
return Ok(true);
}
let mut index_val = Dynamic::UNIT;
for (i, item) in array.iter_mut().enumerate() {
let mut args = [item, &mut index_val];
let found = match ctx.call_fn_raw(filter, true, false, &mut args[..1]) {
Ok(r) => r,
Err(err) => match *err {
EvalAltResult::ErrorFunctionNotFound(fn_sig, _)
if fn_sig.starts_with(filter) =>
{
*args[1] = Dynamic::from(i as INT);
ctx.call_fn_raw(filter, true, false, &mut args)?
}
_ => {
return Err(EvalAltResult::ErrorInFunctionCall(
"all".to_string(),
ctx.source().unwrap_or("").to_string(),
err,
Position::NONE,
)
.into())
}
},
}
.as_bool()
.unwrap_or(false);
if !found {
return Ok(false);
}
}
Ok(true)
} }
#[rhai_fn(return_raw)] #[rhai_fn(return_raw)]
pub fn dedup(ctx: NativeCallContext, array: &mut Array) -> Result<(), Box<EvalAltResult>> { pub fn dedup(ctx: NativeCallContext, array: &mut Array) -> Result<(), Box<EvalAltResult>> {
@ -641,23 +612,14 @@ mod array_functions {
ctx: NativeCallContext, ctx: NativeCallContext,
array: &mut Array, array: &mut Array,
comparer: FnPtr, comparer: FnPtr,
) -> Result<(), Box<EvalAltResult>> {
dedup_with_fn_name(ctx, array, comparer.fn_name())
}
#[rhai_fn(name = "dedup", return_raw)]
fn dedup_with_fn_name(
ctx: NativeCallContext,
array: &mut Array,
comparer: &str,
) -> Result<(), Box<EvalAltResult>> { ) -> Result<(), Box<EvalAltResult>> {
if array.is_empty() { if array.is_empty() {
return Ok(()); return Ok(());
} }
array.dedup_by(|x, y| { array.dedup_by(|x, y| {
let mut args = [x, &mut y.clone()]; comparer
.call_dynamic(&ctx, None, [x.clone(), y.clone()])
ctx.call_fn_raw(comparer, true, false, &mut args)
.unwrap_or_else(|_| Dynamic::FALSE) .unwrap_or_else(|_| Dynamic::FALSE)
.as_bool() .as_bool()
.unwrap_or(false) .unwrap_or(false)
@ -665,13 +627,21 @@ mod array_functions {
Ok(()) Ok(())
} }
#[rhai_fn(name = "dedup", return_raw)]
fn dedup_with_fn_name(
ctx: NativeCallContext,
array: &mut Array,
comparer: &str,
) -> Result<(), Box<EvalAltResult>> {
dedup_by_comparer(ctx, array, FnPtr::new(comparer)?)
}
#[rhai_fn(return_raw, pure)] #[rhai_fn(return_raw, pure)]
pub fn reduce( pub fn reduce(
ctx: NativeCallContext, ctx: NativeCallContext,
array: &mut Array, array: &mut Array,
reducer: FnPtr, reducer: FnPtr,
) -> Result<Dynamic, Box<EvalAltResult>> { ) -> Result<Dynamic, Box<EvalAltResult>> {
reduce_with_fn_name(ctx, array, reducer.fn_name()) reduce_with_initial(ctx, array, reducer, Dynamic::UNIT)
} }
#[rhai_fn(name = "reduce", return_raw, pure)] #[rhai_fn(name = "reduce", return_raw, pure)]
pub fn reduce_with_fn_name( pub fn reduce_with_fn_name(
@ -679,7 +649,7 @@ mod array_functions {
array: &mut Array, array: &mut Array,
reducer: &str, reducer: &str,
) -> Result<Dynamic, Box<EvalAltResult>> { ) -> Result<Dynamic, Box<EvalAltResult>> {
reduce_with_fn_name_with_initial(ctx, array, reducer, Dynamic::UNIT) reduce(ctx, array, FnPtr::new(reducer)?)
} }
#[rhai_fn(name = "reduce", return_raw, pure)] #[rhai_fn(name = "reduce", return_raw, pure)]
pub fn reduce_with_initial( pub fn reduce_with_initial(
@ -687,35 +657,23 @@ mod array_functions {
array: &mut Array, array: &mut Array,
reducer: FnPtr, reducer: FnPtr,
initial: Dynamic, initial: Dynamic,
) -> Result<Dynamic, Box<EvalAltResult>> {
reduce_with_fn_name_with_initial(ctx, array, reducer.fn_name(), initial)
}
#[rhai_fn(name = "reduce", return_raw, pure)]
pub fn reduce_with_fn_name_with_initial(
ctx: NativeCallContext,
array: &mut Array,
reducer: &str,
initial: Dynamic,
) -> Result<Dynamic, Box<EvalAltResult>> { ) -> Result<Dynamic, Box<EvalAltResult>> {
if array.is_empty() { if array.is_empty() {
return Ok(initial); return Ok(initial);
} }
let mut result = initial; let mut result = initial;
let mut index_val = Dynamic::UNIT;
for (i, item) in array.iter_mut().enumerate() { for (i, item) in array.iter().enumerate() {
let mut args = [&mut result, &mut item.clone(), &mut index_val]; let item = item.clone();
result = ctx result = reducer
.call_fn_raw(reducer, true, false, &mut args[..2]) .call_dynamic(&ctx, None, [result.clone(), item.clone()])
.or_else(|err| match *err { .or_else(|err| match *err {
EvalAltResult::ErrorFunctionNotFound(fn_sig, _) EvalAltResult::ErrorFunctionNotFound(fn_sig, _)
if fn_sig.starts_with(reducer) => if fn_sig.starts_with(reducer.fn_name()) =>
{ {
*args[1] = item.clone(); reducer.call_dynamic(&ctx, None, [result, item, (i as INT).into()])
*args[2] = Dynamic::from(i as INT);
ctx.call_fn_raw(reducer, true, false, &mut args)
} }
_ => Err(err), _ => Err(err),
}) })
@ -731,13 +689,22 @@ mod array_functions {
Ok(result) Ok(result)
} }
#[rhai_fn(name = "reduce", return_raw, pure)]
pub fn reduce_with_fn_name_with_initial(
ctx: NativeCallContext,
array: &mut Array,
reducer: &str,
initial: Dynamic,
) -> Result<Dynamic, Box<EvalAltResult>> {
reduce_with_initial(ctx, array, FnPtr::new(reducer)?, initial)
}
#[rhai_fn(return_raw, pure)] #[rhai_fn(return_raw, pure)]
pub fn reduce_rev( pub fn reduce_rev(
ctx: NativeCallContext, ctx: NativeCallContext,
array: &mut Array, array: &mut Array,
reducer: FnPtr, reducer: FnPtr,
) -> Result<Dynamic, Box<EvalAltResult>> { ) -> Result<Dynamic, Box<EvalAltResult>> {
reduce_rev_with_fn_name(ctx, array, reducer.fn_name()) reduce_rev_with_initial(ctx, array, reducer, Dynamic::UNIT)
} }
#[rhai_fn(name = "reduce_rev", return_raw, pure)] #[rhai_fn(name = "reduce_rev", return_raw, pure)]
pub fn reduce_rev_with_fn_name( pub fn reduce_rev_with_fn_name(
@ -745,7 +712,7 @@ mod array_functions {
array: &mut Array, array: &mut Array,
reducer: &str, reducer: &str,
) -> Result<Dynamic, Box<EvalAltResult>> { ) -> Result<Dynamic, Box<EvalAltResult>> {
reduce_rev_with_fn_name_with_initial(ctx, array, reducer, Dynamic::UNIT) reduce_rev(ctx, array, FnPtr::new(reducer)?)
} }
#[rhai_fn(name = "reduce_rev", return_raw, pure)] #[rhai_fn(name = "reduce_rev", return_raw, pure)]
pub fn reduce_rev_with_initial( pub fn reduce_rev_with_initial(
@ -753,35 +720,23 @@ mod array_functions {
array: &mut Array, array: &mut Array,
reducer: FnPtr, reducer: FnPtr,
initial: Dynamic, initial: Dynamic,
) -> Result<Dynamic, Box<EvalAltResult>> {
reduce_rev_with_fn_name_with_initial(ctx, array, reducer.fn_name(), initial)
}
#[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,
) -> Result<Dynamic, Box<EvalAltResult>> { ) -> Result<Dynamic, Box<EvalAltResult>> {
if array.is_empty() { if array.is_empty() {
return Ok(initial); return Ok(initial);
} }
let mut result = initial; let mut result = initial;
let mut index_val = Dynamic::UNIT;
for (i, item) in array.iter_mut().enumerate().rev() { for (i, item) in array.iter().enumerate().rev() {
let mut args = [&mut result, &mut item.clone(), &mut index_val]; let item = item.clone();
result = ctx result = reducer
.call_fn_raw(reducer, true, false, &mut args[..2]) .call_dynamic(&ctx, None, [result.clone(), item.clone()])
.or_else(|err| match *err { .or_else(|err| match *err {
EvalAltResult::ErrorFunctionNotFound(fn_sig, _) EvalAltResult::ErrorFunctionNotFound(fn_sig, _)
if fn_sig.starts_with(reducer) => if fn_sig.starts_with(reducer.fn_name()) =>
{ {
*args[1] = item.clone(); reducer.call_dynamic(&ctx, None, [result, item, (i as INT).into()])
*args[2] = Dynamic::from(i as INT);
ctx.call_fn_raw(reducer, true, false, &mut args)
} }
_ => Err(err), _ => Err(err),
}) })
@ -797,6 +752,15 @@ mod array_functions {
Ok(result) Ok(result)
} }
#[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,
) -> Result<Dynamic, Box<EvalAltResult>> {
reduce_rev_with_initial(ctx, array, FnPtr::new(reducer)?, initial)
}
#[rhai_fn(name = "sort", return_raw)] #[rhai_fn(name = "sort", return_raw)]
pub fn sort_with_fn_name( pub fn sort_with_fn_name(
ctx: NativeCallContext, ctx: NativeCallContext,
@ -903,13 +867,52 @@ mod array_functions {
Ok(()) Ok(())
} }
#[rhai_fn(return_raw, pure)] #[rhai_fn(return_raw)]
pub fn drain( pub fn drain(
ctx: NativeCallContext, ctx: NativeCallContext,
array: &mut Array, array: &mut Array,
filter: FnPtr, filter: FnPtr,
) -> Result<Array, Box<EvalAltResult>> { ) -> Result<Array, Box<EvalAltResult>> {
drain_with_fn_name(ctx, array, filter.fn_name()) if array.is_empty() {
return Ok(Array::new());
}
let mut drained = Array::with_capacity(array.len());
let mut i = 0;
let mut x = 0;
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(
"drain".to_string(),
ctx.source().unwrap_or("").to_string(),
err,
Position::NONE,
))
})?
.as_bool()
.unwrap_or(false)
{
drained.push(array.remove(x));
} else {
x += 1;
}
i += 1;
}
Ok(drained)
} }
#[rhai_fn(name = "drain", return_raw)] #[rhai_fn(name = "drain", return_raw)]
pub fn drain_with_fn_name( pub fn drain_with_fn_name(
@ -917,65 +920,7 @@ mod array_functions {
array: &mut Array, array: &mut Array,
filter: &str, filter: &str,
) -> Result<Array, Box<EvalAltResult>> { ) -> Result<Array, Box<EvalAltResult>> {
if array.is_empty() { drain(ctx, array, FnPtr::new(filter)?)
return Ok(Array::new());
}
let mut index_val = Dynamic::UNIT;
let mut removed = Vec::with_capacity(array.len());
let mut count = 0;
for (i, item) in array.iter_mut().enumerate() {
let mut args = [item, &mut index_val];
let remove = match ctx.call_fn_raw(filter, true, false, &mut args[..1]) {
Ok(r) => r,
Err(err) => match *err {
EvalAltResult::ErrorFunctionNotFound(fn_sig, _)
if fn_sig.starts_with(filter) =>
{
*args[1] = Dynamic::from(i as INT);
ctx.call_fn_raw(filter, true, false, &mut args)?
}
_ => {
return Err(EvalAltResult::ErrorInFunctionCall(
"drain".to_string(),
ctx.source().unwrap_or("").to_string(),
err,
Position::NONE,
)
.into())
}
},
}
.as_bool()
.unwrap_or(false);
removed.push(remove);
if remove {
count += 1;
}
}
if count == 0 {
return Ok(Array::new());
}
let mut result = Vec::with_capacity(count);
let mut x = 0;
let mut i = 0;
while i < array.len() {
if removed[x] {
result.push(array.remove(i));
} else {
i += 1;
}
x += 1;
}
Ok(result.into())
} }
#[rhai_fn(name = "drain")] #[rhai_fn(name = "drain")]
pub fn drain_range(array: &mut Array, start: INT, len: INT) -> Array { pub fn drain_range(array: &mut Array, start: INT, len: INT) -> Array {
@ -1004,13 +949,52 @@ mod array_functions {
array.drain(start..start + len).collect() array.drain(start..start + len).collect()
} }
#[rhai_fn(return_raw, pure)] #[rhai_fn(return_raw)]
pub fn retain( pub fn retain(
ctx: NativeCallContext, ctx: NativeCallContext,
array: &mut Array, array: &mut Array,
filter: FnPtr, filter: FnPtr,
) -> Result<Array, Box<EvalAltResult>> { ) -> Result<Array, Box<EvalAltResult>> {
retain_with_fn_name(ctx, array, filter.fn_name()) if array.is_empty() {
return Ok(Array::new());
}
let mut drained = Array::new();
let mut i = 0;
let mut x = 0;
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(
"retain".to_string(),
ctx.source().unwrap_or("").to_string(),
err,
Position::NONE,
))
})?
.as_bool()
.unwrap_or(false)
{
drained.push(array.remove(x));
} else {
x += 1;
}
i += 1;
}
Ok(drained)
} }
#[rhai_fn(name = "retain", return_raw)] #[rhai_fn(name = "retain", return_raw)]
pub fn retain_with_fn_name( pub fn retain_with_fn_name(
@ -1018,65 +1002,7 @@ mod array_functions {
array: &mut Array, array: &mut Array,
filter: &str, filter: &str,
) -> Result<Array, Box<EvalAltResult>> { ) -> Result<Array, Box<EvalAltResult>> {
if array.is_empty() { retain(ctx, array, FnPtr::new(filter)?)
return Ok(Array::new());
}
let mut index_val = Dynamic::UNIT;
let mut removed = Vec::with_capacity(array.len());
let mut count = 0;
for (i, item) in array.iter_mut().enumerate() {
let mut args = [item, &mut index_val];
let keep = match ctx.call_fn_raw(filter, true, false, &mut args[..1]) {
Ok(r) => r,
Err(err) => match *err {
EvalAltResult::ErrorFunctionNotFound(fn_sig, _)
if fn_sig.starts_with(filter) =>
{
*args[1] = Dynamic::from(i as INT);
ctx.call_fn_raw(filter, true, false, &mut args)?
}
_ => {
return Err(EvalAltResult::ErrorInFunctionCall(
"retain".to_string(),
ctx.source().unwrap_or("").to_string(),
err,
Position::NONE,
)
.into())
}
},
}
.as_bool()
.unwrap_or(false);
removed.push(!keep);
if !keep {
count += 1;
}
}
if count == 0 {
return Ok(Array::new());
}
let mut result = Vec::with_capacity(count);
let mut x = 0;
let mut i = 0;
while i < array.len() {
if removed[x] {
result.push(array.remove(i));
} else {
i += 1;
}
x += 1;
}
Ok(result.into())
} }
#[rhai_fn(name = "retain")] #[rhai_fn(name = "retain")]
pub fn retain_range(array: &mut Array, start: INT, len: INT) -> Array { pub fn retain_range(array: &mut Array, start: INT, len: INT) -> Array {