avm2: Remove custom_object macros

This commit is contained in:
EmperorBale 2021-09-21 21:55:31 -07:00 committed by kmeisthax
parent 54d417c539
commit 3f81910bb6
21 changed files with 378 additions and 948 deletions

View File

@ -28,7 +28,6 @@ mod array_object;
mod bitmapdata_object; mod bitmapdata_object;
mod bytearray_object; mod bytearray_object;
mod class_object; mod class_object;
mod custom_object;
mod date_object; mod date_object;
mod dispatch_object; mod dispatch_object;
mod domain_object; mod domain_object;
@ -60,7 +59,7 @@ pub use crate::avm2::object::loaderinfo_object::{
pub use crate::avm2::object::namespace_object::{namespace_allocator, NamespaceObject}; pub use crate::avm2::object::namespace_object::{namespace_allocator, NamespaceObject};
pub use crate::avm2::object::primitive_object::{primitive_allocator, PrimitiveObject}; pub use crate::avm2::object::primitive_object::{primitive_allocator, PrimitiveObject};
pub use crate::avm2::object::regexp_object::{regexp_allocator, RegExpObject}; pub use crate::avm2::object::regexp_object::{regexp_allocator, RegExpObject};
pub use crate::avm2::object::script_object::ScriptObject; pub use crate::avm2::object::script_object::{ScriptObject, ScriptObjectData};
pub use crate::avm2::object::sound_object::{sound_allocator, SoundObject}; pub use crate::avm2::object::sound_object::{sound_allocator, SoundObject};
pub use crate::avm2::object::soundchannel_object::{soundchannel_allocator, SoundChannelObject}; pub use crate::avm2::object::soundchannel_object::{soundchannel_allocator, SoundChannelObject};
pub use crate::avm2::object::stage_object::{stage_allocator, StageObject}; pub use crate::avm2::object::stage_object::{stage_allocator, StageObject};
@ -96,6 +95,11 @@ pub use crate::avm2::object::xml_object::{xml_allocator, XmlObject};
} }
)] )]
pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy { pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy {
/// Get the base of this object.
/// Any trait method implementations that were not overrided will foward the call to this instead.
fn base(&self) -> Ref<ScriptObjectData<'gc>>;
fn base_mut(&self, mc: MutationContext<'gc, '_>) -> RefMut<ScriptObjectData<'gc>>;
/// Retrieve a property by QName, after multiname resolution, prototype /// Retrieve a property by QName, after multiname resolution, prototype
/// lookups, and all other considerations have been taken. /// lookups, and all other considerations have been taken.
/// ///
@ -106,7 +110,14 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
receiver: Object<'gc>, receiver: Object<'gc>,
name: &QName<'gc>, name: &QName<'gc>,
activation: &mut Activation<'_, 'gc, '_>, activation: &mut Activation<'_, 'gc, '_>,
) -> Result<Value<'gc>, Error>; ) -> Result<Value<'gc>, Error> {
let base = self.base();
let rv = base.get_property_local(receiver, name, activation)?;
drop(base);
rv.resolve(activation)
}
/// Retrieve a property by Multiname lookup. /// Retrieve a property by Multiname lookup.
/// ///
@ -189,7 +200,17 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
name: &QName<'gc>, name: &QName<'gc>,
value: Value<'gc>, value: Value<'gc>,
activation: &mut Activation<'_, 'gc, '_>, activation: &mut Activation<'_, 'gc, '_>,
) -> Result<(), Error>; ) -> Result<(), Error> {
let mut base = self.base_mut(activation.context.gc_context);
let rv = base.set_property_local(receiver, name, value, activation)?;
drop(base);
rv.resolve(activation)?;
Ok(())
}
/// Set a property by Multiname lookup. /// Set a property by Multiname lookup.
/// ///
@ -237,7 +258,16 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
name: &QName<'gc>, name: &QName<'gc>,
value: Value<'gc>, value: Value<'gc>,
activation: &mut Activation<'_, 'gc, '_>, activation: &mut Activation<'_, 'gc, '_>,
) -> Result<(), Error>; ) -> Result<(), Error> {
let mut base = self.base_mut(activation.context.gc_context);
let rv = base.init_property_local(receiver, name, value, activation)?;
drop(base);
rv.resolve(activation)?;
Ok(())
}
/// Initialize a property by Multiname lookup. /// Initialize a property by Multiname lookup.
/// ///
@ -316,7 +346,11 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
} }
/// Retrieve a slot by its index. /// Retrieve a slot by its index.
fn get_slot(self, id: u32) -> Result<Value<'gc>, Error>; fn get_slot(self, id: u32) -> Result<Value<'gc>, Error> {
let base = self.base();
base.get_slot(id)
}
/// Set a slot by its index. /// Set a slot by its index.
fn set_slot( fn set_slot(
@ -324,7 +358,11 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
id: u32, id: u32,
value: Value<'gc>, value: Value<'gc>,
mc: MutationContext<'gc, '_>, mc: MutationContext<'gc, '_>,
) -> Result<(), Error>; ) -> Result<(), Error> {
let mut base = self.base_mut(mc);
base.set_slot(id, value, mc)
}
/// Initialize a slot by its index. /// Initialize a slot by its index.
fn init_slot( fn init_slot(
@ -332,10 +370,18 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
id: u32, id: u32,
value: Value<'gc>, value: Value<'gc>,
mc: MutationContext<'gc, '_>, mc: MutationContext<'gc, '_>,
) -> Result<(), Error>; ) -> Result<(), Error> {
let mut base = self.base_mut(mc);
base.init_slot(id, value, mc)
}
/// Retrieve a method by its index. /// Retrieve a method by its index.
fn get_method(self, id: u32) -> Option<Object<'gc>>; fn get_method(self, id: u32) -> Option<Object<'gc>> {
let base = self.base();
base.get_method(id)
}
/// Retrieves the scope chain of the object at time of its creation. /// Retrieves the scope chain of the object at time of its creation.
/// ///
@ -343,7 +389,11 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
/// object is called, as well as any class methods on the object. /// object is called, as well as any class methods on the object.
/// Non-method functions and prototype functions (ES3 methods) do not use /// Non-method functions and prototype functions (ES3 methods) do not use
/// this scope chain. /// this scope chain.
fn get_scope(self) -> Option<GcCell<'gc, Scope<'gc>>>; fn get_scope(self) -> Option<GcCell<'gc, Scope<'gc>>> {
let base = self.base();
base.get_scope()
}
/// Resolve a multiname into a single QName, if any of the namespaces /// Resolve a multiname into a single QName, if any of the namespaces
/// match. /// match.
@ -381,15 +431,25 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
/// Trait names will be resolve on class objects and object instances, but /// Trait names will be resolve on class objects and object instances, but
/// not prototypes. If you want to search a prototype's provided traits you /// not prototypes. If you want to search a prototype's provided traits you
/// must walk the prototype chain using `resolve_any_trait`. /// must walk the prototype chain using `resolve_any_trait`.
fn resolve_any(self, local_name: AvmString<'gc>) -> Result<Option<Namespace<'gc>>, Error>; fn resolve_any(self, local_name: AvmString<'gc>) -> Result<Option<Namespace<'gc>>, Error> {
let base = self.base();
base.resolve_any(local_name)
}
/// Given a local name of a trait, find the namespace it resides in, if any. /// Given a local name of a trait, find the namespace it resides in, if any.
/// ///
/// This function only works for names which are trait properties, not /// This function only works for names which are trait properties, not
/// dynamic or prototype properties. Furthermore, instance prototypes *will* /// dynamic or prototype properties. Furthermore, instance prototypes *will*
/// resolve trait names here, contrary to their behavior in `resolve_any.` /// resolve trait names here, contrary to their behavior in `resolve_any.`
fn resolve_any_trait(self, local_name: AvmString<'gc>) fn resolve_any_trait(
-> Result<Option<Namespace<'gc>>, Error>; self,
local_name: AvmString<'gc>,
) -> Result<Option<Namespace<'gc>>, Error> {
let base = self.base();
base.resolve_any_trait(local_name)
}
/// Indicates whether or not a property exists on an object. /// Indicates whether or not a property exists on an object.
fn has_property(self, name: &QName<'gc>) -> Result<bool, Error> { fn has_property(self, name: &QName<'gc>) -> Result<bool, Error> {
@ -404,47 +464,83 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
/// Indicates whether or not a property or trait exists on an object and is /// Indicates whether or not a property or trait exists on an object and is
/// not part of the prototype chain. /// not part of the prototype chain.
fn has_own_property(self, name: &QName<'gc>) -> Result<bool, Error>; fn has_own_property(self, name: &QName<'gc>) -> Result<bool, Error> {
let base = self.base();
base.has_own_property(name)
}
/// Returns true if an object has one or more traits of a given name. /// Returns true if an object has one or more traits of a given name.
fn has_trait(self, name: &QName<'gc>) -> Result<bool, Error>; fn has_trait(self, name: &QName<'gc>) -> Result<bool, Error> {
let base = self.base();
base.has_trait(name)
}
/// Check if a particular object contains a virtual getter by the given /// Check if a particular object contains a virtual getter by the given
/// name. /// name.
fn has_own_virtual_getter(self, name: &QName<'gc>) -> bool; fn has_own_virtual_getter(self, name: &QName<'gc>) -> bool {
let base = self.base();
base.has_own_virtual_getter(name)
}
/// Check if a particular object contains a virtual setter by the given /// Check if a particular object contains a virtual setter by the given
/// name. /// name.
fn has_own_virtual_setter(self, name: &QName<'gc>) -> bool; fn has_own_virtual_setter(self, name: &QName<'gc>) -> bool {
let base = self.base();
base.has_own_virtual_setter(name)
}
/// Indicates whether or not a property is overwritable. /// Indicates whether or not a property is overwritable.
fn is_property_overwritable( fn is_property_overwritable(
self, self,
gc_context: MutationContext<'gc, '_>, _gc_context: MutationContext<'gc, '_>,
_name: &QName<'gc>, name: &QName<'gc>,
) -> bool; ) -> bool {
let base = self.base();
base.is_property_overwritable(name)
}
/// Indicates whether or not a property is final. /// Indicates whether or not a property is final.
fn is_property_final(self, _name: &QName<'gc>) -> bool; fn is_property_final(self, name: &QName<'gc>) -> bool {
let base = self.base();
base.is_property_final(name)
}
/// Delete a named property from the object. /// Delete a named property from the object.
/// ///
/// Returns false if the property cannot be deleted. /// Returns false if the property cannot be deleted.
fn delete_property(&self, gc_context: MutationContext<'gc, '_>, name: &QName<'gc>) -> bool; fn delete_property(&self, gc_context: MutationContext<'gc, '_>, name: &QName<'gc>) -> bool {
let mut base = self.base_mut(gc_context);
base.delete_property(name)
}
/// Retrieve the `__proto__` of a given object. /// Retrieve the `__proto__` of a given object.
/// ///
/// The proto is another object used to resolve methods across a class of /// The proto is another object used to resolve methods across a class of
/// multiple objects. It should also be accessible as `__proto__` from /// multiple objects. It should also be accessible as `__proto__` from
/// `get`. /// `get`.
fn proto(&self) -> Option<Object<'gc>>; fn proto(&self) -> Option<Object<'gc>> {
let base = self.base();
base.proto()
}
/// Change the `__proto__` on this object. /// Change the `__proto__` on this object.
/// ///
/// This method primarily exists so that the global scope that player /// This method primarily exists so that the global scope that player
/// globals loads into can be created before its superclasses are. It /// globals loads into can be created before its superclasses are. It
/// should be used sparingly, if at all. /// should be used sparingly, if at all.
fn set_proto(self, mc: MutationContext<'gc, '_>, proto: Object<'gc>); fn set_proto(self, mc: MutationContext<'gc, '_>, proto: Object<'gc>) {
let mut base = self.base_mut(mc);
base.set_proto(proto)
}
/// Retrieve a given enumerable name by index. /// Retrieve a given enumerable name by index.
/// ///
@ -455,12 +551,20 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
/// Objects are responsible for maintaining a consistently ordered and /// Objects are responsible for maintaining a consistently ordered and
/// indexed list of enumerable names which can be queried by this /// indexed list of enumerable names which can be queried by this
/// mechanism. /// mechanism.
fn get_enumerant_name(&self, index: u32) -> Option<QName<'gc>>; fn get_enumerant_name(&self, index: u32) -> Option<QName<'gc>> {
let base = self.base();
base.get_enumerant_name(index)
}
/// Determine if a property is currently enumerable. /// Determine if a property is currently enumerable.
/// ///
/// Properties that do not exist are also not enumerable. /// Properties that do not exist are also not enumerable.
fn property_is_enumerable(&self, name: &QName<'gc>) -> bool; fn property_is_enumerable(&self, name: &QName<'gc>) -> bool {
let base = self.base();
base.property_is_enumerable(name)
}
/// Mark a dynamic property on this object as enumerable. /// Mark a dynamic property on this object as enumerable.
fn set_local_property_is_enumerable( fn set_local_property_is_enumerable(
@ -468,7 +572,11 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
mc: MutationContext<'gc, '_>, mc: MutationContext<'gc, '_>,
name: &QName<'gc>, name: &QName<'gc>,
is_enumerable: bool, is_enumerable: bool,
) -> Result<(), Error>; ) -> Result<(), Error> {
let mut base = self.base_mut(mc);
base.set_local_property_is_enumerable(name, is_enumerable)
}
/// Install a method (or any other non-slot value) on an object. /// Install a method (or any other non-slot value) on an object.
fn install_method( fn install_method(
@ -478,7 +586,11 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
disp_id: u32, disp_id: u32,
function: Object<'gc>, function: Object<'gc>,
is_final: bool, is_final: bool,
); ) {
let mut base = self.base_mut(mc);
base.install_method(name, disp_id, function, is_final)
}
/// Install a getter method on an object property. /// Install a getter method on an object property.
fn install_getter( fn install_getter(
@ -488,7 +600,11 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
disp_id: u32, disp_id: u32,
function: Object<'gc>, function: Object<'gc>,
is_final: bool, is_final: bool,
) -> Result<(), Error>; ) -> Result<(), Error> {
let mut base = self.base_mut(mc);
base.install_getter(name, disp_id, function, is_final)
}
/// Install a setter method on an object property. /// Install a setter method on an object property.
fn install_setter( fn install_setter(
@ -498,7 +614,11 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
disp_id: u32, disp_id: u32,
function: Object<'gc>, function: Object<'gc>,
is_final: bool, is_final: bool,
) -> Result<(), Error>; ) -> Result<(), Error> {
let mut base = self.base_mut(mc);
base.install_setter(name, disp_id, function, is_final)
}
/// Install a dynamic or built-in value property on an object. /// Install a dynamic or built-in value property on an object.
fn install_dynamic_property( fn install_dynamic_property(
@ -506,7 +626,11 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
mc: MutationContext<'gc, '_>, mc: MutationContext<'gc, '_>,
name: QName<'gc>, name: QName<'gc>,
value: Value<'gc>, value: Value<'gc>,
) -> Result<(), Error>; ) -> Result<(), Error> {
let mut base = self.base_mut(mc);
base.install_dynamic_property(name, value)
}
/// Install a slot on an object property. /// Install a slot on an object property.
fn install_slot( fn install_slot(
@ -516,7 +640,11 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
id: u32, id: u32,
value: Value<'gc>, value: Value<'gc>,
is_final: bool, is_final: bool,
); ) {
let mut base = self.base_mut(mc);
base.install_slot(name, id, value, is_final)
}
/// Install a const on an object property. /// Install a const on an object property.
fn install_const( fn install_const(
@ -526,7 +654,11 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
id: u32, id: u32,
value: Value<'gc>, value: Value<'gc>,
is_final: bool, is_final: bool,
); ) {
let mut base = self.base_mut(mc);
base.install_const(name, id, value, is_final)
}
/// Install all instance traits provided by a class. /// Install all instance traits provided by a class.
/// ///
@ -1244,7 +1376,11 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
fn as_ptr(&self) -> *const ObjectPtr; fn as_ptr(&self) -> *const ObjectPtr;
/// Get this object's class, if it has one. /// Get this object's class, if it has one.
fn instance_of(&self) -> Option<Object<'gc>>; fn instance_of(&self) -> Option<Object<'gc>> {
let base = self.base();
base.instance_of()
}
/// Get this object's class's `Class`, if it has one. /// Get this object's class's `Class`, if it has one.
fn instance_of_class_definition(&self) -> Option<GcCell<'gc, Class<'gc>>> { fn instance_of_class_definition(&self) -> Option<GcCell<'gc, Class<'gc>>> {

View File

@ -5,11 +5,9 @@ use crate::avm2::array::ArrayStorage;
use crate::avm2::names::{Namespace, QName}; use crate::avm2::names::{Namespace, QName};
use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::script_object::ScriptObjectData;
use crate::avm2::object::{Object, ObjectPtr, TObject}; use crate::avm2::object::{Object, ObjectPtr, TObject};
use crate::avm2::scope::Scope;
use crate::avm2::value::Value; use crate::avm2::value::Value;
use crate::avm2::Error; use crate::avm2::Error;
use crate::string::AvmString; use crate::string::AvmString;
use crate::{impl_avm2_custom_object, impl_avm2_custom_object_instance};
use gc_arena::{Collect, GcCell, MutationContext}; use gc_arena::{Collect, GcCell, MutationContext};
use std::cell::{Ref, RefMut}; use std::cell::{Ref, RefMut};
@ -77,8 +75,17 @@ impl<'gc> ArrayObject<'gc> {
} }
impl<'gc> TObject<'gc> for ArrayObject<'gc> { impl<'gc> TObject<'gc> for ArrayObject<'gc> {
impl_avm2_custom_object!(base); fn base(&self) -> Ref<ScriptObjectData<'gc>> {
impl_avm2_custom_object_instance!(base); Ref::map(self.0.read(), |read| &read.base)
}
fn base_mut(&self, mc: MutationContext<'gc, '_>) -> RefMut<ScriptObjectData<'gc>> {
RefMut::map(self.0.write(mc), |write| &mut write.base)
}
fn as_ptr(&self) -> *const ObjectPtr {
self.0.as_ptr() as *const ObjectPtr
}
fn get_property_local( fn get_property_local(
self, self,
@ -157,18 +164,6 @@ impl<'gc> TObject<'gc> for ArrayObject<'gc> {
Ok(()) Ok(())
} }
fn is_property_overwritable(
self,
gc_context: MutationContext<'gc, '_>,
name: &QName<'gc>,
) -> bool {
self.0.write(gc_context).base.is_property_overwritable(name)
}
fn is_property_final(self, name: &QName<'gc>) -> bool {
self.0.read().base.is_property_final(name)
}
fn delete_property(&self, gc_context: MutationContext<'gc, '_>, name: &QName<'gc>) -> bool { fn delete_property(&self, gc_context: MutationContext<'gc, '_>, name: &QName<'gc>) -> bool {
if name.namespace().is_public() { if name.namespace().is_public() {
if let Ok(index) = name.local_name().parse::<usize>() { if let Ok(index) = name.local_name().parse::<usize>() {

View File

@ -4,15 +4,11 @@ use crate::avm2::activation::Activation;
use crate::avm2::names::{Namespace, QName}; use crate::avm2::names::{Namespace, QName};
use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::script_object::ScriptObjectData;
use crate::avm2::object::{Object, ObjectPtr, TObject}; use crate::avm2::object::{Object, ObjectPtr, TObject};
use crate::avm2::scope::Scope;
use crate::avm2::value::Value; use crate::avm2::value::Value;
use crate::avm2::Error; use crate::avm2::Error;
use crate::bitmap::bitmap_data::BitmapData; use crate::bitmap::bitmap_data::BitmapData;
use crate::string::AvmString;
use crate::{
impl_avm2_custom_object, impl_avm2_custom_object_instance, impl_avm2_custom_object_properties,
};
use gc_arena::{Collect, GcCell, MutationContext}; use gc_arena::{Collect, GcCell, MutationContext};
use std::cell::{Ref, RefMut};
/// A class instance allocator that allocates BitmapData objects. /// A class instance allocator that allocates BitmapData objects.
pub fn bitmapdata_allocator<'gc>( pub fn bitmapdata_allocator<'gc>(
@ -78,9 +74,17 @@ impl<'gc> BitmapDataObject<'gc> {
} }
impl<'gc> TObject<'gc> for BitmapDataObject<'gc> { impl<'gc> TObject<'gc> for BitmapDataObject<'gc> {
impl_avm2_custom_object!(base); fn base(&self) -> Ref<ScriptObjectData<'gc>> {
impl_avm2_custom_object_properties!(base); Ref::map(self.0.read(), |read| &read.base)
impl_avm2_custom_object_instance!(base); }
fn base_mut(&self, mc: MutationContext<'gc, '_>) -> RefMut<ScriptObjectData<'gc>> {
RefMut::map(self.0.write(mc), |write| &mut write.base)
}
fn as_ptr(&self) -> *const ObjectPtr {
self.0.as_ptr() as *const ObjectPtr
}
fn derive(&self, activation: &mut Activation<'_, 'gc, '_>) -> Result<Object<'gc>, Error> { fn derive(&self, activation: &mut Activation<'_, 'gc, '_>) -> Result<Object<'gc>, Error> {
let base = ScriptObjectData::base_new(Some((*self).into()), None); let base = ScriptObjectData::base_new(Some((*self).into()), None);

View File

@ -3,11 +3,9 @@ use crate::avm2::bytearray::ByteArrayStorage;
use crate::avm2::names::{Namespace, QName}; use crate::avm2::names::{Namespace, QName};
use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::script_object::ScriptObjectData;
use crate::avm2::object::{Object, ObjectPtr, TObject}; use crate::avm2::object::{Object, ObjectPtr, TObject};
use crate::avm2::scope::Scope;
use crate::avm2::value::Value; use crate::avm2::value::Value;
use crate::avm2::Error; use crate::avm2::Error;
use crate::string::AvmString; use crate::string::AvmString;
use crate::{impl_avm2_custom_object, impl_avm2_custom_object_instance};
use gc_arena::{Collect, GcCell, MutationContext}; use gc_arena::{Collect, GcCell, MutationContext};
use std::cell::{Ref, RefMut}; use std::cell::{Ref, RefMut};
@ -43,8 +41,17 @@ pub struct ByteArrayObjectData<'gc> {
} }
impl<'gc> TObject<'gc> for ByteArrayObject<'gc> { impl<'gc> TObject<'gc> for ByteArrayObject<'gc> {
impl_avm2_custom_object!(base); fn base(&self) -> Ref<ScriptObjectData<'gc>> {
impl_avm2_custom_object_instance!(base); Ref::map(self.0.read(), |read| &read.base)
}
fn base_mut(&self, mc: MutationContext<'gc, '_>) -> RefMut<ScriptObjectData<'gc>> {
RefMut::map(self.0.write(mc), |write| &mut write.base)
}
fn as_ptr(&self) -> *const ObjectPtr {
self.0.as_ptr() as *const ObjectPtr
}
fn get_property_local( fn get_property_local(
self, self,
@ -131,18 +138,6 @@ impl<'gc> TObject<'gc> for ByteArrayObject<'gc> {
Ok(()) Ok(())
} }
fn is_property_overwritable(
self,
gc_context: MutationContext<'gc, '_>,
name: &QName<'gc>,
) -> bool {
self.0.write(gc_context).base.is_property_overwritable(name)
}
fn is_property_final(self, name: &QName<'gc>) -> bool {
self.0.read().base.is_property_final(name)
}
fn delete_property(&self, gc_context: MutationContext<'gc, '_>, name: &QName<'gc>) -> bool { fn delete_property(&self, gc_context: MutationContext<'gc, '_>, name: &QName<'gc>) -> bool {
if name.namespace().is_public() { if name.namespace().is_public() {
if let Ok(index) = name.local_name().parse::<usize>() { if let Ok(index) = name.local_name().parse::<usize>() {

View File

@ -11,8 +11,8 @@ use crate::avm2::scope::Scope;
use crate::avm2::value::Value; use crate::avm2::value::Value;
use crate::avm2::Error; use crate::avm2::Error;
use crate::string::AvmString; use crate::string::AvmString;
use crate::{impl_avm2_custom_object, impl_avm2_custom_object_properties};
use gc_arena::{Collect, GcCell, MutationContext}; use gc_arena::{Collect, GcCell, MutationContext};
use std::cell::{Ref, RefMut};
use std::collections::HashMap; use std::collections::HashMap;
/// An Object which can be called to execute its function code. /// An Object which can be called to execute its function code.
@ -356,8 +356,17 @@ impl<'gc> ClassObject<'gc> {
} }
impl<'gc> TObject<'gc> for ClassObject<'gc> { impl<'gc> TObject<'gc> for ClassObject<'gc> {
impl_avm2_custom_object!(base); fn base(&self) -> Ref<ScriptObjectData<'gc>> {
impl_avm2_custom_object_properties!(base); Ref::map(self.0.read(), |read| &read.base)
}
fn base_mut(&self, mc: MutationContext<'gc, '_>) -> RefMut<ScriptObjectData<'gc>> {
RefMut::map(self.0.write(mc), |write| &mut write.base)
}
fn as_ptr(&self) -> *const ObjectPtr {
self.0.as_ptr() as *const ObjectPtr
}
fn to_string(&self, mc: MutationContext<'gc, '_>) -> Result<Value<'gc>, Error> { fn to_string(&self, mc: MutationContext<'gc, '_>) -> Result<Value<'gc>, Error> {
Ok(AvmString::new( Ok(AvmString::new(
@ -488,10 +497,6 @@ impl<'gc> TObject<'gc> for ClassObject<'gc> {
Some(*self) Some(*self)
} }
fn instance_of(&self) -> Option<Object<'gc>> {
self.0.read().base.instance_of()
}
fn set_local_property_is_enumerable( fn set_local_property_is_enumerable(
&self, &self,
mc: MutationContext<'gc, '_>, mc: MutationContext<'gc, '_>,

View File

@ -1,272 +0,0 @@
//! Custom object macro
/// Implement defaults for `TObject` methods that deal with property retrieval,
/// storage, and deletion.
#[macro_export]
macro_rules! impl_avm2_custom_object_properties {
($field:ident) => {
fn get_property_local(
self,
receiver: Object<'gc>,
name: &QName<'gc>,
activation: &mut Activation<'_, 'gc, '_>,
) -> Result<Value<'gc>, Error> {
let read = self.0.read();
let rv = read.$field.get_property_local(receiver, name, activation)?;
drop(read);
rv.resolve(activation)
}
fn set_property_local(
self,
receiver: Object<'gc>,
name: &QName<'gc>,
value: Value<'gc>,
activation: &mut Activation<'_, 'gc, '_>,
) -> Result<(), Error> {
let mut write = self.0.write(activation.context.gc_context);
let rv = write
.$field
.set_property_local(receiver, name, value, activation)?;
drop(write);
rv.resolve(activation)?;
Ok(())
}
fn init_property_local(
self,
receiver: Object<'gc>,
name: &QName<'gc>,
value: Value<'gc>,
activation: &mut Activation<'_, 'gc, '_>,
) -> Result<(), Error> {
let mut write = self.0.write(activation.context.gc_context);
let rv = write
.$field
.init_property_local(receiver, name, value, activation)?;
drop(write);
rv.resolve(activation)?;
Ok(())
}
fn is_property_overwritable(
self,
gc_context: MutationContext<'gc, '_>,
name: &QName<'gc>,
) -> bool {
self.0
.write(gc_context)
.$field
.is_property_overwritable(name)
}
fn is_property_final(self, name: &QName<'gc>) -> bool {
self.0.read().$field.is_property_final(name)
}
fn delete_property(
&self,
gc_context: MutationContext<'gc, '_>,
multiname: &QName<'gc>,
) -> bool {
self.0.write(gc_context).$field.delete_property(multiname)
}
fn has_own_property(self, name: &QName<'gc>) -> Result<bool, Error> {
self.0.read().$field.has_own_property(name)
}
fn resolve_any(self, local_name: AvmString<'gc>) -> Result<Option<Namespace<'gc>>, Error> {
self.0.read().$field.resolve_any(local_name)
}
};
}
/// Implement defaults for `TObject` methods that mark this object as an
/// instance of a class.
#[macro_export]
macro_rules! impl_avm2_custom_object_instance {
($field:ident) => {
fn has_trait(self, name: &QName<'gc>) -> Result<bool, Error> {
self.0.read().$field.has_trait(name)
}
fn get_scope(self) -> Option<GcCell<'gc, Scope<'gc>>> {
self.0.read().$field.get_scope()
}
fn resolve_any_trait(
self,
local_name: AvmString<'gc>,
) -> Result<Option<Namespace<'gc>>, Error> {
self.0.read().$field.resolve_any_trait(local_name)
}
fn instance_of(&self) -> Option<Object<'gc>> {
self.0.read().$field.instance_of()
}
fn set_local_property_is_enumerable(
&self,
mc: MutationContext<'gc, '_>,
name: &QName<'gc>,
is_enumerable: bool,
) -> Result<(), Error> {
self.0
.write(mc)
.$field
.set_local_property_is_enumerable(name, is_enumerable)
}
};
}
/// Implement defaults for `TObject` methods not separated out into a separate
/// macro.
#[macro_export]
macro_rules! impl_avm2_custom_object {
($field:ident) => {
fn get_slot(self, id: u32) -> Result<Value<'gc>, Error> {
self.0.read().$field.get_slot(id)
}
fn set_slot(
self,
id: u32,
value: Value<'gc>,
mc: MutationContext<'gc, '_>,
) -> Result<(), Error> {
self.0.write(mc).$field.set_slot(id, value, mc)
}
fn init_slot(
self,
id: u32,
value: Value<'gc>,
mc: MutationContext<'gc, '_>,
) -> Result<(), Error> {
self.0.write(mc).$field.init_slot(id, value, mc)
}
fn get_method(self, id: u32) -> Option<Object<'gc>> {
self.0.read().$field.get_method(id)
}
fn has_own_virtual_getter(self, name: &QName<'gc>) -> bool {
self.0.read().$field.has_own_virtual_getter(name)
}
fn has_own_virtual_setter(self, name: &QName<'gc>) -> bool {
self.0.read().$field.has_own_virtual_setter(name)
}
fn proto(&self) -> Option<Object<'gc>> {
self.0.read().$field.proto()
}
fn set_proto(self, mc: MutationContext<'gc, '_>, proto: Object<'gc>) {
self.0.write(mc).$field.set_proto(proto)
}
fn get_enumerant_name(&self, index: u32) -> Option<QName<'gc>> {
self.0.read().$field.get_enumerant_name(index)
}
fn property_is_enumerable(&self, name: &QName<'gc>) -> bool {
self.0.read().$field.property_is_enumerable(name)
}
fn as_ptr(&self) -> *const ObjectPtr {
self.0.as_ptr() as *const ObjectPtr
}
fn install_method(
&mut self,
mc: MutationContext<'gc, '_>,
name: QName<'gc>,
disp_id: u32,
function: Object<'gc>,
is_final: bool,
) {
self.0
.write(mc)
.$field
.install_method(name, disp_id, function, is_final)
}
fn install_getter(
&mut self,
mc: MutationContext<'gc, '_>,
name: QName<'gc>,
disp_id: u32,
function: Object<'gc>,
is_final: bool,
) -> Result<(), Error> {
self.0
.write(mc)
.$field
.install_getter(name, disp_id, function, is_final)
}
fn install_setter(
&mut self,
mc: MutationContext<'gc, '_>,
name: QName<'gc>,
disp_id: u32,
function: Object<'gc>,
is_final: bool,
) -> Result<(), Error> {
self.0
.write(mc)
.$field
.install_setter(name, disp_id, function, is_final)
}
fn install_dynamic_property(
&mut self,
mc: MutationContext<'gc, '_>,
name: QName<'gc>,
value: Value<'gc>,
) -> Result<(), Error> {
self.0
.write(mc)
.$field
.install_dynamic_property(name, value)
}
fn install_slot(
&mut self,
mc: MutationContext<'gc, '_>,
name: QName<'gc>,
id: u32,
value: Value<'gc>,
is_final: bool,
) {
self.0
.write(mc)
.$field
.install_slot(name, id, value, is_final)
}
fn install_const(
&mut self,
mc: MutationContext<'gc, '_>,
name: QName<'gc>,
id: u32,
value: Value<'gc>,
is_final: bool,
) {
self.0
.write(mc)
.$field
.install_const(name, id, value, is_final)
}
};
}

View File

@ -1,16 +1,11 @@
use crate::avm2::activation::Activation; use crate::avm2::activation::Activation;
use crate::avm2::names::{Namespace, QName};
use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::script_object::ScriptObjectData;
use crate::avm2::object::{Object, ObjectPtr, TObject}; use crate::avm2::object::{Object, ObjectPtr, TObject};
use crate::avm2::scope::Scope;
use crate::avm2::value::{Hint, Value}; use crate::avm2::value::{Hint, Value};
use crate::avm2::Error; use crate::avm2::Error;
use crate::string::AvmString;
use crate::{
impl_avm2_custom_object, impl_avm2_custom_object_instance, impl_avm2_custom_object_properties,
};
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use gc_arena::{Collect, GcCell, MutationContext}; use gc_arena::{Collect, GcCell, MutationContext};
use std::cell::{Ref, RefMut};
/// A class instance allocator that allocates Date objects. /// A class instance allocator that allocates Date objects.
pub fn date_allocator<'gc>( pub fn date_allocator<'gc>(
@ -58,9 +53,17 @@ pub struct DateObjectData<'gc> {
} }
impl<'gc> TObject<'gc> for DateObject<'gc> { impl<'gc> TObject<'gc> for DateObject<'gc> {
impl_avm2_custom_object!(base); fn base(&self) -> Ref<ScriptObjectData<'gc>> {
impl_avm2_custom_object_properties!(base); Ref::map(self.0.read(), |read| &read.base)
impl_avm2_custom_object_instance!(base); }
fn base_mut(&self, mc: MutationContext<'gc, '_>) -> RefMut<ScriptObjectData<'gc>> {
RefMut::map(self.0.write(mc), |write| &mut write.base)
}
fn as_ptr(&self) -> *const ObjectPtr {
self.0.as_ptr() as *const ObjectPtr
}
fn derive(&self, activation: &mut Activation<'_, 'gc, '_>) -> Result<Object<'gc>, Error> { fn derive(&self, activation: &mut Activation<'_, 'gc, '_>) -> Result<Object<'gc>, Error> {
let this: Object<'gc> = Object::DateObject(*self); let this: Object<'gc> = Object::DateObject(*self);

View File

@ -2,16 +2,10 @@
use crate::avm2::activation::Activation; use crate::avm2::activation::Activation;
use crate::avm2::events::DispatchList; use crate::avm2::events::DispatchList;
use crate::avm2::names::{Namespace, QName};
use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::script_object::ScriptObjectData;
use crate::avm2::object::{Object, ObjectPtr, TObject}; use crate::avm2::object::{Object, ObjectPtr, TObject};
use crate::avm2::scope::Scope;
use crate::avm2::value::Value; use crate::avm2::value::Value;
use crate::avm2::Error; use crate::avm2::Error;
use crate::string::AvmString;
use crate::{
impl_avm2_custom_object, impl_avm2_custom_object_instance, impl_avm2_custom_object_properties,
};
use gc_arena::{Collect, GcCell, MutationContext}; use gc_arena::{Collect, GcCell, MutationContext};
use std::cell::{Ref, RefMut}; use std::cell::{Ref, RefMut};
@ -71,9 +65,17 @@ impl<'gc> DispatchObject<'gc> {
} }
impl<'gc> TObject<'gc> for DispatchObject<'gc> { impl<'gc> TObject<'gc> for DispatchObject<'gc> {
impl_avm2_custom_object!(base); fn base(&self) -> Ref<ScriptObjectData<'gc>> {
impl_avm2_custom_object_properties!(base); Ref::map(self.0.read(), |read| &read.base)
impl_avm2_custom_object_instance!(base); }
fn base_mut(&self, mc: MutationContext<'gc, '_>) -> RefMut<ScriptObjectData<'gc>> {
RefMut::map(self.0.write(mc), |write| &mut write.base)
}
fn as_ptr(&self) -> *const ObjectPtr {
self.0.as_ptr() as *const ObjectPtr
}
fn construct( fn construct(
self, self,

View File

@ -5,14 +5,10 @@ use crate::avm2::domain::Domain;
use crate::avm2::names::{Namespace, QName}; use crate::avm2::names::{Namespace, QName};
use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::script_object::ScriptObjectData;
use crate::avm2::object::{Object, ObjectPtr, TObject}; use crate::avm2::object::{Object, ObjectPtr, TObject};
use crate::avm2::scope::Scope;
use crate::avm2::value::Value; use crate::avm2::value::Value;
use crate::avm2::Error; use crate::avm2::Error;
use crate::string::AvmString;
use crate::{
impl_avm2_custom_object, impl_avm2_custom_object_instance, impl_avm2_custom_object_properties,
};
use gc_arena::{Collect, GcCell, MutationContext}; use gc_arena::{Collect, GcCell, MutationContext};
use std::cell::{Ref, RefMut};
/// A class instance allocator that allocates AppDomain objects. /// A class instance allocator that allocates AppDomain objects.
pub fn appdomain_allocator<'gc>( pub fn appdomain_allocator<'gc>(
@ -114,9 +110,17 @@ impl<'gc> DomainObject<'gc> {
} }
impl<'gc> TObject<'gc> for DomainObject<'gc> { impl<'gc> TObject<'gc> for DomainObject<'gc> {
impl_avm2_custom_object!(base); fn base(&self) -> Ref<ScriptObjectData<'gc>> {
impl_avm2_custom_object_properties!(base); Ref::map(self.0.read(), |read| &read.base)
impl_avm2_custom_object_instance!(base); }
fn base_mut(&self, mc: MutationContext<'gc, '_>) -> RefMut<ScriptObjectData<'gc>> {
RefMut::map(self.0.write(mc), |write| &mut write.base)
}
fn as_ptr(&self) -> *const ObjectPtr {
self.0.as_ptr() as *const ObjectPtr
}
fn as_application_domain(&self) -> Option<Domain<'gc>> { fn as_application_domain(&self) -> Option<Domain<'gc>> {
Some(self.0.read().domain) Some(self.0.read().domain)

View File

@ -5,13 +5,9 @@ use crate::avm2::events::Event;
use crate::avm2::names::{Namespace, QName}; use crate::avm2::names::{Namespace, QName};
use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::script_object::ScriptObjectData;
use crate::avm2::object::{Object, ObjectPtr, TObject}; use crate::avm2::object::{Object, ObjectPtr, TObject};
use crate::avm2::scope::Scope;
use crate::avm2::value::Value; use crate::avm2::value::Value;
use crate::avm2::Error; use crate::avm2::Error;
use crate::string::AvmString; use crate::string::AvmString;
use crate::{
impl_avm2_custom_object, impl_avm2_custom_object_instance, impl_avm2_custom_object_properties,
};
use gc_arena::{Collect, GcCell, MutationContext}; use gc_arena::{Collect, GcCell, MutationContext};
use std::cell::{Ref, RefMut}; use std::cell::{Ref, RefMut};
@ -81,9 +77,17 @@ impl<'gc> EventObject<'gc> {
} }
impl<'gc> TObject<'gc> for EventObject<'gc> { impl<'gc> TObject<'gc> for EventObject<'gc> {
impl_avm2_custom_object!(base); fn base(&self) -> Ref<ScriptObjectData<'gc>> {
impl_avm2_custom_object_properties!(base); Ref::map(self.0.read(), |read| &read.base)
impl_avm2_custom_object_instance!(base); }
fn base_mut(&self, mc: MutationContext<'gc, '_>) -> RefMut<ScriptObjectData<'gc>> {
RefMut::map(self.0.write(mc), |write| &mut write.base)
}
fn as_ptr(&self) -> *const ObjectPtr {
self.0.as_ptr() as *const ObjectPtr
}
fn derive(&self, activation: &mut Activation<'_, 'gc, '_>) -> Result<Object<'gc>, Error> { fn derive(&self, activation: &mut Activation<'_, 'gc, '_>) -> Result<Object<'gc>, Error> {
let base = ScriptObjectData::base_new(Some((*self).into()), None); let base = ScriptObjectData::base_new(Some((*self).into()), None);

View File

@ -9,11 +9,8 @@ use crate::avm2::object::{Object, ObjectPtr, TObject};
use crate::avm2::scope::Scope; use crate::avm2::scope::Scope;
use crate::avm2::value::Value; use crate::avm2::value::Value;
use crate::avm2::Error; use crate::avm2::Error;
use crate::string::AvmString;
use crate::{
impl_avm2_custom_object, impl_avm2_custom_object_instance, impl_avm2_custom_object_properties,
};
use gc_arena::{Collect, GcCell, MutationContext}; use gc_arena::{Collect, GcCell, MutationContext};
use std::cell::{Ref, RefMut};
/// An Object which can be called to execute its function code. /// An Object which can be called to execute its function code.
#[derive(Collect, Debug, Clone, Copy)] #[derive(Collect, Debug, Clone, Copy)]
@ -87,9 +84,17 @@ impl<'gc> FunctionObject<'gc> {
} }
impl<'gc> TObject<'gc> for FunctionObject<'gc> { impl<'gc> TObject<'gc> for FunctionObject<'gc> {
impl_avm2_custom_object!(base); fn base(&self) -> Ref<ScriptObjectData<'gc>> {
impl_avm2_custom_object_properties!(base); Ref::map(self.0.read(), |read| &read.base)
impl_avm2_custom_object_instance!(base); }
fn base_mut(&self, mc: MutationContext<'gc, '_>) -> RefMut<ScriptObjectData<'gc>> {
RefMut::map(self.0.write(mc), |write| &mut write.base)
}
fn as_ptr(&self) -> *const ObjectPtr {
self.0.as_ptr() as *const ObjectPtr
}
fn to_string(&self, _mc: MutationContext<'gc, '_>) -> Result<Value<'gc>, Error> { fn to_string(&self, _mc: MutationContext<'gc, '_>) -> Result<Value<'gc>, Error> {
Ok("function Function() {}".into()) Ok("function Function() {}".into())

View File

@ -1,20 +1,15 @@
//! Loader-info object //! Loader-info object
use crate::avm2::activation::Activation; use crate::avm2::activation::Activation;
use crate::avm2::names::{Namespace, QName};
use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::script_object::ScriptObjectData;
use crate::avm2::object::{Object, ObjectPtr, TObject}; use crate::avm2::object::{Object, ObjectPtr, TObject};
use crate::avm2::scope::Scope;
use crate::avm2::value::Value; use crate::avm2::value::Value;
use crate::avm2::Error; use crate::avm2::Error;
use crate::display_object::DisplayObject; use crate::display_object::DisplayObject;
use crate::string::AvmString; use crate::string::AvmString;
use crate::tag_utils::SwfMovie; use crate::tag_utils::SwfMovie;
use crate::{
impl_avm2_custom_object, impl_avm2_custom_object_instance, impl_avm2_custom_object_properties,
};
use gc_arena::{Collect, GcCell, MutationContext}; use gc_arena::{Collect, GcCell, MutationContext};
use std::cell::Ref; use std::cell::{Ref, RefMut};
use std::sync::Arc; use std::sync::Arc;
/// A class instance allocator that allocates LoaderInfo objects. /// A class instance allocator that allocates LoaderInfo objects.
@ -118,9 +113,17 @@ impl<'gc> LoaderInfoObject<'gc> {
} }
impl<'gc> TObject<'gc> for LoaderInfoObject<'gc> { impl<'gc> TObject<'gc> for LoaderInfoObject<'gc> {
impl_avm2_custom_object!(base); fn base(&self) -> Ref<ScriptObjectData<'gc>> {
impl_avm2_custom_object_properties!(base); Ref::map(self.0.read(), |read| &read.base)
impl_avm2_custom_object_instance!(base); }
fn base_mut(&self, mc: MutationContext<'gc, '_>) -> RefMut<ScriptObjectData<'gc>> {
RefMut::map(self.0.write(mc), |write| &mut write.base)
}
fn as_ptr(&self) -> *const ObjectPtr {
self.0.as_ptr() as *const ObjectPtr
}
fn value_of(&self, mc: MutationContext<'gc, '_>) -> Result<Value<'gc>, Error> { fn value_of(&self, mc: MutationContext<'gc, '_>) -> Result<Value<'gc>, Error> {
if let Some(class) = self.instance_of_class_definition() { if let Some(class) = self.instance_of_class_definition() {

View File

@ -1,18 +1,13 @@
//! Boxed namespaces //! Boxed namespaces
use crate::avm2::activation::Activation; use crate::avm2::activation::Activation;
use crate::avm2::names::{Namespace, QName}; use crate::avm2::names::Namespace;
use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::script_object::ScriptObjectData;
use crate::avm2::object::{Object, ObjectPtr, TObject}; use crate::avm2::object::{Object, ObjectPtr, TObject};
use crate::avm2::scope::Scope;
use crate::avm2::value::Value; use crate::avm2::value::Value;
use crate::avm2::Error; use crate::avm2::Error;
use crate::string::AvmString;
use crate::{
impl_avm2_custom_object, impl_avm2_custom_object_instance, impl_avm2_custom_object_properties,
};
use gc_arena::{Collect, GcCell, MutationContext}; use gc_arena::{Collect, GcCell, MutationContext};
use std::cell::Ref; use std::cell::{Ref, RefMut};
/// A class instance allocator that allocates namespace objects. /// A class instance allocator that allocates namespace objects.
pub fn namespace_allocator<'gc>( pub fn namespace_allocator<'gc>(
@ -71,9 +66,17 @@ impl<'gc> NamespaceObject<'gc> {
} }
impl<'gc> TObject<'gc> for NamespaceObject<'gc> { impl<'gc> TObject<'gc> for NamespaceObject<'gc> {
impl_avm2_custom_object!(base); fn base(&self) -> Ref<ScriptObjectData<'gc>> {
impl_avm2_custom_object_properties!(base); Ref::map(self.0.read(), |read| &read.base)
impl_avm2_custom_object_instance!(base); }
fn base_mut(&self, mc: MutationContext<'gc, '_>) -> RefMut<ScriptObjectData<'gc>> {
RefMut::map(self.0.write(mc), |write| &mut write.base)
}
fn as_ptr(&self) -> *const ObjectPtr {
self.0.as_ptr() as *const ObjectPtr
}
fn to_string(&self, _mc: MutationContext<'gc, '_>) -> Result<Value<'gc>, Error> { fn to_string(&self, _mc: MutationContext<'gc, '_>) -> Result<Value<'gc>, Error> {
Ok(self.0.read().namespace.as_uri().into()) Ok(self.0.read().namespace.as_uri().into())

View File

@ -3,16 +3,11 @@
use std::cell::{Ref, RefMut}; use std::cell::{Ref, RefMut};
use crate::avm2::activation::Activation; use crate::avm2::activation::Activation;
use crate::avm2::names::{Namespace, QName};
use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::script_object::ScriptObjectData;
use crate::avm2::object::{Object, ObjectPtr, TObject}; use crate::avm2::object::{Object, ObjectPtr, TObject};
use crate::avm2::scope::Scope;
use crate::avm2::value::Value; use crate::avm2::value::Value;
use crate::avm2::Error; use crate::avm2::Error;
use crate::string::AvmString; use crate::string::AvmString;
use crate::{
impl_avm2_custom_object, impl_avm2_custom_object_instance, impl_avm2_custom_object_properties,
};
use gc_arena::{Collect, GcCell, MutationContext}; use gc_arena::{Collect, GcCell, MutationContext};
/// A class instance allocator that allocates primitive objects. /// A class instance allocator that allocates primitive objects.
@ -105,9 +100,17 @@ impl<'gc> PrimitiveObject<'gc> {
} }
impl<'gc> TObject<'gc> for PrimitiveObject<'gc> { impl<'gc> TObject<'gc> for PrimitiveObject<'gc> {
impl_avm2_custom_object!(base); fn base(&self) -> Ref<ScriptObjectData<'gc>> {
impl_avm2_custom_object_properties!(base); Ref::map(self.0.read(), |read| &read.base)
impl_avm2_custom_object_instance!(base); }
fn base_mut(&self, mc: MutationContext<'gc, '_>) -> RefMut<ScriptObjectData<'gc>> {
RefMut::map(self.0.write(mc), |write| &mut write.base)
}
fn as_ptr(&self) -> *const ObjectPtr {
self.0.as_ptr() as *const ObjectPtr
}
fn to_string(&self, _mc: MutationContext<'gc, '_>) -> Result<Value<'gc>, Error> { fn to_string(&self, _mc: MutationContext<'gc, '_>) -> Result<Value<'gc>, Error> {
Ok(self.0.read().primitive.clone()) Ok(self.0.read().primitive.clone())

View File

@ -1,17 +1,12 @@
//! Object representation for regexp //! Object representation for regexp
use crate::avm2::activation::Activation; use crate::avm2::activation::Activation;
use crate::avm2::names::{Namespace, QName};
use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::script_object::ScriptObjectData;
use crate::avm2::object::{Object, ObjectPtr, TObject}; use crate::avm2::object::{Object, ObjectPtr, TObject};
use crate::avm2::regexp::RegExp; use crate::avm2::regexp::RegExp;
use crate::avm2::scope::Scope;
use crate::avm2::value::Value; use crate::avm2::value::Value;
use crate::avm2::Error; use crate::avm2::Error;
use crate::string::AvmString; use crate::string::AvmString;
use crate::{
impl_avm2_custom_object, impl_avm2_custom_object_instance, impl_avm2_custom_object_properties,
};
use gc_arena::{Collect, GcCell, MutationContext}; use gc_arena::{Collect, GcCell, MutationContext};
use std::cell::{Ref, RefMut}; use std::cell::{Ref, RefMut};
@ -69,9 +64,17 @@ impl<'gc> RegExpObject<'gc> {
} }
impl<'gc> TObject<'gc> for RegExpObject<'gc> { impl<'gc> TObject<'gc> for RegExpObject<'gc> {
impl_avm2_custom_object!(base); fn base(&self) -> Ref<ScriptObjectData<'gc>> {
impl_avm2_custom_object_properties!(base); Ref::map(self.0.read(), |read| &read.base)
impl_avm2_custom_object_instance!(base); }
fn base_mut(&self, mc: MutationContext<'gc, '_>) -> RefMut<ScriptObjectData<'gc>> {
RefMut::map(self.0.write(mc), |write| &mut write.base)
}
fn as_ptr(&self) -> *const ObjectPtr {
self.0.as_ptr() as *const ObjectPtr
}
fn derive(&self, activation: &mut Activation<'_, 'gc, '_>) -> Result<Object<'gc>, Error> { fn derive(&self, activation: &mut Activation<'_, 'gc, '_>) -> Result<Object<'gc>, Error> {
let base = ScriptObjectData::base_new(Some((*self).into()), None); let base = ScriptObjectData::base_new(Some((*self).into()), None);

View File

@ -12,6 +12,7 @@ use crate::avm2::value::Value;
use crate::avm2::Error; use crate::avm2::Error;
use crate::string::AvmString; use crate::string::AvmString;
use gc_arena::{Collect, GcCell, MutationContext}; use gc_arena::{Collect, GcCell, MutationContext};
use std::cell::{Ref, RefMut};
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt::Debug; use std::fmt::Debug;
@ -60,152 +61,12 @@ pub struct ScriptObjectData<'gc> {
} }
impl<'gc> TObject<'gc> for ScriptObject<'gc> { impl<'gc> TObject<'gc> for ScriptObject<'gc> {
fn get_property_local( fn base(&self) -> Ref<ScriptObjectData<'gc>> {
self, self.0.read()
receiver: Object<'gc>,
name: &QName<'gc>,
activation: &mut Activation<'_, 'gc, '_>,
) -> Result<Value<'gc>, Error> {
let rv = self
.0
.read()
.get_property_local(receiver, name, activation)?;
rv.resolve(activation)
} }
fn set_property_local( fn base_mut(&self, mc: MutationContext<'gc, '_>) -> RefMut<ScriptObjectData<'gc>> {
self, self.0.write(mc)
receiver: Object<'gc>,
name: &QName<'gc>,
value: Value<'gc>,
activation: &mut Activation<'_, 'gc, '_>,
) -> Result<(), Error> {
let rv = self
.0
.write(activation.context.gc_context)
.set_property_local(receiver, name, value, activation)?;
rv.resolve(activation)?;
Ok(())
}
fn init_property_local(
self,
receiver: Object<'gc>,
name: &QName<'gc>,
value: Value<'gc>,
activation: &mut Activation<'_, 'gc, '_>,
) -> Result<(), Error> {
let rv = self
.0
.write(activation.context.gc_context)
.init_property_local(receiver, name, value, activation)?;
rv.resolve(activation)?;
Ok(())
}
fn is_property_overwritable(
self,
gc_context: MutationContext<'gc, '_>,
name: &QName<'gc>,
) -> bool {
self.0.write(gc_context).is_property_overwritable(name)
}
fn is_property_final(self, name: &QName<'gc>) -> bool {
self.0.read().is_property_final(name)
}
fn delete_property(&self, gc_context: MutationContext<'gc, '_>, name: &QName<'gc>) -> bool {
self.0.write(gc_context).delete_property(name)
}
fn get_slot(self, id: u32) -> Result<Value<'gc>, Error> {
self.0.read().get_slot(id)
}
fn set_slot(
self,
id: u32,
value: Value<'gc>,
mc: MutationContext<'gc, '_>,
) -> Result<(), Error> {
self.0.write(mc).set_slot(id, value, mc)
}
fn init_slot(
self,
id: u32,
value: Value<'gc>,
mc: MutationContext<'gc, '_>,
) -> Result<(), Error> {
self.0.write(mc).init_slot(id, value, mc)
}
fn get_method(self, id: u32) -> Option<Object<'gc>> {
self.0.read().get_method(id)
}
fn get_scope(self) -> Option<GcCell<'gc, Scope<'gc>>> {
self.0.read().get_scope()
}
fn resolve_any(self, local_name: AvmString<'gc>) -> Result<Option<Namespace<'gc>>, Error> {
self.0.read().resolve_any(local_name)
}
fn resolve_any_trait(
self,
local_name: AvmString<'gc>,
) -> Result<Option<Namespace<'gc>>, Error> {
self.0.read().resolve_any_trait(local_name)
}
fn has_own_property(self, name: &QName<'gc>) -> Result<bool, Error> {
self.0.read().has_own_property(name)
}
fn has_trait(self, name: &QName<'gc>) -> Result<bool, Error> {
self.0.read().has_trait(name)
}
fn has_own_virtual_getter(self, name: &QName<'gc>) -> bool {
self.0.read().has_own_virtual_getter(name)
}
fn has_own_virtual_setter(self, name: &QName<'gc>) -> bool {
self.0.read().has_own_virtual_setter(name)
}
fn proto(&self) -> Option<Object<'gc>> {
self.0.read().proto
}
fn set_proto(self, mc: MutationContext<'gc, '_>, proto: Object<'gc>) {
self.0.write(mc).set_proto(proto)
}
fn get_enumerant_name(&self, index: u32) -> Option<QName<'gc>> {
self.0.read().get_enumerant_name(index)
}
fn property_is_enumerable(&self, name: &QName<'gc>) -> bool {
self.0.read().property_is_enumerable(name)
}
fn set_local_property_is_enumerable(
&self,
mc: MutationContext<'gc, '_>,
name: &QName<'gc>,
is_enumerable: bool,
) -> Result<(), Error> {
self.0
.write(mc)
.set_local_property_is_enumerable(name, is_enumerable)
} }
fn as_ptr(&self) -> *const ObjectPtr { fn as_ptr(&self) -> *const ObjectPtr {
@ -217,91 +78,9 @@ impl<'gc> TObject<'gc> for ScriptObject<'gc> {
Ok(ScriptObject::object(activation.context.gc_context, this)) Ok(ScriptObject::object(activation.context.gc_context, this))
} }
fn to_string(&self, mc: MutationContext<'gc, '_>) -> Result<Value<'gc>, Error> {
if let Some(class) = self.instance_of_class_definition() {
Ok(AvmString::new(mc, format!("[object {}]", class.read().name().local_name())).into())
} else {
Ok("[object Object]".into())
}
}
fn value_of(&self, _mc: MutationContext<'gc, '_>) -> Result<Value<'gc>, Error> { fn value_of(&self, _mc: MutationContext<'gc, '_>) -> Result<Value<'gc>, Error> {
Ok(Value::Object(Object::from(*self))) Ok(Value::Object(Object::from(*self)))
} }
fn install_method(
&mut self,
mc: MutationContext<'gc, '_>,
name: QName<'gc>,
disp_id: u32,
function: Object<'gc>,
is_final: bool,
) {
self.0
.write(mc)
.install_method(name, disp_id, function, is_final)
}
fn install_getter(
&mut self,
mc: MutationContext<'gc, '_>,
name: QName<'gc>,
disp_id: u32,
function: Object<'gc>,
is_final: bool,
) -> Result<(), Error> {
self.0
.write(mc)
.install_getter(name, disp_id, function, is_final)
}
fn install_setter(
&mut self,
mc: MutationContext<'gc, '_>,
name: QName<'gc>,
disp_id: u32,
function: Object<'gc>,
is_final: bool,
) -> Result<(), Error> {
self.0
.write(mc)
.install_setter(name, disp_id, function, is_final)
}
fn install_dynamic_property(
&mut self,
mc: MutationContext<'gc, '_>,
name: QName<'gc>,
value: Value<'gc>,
) -> Result<(), Error> {
self.0.write(mc).install_dynamic_property(name, value)
}
fn install_slot(
&mut self,
mc: MutationContext<'gc, '_>,
name: QName<'gc>,
id: u32,
value: Value<'gc>,
is_final: bool,
) {
self.0.write(mc).install_slot(name, id, value, is_final)
}
fn install_const(
&mut self,
mc: MutationContext<'gc, '_>,
name: QName<'gc>,
id: u32,
value: Value<'gc>,
is_final: bool,
) {
self.0.write(mc).install_const(name, id, value, is_final)
}
fn instance_of(&self) -> Option<Object<'gc>> {
self.0.read().instance_of()
}
} }
impl<'gc> ScriptObject<'gc> { impl<'gc> ScriptObject<'gc> {

View File

@ -4,15 +4,11 @@ use crate::avm2::activation::Activation;
use crate::avm2::names::{Namespace, QName}; use crate::avm2::names::{Namespace, QName};
use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::script_object::ScriptObjectData;
use crate::avm2::object::{Object, ObjectPtr, TObject}; use crate::avm2::object::{Object, ObjectPtr, TObject};
use crate::avm2::scope::Scope;
use crate::avm2::value::Value; use crate::avm2::value::Value;
use crate::avm2::Error; use crate::avm2::Error;
use crate::backend::audio::SoundHandle; use crate::backend::audio::SoundHandle;
use crate::string::AvmString;
use crate::{
impl_avm2_custom_object, impl_avm2_custom_object_instance, impl_avm2_custom_object_properties,
};
use gc_arena::{Collect, GcCell, MutationContext}; use gc_arena::{Collect, GcCell, MutationContext};
use std::cell::{Ref, RefMut};
/// A class instance allocator that allocates Sound objects. /// A class instance allocator that allocates Sound objects.
pub fn sound_allocator<'gc>( pub fn sound_allocator<'gc>(
@ -81,9 +77,17 @@ impl<'gc> SoundObject<'gc> {
} }
impl<'gc> TObject<'gc> for SoundObject<'gc> { impl<'gc> TObject<'gc> for SoundObject<'gc> {
impl_avm2_custom_object!(base); fn base(&self) -> Ref<ScriptObjectData<'gc>> {
impl_avm2_custom_object_properties!(base); Ref::map(self.0.read(), |read| &read.base)
impl_avm2_custom_object_instance!(base); }
fn base_mut(&self, mc: MutationContext<'gc, '_>) -> RefMut<ScriptObjectData<'gc>> {
RefMut::map(self.0.write(mc), |write| &mut write.base)
}
fn as_ptr(&self) -> *const ObjectPtr {
self.0.as_ptr() as *const ObjectPtr
}
fn value_of(&self, _mc: MutationContext<'gc, '_>) -> Result<Value<'gc>, Error> { fn value_of(&self, _mc: MutationContext<'gc, '_>) -> Result<Value<'gc>, Error> {
Ok(Object::from(*self).into()) Ok(Object::from(*self).into())

View File

@ -4,15 +4,11 @@ use crate::avm2::activation::Activation;
use crate::avm2::names::{Namespace, QName}; use crate::avm2::names::{Namespace, QName};
use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::script_object::ScriptObjectData;
use crate::avm2::object::{Object, ObjectPtr, TObject}; use crate::avm2::object::{Object, ObjectPtr, TObject};
use crate::avm2::scope::Scope;
use crate::avm2::value::Value; use crate::avm2::value::Value;
use crate::avm2::Error; use crate::avm2::Error;
use crate::backend::audio::SoundInstanceHandle; use crate::backend::audio::SoundInstanceHandle;
use crate::string::AvmString;
use crate::{
impl_avm2_custom_object, impl_avm2_custom_object_instance, impl_avm2_custom_object_properties,
};
use gc_arena::{Collect, GcCell, MutationContext}; use gc_arena::{Collect, GcCell, MutationContext};
use std::cell::{Ref, RefMut};
/// A class instance allocator that allocates SoundChannel objects. /// A class instance allocator that allocates SoundChannel objects.
pub fn soundchannel_allocator<'gc>( pub fn soundchannel_allocator<'gc>(
@ -77,14 +73,22 @@ impl<'gc> SoundChannelObject<'gc> {
} }
impl<'gc> TObject<'gc> for SoundChannelObject<'gc> { impl<'gc> TObject<'gc> for SoundChannelObject<'gc> {
impl_avm2_custom_object!(base); fn base(&self) -> Ref<ScriptObjectData<'gc>> {
impl_avm2_custom_object_properties!(base); Ref::map(self.0.read(), |read| &read.base)
impl_avm2_custom_object_instance!(base); }
fn base_mut(&self, mc: MutationContext<'gc, '_>) -> RefMut<ScriptObjectData<'gc>> {
RefMut::map(self.0.write(mc), |write| &mut write.base)
}
fn value_of(&self, _mc: MutationContext<'gc, '_>) -> Result<Value<'gc>, Error> { fn value_of(&self, _mc: MutationContext<'gc, '_>) -> Result<Value<'gc>, Error> {
Ok(Object::from(*self).into()) Ok(Object::from(*self).into())
} }
fn as_ptr(&self) -> *const ObjectPtr {
self.0.as_ptr() as *const ObjectPtr
}
fn derive(&self, activation: &mut Activation<'_, 'gc, '_>) -> Result<Object<'gc>, Error> { fn derive(&self, activation: &mut Activation<'_, 'gc, '_>) -> Result<Object<'gc>, Error> {
let base = ScriptObjectData::base_new(Some((*self).into()), None); let base = ScriptObjectData::base_new(Some((*self).into()), None);

View File

@ -1,16 +1,14 @@
//! AVM2 object impl for the display hierarchy. //! AVM2 object impl for the display hierarchy.
use crate::avm2::activation::Activation; use crate::avm2::activation::Activation;
use crate::avm2::function::Executable;
use crate::avm2::names::{Namespace, QName}; use crate::avm2::names::{Namespace, QName};
use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::script_object::ScriptObjectData;
use crate::avm2::object::{Object, ObjectPtr, TObject}; use crate::avm2::object::{Object, ObjectPtr, TObject};
use crate::avm2::scope::Scope;
use crate::avm2::value::Value; use crate::avm2::value::Value;
use crate::avm2::Error; use crate::avm2::Error;
use crate::display_object::DisplayObject; use crate::display_object::DisplayObject;
use crate::string::AvmString;
use gc_arena::{Collect, GcCell, MutationContext}; use gc_arena::{Collect, GcCell, MutationContext};
use std::cell::{Ref, RefMut};
/// A class instance allocator that allocates Stage objects. /// A class instance allocator that allocates Stage objects.
pub fn stage_allocator<'gc>( pub fn stage_allocator<'gc>(
@ -120,175 +118,18 @@ impl<'gc> StageObject<'gc> {
} }
impl<'gc> TObject<'gc> for StageObject<'gc> { impl<'gc> TObject<'gc> for StageObject<'gc> {
fn get_property_local( fn base(&self) -> Ref<ScriptObjectData<'gc>> {
self, Ref::map(self.0.read(), |read| &read.base)
reciever: Object<'gc>,
name: &QName<'gc>,
activation: &mut Activation<'_, 'gc, '_>,
) -> Result<Value<'gc>, Error> {
let read = self.0.read();
let rv = read.base.get_property_local(reciever, name, activation)?;
drop(read);
rv.resolve(activation)
} }
fn set_property_local( fn base_mut(&self, mc: MutationContext<'gc, '_>) -> RefMut<ScriptObjectData<'gc>> {
self, RefMut::map(self.0.write(mc), |write| &mut write.base)
reciever: Object<'gc>,
name: &QName<'gc>,
value: Value<'gc>,
activation: &mut Activation<'_, 'gc, '_>,
) -> Result<(), Error> {
let mut write = self.0.write(activation.context.gc_context);
let rv = write
.base
.set_property_local(reciever, name, value, activation)?;
drop(write);
rv.resolve(activation)?;
Ok(())
}
fn init_property_local(
self,
reciever: Object<'gc>,
name: &QName<'gc>,
value: Value<'gc>,
activation: &mut Activation<'_, 'gc, '_>,
) -> Result<(), Error> {
let mut write = self.0.write(activation.context.gc_context);
let rv = write
.base
.init_property_local(reciever, name, value, activation)?;
drop(write);
rv.resolve(activation)?;
Ok(())
}
fn is_property_overwritable(
self,
gc_context: MutationContext<'gc, '_>,
name: &QName<'gc>,
) -> bool {
self.0.write(gc_context).base.is_property_overwritable(name)
}
fn is_property_final(self, name: &QName<'gc>) -> bool {
self.0.read().base.is_property_final(name)
}
fn delete_property(
&self,
gc_context: MutationContext<'gc, '_>,
multiname: &QName<'gc>,
) -> bool {
self.0.write(gc_context).base.delete_property(multiname)
}
fn get_slot(self, id: u32) -> Result<Value<'gc>, Error> {
self.0.read().base.get_slot(id)
}
fn set_slot(
self,
id: u32,
value: Value<'gc>,
mc: MutationContext<'gc, '_>,
) -> Result<(), Error> {
self.0.write(mc).base.set_slot(id, value, mc)
}
fn init_slot(
self,
id: u32,
value: Value<'gc>,
mc: MutationContext<'gc, '_>,
) -> Result<(), Error> {
self.0.write(mc).base.init_slot(id, value, mc)
}
fn get_method(self, id: u32) -> Option<Object<'gc>> {
self.0.read().base.get_method(id)
}
fn get_scope(self) -> Option<GcCell<'gc, Scope<'gc>>> {
self.0.read().base.get_scope()
}
fn resolve_any(self, local_name: AvmString<'gc>) -> Result<Option<Namespace<'gc>>, Error> {
self.0.read().base.resolve_any(local_name)
}
fn resolve_any_trait(
self,
local_name: AvmString<'gc>,
) -> Result<Option<Namespace<'gc>>, Error> {
self.0.read().base.resolve_any_trait(local_name)
}
fn has_own_property(self, name: &QName<'gc>) -> Result<bool, Error> {
self.0.read().base.has_own_property(name)
}
fn has_trait(self, name: &QName<'gc>) -> Result<bool, Error> {
self.0.read().base.has_trait(name)
}
fn has_own_virtual_getter(self, name: &QName<'gc>) -> bool {
self.0.read().base.has_own_virtual_getter(name)
}
fn has_own_virtual_setter(self, name: &QName<'gc>) -> bool {
self.0.read().base.has_own_virtual_setter(name)
}
fn proto(&self) -> Option<Object<'gc>> {
self.0.read().base.proto()
}
fn set_proto(self, mc: MutationContext<'gc, '_>, proto: Object<'gc>) {
self.0.write(mc).base.set_proto(proto)
}
fn get_enumerant_name(&self, index: u32) -> Option<QName<'gc>> {
self.0.read().base.get_enumerant_name(index)
}
fn property_is_enumerable(&self, name: &QName<'gc>) -> bool {
self.0.read().base.property_is_enumerable(name)
}
fn set_local_property_is_enumerable(
&self,
mc: MutationContext<'gc, '_>,
name: &QName<'gc>,
is_enumerable: bool,
) -> Result<(), Error> {
self.0
.write(mc)
.base
.set_local_property_is_enumerable(name, is_enumerable)
} }
fn as_ptr(&self) -> *const ObjectPtr { fn as_ptr(&self) -> *const ObjectPtr {
self.0.as_ptr() as *const ObjectPtr self.0.as_ptr() as *const ObjectPtr
} }
fn as_executable(&self) -> Option<Executable<'gc>> {
None
}
fn instance_of(&self) -> Option<Object<'gc>> {
self.0.read().base.instance_of()
}
fn as_display_object(&self) -> Option<DisplayObject<'gc>> { fn as_display_object(&self) -> Option<DisplayObject<'gc>> {
self.0.read().display_object self.0.read().display_object
} }
@ -297,16 +138,6 @@ impl<'gc> TObject<'gc> for StageObject<'gc> {
self.0.write(mc).display_object = Some(obj); self.0.write(mc).display_object = Some(obj);
} }
fn call(
self,
_reciever: Option<Object<'gc>>,
_arguments: &[Value<'gc>],
_activation: &mut Activation<'_, 'gc, '_>,
_base_proto: Option<Object<'gc>>,
) -> Result<Value<'gc>, Error> {
Err("Not a callable function!".into())
}
fn derive(&self, activation: &mut Activation<'_, 'gc, '_>) -> Result<Object<'gc>, Error> { fn derive(&self, activation: &mut Activation<'_, 'gc, '_>) -> Result<Object<'gc>, Error> {
let this: Object<'gc> = Object::StageObject(*self); let this: Object<'gc> = Object::StageObject(*self);
let base = ScriptObjectData::base_new(Some(this), None); let base = ScriptObjectData::base_new(Some(this), None);
@ -324,83 +155,4 @@ impl<'gc> TObject<'gc> for StageObject<'gc> {
fn value_of(&self, _mc: MutationContext<'gc, '_>) -> Result<Value<'gc>, Error> { fn value_of(&self, _mc: MutationContext<'gc, '_>) -> Result<Value<'gc>, Error> {
Ok(Value::Object(Object::from(*self))) Ok(Value::Object(Object::from(*self)))
} }
fn install_method(
&mut self,
mc: MutationContext<'gc, '_>,
name: QName<'gc>,
disp_id: u32,
function: Object<'gc>,
is_final: bool,
) {
self.0
.write(mc)
.base
.install_method(name, disp_id, function, is_final)
}
fn install_getter(
&mut self,
mc: MutationContext<'gc, '_>,
name: QName<'gc>,
disp_id: u32,
function: Object<'gc>,
is_final: bool,
) -> Result<(), Error> {
self.0
.write(mc)
.base
.install_getter(name, disp_id, function, is_final)
}
fn install_setter(
&mut self,
mc: MutationContext<'gc, '_>,
name: QName<'gc>,
disp_id: u32,
function: Object<'gc>,
is_final: bool,
) -> Result<(), Error> {
self.0
.write(mc)
.base
.install_setter(name, disp_id, function, is_final)
}
fn install_dynamic_property(
&mut self,
mc: MutationContext<'gc, '_>,
name: QName<'gc>,
value: Value<'gc>,
) -> Result<(), Error> {
self.0.write(mc).base.install_dynamic_property(name, value)
}
fn install_slot(
&mut self,
mc: MutationContext<'gc, '_>,
name: QName<'gc>,
id: u32,
value: Value<'gc>,
is_final: bool,
) {
self.0
.write(mc)
.base
.install_slot(name, id, value, is_final)
}
fn install_const(
&mut self,
mc: MutationContext<'gc, '_>,
name: QName<'gc>,
id: u32,
value: Value<'gc>,
is_final: bool,
) {
self.0
.write(mc)
.base
.install_const(name, id, value, is_final)
}
} }

View File

@ -4,12 +4,10 @@ use crate::avm2::activation::Activation;
use crate::avm2::names::{Namespace, QName}; use crate::avm2::names::{Namespace, QName};
use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::script_object::ScriptObjectData;
use crate::avm2::object::{Object, ObjectPtr, TObject}; use crate::avm2::object::{Object, ObjectPtr, TObject};
use crate::avm2::scope::Scope;
use crate::avm2::value::Value; use crate::avm2::value::Value;
use crate::avm2::vector::VectorStorage; use crate::avm2::vector::VectorStorage;
use crate::avm2::Error; use crate::avm2::Error;
use crate::string::AvmString; use crate::string::AvmString;
use crate::{impl_avm2_custom_object, impl_avm2_custom_object_instance};
use gc_arena::{Collect, GcCell, MutationContext}; use gc_arena::{Collect, GcCell, MutationContext};
use std::cell::{Ref, RefMut}; use std::cell::{Ref, RefMut};
@ -90,8 +88,17 @@ impl<'gc> VectorObject<'gc> {
} }
impl<'gc> TObject<'gc> for VectorObject<'gc> { impl<'gc> TObject<'gc> for VectorObject<'gc> {
impl_avm2_custom_object!(base); fn base(&self) -> Ref<ScriptObjectData<'gc>> {
impl_avm2_custom_object_instance!(base); Ref::map(self.0.read(), |read| &read.base)
}
fn base_mut(&self, mc: MutationContext<'gc, '_>) -> RefMut<ScriptObjectData<'gc>> {
RefMut::map(self.0.write(mc), |write| &mut write.base)
}
fn as_ptr(&self) -> *const ObjectPtr {
self.0.as_ptr() as *const ObjectPtr
}
fn get_property_local( fn get_property_local(
self, self,
@ -190,18 +197,6 @@ impl<'gc> TObject<'gc> for VectorObject<'gc> {
Ok(()) Ok(())
} }
fn is_property_overwritable(
self,
gc_context: MutationContext<'gc, '_>,
name: &QName<'gc>,
) -> bool {
self.0.write(gc_context).base.is_property_overwritable(name)
}
fn is_property_final(self, name: &QName<'gc>) -> bool {
self.0.read().base.is_property_final(name)
}
fn delete_property(&self, gc_context: MutationContext<'gc, '_>, name: &QName<'gc>) -> bool { fn delete_property(&self, gc_context: MutationContext<'gc, '_>, name: &QName<'gc>) -> bool {
if name.namespace().is_package("") && name.local_name().parse::<usize>().is_ok() { if name.namespace().is_package("") && name.local_name().parse::<usize>().is_ok() {
return true; return true;

View File

@ -1,17 +1,12 @@
//! Object representation for XML objects //! Object representation for XML objects
use crate::avm2::activation::Activation; use crate::avm2::activation::Activation;
use crate::avm2::names::{Namespace, QName};
use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::script_object::ScriptObjectData;
use crate::avm2::object::{Object, ObjectPtr, TObject}; use crate::avm2::object::{Object, ObjectPtr, TObject};
use crate::avm2::scope::Scope;
use crate::avm2::value::Value; use crate::avm2::value::Value;
use crate::avm2::Error; use crate::avm2::Error;
use crate::string::AvmString;
use crate::{
impl_avm2_custom_object, impl_avm2_custom_object_instance, impl_avm2_custom_object_properties,
};
use gc_arena::{Collect, GcCell, MutationContext}; use gc_arena::{Collect, GcCell, MutationContext};
use std::cell::{Ref, RefMut};
/// A class instance allocator that allocates XML objects. /// A class instance allocator that allocates XML objects.
pub fn xml_allocator<'gc>( pub fn xml_allocator<'gc>(
@ -40,9 +35,17 @@ pub struct XmlObjectData<'gc> {
} }
impl<'gc> TObject<'gc> for XmlObject<'gc> { impl<'gc> TObject<'gc> for XmlObject<'gc> {
impl_avm2_custom_object!(base); fn base(&self) -> Ref<ScriptObjectData<'gc>> {
impl_avm2_custom_object_properties!(base); Ref::map(self.0.read(), |read| &read.base)
impl_avm2_custom_object_instance!(base); }
fn base_mut(&self, mc: MutationContext<'gc, '_>) -> RefMut<ScriptObjectData<'gc>> {
RefMut::map(self.0.write(mc), |write| &mut write.base)
}
fn as_ptr(&self) -> *const ObjectPtr {
self.0.as_ptr() as *const ObjectPtr
}
fn derive(&self, activation: &mut Activation<'_, 'gc, '_>) -> Result<Object<'gc>, Error> { fn derive(&self, activation: &mut Activation<'_, 'gc, '_>) -> Result<Object<'gc>, Error> {
let this: Object<'gc> = Object::XmlObject(*self); let this: Object<'gc> = Object::XmlObject(*self);