mirror of
https://github.com/lune-org/lune.git
synced 2024-12-12 13:00:37 +00:00
Implement rest of roblox instance methods, minus attributes
This commit is contained in:
parent
f181445920
commit
97248cccdd
1 changed files with 200 additions and 4 deletions
|
@ -1,4 +1,5 @@
|
||||||
use std::{
|
use std::{
|
||||||
|
collections::VecDeque,
|
||||||
fmt,
|
fmt,
|
||||||
sync::{Arc, RwLock},
|
sync::{Arc, RwLock},
|
||||||
};
|
};
|
||||||
|
@ -36,6 +37,7 @@ impl Instance {
|
||||||
let instance = reader
|
let instance = reader
|
||||||
.get_by_ref(dom_ref)
|
.get_by_ref(dom_ref)
|
||||||
.expect("Failed to find instance in document");
|
.expect("Failed to find instance in document");
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
dom: Arc::clone(dom),
|
dom: Arc::clone(dom),
|
||||||
dom_ref,
|
dom_ref,
|
||||||
|
@ -90,8 +92,10 @@ impl Instance {
|
||||||
.expect("Failed to find instance in document")
|
.expect("Failed to find instance in document")
|
||||||
.parent()
|
.parent()
|
||||||
};
|
};
|
||||||
|
|
||||||
let new_ref = Self::clone_inner(lua, self.dom_ref, parent_ref);
|
let new_ref = Self::clone_inner(lua, self.dom_ref, parent_ref);
|
||||||
let new_inst = Self::new(&self.dom, new_ref);
|
let new_inst = Self::new(&self.dom, new_ref);
|
||||||
|
|
||||||
new_inst.set_parent_to_nil(lua);
|
new_inst.set_parent_to_nil(lua);
|
||||||
new_inst
|
new_inst
|
||||||
}
|
}
|
||||||
|
@ -153,8 +157,11 @@ impl Instance {
|
||||||
.dom
|
.dom
|
||||||
.try_write()
|
.try_write()
|
||||||
.expect("Failed to get write access to document");
|
.expect("Failed to get write access to document");
|
||||||
|
|
||||||
dom.destroy(self.dom_ref);
|
dom.destroy(self.dom_ref);
|
||||||
|
|
||||||
self.is_destroyed = true;
|
self.is_destroyed = true;
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -170,6 +177,28 @@ impl Instance {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Destroys all child instances.
|
||||||
|
|
||||||
|
See [`Instance::destroy`] for more info about
|
||||||
|
what happens when an instance gets destroyed.
|
||||||
|
*/
|
||||||
|
pub fn clear_all_children(&mut self) {
|
||||||
|
let mut dom = self
|
||||||
|
.dom
|
||||||
|
.try_write()
|
||||||
|
.expect("Failed to get write access to document");
|
||||||
|
|
||||||
|
let instance = dom
|
||||||
|
.get_by_ref(self.dom_ref)
|
||||||
|
.expect("Failed to find instance in document");
|
||||||
|
|
||||||
|
let child_refs = instance.children().to_vec();
|
||||||
|
for child_ref in child_refs {
|
||||||
|
dom.destroy(child_ref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Checks if the instance matches or inherits a given class name.
|
Checks if the instance matches or inherits a given class name.
|
||||||
*/
|
*/
|
||||||
|
@ -185,6 +214,7 @@ impl Instance {
|
||||||
.dom
|
.dom
|
||||||
.read()
|
.read()
|
||||||
.expect("Failed to get read access to document");
|
.expect("Failed to get read access to document");
|
||||||
|
|
||||||
dom.get_by_ref(self.dom_ref)
|
dom.get_by_ref(self.dom_ref)
|
||||||
.expect("Failed to find instance in document")
|
.expect("Failed to find instance in document")
|
||||||
.name
|
.name
|
||||||
|
@ -199,6 +229,7 @@ impl Instance {
|
||||||
.dom
|
.dom
|
||||||
.write()
|
.write()
|
||||||
.expect("Failed to get write access to document");
|
.expect("Failed to get write access to document");
|
||||||
|
|
||||||
dom.get_by_ref_mut(self.dom_ref)
|
dom.get_by_ref_mut(self.dom_ref)
|
||||||
.expect("Failed to find instance in document")
|
.expect("Failed to find instance in document")
|
||||||
.name = name.into()
|
.name = name.into()
|
||||||
|
@ -212,10 +243,12 @@ impl Instance {
|
||||||
.dom
|
.dom
|
||||||
.read()
|
.read()
|
||||||
.expect("Failed to get read access to document");
|
.expect("Failed to get read access to document");
|
||||||
|
|
||||||
let parent_ref = dom
|
let parent_ref = dom
|
||||||
.get_by_ref(self.dom_ref)
|
.get_by_ref(self.dom_ref)
|
||||||
.expect("Failed to find instance in document")
|
.expect("Failed to find instance in document")
|
||||||
.parent();
|
.parent();
|
||||||
|
|
||||||
if parent_ref == dom.root_ref() {
|
if parent_ref == dom.root_ref() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
|
@ -236,20 +269,24 @@ impl Instance {
|
||||||
.dom
|
.dom
|
||||||
.write()
|
.write()
|
||||||
.expect("Failed to get read access to source document");
|
.expect("Failed to get read access to source document");
|
||||||
|
|
||||||
let dom_target = parent
|
let dom_target = parent
|
||||||
.dom
|
.dom
|
||||||
.read()
|
.read()
|
||||||
.expect("Failed to get read access to target document");
|
.expect("Failed to get read access to target document");
|
||||||
|
|
||||||
let target_ref = dom_target
|
let target_ref = dom_target
|
||||||
.get_by_ref(parent.dom_ref)
|
.get_by_ref(parent.dom_ref)
|
||||||
.expect("Failed to find instance in target document")
|
.expect("Failed to find instance in target document")
|
||||||
.parent();
|
.parent();
|
||||||
|
|
||||||
if dom_source.root_ref() == dom_target.root_ref() {
|
if dom_source.root_ref() == dom_target.root_ref() {
|
||||||
dom_source.transfer_within(self.dom_ref, target_ref);
|
dom_source.transfer_within(self.dom_ref, target_ref);
|
||||||
} else {
|
} else {
|
||||||
// NOTE: We must drop the previous dom_target read handle here first so
|
// NOTE: We must drop the previous dom_target read handle here first so
|
||||||
// that we can get exclusive write access for transferring across doms
|
// that we can get exclusive write access for transferring across doms
|
||||||
drop(dom_target);
|
drop(dom_target);
|
||||||
|
|
||||||
let mut dom_target = parent
|
let mut dom_target = parent
|
||||||
.dom
|
.dom
|
||||||
.try_write()
|
.try_write()
|
||||||
|
@ -270,12 +307,15 @@ impl Instance {
|
||||||
.dom
|
.dom
|
||||||
.write()
|
.write()
|
||||||
.expect("Failed to get read access to source document");
|
.expect("Failed to get read access to source document");
|
||||||
|
|
||||||
let dom_lua = lua
|
let dom_lua = lua
|
||||||
.app_data_mut::<Arc<RwLock<WeakDom>>>()
|
.app_data_mut::<Arc<RwLock<WeakDom>>>()
|
||||||
.expect("Failed to find internal lua weak dom");
|
.expect("Failed to find internal lua weak dom");
|
||||||
|
|
||||||
let mut dom_target = dom_lua
|
let mut dom_target = dom_lua
|
||||||
.write()
|
.write()
|
||||||
.expect("Failed to get write access to target document");
|
.expect("Failed to get write access to target document");
|
||||||
|
|
||||||
let target_ref = dom_target.root_ref();
|
let target_ref = dom_target.root_ref();
|
||||||
dom_source.transfer(self.dom_ref, &mut dom_target, target_ref)
|
dom_source.transfer(self.dom_ref, &mut dom_target, target_ref)
|
||||||
}
|
}
|
||||||
|
@ -310,6 +350,93 @@ impl Instance {
|
||||||
.insert(name.as_ref().to_string(), value);
|
.insert(name.as_ref().to_string(), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Gets all of the current children of this `Instance`.
|
||||||
|
|
||||||
|
Note that this is a somewhat expensive operation and that other
|
||||||
|
operations using weak dom referents should be preferred if possible.
|
||||||
|
*/
|
||||||
|
pub fn get_children(&self) -> Vec<Instance> {
|
||||||
|
let dom = self
|
||||||
|
.dom
|
||||||
|
.read()
|
||||||
|
.expect("Failed to get read access to document");
|
||||||
|
|
||||||
|
let children = dom
|
||||||
|
.get_by_ref(self.dom_ref)
|
||||||
|
.expect("Failed to find instance in document")
|
||||||
|
.children();
|
||||||
|
|
||||||
|
children
|
||||||
|
.iter()
|
||||||
|
.map(|child_ref| Self::new(&self.dom, *child_ref))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Gets all of the current descendants of this `Instance` using a breadth-first search.
|
||||||
|
|
||||||
|
Note that this is a somewhat expensive operation and that other
|
||||||
|
operations using weak dom referents should be preferred if possible.
|
||||||
|
*/
|
||||||
|
pub fn get_descendants(&self) -> Vec<Instance> {
|
||||||
|
let dom = self
|
||||||
|
.dom
|
||||||
|
.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(),
|
||||||
|
);
|
||||||
|
|
||||||
|
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
|
||||||
|
.iter()
|
||||||
|
.map(|child_ref| Self::new(&self.dom, *child_ref))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Gets the "full name" of this instance.
|
||||||
|
|
||||||
|
This will be a path composed of instance names from the top-level
|
||||||
|
ancestor of this instance down to itself, in the following format:
|
||||||
|
|
||||||
|
`Ancestor.Child.Descendant.Instance`
|
||||||
|
*/
|
||||||
|
pub fn get_full_name(&self) -> String {
|
||||||
|
let dom = self
|
||||||
|
.dom
|
||||||
|
.read()
|
||||||
|
.expect("Failed to get read access to document");
|
||||||
|
let dom_root = dom.root_ref();
|
||||||
|
|
||||||
|
let mut parts = Vec::new();
|
||||||
|
let mut instance_ref = self.dom_ref;
|
||||||
|
|
||||||
|
while let Some(instance) = dom.get_by_ref(instance_ref) {
|
||||||
|
if instance_ref != dom_root && instance.class != "DataModel" {
|
||||||
|
instance_ref = instance.parent();
|
||||||
|
parts.push(instance.name.clone());
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
parts.reverse();
|
||||||
|
parts.join(".")
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Finds a child of the instance using the given predicate callback.
|
Finds a child of the instance using the given predicate callback.
|
||||||
*/
|
*/
|
||||||
|
@ -321,10 +448,12 @@ impl Instance {
|
||||||
.dom
|
.dom
|
||||||
.read()
|
.read()
|
||||||
.expect("Failed to get read access to document");
|
.expect("Failed to get read access to document");
|
||||||
|
|
||||||
let children = dom
|
let children = dom
|
||||||
.get_by_ref(self.dom_ref)
|
.get_by_ref(self.dom_ref)
|
||||||
.expect("Failed to find instance in document")
|
.expect("Failed to find instance in document")
|
||||||
.children();
|
.children();
|
||||||
|
|
||||||
children.iter().find_map(|child_ref| {
|
children.iter().find_map(|child_ref| {
|
||||||
if let Some(child_inst) = dom.get_by_ref(*child_ref) {
|
if let Some(child_inst) = dom.get_by_ref(*child_ref) {
|
||||||
if predicate(child_inst) {
|
if predicate(child_inst) {
|
||||||
|
@ -349,10 +478,12 @@ impl Instance {
|
||||||
.dom
|
.dom
|
||||||
.read()
|
.read()
|
||||||
.expect("Failed to get read access to document");
|
.expect("Failed to get read access to document");
|
||||||
|
|
||||||
let mut ancestor_ref = dom
|
let mut ancestor_ref = dom
|
||||||
.get_by_ref(self.dom_ref)
|
.get_by_ref(self.dom_ref)
|
||||||
.expect("Failed to find instance in document")
|
.expect("Failed to find instance in document")
|
||||||
.parent();
|
.parent();
|
||||||
|
|
||||||
while let Some(ancestor) = dom.get_by_ref(ancestor_ref) {
|
while let Some(ancestor) = dom.get_by_ref(ancestor_ref) {
|
||||||
if predicate(ancestor) {
|
if predicate(ancestor) {
|
||||||
return Some(Self::new(&self.dom, ancestor_ref));
|
return Some(Self::new(&self.dom, ancestor_ref));
|
||||||
|
@ -360,6 +491,40 @@ impl Instance {
|
||||||
ancestor_ref = ancestor.parent();
|
ancestor_ref = ancestor.parent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Finds a descendant of the instance using the given
|
||||||
|
predicate callback and a breadth-first search.
|
||||||
|
*/
|
||||||
|
pub fn find_descendant<F>(&self, predicate: F) -> Option<Instance>
|
||||||
|
where
|
||||||
|
F: Fn(&DomInstance) -> bool,
|
||||||
|
{
|
||||||
|
let dom = self
|
||||||
|
.dom
|
||||||
|
.read()
|
||||||
|
.expect("Failed to get read access to document");
|
||||||
|
|
||||||
|
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_item) = queue
|
||||||
|
.pop_front()
|
||||||
|
.and_then(|queue_ref| dom.get_by_ref(*queue_ref))
|
||||||
|
{
|
||||||
|
if predicate(queue_item) {
|
||||||
|
return Some(Self::new(&self.dom, queue_item.referent()));
|
||||||
|
} else {
|
||||||
|
queue.extend(queue_item.children())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -536,6 +701,7 @@ impl LuaUserData for Instance {
|
||||||
|
|
||||||
* Clone
|
* Clone
|
||||||
* Destroy
|
* Destroy
|
||||||
|
* ClearAllChildren
|
||||||
|
|
||||||
* FindFirstAncestor
|
* FindFirstAncestor
|
||||||
* FindFirstAncestorOfClass
|
* FindFirstAncestorOfClass
|
||||||
|
@ -543,19 +709,25 @@ impl LuaUserData for Instance {
|
||||||
* FindFirstChild
|
* FindFirstChild
|
||||||
* FindFirstChildOfClass
|
* FindFirstChildOfClass
|
||||||
* FindFirstChildWhichIsA
|
* FindFirstChildWhichIsA
|
||||||
|
* FindFirstDescendant
|
||||||
|
|
||||||
|
* GetChildren
|
||||||
|
* GetDescendants
|
||||||
|
* GetFullName
|
||||||
|
|
||||||
|
* IsA
|
||||||
* IsAncestorOf
|
* IsAncestorOf
|
||||||
* IsDescendantOf
|
* IsDescendantOf
|
||||||
|
|
||||||
Not yet implemented, but planned:
|
Not yet implemented, but planned:
|
||||||
|
|
||||||
* FindFirstDescendant
|
|
||||||
* GetChildren
|
|
||||||
* GetDescendants
|
|
||||||
* GetFullName
|
|
||||||
* GetAttribute
|
* GetAttribute
|
||||||
* GetAttributes
|
* GetAttributes
|
||||||
* SetAttribute
|
* SetAttribute
|
||||||
|
|
||||||
|
It should be noted that any methods that deal with events
|
||||||
|
and/or have functionality that affects instances other
|
||||||
|
than this instance itself are intentionally left out.
|
||||||
*/
|
*/
|
||||||
methods.add_method("Clone", |lua, this, ()| {
|
methods.add_method("Clone", |lua, this, ()| {
|
||||||
this.ensure_not_destroyed()?;
|
this.ensure_not_destroyed()?;
|
||||||
|
@ -565,6 +737,22 @@ impl LuaUserData for Instance {
|
||||||
this.destroy();
|
this.destroy();
|
||||||
Ok(())
|
Ok(())
|
||||||
});
|
});
|
||||||
|
methods.add_method_mut("ClearAllChildren", |_, this, ()| {
|
||||||
|
this.clear_all_children();
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
methods.add_method("GetChildren", |lua, this, ()| {
|
||||||
|
this.ensure_not_destroyed()?;
|
||||||
|
this.get_children().to_lua(lua)
|
||||||
|
});
|
||||||
|
methods.add_method("GetDescendants", |lua, this, ()| {
|
||||||
|
this.ensure_not_destroyed()?;
|
||||||
|
this.get_children().to_lua(lua)
|
||||||
|
});
|
||||||
|
methods.add_method("GetFullName", |lua, this, ()| {
|
||||||
|
this.ensure_not_destroyed()?;
|
||||||
|
this.get_full_name().to_lua(lua)
|
||||||
|
});
|
||||||
methods.add_method("FindFirstAncestor", |lua, this, name: String| {
|
methods.add_method("FindFirstAncestor", |lua, this, name: String| {
|
||||||
this.ensure_not_destroyed()?;
|
this.ensure_not_destroyed()?;
|
||||||
this.find_ancestor(|child| child.name == name).to_lua(lua)
|
this.find_ancestor(|child| child.name == name).to_lua(lua)
|
||||||
|
@ -599,6 +787,14 @@ impl LuaUserData for Instance {
|
||||||
this.find_child(|child| class_is_a(&child.class, &class_name).unwrap_or(false))
|
this.find_child(|child| class_is_a(&child.class, &class_name).unwrap_or(false))
|
||||||
.to_lua(lua)
|
.to_lua(lua)
|
||||||
});
|
});
|
||||||
|
methods.add_method("FindFirstDescendant", |lua, this, name: String| {
|
||||||
|
this.ensure_not_destroyed()?;
|
||||||
|
this.find_descendant(|child| child.name == name).to_lua(lua)
|
||||||
|
});
|
||||||
|
methods.add_method("IsA", |_, this, class_name: String| {
|
||||||
|
this.ensure_not_destroyed()?;
|
||||||
|
Ok(class_is_a(&this.class_name, class_name).unwrap_or(false))
|
||||||
|
});
|
||||||
methods.add_method("IsAncestorOf", |_, this, instance: Instance| {
|
methods.add_method("IsAncestorOf", |_, this, instance: Instance| {
|
||||||
this.ensure_not_destroyed()?;
|
this.ensure_not_destroyed()?;
|
||||||
Ok(instance
|
Ok(instance
|
||||||
|
|
Loading…
Reference in a new issue