Snapshot madness

This commit is contained in:
Lucien Greathouse
2018-12-11 23:30:53 -08:00
parent dbd499701f
commit ee0a5cada3
2 changed files with 95 additions and 116 deletions

View File

@@ -1,17 +1,19 @@
use std::{ use std::{
borrow::Cow,
collections::HashMap, collections::HashMap,
path::Path, path::Path,
sync::{Arc, Mutex}, sync::{Arc, Mutex},
str, str,
}; };
use rbx_tree::{RbxTree, RbxId, RbxInstance, RbxValue}; use rbx_tree::{RbxTree, RbxId};
use crate::{ use crate::{
project::{Project, ProjectNode, InstanceProjectNode}, project::{Project, ProjectNode, InstanceProjectNode},
message_queue::{Message, MessageQueue}, message_queue::{Message, MessageQueue},
imfs::{Imfs, ImfsItem, ImfsFile}, imfs::{Imfs, ImfsItem, ImfsFile},
path_map::PathMap, path_map::PathMap,
rbx_snapshot::{RbxSnapshotInstance, RbxSnapshotValue, reify_root},
}; };
pub struct RbxSession { pub struct RbxSession {
@@ -25,11 +27,15 @@ pub struct RbxSession {
impl RbxSession { impl RbxSession {
pub fn new(project: Arc<Project>, imfs: Arc<Mutex<Imfs>>, message_queue: Arc<MessageQueue>) -> RbxSession { pub fn new(project: Arc<Project>, imfs: Arc<Mutex<Imfs>>, message_queue: Arc<MessageQueue>) -> RbxSession {
let (tree, path_id_tree, ids_to_project_paths) = { let tree = {
let temp_imfs = imfs.lock().unwrap(); let temp_imfs = imfs.lock().unwrap();
construct_initial_tree(&project, &temp_imfs) construct_initial_tree(&project, &temp_imfs)
}; };
// TODO: Restore these?
let path_id_tree = PathMap::new();
let ids_to_project_paths = HashMap::new();
RbxSession { RbxSession {
tree, tree,
path_id_tree, path_id_tree,
@@ -113,11 +119,10 @@ impl RbxSession {
} }
pub fn construct_oneoff_tree(project: &Project, imfs: &Imfs) -> RbxTree { pub fn construct_oneoff_tree(project: &Project, imfs: &Imfs) -> RbxTree {
construct_initial_tree(project, imfs).0 construct_initial_tree(project, imfs)
} }
struct ConstructContext<'a> { struct ConstructContext<'a> {
tree: Option<RbxTree>,
imfs: &'a Imfs, imfs: &'a Imfs,
path_id_tree: PathMap<RbxId>, path_id_tree: PathMap<RbxId>,
ids_to_project_paths: HashMap<RbxId, String>, ids_to_project_paths: HashMap<RbxId, String>,
@@ -126,78 +131,49 @@ struct ConstructContext<'a> {
fn construct_initial_tree( fn construct_initial_tree(
project: &Project, project: &Project,
imfs: &Imfs, imfs: &Imfs,
) -> (RbxTree, PathMap<RbxId>, HashMap<RbxId, String>) { ) -> RbxTree {
let path_id_tree = PathMap::new(); let path_id_tree = PathMap::new();
let ids_to_project_paths = HashMap::new(); let ids_to_project_paths = HashMap::new();
let mut context = ConstructContext { let mut context = ConstructContext {
tree: None,
imfs, imfs,
path_id_tree, path_id_tree,
ids_to_project_paths, ids_to_project_paths,
}; };
construct_project_node( let snapshot = construct_project_node(
&mut context, &mut context,
None,
"", "",
&project.name, &project.name,
&project.tree, &project.tree,
); );
let tree = context.tree.unwrap(); reify_root(&snapshot)
(tree, context.path_id_tree, context.ids_to_project_paths)
} }
fn insert_or_create_tree(context: &mut ConstructContext, parent_instance_id: Option<RbxId>, instance: RbxInstance) -> RbxId { fn construct_project_node<'a>(
match (&mut context.tree, parent_instance_id) { context: &mut ConstructContext<'a>,
(Some(tree), Some(parent_instance_id)) => {
tree.insert_instance(instance, parent_instance_id)
},
_ => {
let new_tree = RbxTree::new(instance);
let root_id = new_tree.get_root_id();
context.tree = Some(new_tree);
root_id
},
}
}
fn construct_project_node(
context: &mut ConstructContext,
parent_instance_id: Option<RbxId>,
instance_path: &str, instance_path: &str,
instance_name: &str, instance_name: &'a str,
project_node: &ProjectNode, project_node: &'a ProjectNode,
) { ) -> RbxSnapshotInstance<'a> {
match project_node { match project_node {
ProjectNode::Instance(node) => { ProjectNode::Instance(node) => {
let id = construct_instance_node(context, parent_instance_id, &instance_path, instance_name, node); construct_instance_node(context, &instance_path, instance_name, node)
context.ids_to_project_paths.insert(id, instance_path.to_string());
}, },
ProjectNode::SyncPoint(node) => { ProjectNode::SyncPoint(node) => {
let id = construct_sync_point_node(context, parent_instance_id, instance_name, &node.path); construct_sync_point_node(context, instance_name, &node.path)
context.ids_to_project_paths.insert(id, instance_path.to_string());
}, },
} }
} }
fn construct_instance_node( fn construct_instance_node<'a>(
context: &mut ConstructContext, context: &mut ConstructContext<'a>,
parent_instance_id: Option<RbxId>,
instance_path: &str, instance_path: &str,
instance_name: &str, instance_name: &'a str,
project_node: &InstanceProjectNode, project_node: &'a InstanceProjectNode,
) -> RbxId { ) -> RbxSnapshotInstance<'a> {
let instance = RbxInstance { let mut children = Vec::new();
class_name: project_node.class_name.clone(),
name: instance_name.to_string(),
properties: HashMap::new(),
};
let id = insert_or_create_tree(context, parent_instance_id, instance);
for (child_name, child_project_node) in &project_node.children { for (child_name, child_project_node) in &project_node.children {
let child_path = if instance_path.is_empty() { let child_path = if instance_path.is_empty() {
@@ -206,10 +182,15 @@ fn construct_instance_node(
format!("{}/{}", instance_path, child_name) format!("{}/{}", instance_path, child_name)
}; };
construct_project_node(context, Some(id), &child_path, child_name, child_project_node); children.push(construct_project_node(context, &child_path, child_name, child_project_node));
} }
id RbxSnapshotInstance {
class_name: Cow::Borrowed(&project_node.class_name),
name: Cow::Borrowed(instance_name),
properties: HashMap::new(),
children,
}
} }
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
@@ -233,12 +214,11 @@ fn classify_file(file: &ImfsFile) -> Option<FileType> {
} }
} }
fn construct_sync_point_node( fn construct_sync_point_node<'a>(
context: &mut ConstructContext, context: &mut ConstructContext<'a>,
parent_instance_id: Option<RbxId>, instance_name: &'a str,
instance_name: &str,
file_path: &Path, file_path: &Path,
) -> RbxId { ) -> RbxSnapshotInstance<'a> {
match context.imfs.get(&file_path) { match context.imfs.get(&file_path) {
Some(ImfsItem::File(file)) => { Some(ImfsItem::File(file)) => {
let file_type = classify_file(file).unwrap(); // TODO: Don't die here! let file_type = classify_file(file).unwrap(); // TODO: Don't die here!
@@ -252,35 +232,29 @@ fn construct_sync_point_node(
let contents = str::from_utf8(&file.contents).unwrap(); let contents = str::from_utf8(&file.contents).unwrap();
let mut properties = HashMap::new(); let mut properties = HashMap::new();
properties.insert("Source".to_string(), RbxValue::String { value: contents.to_string() }); properties.insert("Source".to_string(), RbxSnapshotValue::String(Cow::Borrowed(contents)));
let instance = RbxInstance { let instance = RbxSnapshotInstance {
class_name: class_name.to_string(), class_name: Cow::Borrowed(class_name),
name: instance_name.to_string(), name: Cow::Borrowed(instance_name),
properties, properties,
children: Vec::new(),
}; };
let id = insert_or_create_tree(context, parent_instance_id, instance); instance
context.path_id_tree.insert(file.path.clone(), id);
id
}, },
Some(ImfsItem::Directory(directory)) => { Some(ImfsItem::Directory(directory)) => {
let init_path = directory.path.join("init.lua"); let init_path = directory.path.join("init.lua");
let id = if directory.children.contains(&init_path) { let mut instance = if directory.children.contains(&init_path) {
construct_sync_point_node(context, parent_instance_id, instance_name, &init_path) construct_sync_point_node(context, instance_name, &init_path)
} else { } else {
let instance = RbxInstance { RbxSnapshotInstance {
class_name: "Folder".to_string(), class_name: Cow::Borrowed("Folder"),
name: instance_name.to_string(), name: Cow::Borrowed(instance_name),
properties: HashMap::new(), properties: HashMap::new(),
}; children: Vec::new(),
}
let id = insert_or_create_tree(context, parent_instance_id, instance);
context.path_id_tree.insert(directory.path.clone(), id);
id
}; };
for child_path in &directory.children { for child_path in &directory.children {
@@ -290,11 +264,11 @@ fn construct_sync_point_node(
ImfsItem::Directory(_) => child_path.file_name().unwrap().to_str().unwrap(), ImfsItem::Directory(_) => child_path.file_name().unwrap().to_str().unwrap(),
}; };
construct_sync_point_node(context, Some(id), child_instance_name, child_path); instance.children.push(construct_sync_point_node(context, child_instance_name, child_path));
} }
} }
id instance
}, },
None => panic!("Couldn't read {} from disk", file_path.display()), None => panic!("Couldn't read {} from disk", file_path.display()),
} }

View File

@@ -4,57 +4,62 @@ use std::{
collections::HashMap, collections::HashMap,
}; };
use rbx_tree::{RbxTree, RbxId}; use rbx_tree::{RbxTree, RbxId, RbxInstance, RbxValue};
use crate::{
imfs::{Imfs, ImfsItem, ImfsFile, ImfsDirectory},
};
pub struct RbxSnapshotInstance<'a> { pub struct RbxSnapshotInstance<'a> {
name: String, pub name: Cow<'a, str>,
class_name: String, pub class_name: Cow<'a, str>,
properties: HashMap<String, RbxSnapshotValue<'a>>, pub properties: HashMap<String, RbxSnapshotValue<'a>>,
children: Vec<RbxSnapshotInstance<'a>>, pub children: Vec<RbxSnapshotInstance<'a>>,
} }
pub enum RbxSnapshotValue<'a> { pub enum RbxSnapshotValue<'a> {
String(Cow<'a, str>), String(Cow<'a, str>),
} }
pub fn reify(snapshot: RbxSnapshotInstance, tree: &mut RbxTree, parent_id: RbxId) { impl<'a> RbxSnapshotValue<'a> {
unimplemented!() pub fn to_rbx_value(&self) -> RbxValue {
} match self {
RbxSnapshotValue::String(value) => RbxValue::String {
pub fn render<'a>(imfs: &'a Imfs, imfs_item: &'a ImfsItem) -> RbxSnapshotInstance<'a> { value: value.to_string(),
match imfs_item { },
ImfsItem::File(file) => { }
let name = file.path.file_stem().unwrap().to_str().unwrap(); }
let source = str::from_utf8(&file.contents).unwrap(); }
let mut properties = HashMap::new();
properties.insert("Source".to_string(), RbxSnapshotValue::String(Cow::Borrowed(source))); fn reify_core(snapshot: &RbxSnapshotInstance) -> RbxInstance {
let mut properties = HashMap::new();
RbxSnapshotInstance {
name: name.to_string(), for (key, value) in &snapshot.properties {
class_name: "ModuleScript".to_string(), properties.insert(key.clone(), value.to_rbx_value());
properties, }
children: Vec::new(),
} let instance = RbxInstance {
}, name: snapshot.name.to_string(),
ImfsItem::Directory(directory) => { class_name: snapshot.class_name.to_string(),
let name = directory.path.file_name().unwrap().to_str().unwrap(); properties,
let mut children = Vec::new(); };
for child_path in &directory.children { instance
let child_item = imfs.get(child_path).unwrap(); }
children.push(render(imfs, child_item));
} pub fn reify_root(snapshot: &RbxSnapshotInstance) -> RbxTree {
let instance = reify_core(snapshot);
RbxSnapshotInstance { let mut tree = RbxTree::new(instance);
name: name.to_string(), let root_id = tree.get_root_id();
class_name: "Folder".to_string(),
properties: HashMap::new(), for child in &snapshot.children {
children, reify_child(child, &mut tree, root_id);
} }
},
tree
}
fn reify_child(snapshot: &RbxSnapshotInstance, tree: &mut RbxTree, parent_id: RbxId) {
let instance = reify_core(snapshot);
let id = tree.insert_instance(instance, parent_id);
for child in &snapshot.children {
reify_child(child, tree, id);
} }
} }