Skip to content

Commit cce5a1e

Browse files
authored
Merge pull request #1086 from yinho999/bug/array-index_of
fix: array.index_of(string) misdispatches to deprecated fn-name overload
2 parents 4e8bb86 + 0fb6ffa commit cce5a1e

4 files changed

Lines changed: 111 additions & 17 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ Bug fixes
99

1010
* `Engine::compact_script` now properly compacts scripts with custom syntax that uses `$raw$` (thanks [`@yuvalrakavy`](https://github.com/yuvalrakavy) [`#1079`](https://github.com/rhaiscript/rhai/pull/1079)).
1111
* The string methods `split`, `split_rev` and their variants are now marked pure so they can be called on `const` strings ([`#1081`](https://github.com/rhaiscript/rhai/issues/1081)).
12+
* `array.index_of` now falls back to value comparison for string argument when no script function of that name is registered ([`#795`](https://github.com/rhaiscript/rhai/issues/795)).
1213

1314
New features
1415
------------

src/api/deprecated.rs

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -848,6 +848,7 @@ use crate::plugin::*;
848848
#[export_module]
849849
pub mod deprecated_array_functions {
850850
use crate::packages::array_basic::array_functions::*;
851+
use crate::packages::array_basic::index_of_start_inner;
851852
use crate::{Array, INT};
852853

853854
/// Iterate through all the elements in the array, applying a function named by `mapper` to each
@@ -963,7 +964,25 @@ pub mod deprecated_array_functions {
963964
array: &mut Array,
964965
filter: &str,
965966
) -> RhaiResultOf<INT> {
966-
index_of_filter(ctx, array, FnPtr::new(filter)?)
967+
if array.is_empty() {
968+
return Ok(-1);
969+
}
970+
if let Ok(fp) = FnPtr::new(filter) {
971+
match index_of_start_inner(&ctx, array, fp, 0) {
972+
Ok(found) => return Ok(found),
973+
Err(err) => match *err {
974+
EvalAltResult::ErrorFunctionNotFound(ref sig, ..)
975+
if sig.starts_with(filter) => {}
976+
EvalAltResult::ErrorInFunctionCall(_, _, ref inner, _) => match **inner {
977+
EvalAltResult::ErrorFunctionNotFound(ref sig, ..)
978+
if sig.starts_with(filter) => {}
979+
_ => return Err(err),
980+
},
981+
_ => return Err(err),
982+
},
983+
}
984+
}
985+
index_of_starting_from(ctx, array, filter.into(), 0)
967986
}
968987
/// Iterate through all the elements in the array, starting from a particular `start` position,
969988
/// applying a function named by `filter` to each element in turn, and return the index of the
@@ -1015,7 +1034,26 @@ pub mod deprecated_array_functions {
10151034
filter: &str,
10161035
start: INT,
10171036
) -> RhaiResultOf<INT> {
1018-
index_of_filter_starting_from(ctx, array, FnPtr::new(filter)?, start)
1037+
if array.is_empty() {
1038+
return Ok(-1);
1039+
}
1040+
1041+
if let Ok(fp) = FnPtr::new(filter) {
1042+
match index_of_start_inner(&ctx, array, fp, start) {
1043+
Ok(found) => return Ok(found),
1044+
Err(err) => match *err {
1045+
EvalAltResult::ErrorFunctionNotFound(ref sig, ..)
1046+
if sig.starts_with(filter) => {}
1047+
EvalAltResult::ErrorInFunctionCall(_, _, ref inner, _) => match **inner {
1048+
EvalAltResult::ErrorFunctionNotFound(ref sig, ..)
1049+
if sig.starts_with(filter) => {}
1050+
_ => return Err(err),
1051+
},
1052+
_ => return Err(err),
1053+
},
1054+
}
1055+
}
1056+
index_of_starting_from(ctx, array, filter.into(), start)
10191057
}
10201058
/// Return `true` if any element in the array that returns `true` when applied a function named
10211059
/// by `filter`.

src/packages/array_basic.rs

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,33 @@ def_package! {
2626
}
2727
}
2828

29+
/// Temporary helper function supporting deprecated `index_of_by_fn_name*` functions.
30+
/// Can be removed in the next major version
31+
pub(crate) fn index_of_start_inner(
32+
ctx: &NativeCallContext,
33+
array: &mut Array,
34+
filter: FnPtr,
35+
start: INT,
36+
) -> RhaiResultOf<INT> {
37+
if array.is_empty() {
38+
return Ok(-1);
39+
}
40+
let (start, ..) = calc_offset_len(array.len(), start, 0);
41+
for (i, item) in array.iter_mut().enumerate().skip(start) {
42+
let ex = [INT::try_from(i).unwrap_or(INT::MAX).into()];
43+
44+
if filter
45+
.call_raw_with_extra_args("index_of", &ctx, Some(item), [], ex, Some(0))?
46+
.as_bool()
47+
.unwrap_or(false)
48+
{
49+
return Ok(INT::try_from(i).unwrap_or(INT::MAX));
50+
}
51+
}
52+
53+
Ok(-1 as INT)
54+
}
55+
2956
#[export_module]
3057
pub mod array_functions {
3158
/// Number of elements in the array.
@@ -974,21 +1001,7 @@ pub mod array_functions {
9741001
return Ok(-1);
9751002
}
9761003

977-
let (start, ..) = calc_offset_len(array.len(), start, 0);
978-
979-
for (i, item) in array.iter_mut().enumerate().skip(start) {
980-
let ex = [INT::try_from(i).unwrap_or(INT::MAX).into()];
981-
982-
if filter
983-
.call_raw_with_extra_args("index_of", &ctx, Some(item), [], ex, Some(0))?
984-
.as_bool()
985-
.unwrap_or(false)
986-
{
987-
return Ok(INT::try_from(i).unwrap_or(INT::MAX));
988-
}
989-
}
990-
991-
Ok(-1 as INT)
1004+
index_of_start_inner(&ctx, array, filter, start)
9921005
}
9931006
/// Iterate through all the elements in the array, applying a `filter` function to each element
9941007
/// in turn, and return a copy of the first element that returns `true`. If no element returns

tests/arrays.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,48 @@ fn test_arrays_elvis() {
501501
engine.run("let x = (); x?[2] = 42").unwrap();
502502
}
503503

504+
#[test]
505+
fn test_arrays_index_of() {
506+
let engine = Engine::new();
507+
// INT array
508+
assert_eq!(engine.eval::<INT>("index_of([1, 2, 3], 2)").unwrap(), 1);
509+
// String array
510+
assert_eq!(engine.eval::<INT>(r#"index_of(["hi", "hello", "world"], "hello")"#).unwrap(), 1);
511+
assert_eq!(engine.eval::<INT>(r#"index_of(["a","b","c","b"], "b", 2)"#).unwrap(), 3);
512+
assert_eq!(engine.eval::<INT>(r#"index_of(["a","b"], "missing")"#).unwrap(), -1);
513+
514+
// Cross-type behavior
515+
assert_eq!(engine.eval::<INT>(r#"index_of([1,2,3], "foo")"#).unwrap(), -1);
516+
}
517+
518+
#[test]
519+
#[cfg(not(feature = "no_object"))]
520+
#[cfg(not(feature = "no_function"))]
521+
fn test_arrays_index_of_with_named_fn() {
522+
let engine = Engine::new();
523+
assert_eq!(
524+
engine
525+
.eval::<INT>(
526+
r#"
527+
fn is_two(x) { x == 2 }
528+
[1,2,3,2].index_of("is_two")
529+
"#
530+
)
531+
.unwrap(),
532+
1
533+
);
534+
assert_eq!(
535+
engine
536+
.eval::<INT>(
537+
r#"
538+
fn is_two(x) { x == 2 }
539+
[1,2,3,2].index_of("is_two", 2)
540+
"#
541+
)
542+
.unwrap(),
543+
3
544+
);
545+
}
504546
#[test]
505547
#[cfg(feature = "internals")]
506548
fn test_array_invalid_index_callback() {

0 commit comments

Comments
 (0)