Start using multimap correctly for path tracking in RojoTree

This commit is contained in:
Lucien Greathouse
2019-09-09 11:50:58 -07:00
parent 8dbc6ab7d3
commit 618185a52d
4 changed files with 57 additions and 42 deletions

View File

@@ -14,8 +14,8 @@ pub mod project;
mod auth_cookie; mod auth_cookie;
mod imfs; mod imfs;
mod mapset;
mod message_queue; mod message_queue;
mod multimap;
mod path_map; mod path_map;
mod path_serializer; mod path_serializer;
mod serve_session; mod serve_session;

View File

@@ -7,14 +7,14 @@ use std::{
/// A map whose value contains a set of multiple values. /// A map whose value contains a set of multiple values.
#[derive(Clone)] #[derive(Clone)]
pub struct MapSet<K, V> { pub struct MultiMap<K, V> {
inner: HashMap<K, Vec<V>>, inner: HashMap<K, Vec<V>>,
} }
#[allow(dead_code)] // This is a core library-ish struct, unused stuff is ok #[allow(dead_code)] // This is a core library-ish struct, unused stuff is ok
impl<K: Hash + Eq, V: Eq> MapSet<K, V> { impl<K: Hash + Eq, V: Eq> MultiMap<K, V> {
pub fn new() -> Self { pub fn new() -> Self {
MapSet { MultiMap {
inner: HashMap::new(), inner: HashMap::new(),
} }
} }
@@ -56,13 +56,13 @@ impl<K: Hash + Eq, V: Eq> MapSet<K, V> {
} }
} }
impl<K: Debug + Hash + Eq, V: Debug + Eq> Debug for MapSet<K, V> { impl<K: Debug + Hash + Eq, V: Debug + Eq> Debug for MultiMap<K, V> {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
self.inner.fmt(formatter) self.inner.fmt(formatter)
} }
} }
impl<K: Hash + Eq, V: Eq> PartialEq for MapSet<K, V> { impl<K: Hash + Eq, V: Eq> PartialEq for MultiMap<K, V> {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
self.inner == other.inner self.inner == other.inner
} }

View File

@@ -17,18 +17,6 @@ pub struct InstanceMetadata {
pub source: Option<InstanceSource>, pub source: Option<InstanceSource>,
} }
#[derive(Debug, Clone, PartialEq)]
pub enum InstanceSource {
File {
path: PathBuf,
},
ProjectFile {
path: PathBuf,
name: String,
node: ProjectNode,
},
}
impl Default for InstanceMetadata { impl Default for InstanceMetadata {
fn default() -> Self { fn default() -> Self {
InstanceMetadata { InstanceMetadata {
@@ -37,3 +25,9 @@ impl Default for InstanceMetadata {
} }
} }
} }
#[derive(Debug, Clone, PartialEq)]
pub struct InstanceSource {
pub path: PathBuf,
pub project_node: Option<(String, ProjectNode)>,
}

View File

@@ -2,7 +2,7 @@ use std::{collections::HashMap, path::PathBuf};
use rbx_dom_weak::{RbxId, RbxInstance, RbxInstanceProperties, RbxTree}; use rbx_dom_weak::{RbxId, RbxInstance, RbxInstanceProperties, RbxTree};
use crate::mapset::MapSet; use crate::multimap::MultiMap;
use super::InstanceMetadata; use super::InstanceMetadata;
@@ -17,7 +17,7 @@ pub struct RojoTree {
/// Metadata associated with each instance that is kept up-to-date with the /// Metadata associated with each instance that is kept up-to-date with the
/// set of actual instances. /// set of actual instances.
metadata: HashMap<RbxId, InstanceMetadata>, metadata_map: HashMap<RbxId, InstanceMetadata>,
/// A multimap from source paths to all of the root instances that were /// A multimap from source paths to all of the root instances that were
/// constructed from that path. /// constructed from that path.
@@ -26,20 +26,19 @@ pub struct RojoTree {
/// value portion of the map is also a set in order to support the same path /// value portion of the map is also a set in order to support the same path
/// appearing multiple times in the same Rojo project. This is sometimes /// appearing multiple times in the same Rojo project. This is sometimes
/// called "path aliasing" in various Rojo documentation. /// called "path aliasing" in various Rojo documentation.
path_to_id: MapSet<PathBuf, RbxId>, path_to_ids: MultiMap<PathBuf, RbxId>,
} }
impl RojoTree { impl RojoTree {
pub fn new(root: InstancePropertiesWithMeta) -> RojoTree { pub fn new(root: InstancePropertiesWithMeta) -> RojoTree {
let inner = RbxTree::new(root.inner); let mut tree = RojoTree {
let mut metadata = HashMap::new(); inner: RbxTree::new(root.inner),
metadata.insert(inner.get_root_id(), root.metadata); metadata_map: HashMap::new(),
path_to_ids: MultiMap::new(),
};
RojoTree { tree.insert_metadata(tree.inner.get_root_id(), root.metadata);
inner, tree
metadata,
path_to_id: MapSet::new(),
}
} }
pub fn get_root_id(&self) -> RbxId { pub fn get_root_id(&self) -> RbxId {
@@ -48,7 +47,7 @@ impl RojoTree {
pub fn get_instance(&self, id: RbxId) -> Option<InstanceWithMeta> { pub fn get_instance(&self, id: RbxId) -> Option<InstanceWithMeta> {
if let Some(inner) = self.inner.get_instance(id) { if let Some(inner) = self.inner.get_instance(id) {
let metadata = self.metadata.get(&id).unwrap(); let metadata = self.metadata_map.get(&id).unwrap();
Some(InstanceWithMeta { inner, metadata }) Some(InstanceWithMeta { inner, metadata })
} else { } else {
@@ -58,7 +57,7 @@ impl RojoTree {
pub fn get_instance_mut(&mut self, id: RbxId) -> Option<InstanceWithMetaMut> { pub fn get_instance_mut(&mut self, id: RbxId) -> Option<InstanceWithMetaMut> {
if let Some(inner) = self.inner.get_instance_mut(id) { if let Some(inner) = self.inner.get_instance_mut(id) {
let metadata = self.metadata.get_mut(&id).unwrap(); let metadata = self.metadata_map.get_mut(&id).unwrap();
Some(InstanceWithMetaMut { inner, metadata }) Some(InstanceWithMetaMut { inner, metadata })
} else { } else {
@@ -72,33 +71,55 @@ impl RojoTree {
parent_id: RbxId, parent_id: RbxId,
) -> RbxId { ) -> RbxId {
let id = self.inner.insert_instance(properties.inner, parent_id); let id = self.inner.insert_instance(properties.inner, parent_id);
self.metadata.insert(id, properties.metadata); self.insert_metadata(id, properties.metadata);
id id
} }
pub fn remove_instance(&mut self, id: RbxId) -> Option<RojoTree> { pub fn remove_instance(&mut self, id: RbxId) -> Option<RojoTree> {
if let Some(inner) = self.inner.remove_instance(id) { if let Some(inner) = self.inner.remove_instance(id) {
let mut metadata = HashMap::new(); let mut metadata_map = HashMap::new();
let mut path_to_id = MapSet::new(); // TODO let mut path_to_ids = MultiMap::new();
let root_meta = self.metadata.remove(&id).unwrap();
metadata.insert(id, root_meta);
self.move_metadata(id, &mut metadata_map, &mut path_to_ids);
for instance in inner.descendants(id) { for instance in inner.descendants(id) {
let instance_meta = self.metadata.remove(&instance.get_id()).unwrap(); self.move_metadata(instance.get_id(), &mut metadata_map, &mut path_to_ids);
metadata.insert(instance.get_id(), instance_meta);
} }
Some(RojoTree { Some(RojoTree {
inner, inner,
metadata, metadata_map,
path_to_id, path_to_ids,
}) })
} else { } else {
None None
} }
} }
fn insert_metadata(&mut self, id: RbxId, metadata: InstanceMetadata) {
if let Some(source) = &metadata.source {
self.path_to_ids.insert(source.path.clone(), id);
}
self.metadata_map.insert(id, metadata);
}
/// Moves the Rojo metadata from the instance with the given ID from this
/// tree into some loose maps.
fn move_metadata(
&mut self,
id: RbxId,
metadata_map: &mut HashMap<RbxId, InstanceMetadata>,
path_to_ids: &mut MultiMap<PathBuf, RbxId>,
) {
let metadata = self.metadata_map.remove(&id).unwrap();
if let Some(source) = &metadata.source {
self.path_to_ids.remove(&source.path, id);
path_to_ids.insert(source.path.clone(), id);
}
metadata_map.insert(id, metadata);
}
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]