From ee108e414fbf15dafc97475e05645016972486c4 Mon Sep 17 00:00:00 2001 From: Lucien Greathouse Date: Thu, 31 May 2018 00:24:27 -0700 Subject: [PATCH] Track both parent and children on instances --- server/src/rbx.rs | 2 + server/src/rbx_session.rs | 128 ++++++++++++++++++++++++++++++++------ server/src/web.rs | 2 +- 3 files changed, 112 insertions(+), 20 deletions(-) diff --git a/server/src/rbx.rs b/server/src/rbx.rs index 0eb7361a..2db2cf39 100644 --- a/server/src/rbx.rs +++ b/server/src/rbx.rs @@ -19,4 +19,6 @@ pub struct RbxInstance { /// All of the children of this instance. Order is relevant to preserve! pub children: Vec, + + pub parent: Option, } diff --git a/server/src/rbx_session.rs b/server/src/rbx_session.rs index 7af72cb1..93186158 100644 --- a/server/src/rbx_session.rs +++ b/server/src/rbx_session.rs @@ -9,6 +9,12 @@ use session::SessionConfig; use vfs_session::{VfsSession, FileItem, FileChange}; use message_session::{Message, MessageSession}; +fn insert_if_missing(vec: &mut Vec, value: T) { + if !vec.contains(&value) { + vec.push(value); + } +} + // TODO: Rethink data structure and insertion/update behavior. Maybe break some // pieces off into a new object? fn file_to_instances( @@ -16,6 +22,7 @@ fn file_to_instances( partition: &Partition, output: &mut HashMap, instances_by_route: &mut HashMap, + parent_id: Option, ) -> (Id, Vec) { match file_item { FileItem::File { contents, route } => { @@ -37,6 +44,7 @@ fn file_to_instances( class_name: "StringValue".to_string(), properties, children: Vec::new(), + parent: parent_id, }); (primary_id, vec![primary_id]) @@ -57,7 +65,7 @@ fn file_to_instances( let mut changed_ids = vec![primary_id]; for child_file_item in children.values() { - let (child_id, mut child_changed_ids) = file_to_instances(child_file_item, partition, output, instances_by_route); + let (child_id, mut child_changed_ids) = file_to_instances(child_file_item, partition, output, instances_by_route, Some(primary_id)); child_ids.push(child_id); changed_ids.push(child_id); @@ -73,6 +81,7 @@ fn file_to_instances( class_name: "Folder".to_string(), properties: HashMap::new(), children: child_ids, + parent: parent_id, }); (primary_id, changed_ids) @@ -110,16 +119,56 @@ impl RbxSession { } } - pub fn retrieve_instance<'a, 'b>(&'a self, id: Id, output: &'b mut HashMap) { - let requested_instance = match self.instances.get(&id) { - Some(instance) => instance, - None => return, - }; + pub fn delete_instance(&mut self, id: Id) -> Vec { + let mut ids_to_visit = vec![id]; + let mut ids_deleted = Vec::new(); - output.insert(id, requested_instance); + for instance in self.instances.values_mut() { + match instance.children.iter().position(|&v| v == id) { + Some(index) => { + instance.children.remove(index); + }, + None => {}, + } + } - for child_id in &requested_instance.children { - self.retrieve_instance(*child_id, output); + loop { + let id = match ids_to_visit.pop() { + Some(id) => id, + None => break, + }; + + match self.instances.get(&id) { + Some(instance) => ids_to_visit.extend_from_slice(&instance.children), + None => continue, + } + + self.instances.remove(&id); + ids_deleted.push(id); + } + + ids_deleted + } + + pub fn get_instance<'a, 'b>(&'a self, id: Id, output: &'b mut HashMap) { + let mut ids_to_visit = vec![id]; + + loop { + let id = match ids_to_visit.pop() { + Some(id) => id, + None => break, + }; + + match self.instances.get(&id) { + Some(instance) => { + output.insert(id, instance); + + for child_id in &instance.children { + ids_to_visit.push(*child_id); + } + }, + None => continue, + } } } @@ -133,7 +182,21 @@ impl RbxSession { route: Vec::new(), }; let file_item = vfs_session.get_by_route(&route).unwrap(); - let (root_id, _) = file_to_instances(file_item, partition, &mut self.instances, &mut self.instances_by_route); + + let parent_id = match route.parent() { + Some(parent_route) => match self.instances_by_route.get(&parent_route) { + Some(&parent_id) => Some(parent_id), + None => None, + }, + None => None, + }; + + let (root_id, _) = file_to_instances(file_item, partition, &mut self.instances, &mut self.instances_by_route, parent_id); + + if let Some(parent_id) = parent_id { + insert_if_missing(&mut self.instances.get_mut(&parent_id).unwrap().children, root_id); + } + self.partition_instances.insert(partition.name.clone(), root_id); } } @@ -146,7 +209,20 @@ impl RbxSession { FileChange::Created(route) | FileChange::Updated(route) => { let file_item = vfs_session.get_by_route(route).unwrap(); let partition = self.config.partitions.get(&route.partition).unwrap(); - let (_, changed_ids) = file_to_instances(file_item, partition, &mut self.instances, &mut self.instances_by_route); + + let parent_id = match route.parent() { + Some(parent_route) => match self.instances_by_route.get(&parent_route) { + Some(&parent_id) => Some(parent_id), + None => None, + }, + None => None, + }; + + let (root_id, changed_ids) = file_to_instances(file_item, partition, &mut self.instances, &mut self.instances_by_route, parent_id); + + if let Some(parent_id) = parent_id { + insert_if_missing(&mut self.instances.get_mut(&parent_id).unwrap().children, root_id); + } let messages = changed_ids .iter() @@ -156,11 +232,11 @@ impl RbxSession { self.message_session.push_messages(&messages); }, FileChange::Deleted(route) => { - // TODO: Handle deletion of children here and in Moved case. match self.instances_by_route.get(route) { - Some(id) => { - self.instances.remove(id); - self.message_session.push_messages(&[Message::InstanceChanged { id: *id }]); + Some(&id) => { + self.delete_instance(id); + self.instances_by_route.remove(route); + self.message_session.push_messages(&[Message::InstanceChanged { id }]); }, None => (), } @@ -169,16 +245,30 @@ impl RbxSession { let mut messages = Vec::new(); match self.instances_by_route.get(from_route) { - Some(id) => { - self.instances.remove(id); - messages.push(Message::InstanceChanged { id: *id }); + Some(&id) => { + self.delete_instance(id); + self.instances_by_route.remove(from_route); + messages.push(Message::InstanceChanged { id }); }, None => (), } let file_item = vfs_session.get_by_route(to_route).unwrap(); let partition = self.config.partitions.get(&to_route.partition).unwrap(); - let (_, changed_ids) = file_to_instances(file_item, partition, &mut self.instances, &mut self.instances_by_route); + + let parent_id = match to_route.parent() { + Some(parent_route) => match self.instances_by_route.get(&parent_route) { + Some(&parent_id) => Some(parent_id), + None => None, + }, + None => None, + }; + + let (root_id, changed_ids) = file_to_instances(file_item, partition, &mut self.instances, &mut self.instances_by_route, parent_id); + + if let Some(parent_id) = parent_id { + insert_if_missing(&mut self.instances.get_mut(&parent_id).unwrap().children, root_id); + } for id in changed_ids { messages.push(Message::InstanceChanged { id }); diff --git a/server/src/web.rs b/server/src/web.rs index dd8df80c..4c70fe68 100644 --- a/server/src/web.rs +++ b/server/src/web.rs @@ -162,7 +162,7 @@ pub fn start(config: WebConfig) { let mut instances = HashMap::new(); for requested_id in &requested_ids { - rbx_session.retrieve_instance(*requested_id, &mut instances); + rbx_session.get_instance(*requested_id, &mut instances); } Response::json(&ReadResponse {