mirror of
https://github.com/rojo-rbx/rojo.git
synced 2026-04-24 22:56:02 +00:00
Document snapshot pipeline
This commit is contained in:
@@ -1,8 +1,32 @@
|
|||||||
//! This module defines the instance snapshot subsystem of Rojo.
|
//! This module defines the instance snapshot subsystem of Rojo.
|
||||||
//!
|
//!
|
||||||
//! It defines a way to define the instance tree of a project as a pure function
|
//! Snapshots define a way to define the instance tree of a project as a pure
|
||||||
//! of the filesystem by providing a lightweight instance 'snapshot' type, a
|
//! function of the filesystem by providing a lightweight instance 'snapshot'
|
||||||
//! method to generate minimal patches, and a method that applies those patches.
|
//! type, a method to generate minimal patches, and a method that applies those
|
||||||
|
//! patches.
|
||||||
|
//!
|
||||||
|
//! Changes in Rojo go through a pipeline of transformations once they hit the
|
||||||
|
//! snapshot subsystem.
|
||||||
|
//!
|
||||||
|
//! 1. Instance snapshots are generated by Rojo's snapshot middleware,
|
||||||
|
//! representing a set of instances and their metadata. These will
|
||||||
|
//! usually contain data that hasn't actually changed, and how coarsely
|
||||||
|
//! the snapshots happen is defined outside this part of the code.
|
||||||
|
//!
|
||||||
|
//! 2. Input snapshots are turned into `PatchSet` objects by Rojo's diffing
|
||||||
|
//! algorithm via `compute_patch_set`. This operation doesn't mutate the
|
||||||
|
//! instance tree, so work at this point can be thrown away.
|
||||||
|
//!
|
||||||
|
//! `PatchSet` prescribe what changes need to be applied to the current
|
||||||
|
//! tree to get the next tree. It isn't useful for describing those
|
||||||
|
//! changes after the fact, since Rojo needs to assign IDs to created
|
||||||
|
//! instances, which happens during patch application, not generation!
|
||||||
|
//!
|
||||||
|
//! 3. Patch sets are applied to the tree with `apply_patch_set`, which
|
||||||
|
//! mutates the relevant instances. `apply_patch_set` returns a new
|
||||||
|
//! object, `AppliedPatchSet`. Applied patch sets describe the transform
|
||||||
|
//! that was applied, and are suitable for cases where another tree needs
|
||||||
|
//! to be synchronized with Rojo's, like the Rojo Studio plugin.
|
||||||
//!
|
//!
|
||||||
//! The aim with this approach is to reduce the number of bugs that arise from
|
//! The aim with this approach is to reduce the number of bugs that arise from
|
||||||
//! attempting to manually update instances in response to filesystem updates.
|
//! attempting to manually update instances in response to filesystem updates.
|
||||||
@@ -26,7 +50,7 @@ mod patch_compute;
|
|||||||
mod tree;
|
mod tree;
|
||||||
|
|
||||||
pub use instance_snapshot::InstanceSnapshot;
|
pub use instance_snapshot::InstanceSnapshot;
|
||||||
pub use metadata::*;
|
pub use metadata::InstanceMetadata;
|
||||||
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;
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ pub struct PatchUpdate {
|
|||||||
///
|
///
|
||||||
// TODO: Introduce machinery to detect conflicts, like keeping previous +
|
// TODO: Introduce machinery to detect conflicts, like keeping previous +
|
||||||
// current values in all fields.
|
// current values in all fields.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Default)]
|
||||||
pub struct AppliedPatchSet {
|
pub struct AppliedPatchSet {
|
||||||
pub removed: Vec<RbxId>,
|
pub removed: Vec<RbxId>,
|
||||||
pub added: Vec<AppliedPatchAdd>,
|
pub added: Vec<AppliedPatchAdd>,
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ pub fn apply_patch_set(tree: &mut RojoTree, patch_set: PatchSet) -> AppliedPatch
|
|||||||
let mut context = PatchApplyContext::default();
|
let mut context = PatchApplyContext::default();
|
||||||
|
|
||||||
for removed_id in patch_set.removed_instances {
|
for removed_id in patch_set.removed_instances {
|
||||||
tree.remove_instance(removed_id);
|
apply_remove_instance(&mut context, tree, removed_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
for add_patch in patch_set.added_instances {
|
for add_patch in patch_set.added_instances {
|
||||||
@@ -21,22 +21,21 @@ pub fn apply_patch_set(tree: &mut RojoTree, patch_set: PatchSet) -> AppliedPatch
|
|||||||
}
|
}
|
||||||
|
|
||||||
for update_patch in patch_set.updated_instances {
|
for update_patch in patch_set.updated_instances {
|
||||||
apply_update_child(&context, tree, update_patch);
|
apply_update_child(&mut context, tree, update_patch);
|
||||||
}
|
}
|
||||||
|
|
||||||
apply_deferred_properties(context, tree);
|
finalize_patch_application(context, tree)
|
||||||
|
|
||||||
// TODO: Actually calculate patch set
|
|
||||||
AppliedPatchSet::new()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct PatchApplyContext {
|
struct PatchApplyContext {
|
||||||
snapshot_id_to_instance_id: HashMap<RbxId, RbxId>,
|
snapshot_id_to_instance_id: HashMap<RbxId, RbxId>,
|
||||||
properties_to_apply: HashMap<RbxId, HashMap<String, RbxValue>>,
|
properties_to_apply: HashMap<RbxId, HashMap<String, RbxValue>>,
|
||||||
|
applied_patch_set: AppliedPatchSet,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Apply properties that were deferred in order to get more information.
|
/// Finalize this patch application, consuming the context, applying any
|
||||||
|
/// deferred property updates, and returning the finally applied patch set.
|
||||||
///
|
///
|
||||||
/// Ref properties from snapshots refer to eachother via snapshot ID. Some of
|
/// Ref properties from snapshots refer to eachother via snapshot ID. Some of
|
||||||
/// these properties are transformed when the patch is computed, notably the
|
/// these properties are transformed when the patch is computed, notably the
|
||||||
@@ -45,7 +44,7 @@ struct PatchApplyContext {
|
|||||||
/// The remaining Ref properties need to be handled during patch application,
|
/// The remaining Ref properties need to be handled during patch application,
|
||||||
/// where we build up a map of snapshot IDs to instance IDs as they're created,
|
/// where we build up a map of snapshot IDs to instance IDs as they're created,
|
||||||
/// then apply properties all at once at the end.
|
/// then apply properties all at once at the end.
|
||||||
fn apply_deferred_properties(context: PatchApplyContext, tree: &mut RojoTree) {
|
fn finalize_patch_application(context: PatchApplyContext, tree: &mut RojoTree) -> AppliedPatchSet {
|
||||||
for (id, mut properties) in context.properties_to_apply {
|
for (id, mut properties) in context.properties_to_apply {
|
||||||
let mut instance = tree
|
let mut instance = tree
|
||||||
.get_instance_mut(id)
|
.get_instance_mut(id)
|
||||||
@@ -63,6 +62,20 @@ fn apply_deferred_properties(context: PatchApplyContext, tree: &mut RojoTree) {
|
|||||||
|
|
||||||
*instance.properties_mut() = properties;
|
*instance.properties_mut() = properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
context.applied_patch_set
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_remove_instance(context: &mut PatchApplyContext, tree: &mut RojoTree, removed_id: RbxId) {
|
||||||
|
match tree.remove_instance(removed_id) {
|
||||||
|
Some(_) => context.applied_patch_set.removed.push(removed_id),
|
||||||
|
None => {
|
||||||
|
log::warn!(
|
||||||
|
"Patch application error: Tried to remove instance {} but it did not exist.",
|
||||||
|
removed_id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_add_child(
|
fn apply_add_child(
|
||||||
@@ -98,7 +111,7 @@ fn apply_add_child(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_update_child(context: &PatchApplyContext, tree: &mut RojoTree, patch: PatchUpdate) {
|
fn apply_update_child(context: &mut PatchApplyContext, tree: &mut RojoTree, patch: PatchUpdate) {
|
||||||
if let Some(metadata) = patch.changed_metadata {
|
if let Some(metadata) = patch.changed_metadata {
|
||||||
tree.update_metadata(patch.id, metadata);
|
tree.update_metadata(patch.id, metadata);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user