@@ -104,6 +104,9 @@ pub struct ClassData<'gc> {
104104 /// superinterfaces, nor interfaces implemented by the superclass.
105105 direct_interfaces : Vec < Class < ' gc > > ,
106106
107+ /// The list of all interfaces implemented by this class.
108+ all_interfaces : Vec < Class < ' gc > > ,
109+
107110 /// The instance allocator for this class.
108111 ///
109112 /// If `None`, then instances of this object will be allocated the same way
@@ -163,7 +166,7 @@ pub struct ClassData<'gc> {
163166 /// Maps a type parameter to the application of this class with that parameter.
164167 ///
165168 /// Only applicable if this class is generic.
166- applications : FnvHashMap < Option < ClassKey < ' gc > > , Class < ' gc > > ,
169+ applications : FnvHashMap < Option < Class < ' gc > > , Class < ' gc > > ,
167170
168171 /// Whether or not this is a system-defined class.
169172 ///
@@ -184,29 +187,17 @@ impl PartialEq for Class<'_> {
184187 }
185188}
186189
187- impl < ' gc > core:: fmt:: Debug for Class < ' gc > {
188- fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> Result < ( ) , std:: fmt:: Error > {
189- f. debug_struct ( "Class" ) . field ( "name" , & self . name ( ) ) . finish ( )
190- }
191- }
192-
193- /// Allows using a `Class<'gc>` as a HashMap key,
194- /// using the pointer address for hashing/equality.
195- #[ derive( Collect , Copy , Clone ) ]
196- #[ collect( no_drop) ]
197- struct ClassKey < ' gc > ( Class < ' gc > ) ;
190+ impl Eq for Class < ' _ > { }
198191
199- impl PartialEq for ClassKey < ' _ > {
200- fn eq ( & self , other : & Self ) -> bool {
201- self . 0 == other . 0
192+ impl Hash for Class < ' _ > {
193+ fn hash < H : Hasher > ( & self , state : & mut H ) {
194+ self . 0 . as_ptr ( ) . hash ( state ) ;
202195 }
203196}
204197
205- impl Eq for ClassKey < ' _ > { }
206-
207- impl Hash for ClassKey < ' _ > {
208- fn hash < H : Hasher > ( & self , state : & mut H ) {
209- self . 0 . 0 . as_ptr ( ) . hash ( state) ;
198+ impl < ' gc > core:: fmt:: Debug for Class < ' gc > {
199+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> Result < ( ) , std:: fmt:: Error > {
200+ f. debug_struct ( "Class" ) . field ( "name" , & self . name ( ) ) . finish ( )
210201 }
211202}
212203
@@ -237,6 +228,7 @@ impl<'gc> Class<'gc> {
237228 attributes : ClassAttributes :: empty ( ) ,
238229 protected_namespace : None ,
239230 direct_interfaces : Vec :: new ( ) ,
231+ all_interfaces : Vec :: new ( ) ,
240232 instance_allocator : None ,
241233 instance_init,
242234 native_instance_init,
@@ -255,8 +247,7 @@ impl<'gc> Class<'gc> {
255247 }
256248
257249 pub fn add_application ( self , mc : & Mutation < ' gc > , param : Option < Class < ' gc > > , cls : Class < ' gc > ) {
258- let key = param. map ( ClassKey ) ;
259- self . 0 . write ( mc) . applications . insert ( key, cls) ;
250+ self . 0 . write ( mc) . applications . insert ( param, cls) ;
260251 }
261252
262253 /// Apply type parameters to an existing class.
@@ -271,9 +262,7 @@ impl<'gc> Class<'gc> {
271262 let mc = context. gc_context ;
272263 let this_read = this. 0 . read ( ) ;
273264
274- let key = param. map ( ClassKey ) ;
275-
276- if let Some ( application) = this_read. applications . get ( & key) {
265+ if let Some ( application) = this_read. applications . get ( & param) {
277266 return * application;
278267 }
279268
@@ -312,7 +301,7 @@ impl<'gc> Class<'gc> {
312301
313302 drop ( this_read) ;
314303
315- this. 0 . write ( mc) . applications . insert ( key , new_class) ;
304+ this. 0 . write ( mc) . applications . insert ( Some ( param ) , new_class) ;
316305 new_class
317306 }
318307
@@ -464,6 +453,7 @@ impl<'gc> Class<'gc> {
464453 attributes,
465454 protected_namespace,
466455 direct_interfaces : interfaces,
456+ all_interfaces : Vec :: new ( ) ,
467457 instance_allocator,
468458 instance_init,
469459 native_instance_init,
@@ -658,7 +648,7 @@ impl<'gc> Class<'gc> {
658648 // interfaces (i.e. those that were not already implemented by the superclass)
659649 // Otherwise, our behavior diverges from Flash Player in certain cases.
660650 // See the ignored test 'tests/tests/swfs/avm2/weird_superinterface_properties/'
661- for interface in interfaces {
651+ for interface in & interfaces {
662652 for interface_trait in & * interface. instance_traits ( ) {
663653 if !interface_trait. name ( ) . namespace ( ) . is_public ( ) {
664654 let public_name = QName :: new (
@@ -674,6 +664,8 @@ impl<'gc> Class<'gc> {
674664 }
675665 }
676666
667+ self . 0 . write ( context. gc_context ) . all_interfaces = interfaces;
668+
677669 Ok ( ( ) )
678670 }
679671
@@ -704,6 +696,7 @@ impl<'gc> Class<'gc> {
704696 attributes : ClassAttributes :: empty ( ) ,
705697 protected_namespace : None ,
706698 direct_interfaces : Vec :: new ( ) ,
699+ all_interfaces : Vec :: new ( ) ,
707700 instance_allocator : None ,
708701 instance_init : Method :: from_builtin (
709702 |_, _, _| Ok ( Value :: Undefined ) ,
@@ -737,6 +730,36 @@ impl<'gc> Class<'gc> {
737730 Ok ( class)
738731 }
739732
733+ /// Determine if this class has a given type in its superclass chain.
734+ ///
735+ /// The given class `test_class` should be either a superclass or
736+ /// interface we are checking against this class.
737+ ///
738+ /// To test if a class *instance* is of a given type, see `Object::is_of_type`.
739+ pub fn has_class_in_chain ( self , test_class : Class < ' gc > ) -> bool {
740+ let mut my_class = Some ( self ) ;
741+
742+ while let Some ( class) = my_class {
743+ if class == test_class {
744+ return true ;
745+ }
746+
747+ my_class = class. super_class ( )
748+ }
749+
750+ // A `Class` stores all of the interfaces it implements, including
751+ // those from superinterfaces and superclasses (recursively).
752+ if test_class. is_interface ( ) {
753+ for interface in & * self . all_interfaces ( ) {
754+ if * interface == test_class {
755+ return true ;
756+ }
757+ }
758+ }
759+
760+ false
761+ }
762+
740763 pub fn instance_vtable ( self ) -> VTable < ' gc > {
741764 self . 0 . read ( ) . instance_vtable
742765 }
@@ -749,6 +772,26 @@ impl<'gc> Class<'gc> {
749772 self . 0 . try_read ( ) . map ( |r| r. name )
750773 }
751774
775+ /// Attempts to obtain the name of this class.
776+ /// If we are unable to read from the necessary `GcCell`,
777+ /// the returned value will be some kind of error message.
778+ ///
779+ /// This should only be used in a debug context, where
780+ /// we need infallible access to *something* to print
781+ /// out.
782+ pub fn debug_name ( self ) -> Box < dyn fmt:: Debug + ' gc > {
783+ let class_name = self . try_name ( ) ;
784+
785+ match class_name {
786+ Ok ( class_name) => Box :: new ( class_name) ,
787+ Err ( err) => Box :: new ( err) ,
788+ }
789+ }
790+
791+ pub fn param ( self ) -> Option < Option < Class < ' gc > > > {
792+ self . 0 . read ( ) . param
793+ }
794+
752795 pub fn set_param ( self , mc : & Mutation < ' gc > , param : Option < Option < Class < ' gc > > > ) {
753796 self . 0 . write ( mc) . param = param;
754797 }
@@ -1079,6 +1122,10 @@ impl<'gc> Class<'gc> {
10791122 Ref :: map ( self . 0 . read ( ) , |c| & c. direct_interfaces )
10801123 }
10811124
1125+ pub fn all_interfaces ( & self ) -> Ref < Vec < Class < ' gc > > > {
1126+ Ref :: map ( self . 0 . read ( ) , |c| & c. all_interfaces )
1127+ }
1128+
10821129 /// Determine if this class is sealed (no dynamic properties)
10831130 pub fn is_sealed ( self ) -> bool {
10841131 self . 0 . read ( ) . attributes . contains ( ClassAttributes :: SEALED )
0 commit comments