mirror of
https://github.com/rojo-rbx/rojo.git
synced 2026-04-24 14:45:56 +00:00
Implement metadata, replacing source field and laying foundations
This commit is contained in:
@@ -1,10 +1,10 @@
|
|||||||
//! Defines the structure of an instance snapshot.
|
//! Defines the structure of an instance snapshot.
|
||||||
|
|
||||||
use std::{borrow::Cow, collections::HashMap, path::PathBuf};
|
use std::{borrow::Cow, collections::HashMap};
|
||||||
|
|
||||||
use rbx_dom_weak::{RbxId, RbxTree, RbxValue};
|
use rbx_dom_weak::{RbxId, RbxTree, RbxValue};
|
||||||
|
|
||||||
use crate::project::ProjectNode;
|
use super::InstanceMetadata;
|
||||||
|
|
||||||
/// A lightweight description of what an instance should look like. Attempts to
|
/// A lightweight description of what an instance should look like. Attempts to
|
||||||
/// be somewhat memory efficient by borrowing from its source data, indicated by
|
/// be somewhat memory efficient by borrowing from its source data, indicated by
|
||||||
@@ -18,14 +18,21 @@ pub struct InstanceSnapshot<'source> {
|
|||||||
/// A temporary ID applied to the snapshot that's used for Ref properties.
|
/// A temporary ID applied to the snapshot that's used for Ref properties.
|
||||||
pub snapshot_id: Option<RbxId>,
|
pub snapshot_id: Option<RbxId>,
|
||||||
|
|
||||||
/// A complete view of where this snapshot came from. It should contain
|
/// Rojo-specific metadata associated with the instance.
|
||||||
/// enough information, if not None, to recreate this snapshot
|
pub metadata: InstanceMetadata,
|
||||||
/// deterministically assuming the source has not changed state.
|
|
||||||
pub source: Option<SnapshotSource>,
|
|
||||||
|
|
||||||
|
/// Correpsonds to the Name property of the instance.
|
||||||
pub name: Cow<'source, str>,
|
pub name: Cow<'source, str>,
|
||||||
|
|
||||||
|
/// Corresponds to the ClassName property of the instance.
|
||||||
pub class_name: Cow<'source, str>,
|
pub class_name: Cow<'source, str>,
|
||||||
|
|
||||||
|
/// All other properties of the instance, weakly-typed.
|
||||||
pub properties: HashMap<String, RbxValue>,
|
pub properties: HashMap<String, RbxValue>,
|
||||||
|
|
||||||
|
/// The children of the instance represented as more snapshots.
|
||||||
|
///
|
||||||
|
/// Order is relevant for Roblox instances!
|
||||||
pub children: Vec<InstanceSnapshot<'source>>,
|
pub children: Vec<InstanceSnapshot<'source>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,7 +46,7 @@ impl<'source> InstanceSnapshot<'source> {
|
|||||||
|
|
||||||
InstanceSnapshot {
|
InstanceSnapshot {
|
||||||
snapshot_id: None,
|
snapshot_id: None,
|
||||||
source: self.source.clone(),
|
metadata: self.metadata.clone(),
|
||||||
name: Cow::Owned(self.name.clone().into_owned()),
|
name: Cow::Owned(self.name.clone().into_owned()),
|
||||||
class_name: Cow::Owned(self.class_name.clone().into_owned()),
|
class_name: Cow::Owned(self.class_name.clone().into_owned()),
|
||||||
properties: self.properties.clone(),
|
properties: self.properties.clone(),
|
||||||
@@ -61,7 +68,7 @@ impl<'source> InstanceSnapshot<'source> {
|
|||||||
|
|
||||||
InstanceSnapshot {
|
InstanceSnapshot {
|
||||||
snapshot_id: Some(id),
|
snapshot_id: Some(id),
|
||||||
source: None,
|
metadata: InstanceMetadata::default(),
|
||||||
name: Cow::Owned(instance.name.clone()),
|
name: Cow::Owned(instance.name.clone()),
|
||||||
class_name: Cow::Owned(instance.class_name.clone()),
|
class_name: Cow::Owned(instance.class_name.clone()),
|
||||||
properties: instance.properties.clone(),
|
properties: instance.properties.clone(),
|
||||||
@@ -70,14 +77,15 @@ impl<'source> InstanceSnapshot<'source> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
impl<'source> Default for InstanceSnapshot<'source> {
|
||||||
pub enum SnapshotSource {
|
fn default() -> InstanceSnapshot<'source> {
|
||||||
File {
|
InstanceSnapshot {
|
||||||
path: PathBuf,
|
snapshot_id: None,
|
||||||
},
|
metadata: InstanceMetadata::default(),
|
||||||
ProjectFile {
|
name: Cow::Borrowed("DEFAULT"),
|
||||||
path: PathBuf,
|
class_name: Cow::Borrowed("DEFAULT"),
|
||||||
name: String,
|
properties: HashMap::new(),
|
||||||
node: ProjectNode,
|
children: Vec::new(),
|
||||||
},
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
127
src/snapshot/metadata.rs
Normal file
127
src/snapshot/metadata.rs
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
use std::{collections::HashMap, path::PathBuf};
|
||||||
|
|
||||||
|
use rbx_dom_weak::{RbxId, RbxInstance, RbxInstanceProperties, RbxTree};
|
||||||
|
|
||||||
|
use crate::project::ProjectNode;
|
||||||
|
|
||||||
|
/// Rojo-specific metadata that can be associated with an instance or a snapshot
|
||||||
|
/// of an instance.
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub struct InstanceMetadata {
|
||||||
|
/// Whether instances not present in the source should be ignored when
|
||||||
|
/// live-syncing. This is useful when there are instances that Rojo does not
|
||||||
|
/// manage.
|
||||||
|
pub ignore_unknown_instances: bool,
|
||||||
|
|
||||||
|
/// A complete view of where this snapshot came from. It should contain
|
||||||
|
/// enough information, if not None, to recreate this snapshot
|
||||||
|
/// deterministically assuming the source has not changed state.
|
||||||
|
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 {
|
||||||
|
fn default() -> Self {
|
||||||
|
InstanceMetadata {
|
||||||
|
ignore_unknown_instances: false,
|
||||||
|
source: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct InstancePropertiesWithMeta {
|
||||||
|
pub inner: RbxInstanceProperties,
|
||||||
|
pub metadata: InstanceMetadata,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct InstanceWithMeta<'a> {
|
||||||
|
pub inner: &'a RbxInstance,
|
||||||
|
pub metadata: &'a InstanceMetadata,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct InstanceWithMetaMut<'a> {
|
||||||
|
pub inner: &'a mut RbxInstance,
|
||||||
|
pub metadata: &'a mut InstanceMetadata,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct TreeWithMetadata {
|
||||||
|
inner: RbxTree,
|
||||||
|
metadata: HashMap<RbxId, InstanceMetadata>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TreeWithMetadata {
|
||||||
|
pub fn new(root: InstancePropertiesWithMeta) -> TreeWithMetadata {
|
||||||
|
let inner = RbxTree::new(root.inner);
|
||||||
|
let mut metadata = HashMap::new();
|
||||||
|
metadata.insert(inner.get_root_id(), root.metadata);
|
||||||
|
|
||||||
|
TreeWithMetadata { inner, metadata }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_root_id(&self) -> RbxId {
|
||||||
|
self.inner.get_root_id()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_instance(&self, id: RbxId) -> Option<InstanceWithMeta> {
|
||||||
|
if let Some(inner) = self.inner.get_instance(id) {
|
||||||
|
let metadata = self.metadata.get(&id).unwrap();
|
||||||
|
|
||||||
|
Some(InstanceWithMeta { inner, metadata })
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_instance_mut(&mut self, id: RbxId) -> Option<InstanceWithMetaMut> {
|
||||||
|
if let Some(inner) = self.inner.get_instance_mut(id) {
|
||||||
|
let metadata = self.metadata.get_mut(&id).unwrap();
|
||||||
|
|
||||||
|
Some(InstanceWithMetaMut { inner, metadata })
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert_instance(
|
||||||
|
&mut self,
|
||||||
|
properties: InstancePropertiesWithMeta,
|
||||||
|
parent_id: RbxId,
|
||||||
|
) -> RbxId {
|
||||||
|
let id = self.inner.insert_instance(properties.inner, parent_id);
|
||||||
|
self.metadata.insert(id, properties.metadata);
|
||||||
|
id
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove_instance(&mut self, id: RbxId) -> Option<TreeWithMetadata> {
|
||||||
|
if let Some(inner) = self.inner.remove_instance(id) {
|
||||||
|
let mut metadata = HashMap::new();
|
||||||
|
|
||||||
|
let root_meta = self.metadata.remove(&id).unwrap();
|
||||||
|
metadata.insert(id, root_meta);
|
||||||
|
|
||||||
|
for instance in inner.descendants(id) {
|
||||||
|
let instance_meta = self.metadata.remove(&instance.get_id()).unwrap();
|
||||||
|
metadata.insert(instance.get_id(), instance_meta);
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(TreeWithMetadata { inner, metadata })
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,11 +19,13 @@
|
|||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
mod instance_snapshot;
|
mod instance_snapshot;
|
||||||
|
mod metadata;
|
||||||
mod patch;
|
mod patch;
|
||||||
mod patch_apply;
|
mod patch_apply;
|
||||||
mod patch_compute;
|
mod patch_compute;
|
||||||
|
|
||||||
pub use instance_snapshot::InstanceSnapshot;
|
pub use instance_snapshot::InstanceSnapshot;
|
||||||
|
pub use metadata::*;
|
||||||
pub use patch::*;
|
pub use patch::*;
|
||||||
pub use patch_apply::apply_patch_set;
|
pub use patch_apply::apply_patch_set;
|
||||||
pub use patch_compute::compute_patch_set;
|
pub use patch_compute::compute_patch_set;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use std::collections::HashMap;
|
|||||||
|
|
||||||
use rbx_dom_weak::{RbxId, RbxValue};
|
use rbx_dom_weak::{RbxId, RbxValue};
|
||||||
|
|
||||||
use super::InstanceSnapshot;
|
use super::{InstanceMetadata, InstanceSnapshot};
|
||||||
|
|
||||||
/// A set of different kinds of patches that can be applied to an RbxTree.
|
/// A set of different kinds of patches that can be applied to an RbxTree.
|
||||||
#[derive(Debug, Default, Clone, PartialEq)]
|
#[derive(Debug, Default, Clone, PartialEq)]
|
||||||
@@ -41,4 +41,7 @@ pub struct PatchUpdateInstance {
|
|||||||
/// Contains all changed properties. If a property is assigned to `None`,
|
/// Contains all changed properties. If a property is assigned to `None`,
|
||||||
/// then that property has been removed.
|
/// then that property has been removed.
|
||||||
pub changed_properties: HashMap<String, Option<RbxValue>>,
|
pub changed_properties: HashMap<String, Option<RbxValue>>,
|
||||||
|
|
||||||
|
/// Changed Rojo-specific metadata, if any of it changed.
|
||||||
|
pub changed_metadata: Option<InstanceMetadata>,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ mod test {
|
|||||||
use maplit::hashmap;
|
use maplit::hashmap;
|
||||||
use rbx_dom_weak::RbxValue;
|
use rbx_dom_weak::RbxValue;
|
||||||
|
|
||||||
use super::super::patch::PatchAddInstance;
|
use super::super::PatchAddInstance;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn add_from_empty() {
|
fn add_from_empty() {
|
||||||
@@ -159,7 +159,7 @@ mod test {
|
|||||||
|
|
||||||
let snapshot = InstanceSnapshot {
|
let snapshot = InstanceSnapshot {
|
||||||
snapshot_id: None,
|
snapshot_id: None,
|
||||||
source: None,
|
metadata: Default::default(),
|
||||||
name: Cow::Borrowed("Foo"),
|
name: Cow::Borrowed("Foo"),
|
||||||
class_name: Cow::Borrowed("Bar"),
|
class_name: Cow::Borrowed("Bar"),
|
||||||
properties: hashmap! {
|
properties: hashmap! {
|
||||||
@@ -218,6 +218,7 @@ mod test {
|
|||||||
// Baz has been added
|
// Baz has been added
|
||||||
"Baz".to_owned() => Some(RbxValue::Int32 { value: 10 }),
|
"Baz".to_owned() => Some(RbxValue::Int32 { value: 10 }),
|
||||||
},
|
},
|
||||||
|
changed_metadata: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let patch_set = PatchSet {
|
let patch_set = PatchSet {
|
||||||
|
|||||||
@@ -140,6 +140,7 @@ fn compute_property_patches(
|
|||||||
changed_name,
|
changed_name,
|
||||||
changed_class_name,
|
changed_class_name,
|
||||||
changed_properties,
|
changed_properties,
|
||||||
|
changed_metadata: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,7 +245,7 @@ mod test {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
source: None,
|
metadata: Default::default(),
|
||||||
name: Cow::Borrowed("foo"),
|
name: Cow::Borrowed("foo"),
|
||||||
class_name: Cow::Borrowed("foo"),
|
class_name: Cow::Borrowed("foo"),
|
||||||
children: Vec::new(),
|
children: Vec::new(),
|
||||||
@@ -262,6 +263,7 @@ mod test {
|
|||||||
value: Some(root_id),
|
value: Some(root_id),
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
changed_metadata: None,
|
||||||
}],
|
}],
|
||||||
added_instances: Vec::new(),
|
added_instances: Vec::new(),
|
||||||
removed_instances: Vec::new(),
|
removed_instances: Vec::new(),
|
||||||
@@ -295,13 +297,13 @@ mod test {
|
|||||||
},
|
},
|
||||||
|
|
||||||
snapshot_id: None,
|
snapshot_id: None,
|
||||||
source: None,
|
metadata: Default::default(),
|
||||||
name: Cow::Borrowed("child"),
|
name: Cow::Borrowed("child"),
|
||||||
class_name: Cow::Borrowed("child"),
|
class_name: Cow::Borrowed("child"),
|
||||||
children: Vec::new(),
|
children: Vec::new(),
|
||||||
}],
|
}],
|
||||||
|
|
||||||
source: None,
|
metadata: Default::default(),
|
||||||
properties: HashMap::new(),
|
properties: HashMap::new(),
|
||||||
name: Cow::Borrowed("foo"),
|
name: Cow::Borrowed("foo"),
|
||||||
class_name: Cow::Borrowed("foo"),
|
class_name: Cow::Borrowed("foo"),
|
||||||
@@ -314,7 +316,7 @@ mod test {
|
|||||||
parent_id: root_id,
|
parent_id: root_id,
|
||||||
instance: InstanceSnapshot {
|
instance: InstanceSnapshot {
|
||||||
snapshot_id: None,
|
snapshot_id: None,
|
||||||
source: None,
|
metadata: Default::default(),
|
||||||
properties: hashmap! {
|
properties: hashmap! {
|
||||||
"Self".to_owned() => RbxValue::Ref {
|
"Self".to_owned() => RbxValue::Ref {
|
||||||
value: Some(root_id),
|
value: Some(root_id),
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ impl SnapshotMiddleware for SnapshotCsv {
|
|||||||
|
|
||||||
Ok(Some(InstanceSnapshot {
|
Ok(Some(InstanceSnapshot {
|
||||||
snapshot_id: None,
|
snapshot_id: None,
|
||||||
source: None, // TODO
|
metadata: Default::default(), // TODO
|
||||||
name: Cow::Owned(instance_name),
|
name: Cow::Owned(instance_name),
|
||||||
class_name: Cow::Borrowed("LocalizationTable"),
|
class_name: Cow::Borrowed("LocalizationTable"),
|
||||||
properties: hashmap! {
|
properties: hashmap! {
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ impl SnapshotMiddleware for SnapshotDir {
|
|||||||
|
|
||||||
Ok(Some(InstanceSnapshot {
|
Ok(Some(InstanceSnapshot {
|
||||||
snapshot_id: None,
|
snapshot_id: None,
|
||||||
source: None, // TODO
|
metadata: Default::default(), // TODO
|
||||||
name: Cow::Owned(instance_name),
|
name: Cow::Owned(instance_name),
|
||||||
class_name: Cow::Borrowed("Folder"),
|
class_name: Cow::Borrowed("Folder"),
|
||||||
properties: HashMap::new(),
|
properties: HashMap::new(),
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ impl JsonModelCore {
|
|||||||
|
|
||||||
InstanceSnapshot {
|
InstanceSnapshot {
|
||||||
snapshot_id: None,
|
snapshot_id: None,
|
||||||
source: None, // TODO
|
metadata: Default::default(), // TODO
|
||||||
name: Cow::Owned(name),
|
name: Cow::Owned(name),
|
||||||
class_name: Cow::Owned(class_name),
|
class_name: Cow::Owned(class_name),
|
||||||
properties,
|
properties,
|
||||||
@@ -170,7 +170,7 @@ mod test {
|
|||||||
instance_snapshot,
|
instance_snapshot,
|
||||||
InstanceSnapshot {
|
InstanceSnapshot {
|
||||||
snapshot_id: None,
|
snapshot_id: None,
|
||||||
source: None, // TODO
|
metadata: Default::default(), // TODO
|
||||||
name: Cow::Borrowed("foo"),
|
name: Cow::Borrowed("foo"),
|
||||||
class_name: Cow::Borrowed("IntValue"),
|
class_name: Cow::Borrowed("IntValue"),
|
||||||
properties: hashmap! {
|
properties: hashmap! {
|
||||||
@@ -180,7 +180,7 @@ mod test {
|
|||||||
},
|
},
|
||||||
children: vec![InstanceSnapshot {
|
children: vec![InstanceSnapshot {
|
||||||
snapshot_id: None,
|
snapshot_id: None,
|
||||||
source: None, // TODO
|
metadata: Default::default(), // TODO
|
||||||
name: Cow::Borrowed("The Child"),
|
name: Cow::Borrowed("The Child"),
|
||||||
class_name: Cow::Borrowed("StringValue"),
|
class_name: Cow::Borrowed("StringValue"),
|
||||||
properties: HashMap::new(),
|
properties: HashMap::new(),
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ fn snapshot_lua_file<F: ImfsFetcher>(
|
|||||||
|
|
||||||
Ok(Some(InstanceSnapshot {
|
Ok(Some(InstanceSnapshot {
|
||||||
snapshot_id: None,
|
snapshot_id: None,
|
||||||
source: None, // TODO
|
metadata: Default::default(), // TODO
|
||||||
name: Cow::Owned(instance_name.to_owned()),
|
name: Cow::Owned(instance_name.to_owned()),
|
||||||
class_name: Cow::Borrowed(class_name),
|
class_name: Cow::Borrowed(class_name),
|
||||||
properties,
|
properties,
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ fn snapshot_project_node<F: ImfsFetcher>(
|
|||||||
|
|
||||||
Ok(Some(InstanceSnapshot {
|
Ok(Some(InstanceSnapshot {
|
||||||
snapshot_id: None,
|
snapshot_id: None,
|
||||||
source: None, // TODO
|
metadata: Default::default(), // TODO
|
||||||
name,
|
name,
|
||||||
class_name,
|
class_name,
|
||||||
properties,
|
properties,
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ impl SnapshotMiddleware for SnapshotTxt {
|
|||||||
|
|
||||||
Ok(Some(InstanceSnapshot {
|
Ok(Some(InstanceSnapshot {
|
||||||
snapshot_id: None,
|
snapshot_id: None,
|
||||||
source: None, // TODO
|
metadata: Default::default(), // TODO
|
||||||
name: Cow::Owned(instance_name),
|
name: Cow::Owned(instance_name),
|
||||||
class_name: Cow::Borrowed("StringValue"),
|
class_name: Cow::Borrowed("StringValue"),
|
||||||
properties,
|
properties,
|
||||||
|
|||||||
Reference in New Issue
Block a user