From fa07d16cf467d0952465bb92166ddf6eccfe53f2 Mon Sep 17 00:00:00 2001
From: Quaternions <krakow20@gmail.com>
Date: Fri, 18 Apr 2025 11:06:55 -0700
Subject: [PATCH] refactor some util functions to use new rbx-dom features

---
 lib/rbx_loader/src/rbx.rs                     | 42 ++++++++-----------
 lib/roblox_emulator/src/context.rs            | 21 ++++------
 .../src/runner/instance/instance.rs           | 10 ++++-
 3 files changed, 34 insertions(+), 39 deletions(-)

diff --git a/lib/rbx_loader/src/rbx.rs b/lib/rbx_loader/src/rbx.rs
index 15cbf2e..78fdbd6 100644
--- a/lib/rbx_loader/src/rbx.rs
+++ b/lib/rbx_loader/src/rbx.rs
@@ -18,31 +18,25 @@ fn static_ustr(s:&'static str)->rbx_dom_weak::Ustr{
 	rbx_dom_weak::ustr(s)
 }
 
-fn class_is_a(class: &str, superclass: &str) -> bool {
-	if class==superclass {
-		return true
-	}
-	let class_descriptor=rbx_reflection_database::get().classes.get(class);
-	if let Some(descriptor) = &class_descriptor {
-		if let Some(class_super) = &descriptor.superclass {
-			return class_is_a(&class_super, superclass)
-		}
-	}
-	false
-}
-fn recursive_collect_superclass(objects: &mut std::vec::Vec<rbx_dom_weak::types::Ref>,dom: &rbx_dom_weak::WeakDom, instance: &rbx_dom_weak::Instance, superclass: &str){
-	let mut stack=vec![instance];
-	while let Some(item)=stack.pop(){
-		for &referent in item.children(){
-			if let Some(c)=dom.get_by_ref(referent){
-				if class_is_a(c.class.as_str(),superclass){
-					objects.push(c.referent());//copy ref
-				}
-				stack.push(c);
-			}
-		}
-	}
+fn recursive_collect_superclass(
+	objects:&mut std::vec::Vec<rbx_dom_weak::types::Ref>,
+	dom:&rbx_dom_weak::WeakDom,
+	instance:&rbx_dom_weak::Instance,
+	superclass:&str
+){
+	let instance=instance;
+	let db=rbx_reflection_database::get();
+	let Some(superclass)=db.classes.get(superclass)else{
+		return;
+	};
+	objects.extend(
+		dom.descendants_of(instance.referent()).filter_map(|instance|{
+			let class=db.classes.get(instance.class.as_str())?;
+			db.has_superclass(class,superclass).then(||instance.referent())
+		})
+	);
 }
+
 fn planar64_affine3_from_roblox(cf:&rbx_dom_weak::types::CFrame,size:&rbx_dom_weak::types::Vector3)->Planar64Affine3{
 	Planar64Affine3::new(
 		Planar64Mat3::from_cols([
diff --git a/lib/roblox_emulator/src/context.rs b/lib/roblox_emulator/src/context.rs
index 7dd360b..17b0ea5 100644
--- a/lib/roblox_emulator/src/context.rs
+++ b/lib/roblox_emulator/src/context.rs
@@ -5,16 +5,6 @@ fn static_ustr(s:&'static str)->rbx_dom_weak::Ustr{
 	rbx_dom_weak::ustr(s)
 }
 
-pub fn class_is_a(class:&str,superclass:&str)->bool{
-	class==superclass
-	||rbx_reflection_database::get().classes.get(class)
-	.is_some_and(|descriptor|
-		descriptor.superclass.as_ref().is_some_and(|class_super|
-			class_is_a(class_super,superclass)
-		)
-	)
-}
-
 #[repr(transparent)]
 pub struct Context{
 	pub(crate)dom:WeakDom,
@@ -43,9 +33,14 @@ impl Context{
 	}
 	/// Creates an iterator over all items of a particular class.
 	pub fn superclass_iter<'a>(&'a self,superclass:&'a str)->impl Iterator<Item=Ref>+'a{
-		self.dom.descendants().filter(|&instance|
-			class_is_a(instance.class.as_ref(),superclass)
-		).map(|instance|instance.referent())
+		let db=rbx_reflection_database::get();
+		let Some(superclass)=db.classes.get(superclass)else{
+			panic!("Invalid class");
+		};
+		self.dom.descendants().filter_map(|instance|{
+			let class=db.classes.get(instance.class.as_str())?;
+			db.has_superclass(class,superclass).then(||instance.referent())
+		})
 	}
 	pub fn scripts(&self)->Vec<crate::runner::instance::Instance>{
 		self.superclass_iter("LuaSourceContainer").map(crate::runner::instance::Instance::new).collect()
diff --git a/lib/roblox_emulator/src/runner/instance/instance.rs b/lib/roblox_emulator/src/runner/instance/instance.rs
index 4400a2a..78c6bf4 100644
--- a/lib/roblox_emulator/src/runner/instance/instance.rs
+++ b/lib/roblox_emulator/src/runner/instance/instance.rs
@@ -48,7 +48,13 @@ fn coerce_float32(value:&mlua::Value)->Option<f32>{
 		_=>None,
 	}
 }
-
+pub fn class_is_a(class:&str,superclass:&str)->bool{
+	let db=rbx_reflection_database::get();
+	let (Some(class),Some(superclass))=(db.classes.get(class),db.classes.get(superclass))else{
+		return false;
+	};
+	db.has_superclass(class,superclass)
+}
 fn get_full_name(dom:&rbx_dom_weak::WeakDom,instance:&rbx_dom_weak::Instance)->String{
 	let mut full_name=instance.name.clone();
 	let mut pref=instance.parent();
@@ -196,7 +202,7 @@ impl mlua::UserData for Instance{
 		methods.add_method("IsA",|lua,this,classname:mlua::String|
 			dom_mut(lua,|dom|{
 				let instance=this.get(dom)?;
-				Ok(crate::context::class_is_a(instance.class.as_str(),&*classname.to_str()?))
+				Ok(class_is_a(instance.class.as_str(),&*classname.to_str()?))
 			})
 		);
 		methods.add_method("Destroy",|lua,this,()|