From 9f13b8e6679679f2db4f427b6cfb1968a04f1aa4 Mon Sep 17 00:00:00 2001 From: Filip Tibell Date: Wed, 22 Mar 2023 10:28:49 +0100 Subject: [PATCH] Don't allow instances to be created from dom roots --- packages/lib-roblox/src/instance/mod.rs | 111 ++++++++++-------------- 1 file changed, 47 insertions(+), 64 deletions(-) diff --git a/packages/lib-roblox/src/instance/mod.rs b/packages/lib-roblox/src/instance/mod.rs index 7665185..0a1b830 100644 --- a/packages/lib-roblox/src/instance/mod.rs +++ b/packages/lib-roblox/src/instance/mod.rs @@ -24,28 +24,31 @@ lazy_static::lazy_static! { pub struct Instance { dom_ref: DomRef, class_name: String, - is_root: bool, } impl Instance { /** Creates a new `Instance` from an existing dom object ref. - Panics if the instance does not exist in the internal dom. + Panics if the instance does not exist in the internal dom, + or if the given dom object ref points to the dom root. */ fn new(dom_ref: DomRef) -> Self { - let reader = INTERNAL_DOM + let dom = INTERNAL_DOM .try_read() .expect("Failed to get read access to document"); - let instance = reader + let instance = dom .get_by_ref(dom_ref) .expect("Failed to find instance in document"); + if instance.referent() == dom.root_ref() { + panic!("Instances can not be created from dom roots") + } + Self { dom_ref, class_name: instance.class.clone(), - is_root: dom_ref == reader.root_ref(), } } @@ -69,7 +72,6 @@ impl Instance { Self { dom_ref, class_name: class_name.to_string(), - is_root: false, } } @@ -78,6 +80,8 @@ impl Instance { it from an external weak dom to the internal one. An orphaned instance is an instance at the root of a weak dom. + + Panics if the given dom ref is the root dom ref of the external weak dom. */ pub fn from_external_dom(external_dom: &mut WeakDom, external_dom_ref: DomRef) -> Self { { @@ -95,7 +99,8 @@ impl Instance { /** Transfers an instance to an external weak dom. - This will place the instance at the root of the weak dom and return its referent. + This will place the instance as a child of the + root of the weak dom, and return its referent. */ pub fn into_external_dom(self, external_dom: &mut WeakDom) -> DomRef { let mut dom = INTERNAL_DOM @@ -177,8 +182,8 @@ impl Instance { } /** - Destroys the instance, unless it is the root instance, removing - it completely from the weak dom with no way of recovering it. + Destroys the instance, removing it completely + from the weak dom with no way of recovering it. All member methods will throw errors when called from lua and panic when called from rust after the instance has been destroyed. @@ -190,7 +195,7 @@ impl Instance { on the Roblox Developer Hub */ pub fn destroy(&mut self) -> bool { - if self.is_root || self.is_destroyed() { + if self.is_destroyed() { false } else { let mut dom = INTERNAL_DOM @@ -313,24 +318,16 @@ impl Instance { on the Roblox Developer Hub */ pub fn get_parent(&self) -> Option { - if self.is_root { - return None; - } + let dom = INTERNAL_DOM + .try_read() + .expect("Failed to get read access to document"); - let (nil_parent_ref, parent_ref) = { - let dom = INTERNAL_DOM - .try_read() - .expect("Failed to get read access to document"); + let parent_ref = dom + .get_by_ref(self.dom_ref) + .expect("Failed to find instance in document") + .parent(); - let parent_ref = dom - .get_by_ref(self.dom_ref) - .expect("Failed to find instance in document") - .parent(); - - (dom.root_ref(), parent_ref) - }; - - if parent_ref == nil_parent_ref { + if parent_ref == dom.root_ref() { None } else { Some(Self::new(parent_ref)) @@ -349,10 +346,6 @@ impl Instance { on the Roblox Developer Hub */ pub fn set_parent(&self, parent: Option) { - if self.is_root { - panic!("Root instance can not be reparented") - } - let mut dom = INTERNAL_DOM .try_write() .expect("Failed to get write access to target document"); @@ -405,16 +398,15 @@ impl Instance { on the Roblox Developer Hub */ pub fn get_children(&self) -> Vec { - let children = { - let dom = INTERNAL_DOM - .try_read() - .expect("Failed to get read access to document"); + let dom = INTERNAL_DOM + .try_read() + .expect("Failed to get read access to document"); - dom.get_by_ref(self.dom_ref) - .expect("Failed to find instance in document") - .children() - .to_vec() - }; + let children = dom + .get_by_ref(self.dom_ref) + .expect("Failed to find instance in document") + .children() + .to_vec(); children.into_iter().map(Self::new).collect() } @@ -430,28 +422,24 @@ impl Instance { on the Roblox Developer Hub */ pub fn get_descendants(&self) -> Vec { - let descendants = { - let dom = INTERNAL_DOM - .try_read() - .expect("Failed to get read access to document"); + let dom = INTERNAL_DOM + .try_read() + .expect("Failed to get read access to document"); - let mut descendants = Vec::new(); - let mut queue = VecDeque::from_iter( - dom.get_by_ref(self.dom_ref) - .expect("Failed to find instance in document") - .children(), - ); + let mut descendants = Vec::new(); + let mut queue = VecDeque::from_iter( + dom.get_by_ref(self.dom_ref) + .expect("Failed to find instance in document") + .children(), + ); - while let Some(queue_ref) = queue.pop_front() { - descendants.push(*queue_ref); - let queue_inst = dom.get_by_ref(*queue_ref).unwrap(); - for queue_ref_inner in queue_inst.children().iter().rev() { - queue.push_front(queue_ref_inner); - } + while let Some(queue_ref) = queue.pop_front() { + descendants.push(*queue_ref); + let queue_inst = dom.get_by_ref(*queue_ref).unwrap(); + for queue_ref_inner in queue_inst.children().iter().rev() { + queue.push_front(queue_ref_inner); } - - descendants - }; + } descendants.into_iter().map(Self::new).collect() } @@ -712,12 +700,7 @@ impl LuaUserData for Instance { return Ok(()); } "Parent" => { - if this.is_root { - return Err(LuaError::RuntimeError(format!( - "Failed to set property '{}' - root instance can not be reparented", - prop_name - ))); - } else if this.get_class_name() == "DataModel" { + if this.get_class_name() == "DataModel" { return Err(LuaError::RuntimeError(format!( "Failed to set property '{}' - DataModel can not be reparented", prop_name