avm2: Implement `indexOf` and `lastIndexOf`
This commit is contained in:
parent
7aa1ab82e4
commit
0ece924877
|
@ -2,6 +2,15 @@
|
|||
|
||||
use crate::avm2::value::Value;
|
||||
use gc_arena::Collect;
|
||||
use std::iter::ExactSizeIterator;
|
||||
|
||||
/// Trait which exists purely so that we can reverse the iterators that come
|
||||
/// out of `ArrayStorage.iter`.
|
||||
///
|
||||
/// Not to be confused with the `ArrayIterator` struct in `globals::array`.
|
||||
pub trait ArrayIterator: DoubleEndedIterator + ExactSizeIterator {}
|
||||
|
||||
impl<T> ArrayIterator for T where T: DoubleEndedIterator + ExactSizeIterator {}
|
||||
|
||||
/// The array storage portion of an array object.
|
||||
///
|
||||
|
@ -93,7 +102,7 @@ impl<'gc> ArrayStorage<'gc> {
|
|||
}
|
||||
|
||||
/// Iterate over array values.
|
||||
pub fn iter<'a>(&'a self) -> impl Iterator<Item = Option<Value<'gc>>> + 'a {
|
||||
pub fn iter<'a>(&'a self) -> impl ArrayIterator<Item = Option<Value<'gc>>> + 'a {
|
||||
self.storage.iter().cloned()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -452,6 +452,64 @@ pub fn some<'gc>(
|
|||
Ok(Value::Undefined)
|
||||
}
|
||||
|
||||
/// Implements `Array.indexOf`
|
||||
pub fn index_of<'gc>(
|
||||
activation: &mut Activation<'_, 'gc, '_>,
|
||||
this: Option<Object<'gc>>,
|
||||
args: &[Value<'gc>],
|
||||
) -> Result<Value<'gc>, Error> {
|
||||
if let Some(this) = this {
|
||||
if let Some(array) = this.as_array_storage() {
|
||||
let search_val = args.get(0).cloned().unwrap_or(Value::Undefined);
|
||||
let from = args
|
||||
.get(1)
|
||||
.cloned()
|
||||
.unwrap_or_else(|| 0.into())
|
||||
.coerce_to_u32(activation)?;
|
||||
|
||||
for (i, val) in array.iter().enumerate() {
|
||||
let val = resolve_array_hole(activation, this, i, val)?;
|
||||
if i >= from as usize && val == search_val {
|
||||
return Ok(i.into());
|
||||
}
|
||||
}
|
||||
|
||||
return Ok((-1).into());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Value::Undefined)
|
||||
}
|
||||
|
||||
/// Implements `Array.lastIndexOf`
|
||||
pub fn last_index_of<'gc>(
|
||||
activation: &mut Activation<'_, 'gc, '_>,
|
||||
this: Option<Object<'gc>>,
|
||||
args: &[Value<'gc>],
|
||||
) -> Result<Value<'gc>, Error> {
|
||||
if let Some(this) = this {
|
||||
if let Some(array) = this.as_array_storage() {
|
||||
let search_val = args.get(0).cloned().unwrap_or(Value::Undefined);
|
||||
let from = args
|
||||
.get(1)
|
||||
.cloned()
|
||||
.unwrap_or_else(|| i32::MAX.into())
|
||||
.coerce_to_u32(activation)?;
|
||||
|
||||
for (i, val) in array.iter().enumerate().rev() {
|
||||
let val = resolve_array_hole(activation, this, i, val)?;
|
||||
if i <= from as usize && val == search_val {
|
||||
return Ok(i.into());
|
||||
}
|
||||
}
|
||||
|
||||
return Ok((-1).into());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Value::Undefined)
|
||||
}
|
||||
|
||||
/// Construct `Array`'s class.
|
||||
pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>> {
|
||||
let class = Class::new(
|
||||
|
@ -512,5 +570,15 @@ pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>
|
|||
Method::from_builtin(some),
|
||||
));
|
||||
|
||||
class.write(mc).define_instance_trait(Trait::from_method(
|
||||
QName::new(Namespace::public_namespace(), "indexOf"),
|
||||
Method::from_builtin(index_of),
|
||||
));
|
||||
|
||||
class.write(mc).define_instance_trait(Trait::from_method(
|
||||
QName::new(Namespace::public_namespace(), "lastIndexOf"),
|
||||
Method::from_builtin(last_index_of),
|
||||
));
|
||||
|
||||
class
|
||||
}
|
||||
|
|
|
@ -369,6 +369,8 @@ swf_tests! {
|
|||
(as3_array_filter, "avm2/array_filter", 1),
|
||||
(as3_array_every, "avm2/array_every", 1),
|
||||
(as3_array_some, "avm2/array_some", 1),
|
||||
(as3_array_indexof, "avm2/array_indexof", 1),
|
||||
(as3_array_lastindexof, "avm2/array_lastindexof", 1),
|
||||
}
|
||||
|
||||
// TODO: These tests have some inaccuracies currently, so we use approx_eq to test that numeric values are close enough.
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
package {
|
||||
public class Test {
|
||||
}
|
||||
}
|
||||
|
||||
trace("//var a = new Array(5,\"5\",3,false,4,5,undefined,9)");
|
||||
var a = new Array(5,"5",3,false,4,5,undefined,9);
|
||||
|
||||
trace("//a.indexOf(5);")
|
||||
trace(a.indexOf(5));
|
||||
|
||||
trace("//a.indexOf(5, 1);")
|
||||
trace(a.indexOf(5, 1));
|
||||
|
||||
trace("//a.indexOf(5, 2);")
|
||||
trace(a.indexOf(5, 2));
|
||||
|
||||
trace("//a.indexOf(5, 6);")
|
||||
trace(a.indexOf(5, 6));
|
||||
|
||||
trace("//a.indexOf(5, 10);")
|
||||
trace(a.indexOf(5, 10));
|
||||
|
||||
trace("//a.indexOf(true);");
|
||||
trace(a.indexOf(true));
|
||||
|
||||
trace("//a.indexOf(undefined);");
|
||||
trace(a.indexOf(undefined));
|
||||
|
||||
trace("//a.indexOf(\"5\");");
|
||||
trace(a.indexOf("5"));
|
|
@ -0,0 +1,17 @@
|
|||
//var a = new Array(5,"5",3,false,4,5,undefined,9)
|
||||
//a.indexOf(5);
|
||||
0
|
||||
//a.indexOf(5, 1);
|
||||
5
|
||||
//a.indexOf(5, 2);
|
||||
5
|
||||
//a.indexOf(5, 6);
|
||||
-1
|
||||
//a.indexOf(5, 10);
|
||||
-1
|
||||
//a.indexOf(true);
|
||||
-1
|
||||
//a.indexOf(undefined);
|
||||
6
|
||||
//a.indexOf("5");
|
||||
1
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,31 @@
|
|||
package {
|
||||
public class Test {
|
||||
}
|
||||
}
|
||||
|
||||
trace("//var a = new Array(5,\"5\",3,false,4,5,undefined,9)");
|
||||
var a = new Array(5,"5",3,false,4,5,undefined,9);
|
||||
|
||||
trace("//a.lastIndexOf(5);")
|
||||
trace(a.lastIndexOf(5));
|
||||
|
||||
trace("//a.lastIndexOf(5, 1);")
|
||||
trace(a.lastIndexOf(5, 1));
|
||||
|
||||
trace("//a.lastIndexOf(5, 2);")
|
||||
trace(a.lastIndexOf(5, 2));
|
||||
|
||||
trace("//a.lastIndexOf(5, 6);")
|
||||
trace(a.lastIndexOf(5, 6));
|
||||
|
||||
trace("//a.lastIndexOf(5, 10);")
|
||||
trace(a.lastIndexOf(5, 10));
|
||||
|
||||
trace("//a.lastIndexOf(true);");
|
||||
trace(a.lastIndexOf(true));
|
||||
|
||||
trace("//a.lastIndexOf(undefined);");
|
||||
trace(a.lastIndexOf(undefined));
|
||||
|
||||
trace("//a.lastIndexOf(\"5\");");
|
||||
trace(a.lastIndexOf("5"));
|
|
@ -0,0 +1,17 @@
|
|||
//var a = new Array(5,"5",3,false,4,5,undefined,9)
|
||||
//a.lastIndexOf(5);
|
||||
5
|
||||
//a.lastIndexOf(5, 1);
|
||||
0
|
||||
//a.lastIndexOf(5, 2);
|
||||
0
|
||||
//a.lastIndexOf(5, 6);
|
||||
5
|
||||
//a.lastIndexOf(5, 10);
|
||||
5
|
||||
//a.lastIndexOf(true);
|
||||
-1
|
||||
//a.lastIndexOf(undefined);
|
||||
6
|
||||
//a.lastIndexOf("5");
|
||||
1
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue