From 3f81910bb683ba5fdc9ea13656c0b94b212a8bd5 Mon Sep 17 00:00:00 2001 From: EmperorBale Date: Tue, 21 Sep 2021 21:55:31 -0700 Subject: [PATCH] avm2: Remove custom_object macros --- core/src/avm2/object.rs | 204 ++++++++++++--- core/src/avm2/object/array_object.rs | 27 +- core/src/avm2/object/bitmapdata_object.rs | 20 +- core/src/avm2/object/bytearray_object.rs | 27 +- core/src/avm2/object/class_object.rs | 19 +- core/src/avm2/object/custom_object.rs | 272 -------------------- core/src/avm2/object/date_object.rs | 21 +- core/src/avm2/object/dispatch_object.rs | 20 +- core/src/avm2/object/domain_object.rs | 20 +- core/src/avm2/object/event_object.rs | 18 +- core/src/avm2/object/function_object.rs | 19 +- core/src/avm2/object/loaderinfo_object.rs | 21 +- core/src/avm2/object/namespace_object.rs | 23 +- core/src/avm2/object/primitive_object.rs | 19 +- core/src/avm2/object/regexp_object.rs | 19 +- core/src/avm2/object/script_object.rs | 231 +---------------- core/src/avm2/object/sound_object.rs | 20 +- core/src/avm2/object/soundchannel_object.rs | 20 +- core/src/avm2/object/stage_object.rs | 258 +------------------ core/src/avm2/object/vector_object.rs | 27 +- core/src/avm2/object/xml_object.rs | 21 +- 21 files changed, 378 insertions(+), 948 deletions(-) delete mode 100644 core/src/avm2/object/custom_object.rs diff --git a/core/src/avm2/object.rs b/core/src/avm2/object.rs index 2f9ee841d..0224ec0fe 100644 --- a/core/src/avm2/object.rs +++ b/core/src/avm2/object.rs @@ -28,7 +28,6 @@ mod array_object; mod bitmapdata_object; mod bytearray_object; mod class_object; -mod custom_object; mod date_object; mod dispatch_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::primitive_object::{primitive_allocator, PrimitiveObject}; 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::soundchannel_object::{soundchannel_allocator, SoundChannelObject}; 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> + 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>; + fn base_mut(&self, mc: MutationContext<'gc, '_>) -> RefMut>; + /// Retrieve a property by QName, after multiname resolution, prototype /// lookups, and all other considerations have been taken. /// @@ -106,7 +110,14 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into> + Clone + Copy receiver: Object<'gc>, name: &QName<'gc>, activation: &mut Activation<'_, 'gc, '_>, - ) -> Result, Error>; + ) -> Result, 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. /// @@ -189,7 +200,17 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into> + Clone + Copy name: &QName<'gc>, value: Value<'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. /// @@ -237,7 +258,16 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into> + Clone + Copy name: &QName<'gc>, value: Value<'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. /// @@ -316,7 +346,11 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into> + Clone + Copy } /// Retrieve a slot by its index. - fn get_slot(self, id: u32) -> Result, Error>; + fn get_slot(self, id: u32) -> Result, Error> { + let base = self.base(); + + base.get_slot(id) + } /// Set a slot by its index. fn set_slot( @@ -324,7 +358,11 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into> + Clone + Copy id: u32, value: Value<'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. fn init_slot( @@ -332,10 +370,18 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into> + Clone + Copy id: u32, value: Value<'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. - fn get_method(self, id: u32) -> Option>; + fn get_method(self, id: u32) -> Option> { + let base = self.base(); + + base.get_method(id) + } /// Retrieves the scope chain of the object at time of its creation. /// @@ -343,7 +389,11 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into> + Clone + Copy /// object is called, as well as any class methods on the object. /// Non-method functions and prototype functions (ES3 methods) do not use /// this scope chain. - fn get_scope(self) -> Option>>; + fn get_scope(self) -> Option>> { + let base = self.base(); + + base.get_scope() + } /// Resolve a multiname into a single QName, if any of the namespaces /// match. @@ -381,15 +431,25 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into> + Clone + Copy /// 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 /// must walk the prototype chain using `resolve_any_trait`. - fn resolve_any(self, local_name: AvmString<'gc>) -> Result>, Error>; + fn resolve_any(self, local_name: AvmString<'gc>) -> Result>, 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. /// /// This function only works for names which are trait properties, not /// dynamic or prototype properties. Furthermore, instance prototypes *will* /// resolve trait names here, contrary to their behavior in `resolve_any.` - fn resolve_any_trait(self, local_name: AvmString<'gc>) - -> Result>, Error>; + fn resolve_any_trait( + self, + local_name: AvmString<'gc>, + ) -> Result>, Error> { + let base = self.base(); + + base.resolve_any_trait(local_name) + } /// Indicates whether or not a property exists on an object. fn has_property(self, name: &QName<'gc>) -> Result { @@ -404,47 +464,83 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into> + Clone + Copy /// Indicates whether or not a property or trait exists on an object and is /// not part of the prototype chain. - fn has_own_property(self, name: &QName<'gc>) -> Result; + fn has_own_property(self, name: &QName<'gc>) -> Result { + let base = self.base(); + + base.has_own_property(name) + } /// Returns true if an object has one or more traits of a given name. - fn has_trait(self, name: &QName<'gc>) -> Result; + fn has_trait(self, name: &QName<'gc>) -> Result { + let base = self.base(); + + base.has_trait(name) + } /// Check if a particular object contains a virtual getter by the given /// 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 /// 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. fn is_property_overwritable( self, - gc_context: MutationContext<'gc, '_>, - _name: &QName<'gc>, - ) -> bool; + _gc_context: MutationContext<'gc, '_>, + name: &QName<'gc>, + ) -> bool { + let base = self.base(); + + base.is_property_overwritable(name) + } /// 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. /// /// 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. /// /// The proto is another object used to resolve methods across a class of /// multiple objects. It should also be accessible as `__proto__` from /// `get`. - fn proto(&self) -> Option>; + fn proto(&self) -> Option> { + let base = self.base(); + + base.proto() + } /// Change the `__proto__` on this object. /// /// This method primarily exists so that the global scope that player /// globals loads into can be created before its superclasses are. It /// 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. /// @@ -455,12 +551,20 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into> + Clone + Copy /// Objects are responsible for maintaining a consistently ordered and /// indexed list of enumerable names which can be queried by this /// mechanism. - fn get_enumerant_name(&self, index: u32) -> Option>; + fn get_enumerant_name(&self, index: u32) -> Option> { + let base = self.base(); + + base.get_enumerant_name(index) + } /// Determine if a property is currently 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. fn set_local_property_is_enumerable( @@ -468,7 +572,11 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into> + Clone + Copy mc: MutationContext<'gc, '_>, name: &QName<'gc>, 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. fn install_method( @@ -478,7 +586,11 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into> + Clone + Copy disp_id: u32, function: Object<'gc>, 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. fn install_getter( @@ -488,7 +600,11 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into> + Clone + Copy disp_id: u32, function: Object<'gc>, 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. fn install_setter( @@ -498,7 +614,11 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into> + Clone + Copy disp_id: u32, function: Object<'gc>, 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. fn install_dynamic_property( @@ -506,7 +626,11 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into> + Clone + Copy mc: MutationContext<'gc, '_>, name: QName<'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. fn install_slot( @@ -516,7 +640,11 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into> + Clone + Copy id: u32, value: Value<'gc>, 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. fn install_const( @@ -526,7 +654,11 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into> + Clone + Copy id: u32, value: Value<'gc>, 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. /// @@ -1244,7 +1376,11 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into> + Clone + Copy fn as_ptr(&self) -> *const ObjectPtr; /// Get this object's class, if it has one. - fn instance_of(&self) -> Option>; + fn instance_of(&self) -> Option> { + let base = self.base(); + + base.instance_of() + } /// Get this object's class's `Class`, if it has one. fn instance_of_class_definition(&self) -> Option>> { diff --git a/core/src/avm2/object/array_object.rs b/core/src/avm2/object/array_object.rs index 7e081f674..d23f52795 100644 --- a/core/src/avm2/object/array_object.rs +++ b/core/src/avm2/object/array_object.rs @@ -5,11 +5,9 @@ use crate::avm2::array::ArrayStorage; use crate::avm2::names::{Namespace, QName}; use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::{Object, ObjectPtr, TObject}; -use crate::avm2::scope::Scope; use crate::avm2::value::Value; use crate::avm2::Error; use crate::string::AvmString; -use crate::{impl_avm2_custom_object, impl_avm2_custom_object_instance}; use gc_arena::{Collect, GcCell, MutationContext}; use std::cell::{Ref, RefMut}; @@ -77,8 +75,17 @@ impl<'gc> ArrayObject<'gc> { } impl<'gc> TObject<'gc> for ArrayObject<'gc> { - impl_avm2_custom_object!(base); - impl_avm2_custom_object_instance!(base); + fn base(&self) -> Ref> { + Ref::map(self.0.read(), |read| &read.base) + } + + fn base_mut(&self, mc: MutationContext<'gc, '_>) -> RefMut> { + 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( self, @@ -157,18 +164,6 @@ impl<'gc> TObject<'gc> for ArrayObject<'gc> { 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 { if name.namespace().is_public() { if let Ok(index) = name.local_name().parse::() { diff --git a/core/src/avm2/object/bitmapdata_object.rs b/core/src/avm2/object/bitmapdata_object.rs index 16ea82fb4..e598cf3f4 100644 --- a/core/src/avm2/object/bitmapdata_object.rs +++ b/core/src/avm2/object/bitmapdata_object.rs @@ -4,15 +4,11 @@ use crate::avm2::activation::Activation; use crate::avm2::names::{Namespace, QName}; use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::{Object, ObjectPtr, TObject}; -use crate::avm2::scope::Scope; use crate::avm2::value::Value; use crate::avm2::Error; 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 std::cell::{Ref, RefMut}; /// A class instance allocator that allocates BitmapData objects. pub fn bitmapdata_allocator<'gc>( @@ -78,9 +74,17 @@ impl<'gc> BitmapDataObject<'gc> { } impl<'gc> TObject<'gc> for BitmapDataObject<'gc> { - impl_avm2_custom_object!(base); - impl_avm2_custom_object_properties!(base); - impl_avm2_custom_object_instance!(base); + fn base(&self) -> Ref> { + Ref::map(self.0.read(), |read| &read.base) + } + + fn base_mut(&self, mc: MutationContext<'gc, '_>) -> RefMut> { + 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, Error> { let base = ScriptObjectData::base_new(Some((*self).into()), None); diff --git a/core/src/avm2/object/bytearray_object.rs b/core/src/avm2/object/bytearray_object.rs index bee7b6e7b..a870a3e7a 100644 --- a/core/src/avm2/object/bytearray_object.rs +++ b/core/src/avm2/object/bytearray_object.rs @@ -3,11 +3,9 @@ use crate::avm2::bytearray::ByteArrayStorage; use crate::avm2::names::{Namespace, QName}; use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::{Object, ObjectPtr, TObject}; -use crate::avm2::scope::Scope; use crate::avm2::value::Value; use crate::avm2::Error; use crate::string::AvmString; -use crate::{impl_avm2_custom_object, impl_avm2_custom_object_instance}; use gc_arena::{Collect, GcCell, MutationContext}; use std::cell::{Ref, RefMut}; @@ -43,8 +41,17 @@ pub struct ByteArrayObjectData<'gc> { } impl<'gc> TObject<'gc> for ByteArrayObject<'gc> { - impl_avm2_custom_object!(base); - impl_avm2_custom_object_instance!(base); + fn base(&self) -> Ref> { + Ref::map(self.0.read(), |read| &read.base) + } + + fn base_mut(&self, mc: MutationContext<'gc, '_>) -> RefMut> { + 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( self, @@ -131,18 +138,6 @@ impl<'gc> TObject<'gc> for ByteArrayObject<'gc> { 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 { if name.namespace().is_public() { if let Ok(index) = name.local_name().parse::() { diff --git a/core/src/avm2/object/class_object.rs b/core/src/avm2/object/class_object.rs index 4b8fc1234..0ca1d9b64 100644 --- a/core/src/avm2/object/class_object.rs +++ b/core/src/avm2/object/class_object.rs @@ -11,8 +11,8 @@ use crate::avm2::scope::Scope; use crate::avm2::value::Value; use crate::avm2::Error; use crate::string::AvmString; -use crate::{impl_avm2_custom_object, impl_avm2_custom_object_properties}; use gc_arena::{Collect, GcCell, MutationContext}; +use std::cell::{Ref, RefMut}; use std::collections::HashMap; /// 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_avm2_custom_object!(base); - impl_avm2_custom_object_properties!(base); + fn base(&self) -> Ref> { + Ref::map(self.0.read(), |read| &read.base) + } + + fn base_mut(&self, mc: MutationContext<'gc, '_>) -> RefMut> { + 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, Error> { Ok(AvmString::new( @@ -488,10 +497,6 @@ impl<'gc> TObject<'gc> for ClassObject<'gc> { Some(*self) } - fn instance_of(&self) -> Option> { - self.0.read().base.instance_of() - } - fn set_local_property_is_enumerable( &self, mc: MutationContext<'gc, '_>, diff --git a/core/src/avm2/object/custom_object.rs b/core/src/avm2/object/custom_object.rs deleted file mode 100644 index 773d9a0b3..000000000 --- a/core/src/avm2/object/custom_object.rs +++ /dev/null @@ -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, 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 { - self.0.read().$field.has_own_property(name) - } - - fn resolve_any(self, local_name: AvmString<'gc>) -> Result>, 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 { - self.0.read().$field.has_trait(name) - } - - fn get_scope(self) -> Option>> { - self.0.read().$field.get_scope() - } - - fn resolve_any_trait( - self, - local_name: AvmString<'gc>, - ) -> Result>, Error> { - self.0.read().$field.resolve_any_trait(local_name) - } - - fn instance_of(&self) -> Option> { - 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, 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> { - 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> { - 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> { - 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) - } - }; -} diff --git a/core/src/avm2/object/date_object.rs b/core/src/avm2/object/date_object.rs index 14d0bfc0e..bedcddfdc 100644 --- a/core/src/avm2/object/date_object.rs +++ b/core/src/avm2/object/date_object.rs @@ -1,16 +1,11 @@ use crate::avm2::activation::Activation; -use crate::avm2::names::{Namespace, QName}; use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::{Object, ObjectPtr, TObject}; -use crate::avm2::scope::Scope; use crate::avm2::value::{Hint, Value}; 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 gc_arena::{Collect, GcCell, MutationContext}; +use std::cell::{Ref, RefMut}; /// A class instance allocator that allocates Date objects. pub fn date_allocator<'gc>( @@ -58,9 +53,17 @@ pub struct DateObjectData<'gc> { } impl<'gc> TObject<'gc> for DateObject<'gc> { - impl_avm2_custom_object!(base); - impl_avm2_custom_object_properties!(base); - impl_avm2_custom_object_instance!(base); + fn base(&self) -> Ref> { + Ref::map(self.0.read(), |read| &read.base) + } + + fn base_mut(&self, mc: MutationContext<'gc, '_>) -> RefMut> { + 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, Error> { let this: Object<'gc> = Object::DateObject(*self); diff --git a/core/src/avm2/object/dispatch_object.rs b/core/src/avm2/object/dispatch_object.rs index b58864894..8cfda863d 100644 --- a/core/src/avm2/object/dispatch_object.rs +++ b/core/src/avm2/object/dispatch_object.rs @@ -2,16 +2,10 @@ use crate::avm2::activation::Activation; use crate::avm2::events::DispatchList; -use crate::avm2::names::{Namespace, QName}; use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::{Object, ObjectPtr, TObject}; -use crate::avm2::scope::Scope; use crate::avm2::value::Value; 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 std::cell::{Ref, RefMut}; @@ -71,9 +65,17 @@ impl<'gc> DispatchObject<'gc> { } impl<'gc> TObject<'gc> for DispatchObject<'gc> { - impl_avm2_custom_object!(base); - impl_avm2_custom_object_properties!(base); - impl_avm2_custom_object_instance!(base); + fn base(&self) -> Ref> { + Ref::map(self.0.read(), |read| &read.base) + } + + fn base_mut(&self, mc: MutationContext<'gc, '_>) -> RefMut> { + 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( self, diff --git a/core/src/avm2/object/domain_object.rs b/core/src/avm2/object/domain_object.rs index 5b58b4eb3..b651b2171 100644 --- a/core/src/avm2/object/domain_object.rs +++ b/core/src/avm2/object/domain_object.rs @@ -5,14 +5,10 @@ use crate::avm2::domain::Domain; use crate::avm2::names::{Namespace, QName}; use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::{Object, ObjectPtr, TObject}; -use crate::avm2::scope::Scope; use crate::avm2::value::Value; 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 std::cell::{Ref, RefMut}; /// A class instance allocator that allocates AppDomain objects. pub fn appdomain_allocator<'gc>( @@ -114,9 +110,17 @@ impl<'gc> DomainObject<'gc> { } impl<'gc> TObject<'gc> for DomainObject<'gc> { - impl_avm2_custom_object!(base); - impl_avm2_custom_object_properties!(base); - impl_avm2_custom_object_instance!(base); + fn base(&self) -> Ref> { + Ref::map(self.0.read(), |read| &read.base) + } + + fn base_mut(&self, mc: MutationContext<'gc, '_>) -> RefMut> { + 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> { Some(self.0.read().domain) diff --git a/core/src/avm2/object/event_object.rs b/core/src/avm2/object/event_object.rs index 48d740bda..82315ea8a 100644 --- a/core/src/avm2/object/event_object.rs +++ b/core/src/avm2/object/event_object.rs @@ -5,13 +5,9 @@ use crate::avm2::events::Event; use crate::avm2::names::{Namespace, QName}; use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::{Object, ObjectPtr, TObject}; -use crate::avm2::scope::Scope; use crate::avm2::value::Value; 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 std::cell::{Ref, RefMut}; @@ -81,9 +77,17 @@ impl<'gc> EventObject<'gc> { } impl<'gc> TObject<'gc> for EventObject<'gc> { - impl_avm2_custom_object!(base); - impl_avm2_custom_object_properties!(base); - impl_avm2_custom_object_instance!(base); + fn base(&self) -> Ref> { + Ref::map(self.0.read(), |read| &read.base) + } + + fn base_mut(&self, mc: MutationContext<'gc, '_>) -> RefMut> { + 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, Error> { let base = ScriptObjectData::base_new(Some((*self).into()), None); diff --git a/core/src/avm2/object/function_object.rs b/core/src/avm2/object/function_object.rs index 7c7d878ca..58ed88a9b 100644 --- a/core/src/avm2/object/function_object.rs +++ b/core/src/avm2/object/function_object.rs @@ -9,11 +9,8 @@ use crate::avm2::object::{Object, ObjectPtr, TObject}; use crate::avm2::scope::Scope; use crate::avm2::value::Value; 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 std::cell::{Ref, RefMut}; /// An Object which can be called to execute its function code. #[derive(Collect, Debug, Clone, Copy)] @@ -87,9 +84,17 @@ impl<'gc> FunctionObject<'gc> { } impl<'gc> TObject<'gc> for FunctionObject<'gc> { - impl_avm2_custom_object!(base); - impl_avm2_custom_object_properties!(base); - impl_avm2_custom_object_instance!(base); + fn base(&self) -> Ref> { + Ref::map(self.0.read(), |read| &read.base) + } + + fn base_mut(&self, mc: MutationContext<'gc, '_>) -> RefMut> { + 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, Error> { Ok("function Function() {}".into()) diff --git a/core/src/avm2/object/loaderinfo_object.rs b/core/src/avm2/object/loaderinfo_object.rs index 06dc80ac0..f945873fd 100644 --- a/core/src/avm2/object/loaderinfo_object.rs +++ b/core/src/avm2/object/loaderinfo_object.rs @@ -1,20 +1,15 @@ //! Loader-info object use crate::avm2::activation::Activation; -use crate::avm2::names::{Namespace, QName}; use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::{Object, ObjectPtr, TObject}; -use crate::avm2::scope::Scope; use crate::avm2::value::Value; use crate::avm2::Error; use crate::display_object::DisplayObject; use crate::string::AvmString; 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 std::cell::Ref; +use std::cell::{Ref, RefMut}; use std::sync::Arc; /// A class instance allocator that allocates LoaderInfo objects. @@ -118,9 +113,17 @@ impl<'gc> LoaderInfoObject<'gc> { } impl<'gc> TObject<'gc> for LoaderInfoObject<'gc> { - impl_avm2_custom_object!(base); - impl_avm2_custom_object_properties!(base); - impl_avm2_custom_object_instance!(base); + fn base(&self) -> Ref> { + Ref::map(self.0.read(), |read| &read.base) + } + + fn base_mut(&self, mc: MutationContext<'gc, '_>) -> RefMut> { + 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, Error> { if let Some(class) = self.instance_of_class_definition() { diff --git a/core/src/avm2/object/namespace_object.rs b/core/src/avm2/object/namespace_object.rs index 5640399cc..de09a61d2 100644 --- a/core/src/avm2/object/namespace_object.rs +++ b/core/src/avm2/object/namespace_object.rs @@ -1,18 +1,13 @@ //! Boxed namespaces 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::{Object, ObjectPtr, TObject}; -use crate::avm2::scope::Scope; use crate::avm2::value::Value; 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 std::cell::Ref; +use std::cell::{Ref, RefMut}; /// A class instance allocator that allocates namespace objects. pub fn namespace_allocator<'gc>( @@ -71,9 +66,17 @@ impl<'gc> NamespaceObject<'gc> { } impl<'gc> TObject<'gc> for NamespaceObject<'gc> { - impl_avm2_custom_object!(base); - impl_avm2_custom_object_properties!(base); - impl_avm2_custom_object_instance!(base); + fn base(&self) -> Ref> { + Ref::map(self.0.read(), |read| &read.base) + } + + fn base_mut(&self, mc: MutationContext<'gc, '_>) -> RefMut> { + 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, Error> { Ok(self.0.read().namespace.as_uri().into()) diff --git a/core/src/avm2/object/primitive_object.rs b/core/src/avm2/object/primitive_object.rs index 1f16b92a6..d85733f0f 100644 --- a/core/src/avm2/object/primitive_object.rs +++ b/core/src/avm2/object/primitive_object.rs @@ -3,16 +3,11 @@ use std::cell::{Ref, RefMut}; use crate::avm2::activation::Activation; -use crate::avm2::names::{Namespace, QName}; use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::{Object, ObjectPtr, TObject}; -use crate::avm2::scope::Scope; use crate::avm2::value::Value; 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}; /// A class instance allocator that allocates primitive objects. @@ -105,9 +100,17 @@ impl<'gc> PrimitiveObject<'gc> { } impl<'gc> TObject<'gc> for PrimitiveObject<'gc> { - impl_avm2_custom_object!(base); - impl_avm2_custom_object_properties!(base); - impl_avm2_custom_object_instance!(base); + fn base(&self) -> Ref> { + Ref::map(self.0.read(), |read| &read.base) + } + + fn base_mut(&self, mc: MutationContext<'gc, '_>) -> RefMut> { + 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, Error> { Ok(self.0.read().primitive.clone()) diff --git a/core/src/avm2/object/regexp_object.rs b/core/src/avm2/object/regexp_object.rs index 95be7f3bc..c61945088 100644 --- a/core/src/avm2/object/regexp_object.rs +++ b/core/src/avm2/object/regexp_object.rs @@ -1,17 +1,12 @@ //! Object representation for regexp use crate::avm2::activation::Activation; -use crate::avm2::names::{Namespace, QName}; use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::{Object, ObjectPtr, TObject}; use crate::avm2::regexp::RegExp; -use crate::avm2::scope::Scope; use crate::avm2::value::Value; 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 std::cell::{Ref, RefMut}; @@ -69,9 +64,17 @@ impl<'gc> RegExpObject<'gc> { } impl<'gc> TObject<'gc> for RegExpObject<'gc> { - impl_avm2_custom_object!(base); - impl_avm2_custom_object_properties!(base); - impl_avm2_custom_object_instance!(base); + fn base(&self) -> Ref> { + Ref::map(self.0.read(), |read| &read.base) + } + + fn base_mut(&self, mc: MutationContext<'gc, '_>) -> RefMut> { + 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, Error> { let base = ScriptObjectData::base_new(Some((*self).into()), None); diff --git a/core/src/avm2/object/script_object.rs b/core/src/avm2/object/script_object.rs index 172a4493a..d7d04ae9f 100644 --- a/core/src/avm2/object/script_object.rs +++ b/core/src/avm2/object/script_object.rs @@ -12,6 +12,7 @@ use crate::avm2::value::Value; use crate::avm2::Error; use crate::string::AvmString; use gc_arena::{Collect, GcCell, MutationContext}; +use std::cell::{Ref, RefMut}; use std::collections::HashMap; use std::fmt::Debug; @@ -60,152 +61,12 @@ pub struct ScriptObjectData<'gc> { } impl<'gc> TObject<'gc> for ScriptObject<'gc> { - fn get_property_local( - self, - receiver: Object<'gc>, - name: &QName<'gc>, - activation: &mut Activation<'_, 'gc, '_>, - ) -> Result, Error> { - let rv = self - .0 - .read() - .get_property_local(receiver, name, activation)?; - - rv.resolve(activation) + fn base(&self) -> Ref> { + self.0.read() } - fn set_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) - .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, 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> { - self.0.read().get_method(id) - } - - fn get_scope(self) -> Option>> { - self.0.read().get_scope() - } - - fn resolve_any(self, local_name: AvmString<'gc>) -> Result>, Error> { - self.0.read().resolve_any(local_name) - } - - fn resolve_any_trait( - self, - local_name: AvmString<'gc>, - ) -> Result>, Error> { - self.0.read().resolve_any_trait(local_name) - } - - fn has_own_property(self, name: &QName<'gc>) -> Result { - self.0.read().has_own_property(name) - } - - fn has_trait(self, name: &QName<'gc>) -> Result { - 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> { - 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> { - 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 base_mut(&self, mc: MutationContext<'gc, '_>) -> RefMut> { + self.0.write(mc) } 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)) } - fn to_string(&self, mc: MutationContext<'gc, '_>) -> Result, 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, Error> { 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> { - self.0.read().instance_of() - } } impl<'gc> ScriptObject<'gc> { diff --git a/core/src/avm2/object/sound_object.rs b/core/src/avm2/object/sound_object.rs index 1b57e7b11..2bf942eee 100644 --- a/core/src/avm2/object/sound_object.rs +++ b/core/src/avm2/object/sound_object.rs @@ -4,15 +4,11 @@ use crate::avm2::activation::Activation; use crate::avm2::names::{Namespace, QName}; use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::{Object, ObjectPtr, TObject}; -use crate::avm2::scope::Scope; use crate::avm2::value::Value; use crate::avm2::Error; 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 std::cell::{Ref, RefMut}; /// A class instance allocator that allocates Sound objects. pub fn sound_allocator<'gc>( @@ -81,9 +77,17 @@ impl<'gc> SoundObject<'gc> { } impl<'gc> TObject<'gc> for SoundObject<'gc> { - impl_avm2_custom_object!(base); - impl_avm2_custom_object_properties!(base); - impl_avm2_custom_object_instance!(base); + fn base(&self) -> Ref> { + Ref::map(self.0.read(), |read| &read.base) + } + + fn base_mut(&self, mc: MutationContext<'gc, '_>) -> RefMut> { + 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, Error> { Ok(Object::from(*self).into()) diff --git a/core/src/avm2/object/soundchannel_object.rs b/core/src/avm2/object/soundchannel_object.rs index 782634b98..59743a364 100644 --- a/core/src/avm2/object/soundchannel_object.rs +++ b/core/src/avm2/object/soundchannel_object.rs @@ -4,15 +4,11 @@ use crate::avm2::activation::Activation; use crate::avm2::names::{Namespace, QName}; use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::{Object, ObjectPtr, TObject}; -use crate::avm2::scope::Scope; use crate::avm2::value::Value; use crate::avm2::Error; 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 std::cell::{Ref, RefMut}; /// A class instance allocator that allocates SoundChannel objects. pub fn soundchannel_allocator<'gc>( @@ -77,14 +73,22 @@ impl<'gc> SoundChannelObject<'gc> { } impl<'gc> TObject<'gc> for SoundChannelObject<'gc> { - impl_avm2_custom_object!(base); - impl_avm2_custom_object_properties!(base); - impl_avm2_custom_object_instance!(base); + fn base(&self) -> Ref> { + Ref::map(self.0.read(), |read| &read.base) + } + + fn base_mut(&self, mc: MutationContext<'gc, '_>) -> RefMut> { + RefMut::map(self.0.write(mc), |write| &mut write.base) + } fn value_of(&self, _mc: MutationContext<'gc, '_>) -> Result, Error> { 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, Error> { let base = ScriptObjectData::base_new(Some((*self).into()), None); diff --git a/core/src/avm2/object/stage_object.rs b/core/src/avm2/object/stage_object.rs index 1693041b0..d79b7faee 100644 --- a/core/src/avm2/object/stage_object.rs +++ b/core/src/avm2/object/stage_object.rs @@ -1,16 +1,14 @@ //! AVM2 object impl for the display hierarchy. use crate::avm2::activation::Activation; -use crate::avm2::function::Executable; use crate::avm2::names::{Namespace, QName}; use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::{Object, ObjectPtr, TObject}; -use crate::avm2::scope::Scope; use crate::avm2::value::Value; use crate::avm2::Error; use crate::display_object::DisplayObject; -use crate::string::AvmString; use gc_arena::{Collect, GcCell, MutationContext}; +use std::cell::{Ref, RefMut}; /// A class instance allocator that allocates Stage objects. pub fn stage_allocator<'gc>( @@ -120,175 +118,18 @@ impl<'gc> StageObject<'gc> { } impl<'gc> TObject<'gc> for StageObject<'gc> { - fn get_property_local( - self, - reciever: Object<'gc>, - name: &QName<'gc>, - activation: &mut Activation<'_, 'gc, '_>, - ) -> Result, Error> { - let read = self.0.read(); - let rv = read.base.get_property_local(reciever, name, activation)?; - - drop(read); - - rv.resolve(activation) + fn base(&self) -> Ref> { + Ref::map(self.0.read(), |read| &read.base) } - fn set_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 - .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, 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> { - self.0.read().base.get_method(id) - } - - fn get_scope(self) -> Option>> { - self.0.read().base.get_scope() - } - - fn resolve_any(self, local_name: AvmString<'gc>) -> Result>, Error> { - self.0.read().base.resolve_any(local_name) - } - - fn resolve_any_trait( - self, - local_name: AvmString<'gc>, - ) -> Result>, Error> { - self.0.read().base.resolve_any_trait(local_name) - } - - fn has_own_property(self, name: &QName<'gc>) -> Result { - self.0.read().base.has_own_property(name) - } - - fn has_trait(self, name: &QName<'gc>) -> Result { - 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> { - 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> { - 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 base_mut(&self, mc: MutationContext<'gc, '_>) -> RefMut> { + 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_executable(&self) -> Option> { - None - } - - fn instance_of(&self) -> Option> { - self.0.read().base.instance_of() - } - fn as_display_object(&self) -> Option> { self.0.read().display_object } @@ -297,16 +138,6 @@ impl<'gc> TObject<'gc> for StageObject<'gc> { self.0.write(mc).display_object = Some(obj); } - fn call( - self, - _reciever: Option>, - _arguments: &[Value<'gc>], - _activation: &mut Activation<'_, 'gc, '_>, - _base_proto: Option>, - ) -> Result, Error> { - Err("Not a callable function!".into()) - } - fn derive(&self, activation: &mut Activation<'_, 'gc, '_>) -> Result, Error> { let this: Object<'gc> = Object::StageObject(*self); 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, Error> { 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) - } } diff --git a/core/src/avm2/object/vector_object.rs b/core/src/avm2/object/vector_object.rs index 5a3244a78..50806bc70 100644 --- a/core/src/avm2/object/vector_object.rs +++ b/core/src/avm2/object/vector_object.rs @@ -4,12 +4,10 @@ use crate::avm2::activation::Activation; use crate::avm2::names::{Namespace, QName}; use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::{Object, ObjectPtr, TObject}; -use crate::avm2::scope::Scope; use crate::avm2::value::Value; use crate::avm2::vector::VectorStorage; use crate::avm2::Error; use crate::string::AvmString; -use crate::{impl_avm2_custom_object, impl_avm2_custom_object_instance}; use gc_arena::{Collect, GcCell, MutationContext}; use std::cell::{Ref, RefMut}; @@ -90,8 +88,17 @@ impl<'gc> VectorObject<'gc> { } impl<'gc> TObject<'gc> for VectorObject<'gc> { - impl_avm2_custom_object!(base); - impl_avm2_custom_object_instance!(base); + fn base(&self) -> Ref> { + Ref::map(self.0.read(), |read| &read.base) + } + + fn base_mut(&self, mc: MutationContext<'gc, '_>) -> RefMut> { + 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( self, @@ -190,18 +197,6 @@ impl<'gc> TObject<'gc> for VectorObject<'gc> { 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 { if name.namespace().is_package("") && name.local_name().parse::().is_ok() { return true; diff --git a/core/src/avm2/object/xml_object.rs b/core/src/avm2/object/xml_object.rs index eac473551..b1a5fc035 100644 --- a/core/src/avm2/object/xml_object.rs +++ b/core/src/avm2/object/xml_object.rs @@ -1,17 +1,12 @@ //! Object representation for XML objects use crate::avm2::activation::Activation; -use crate::avm2::names::{Namespace, QName}; use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::{Object, ObjectPtr, TObject}; -use crate::avm2::scope::Scope; use crate::avm2::value::Value; 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 std::cell::{Ref, RefMut}; /// A class instance allocator that allocates XML objects. pub fn xml_allocator<'gc>( @@ -40,9 +35,17 @@ pub struct XmlObjectData<'gc> { } impl<'gc> TObject<'gc> for XmlObject<'gc> { - impl_avm2_custom_object!(base); - impl_avm2_custom_object_properties!(base); - impl_avm2_custom_object_instance!(base); + fn base(&self) -> Ref> { + Ref::map(self.0.read(), |read| &read.base) + } + + fn base_mut(&self, mc: MutationContext<'gc, '_>) -> RefMut> { + 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, Error> { let this: Object<'gc> = Object::XmlObject(*self);