diff --git a/src/snapshot/mod.rs b/src/snapshot/mod.rs index 08cb6b31..47ef4794 100644 --- a/src/snapshot/mod.rs +++ b/src/snapshot/mod.rs @@ -1,8 +1,32 @@ //! 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 -//! of the filesystem by providing a lightweight instance 'snapshot' type, a -//! method to generate minimal patches, and a method that applies those patches. +//! Snapshots define a way to define the instance tree of a project as a pure +//! function of the filesystem by providing a lightweight instance 'snapshot' +//! 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 //! attempting to manually update instances in response to filesystem updates. @@ -26,7 +50,7 @@ mod patch_compute; mod tree; pub use instance_snapshot::InstanceSnapshot; -pub use metadata::*; +pub use metadata::InstanceMetadata; pub use patch::*; pub use patch_apply::apply_patch_set; pub use patch_compute::compute_patch_set; diff --git a/src/snapshot/patch.rs b/src/snapshot/patch.rs index ca77df7c..7833a677 100644 --- a/src/snapshot/patch.rs +++ b/src/snapshot/patch.rs @@ -60,7 +60,7 @@ pub struct PatchUpdate { /// // TODO: Introduce machinery to detect conflicts, like keeping previous + // current values in all fields. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Default)] pub struct AppliedPatchSet { pub removed: Vec, pub added: Vec, diff --git a/src/snapshot/patch_apply.rs b/src/snapshot/patch_apply.rs index 0d7c9b78..7463f3c6 100644 --- a/src/snapshot/patch_apply.rs +++ b/src/snapshot/patch_apply.rs @@ -13,7 +13,7 @@ pub fn apply_patch_set(tree: &mut RojoTree, patch_set: PatchSet) -> AppliedPatch let mut context = PatchApplyContext::default(); 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 { @@ -21,22 +21,21 @@ pub fn apply_patch_set(tree: &mut RojoTree, patch_set: PatchSet) -> AppliedPatch } 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); - - // TODO: Actually calculate patch set - AppliedPatchSet::new() + finalize_patch_application(context, tree) } #[derive(Default)] struct PatchApplyContext { snapshot_id_to_instance_id: HashMap, properties_to_apply: HashMap>, + 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 /// 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, /// 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. -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 { let mut instance = tree .get_instance_mut(id) @@ -63,6 +62,20 @@ fn apply_deferred_properties(context: PatchApplyContext, tree: &mut RojoTree) { *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( @@ -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 { tree.update_metadata(patch.id, metadata); }