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 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);
|
||||
} else {
|
||||
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 {
|
||||
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;
|
||||
break;
|
||||
} 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 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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
/// eventually return `None`. Furthermore, returning `0`, while valid, is
|
||||
/// 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();
|
||||
|
||||
base.get_next_enumerant(last_index)
|
||||
Ok(base.get_next_enumerant(last_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
|
||||
/// valid here. A value of `None` indicates that no enumerant with that
|
||||
/// 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();
|
||||
|
||||
base.get_enumerant_name(index)
|
||||
Ok(base.get_enumerant_name(index).unwrap_or(Value::Undefined))
|
||||
}
|
||||
|
||||
/// 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,
|
||||
activation: &mut Activation<'_, 'gc, '_>,
|
||||
) -> Result<Value<'gc>, Error> {
|
||||
let name = self.get_enumerant_name(index);
|
||||
if let Some(name) = name {
|
||||
let name = name.coerce_to_string(activation)?;
|
||||
Ok(self.get_property(self.into(), &QName::dynamic_name(name).into(), activation)?)
|
||||
} else {
|
||||
Ok(Value::Undefined)
|
||||
}
|
||||
let name = self
|
||||
.get_enumerant_name(index, activation)?
|
||||
.coerce_to_string(activation)?;
|
||||
self.get_property(self.into(), &QName::dynamic_name(name).into(), activation)
|
||||
}
|
||||
|
||||
/// 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)
|
||||
}
|
||||
|
||||
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 last_enumerant = read.base.get_last_enumerant();
|
||||
let array_length = read.array.length() as u32;
|
||||
|
||||
if last_index < last_enumerant + array_length {
|
||||
Some(last_index.saturating_add(1))
|
||||
Ok(Some(last_index.saturating_add(1)))
|
||||
} 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;
|
||||
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 {
|
||||
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)
|
||||
}
|
||||
|
||||
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 last_enumerant = read.base.get_last_enumerant();
|
||||
let object_space_length = read.object_space.keys().len() as u32;
|
||||
|
||||
if last_index < last_enumerant + object_space_length {
|
||||
Some(last_index.saturating_add(1))
|
||||
Ok(Some(last_index.saturating_add(1)))
|
||||
} 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 last_enumerant = read.base.get_last_enumerant();
|
||||
|
||||
if index < last_enumerant {
|
||||
read.base.get_enumerant_name(index)
|
||||
Ok(read
|
||||
.base
|
||||
.get_enumerant_name(index)
|
||||
.unwrap_or(Value::Undefined))
|
||||
} else {
|
||||
let object_space_index = index.saturating_sub(last_enumerant);
|
||||
|
||||
read.object_space
|
||||
Ok(read
|
||||
.object_space
|
||||
.keys()
|
||||
.nth(object_space_index as usize)
|
||||
.cloned()
|
||||
.map(|v| v.into())
|
||||
.unwrap_or(Value::Undefined))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -221,4 +221,43 @@ impl<'gc> TObject<'gc> for ProxyObject<'gc> {
|
|||
)?
|
||||
.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)
|
||||
}
|
||||
|
||||
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 {
|
||||
Some(last_index.saturating_add(1))
|
||||
Ok(Some(last_index.saturating_add(1)))
|
||||
} 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 {
|
||||
index.checked_sub(1).map(|index| index.into())
|
||||
Ok(index
|
||||
.checked_sub(1)
|
||||
.map(|index| index.into())
|
||||
.unwrap_or(Value::Undefined))
|
||||
} else {
|
||||
None
|
||||
Ok("".into())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue