avm2: Impl `Proxy`'s enumeration-related methods.
This commit is contained in:
parent
4289f89350
commit
4cfa3253d5
|
@ -2442,7 +2442,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
|
||||||
let cur_index = self.context.avm2.pop().coerce_to_u32(self)?;
|
let cur_index = self.context.avm2.pop().coerce_to_u32(self)?;
|
||||||
let object = self.context.avm2.pop().coerce_to_object(self)?;
|
let object = self.context.avm2.pop().coerce_to_object(self)?;
|
||||||
|
|
||||||
if let Some(next_index) = object.get_next_enumerant(cur_index) {
|
if let Some(next_index) = object.get_next_enumerant(cur_index, self)? {
|
||||||
self.context.avm2.push(next_index);
|
self.context.avm2.push(next_index);
|
||||||
} else {
|
} else {
|
||||||
self.context.avm2.push(0.0);
|
self.context.avm2.push(0.0);
|
||||||
|
@ -2463,7 +2463,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
|
||||||
);
|
);
|
||||||
|
|
||||||
while let Some(cur_object) = object {
|
while let Some(cur_object) = object {
|
||||||
if let Some(index) = cur_object.get_next_enumerant(cur_index) {
|
if let Some(index) = cur_object.get_next_enumerant(cur_index, self)? {
|
||||||
cur_index = index;
|
cur_index = index;
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
|
@ -2491,9 +2491,9 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
|
||||||
let cur_index = self.context.avm2.pop().coerce_to_number(self)?;
|
let cur_index = self.context.avm2.pop().coerce_to_number(self)?;
|
||||||
let object = self.context.avm2.pop().coerce_to_object(self)?;
|
let object = self.context.avm2.pop().coerce_to_object(self)?;
|
||||||
|
|
||||||
let name = object.get_enumerant_name(cur_index as u32);
|
let name = object.get_enumerant_name(cur_index as u32, self)?;
|
||||||
|
|
||||||
self.context.avm2.push(name.unwrap_or(Value::Undefined));
|
self.context.avm2.push(name);
|
||||||
|
|
||||||
Ok(FrameControl::Continue)
|
Ok(FrameControl::Continue)
|
||||||
}
|
}
|
||||||
|
|
|
@ -794,10 +794,14 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
|
||||||
/// Repeated calls to this function with prior return values must
|
/// Repeated calls to this function with prior return values must
|
||||||
/// eventually return `None`. Furthermore, returning `0`, while valid, is
|
/// eventually return `None`. Furthermore, returning `0`, while valid, is
|
||||||
/// treated by AVM2 code as signalling `None`.
|
/// treated by AVM2 code as signalling `None`.
|
||||||
fn get_next_enumerant(self, last_index: u32) -> Option<u32> {
|
fn get_next_enumerant(
|
||||||
|
self,
|
||||||
|
last_index: u32,
|
||||||
|
_activation: &mut Activation<'_, 'gc, '_>,
|
||||||
|
) -> Result<Option<u32>, Error> {
|
||||||
let base = self.base();
|
let base = self.base();
|
||||||
|
|
||||||
base.get_next_enumerant(last_index)
|
Ok(base.get_next_enumerant(last_index))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieve a given enumerable name by index.
|
/// Retrieve a given enumerable name by index.
|
||||||
|
@ -806,10 +810,14 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
|
||||||
/// `get_next_enumerant`. Only enumerants returned by that function are
|
/// `get_next_enumerant`. Only enumerants returned by that function are
|
||||||
/// valid here. A value of `None` indicates that no enumerant with that
|
/// valid here. A value of `None` indicates that no enumerant with that
|
||||||
/// index exists.
|
/// index exists.
|
||||||
fn get_enumerant_name(self, index: u32) -> Option<Value<'gc>> {
|
fn get_enumerant_name(
|
||||||
|
self,
|
||||||
|
index: u32,
|
||||||
|
_activation: &mut Activation<'_, 'gc, '_>,
|
||||||
|
) -> Result<Value<'gc>, Error> {
|
||||||
let base = self.base();
|
let base = self.base();
|
||||||
|
|
||||||
base.get_enumerant_name(index)
|
Ok(base.get_enumerant_name(index).unwrap_or(Value::Undefined))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieve a given enumerable value by index.
|
/// Retrieve a given enumerable value by index.
|
||||||
|
@ -821,13 +829,10 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
|
||||||
index: u32,
|
index: u32,
|
||||||
activation: &mut Activation<'_, 'gc, '_>,
|
activation: &mut Activation<'_, 'gc, '_>,
|
||||||
) -> Result<Value<'gc>, Error> {
|
) -> Result<Value<'gc>, Error> {
|
||||||
let name = self.get_enumerant_name(index);
|
let name = self
|
||||||
if let Some(name) = name {
|
.get_enumerant_name(index, activation)?
|
||||||
let name = name.coerce_to_string(activation)?;
|
.coerce_to_string(activation)?;
|
||||||
Ok(self.get_property(self.into(), &QName::dynamic_name(name).into(), activation)?)
|
self.get_property(self.into(), &QName::dynamic_name(name).into(), activation)
|
||||||
} else {
|
|
||||||
Ok(Value::Undefined)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determine if a property is currently enumerable.
|
/// Determine if a property is currently enumerable.
|
||||||
|
|
|
@ -199,24 +199,38 @@ impl<'gc> TObject<'gc> for ArrayObject<'gc> {
|
||||||
self.0.read().base.resolve_any(local_name)
|
self.0.read().base.resolve_any(local_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_next_enumerant(self, last_index: u32) -> Option<u32> {
|
fn get_next_enumerant(
|
||||||
|
self,
|
||||||
|
last_index: u32,
|
||||||
|
_activation: &mut Activation<'_, 'gc, '_>,
|
||||||
|
) -> Result<Option<u32>, Error> {
|
||||||
let read = self.0.read();
|
let read = self.0.read();
|
||||||
let last_enumerant = read.base.get_last_enumerant();
|
let last_enumerant = read.base.get_last_enumerant();
|
||||||
let array_length = read.array.length() as u32;
|
let array_length = read.array.length() as u32;
|
||||||
|
|
||||||
if last_index < last_enumerant + array_length {
|
if last_index < last_enumerant + array_length {
|
||||||
Some(last_index.saturating_add(1))
|
Ok(Some(last_index.saturating_add(1)))
|
||||||
} else {
|
} else {
|
||||||
None
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_enumerant_name(self, index: u32) -> Option<Value<'gc>> {
|
fn get_enumerant_name(
|
||||||
|
self,
|
||||||
|
index: u32,
|
||||||
|
_activation: &mut Activation<'_, 'gc, '_>,
|
||||||
|
) -> Result<Value<'gc>, Error> {
|
||||||
let arr_len = self.0.read().array.length() as u32;
|
let arr_len = self.0.read().array.length() as u32;
|
||||||
if arr_len >= index {
|
if arr_len >= index {
|
||||||
index.checked_sub(1).map(|index| index.into())
|
Ok(index
|
||||||
|
.checked_sub(1)
|
||||||
|
.map(|index| index.into())
|
||||||
|
.unwrap_or(Value::Undefined))
|
||||||
} else {
|
} else {
|
||||||
self.base().get_enumerant_name(index - arr_len)
|
Ok(self
|
||||||
|
.base()
|
||||||
|
.get_enumerant_name(index - arr_len)
|
||||||
|
.unwrap_or(Value::Undefined))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -111,32 +111,45 @@ impl<'gc> TObject<'gc> for DictionaryObject<'gc> {
|
||||||
Some(self)
|
Some(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_next_enumerant(self, last_index: u32) -> Option<u32> {
|
fn get_next_enumerant(
|
||||||
|
self,
|
||||||
|
last_index: u32,
|
||||||
|
_activation: &mut Activation<'_, 'gc, '_>,
|
||||||
|
) -> Result<Option<u32>, Error> {
|
||||||
let read = self.0.read();
|
let read = self.0.read();
|
||||||
let last_enumerant = read.base.get_last_enumerant();
|
let last_enumerant = read.base.get_last_enumerant();
|
||||||
let object_space_length = read.object_space.keys().len() as u32;
|
let object_space_length = read.object_space.keys().len() as u32;
|
||||||
|
|
||||||
if last_index < last_enumerant + object_space_length {
|
if last_index < last_enumerant + object_space_length {
|
||||||
Some(last_index.saturating_add(1))
|
Ok(Some(last_index.saturating_add(1)))
|
||||||
} else {
|
} else {
|
||||||
None
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_enumerant_name(self, index: u32) -> Option<Value<'gc>> {
|
fn get_enumerant_name(
|
||||||
|
self,
|
||||||
|
index: u32,
|
||||||
|
_activation: &mut Activation<'_, 'gc, '_>,
|
||||||
|
) -> Result<Value<'gc>, Error> {
|
||||||
let read = self.0.read();
|
let read = self.0.read();
|
||||||
let last_enumerant = read.base.get_last_enumerant();
|
let last_enumerant = read.base.get_last_enumerant();
|
||||||
|
|
||||||
if index < last_enumerant {
|
if index < last_enumerant {
|
||||||
read.base.get_enumerant_name(index)
|
Ok(read
|
||||||
|
.base
|
||||||
|
.get_enumerant_name(index)
|
||||||
|
.unwrap_or(Value::Undefined))
|
||||||
} else {
|
} else {
|
||||||
let object_space_index = index.saturating_sub(last_enumerant);
|
let object_space_index = index.saturating_sub(last_enumerant);
|
||||||
|
|
||||||
read.object_space
|
Ok(read
|
||||||
|
.object_space
|
||||||
.keys()
|
.keys()
|
||||||
.nth(object_space_index as usize)
|
.nth(object_space_index as usize)
|
||||||
.cloned()
|
.cloned()
|
||||||
.map(|v| v.into())
|
.map(|v| v.into())
|
||||||
|
.unwrap_or(Value::Undefined))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -221,4 +221,43 @@ impl<'gc> TObject<'gc> for ProxyObject<'gc> {
|
||||||
)?
|
)?
|
||||||
.coerce_to_boolean())
|
.coerce_to_boolean())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_next_enumerant(
|
||||||
|
self,
|
||||||
|
last_index: u32,
|
||||||
|
activation: &mut Activation<'_, 'gc, '_>,
|
||||||
|
) -> Result<Option<u32>, Error> {
|
||||||
|
Ok(Some(
|
||||||
|
self.call_property(
|
||||||
|
&QName::new(Namespace::Namespace(NS_FLASH_PROXY.into()), "nextNameIndex").into(),
|
||||||
|
&[last_index.into()],
|
||||||
|
activation,
|
||||||
|
)?
|
||||||
|
.coerce_to_u32(activation)?,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_enumerant_name(
|
||||||
|
self,
|
||||||
|
index: u32,
|
||||||
|
activation: &mut Activation<'_, 'gc, '_>,
|
||||||
|
) -> Result<Value<'gc>, Error> {
|
||||||
|
self.call_property(
|
||||||
|
&QName::new(Namespace::Namespace(NS_FLASH_PROXY.into()), "nextName").into(),
|
||||||
|
&[index.into()],
|
||||||
|
activation,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_enumerant_value(
|
||||||
|
self,
|
||||||
|
index: u32,
|
||||||
|
activation: &mut Activation<'_, 'gc, '_>,
|
||||||
|
) -> Result<Value<'gc>, Error> {
|
||||||
|
self.call_property(
|
||||||
|
&QName::new(Namespace::Namespace(NS_FLASH_PROXY.into()), "nextValue").into(),
|
||||||
|
&[index.into()],
|
||||||
|
activation,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -227,19 +227,30 @@ impl<'gc> TObject<'gc> for VectorObject<'gc> {
|
||||||
self.0.read().base.resolve_any(local_name)
|
self.0.read().base.resolve_any(local_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_next_enumerant(self, last_index: u32) -> Option<u32> {
|
fn get_next_enumerant(
|
||||||
|
self,
|
||||||
|
last_index: u32,
|
||||||
|
_activation: &mut Activation<'_, 'gc, '_>,
|
||||||
|
) -> Result<Option<u32>, Error> {
|
||||||
if last_index < self.0.read().vector.length() as u32 {
|
if last_index < self.0.read().vector.length() as u32 {
|
||||||
Some(last_index.saturating_add(1))
|
Ok(Some(last_index.saturating_add(1)))
|
||||||
} else {
|
} else {
|
||||||
None
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_enumerant_name(self, index: u32) -> Option<Value<'gc>> {
|
fn get_enumerant_name(
|
||||||
|
self,
|
||||||
|
index: u32,
|
||||||
|
_activation: &mut Activation<'_, 'gc, '_>,
|
||||||
|
) -> Result<Value<'gc>, Error> {
|
||||||
if self.0.read().vector.length() as u32 >= index {
|
if self.0.read().vector.length() as u32 >= index {
|
||||||
index.checked_sub(1).map(|index| index.into())
|
Ok(index
|
||||||
|
.checked_sub(1)
|
||||||
|
.map(|index| index.into())
|
||||||
|
.unwrap_or(Value::Undefined))
|
||||||
} else {
|
} else {
|
||||||
None
|
Ok("".into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue