Skip to content

Commit

Permalink
Use a proper deferred system for linking referents in syncback
Browse files Browse the repository at this point in the history
  • Loading branch information
Dekkonot committed Feb 15, 2024
1 parent 7a57b3c commit 84a96ec
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 39 deletions.
9 changes: 6 additions & 3 deletions src/syncback/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ pub use file_names::{name_for_inst, validate_file_name};
pub use fs_snapshot::FsSnapshot;
pub use hash::*;
pub use property_filter::filter_properties;
pub use ref_properties::link_referents;
pub use ref_properties::collect_referents;
pub use snapshot::{filter_out_property, SyncbackData, SyncbackSnapshot};

pub fn syncback_loop<'old>(
Expand All @@ -41,8 +41,8 @@ pub fn syncback_loop<'old>(
log::debug!("Mapping doms together");
let ref_map = match_descendants(old_tree.inner(), &new_tree);

log::debug!("Linking referents for new DOM...");
link_referents(&mut new_tree)?;
log::debug!("Collecting referents for new DOM...");
let deferred_referents = collect_referents(&new_tree)?;

log::debug!("Pre-filtering properties on new DOM");
for referent in descendants(&new_tree, new_tree.root_ref()) {
Expand All @@ -61,6 +61,9 @@ pub fn syncback_loop<'old>(
log::debug!("Hashing file DOM");
let new_hashes = hash_tree(&new_tree, new_tree.root_ref());

log::debug!("Linking referents for new DOM");
deferred_referents.link(&mut new_tree)?;

if let Some(syncback_rules) = &project.syncback_rules {
// I think this is a neat way to handle `sync_current_camera` being
// Option<bool>!
Expand Down
87 changes: 51 additions & 36 deletions src/syncback/ref_properties.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,23 @@
use std::collections::VecDeque;

use rbx_dom_weak::{
types::{Attributes, Variant},
types::{Attributes, Ref, Variant},
Instance, WeakDom,
};

use crate::{multimap::MultiMap, REF_ID_ATTRIBUTE_NAME, REF_POINTER_ATTRIBUTE_PREFIX};

use super::get_inst_path;

/// Iterates through a WeakDom and links referent properties using attributes.
pub fn link_referents(dom: &mut WeakDom) -> anyhow::Result<()> {
pub struct RefRewrites {
links: MultiMap<Ref, (String, Ref)>,
}

/// Iterates through a WeakDom and collects referent properties.
///
/// They can be linked to a dom later using the `link` method on the returned
/// struct.
pub fn collect_referents(dom: &WeakDom) -> anyhow::Result<RefRewrites> {
let mut links = MultiMap::new();
let mut queue = VecDeque::new();

Expand All @@ -37,48 +44,56 @@ pub fn link_referents(dom: &mut WeakDom) -> anyhow::Result<()> {
}
}
}
let mut rewrites = Vec::new();

for (pointer_ref, ref_properties) in links {
for (prop_name, target_ref) in ref_properties {
log::debug!(
"Linking {}.{prop_name} to {} ({pointer_ref} to {target_ref})",
dom.get_by_ref(pointer_ref).unwrap().name,
dom.get_by_ref(target_ref).unwrap().name,
);
let target_inst = dom
.get_by_ref_mut(target_ref)
.expect("Ref properties that aren't in DOM should be filtered");
Ok(RefRewrites { links })
}

let attributes = get_or_insert_attributes(target_inst)?;
if attributes.get(REF_ID_ATTRIBUTE_NAME).is_none() {
attributes.insert(
REF_ID_ATTRIBUTE_NAME.to_owned(),
Variant::String(target_ref.to_string()),
impl RefRewrites {
/// Links referents for the provided DOM, using the links stored in this
/// struct.
pub fn link(self, dom: &mut WeakDom) -> anyhow::Result<()> {
let mut rewrites = Vec::new();
for (pointer_ref, ref_properties) in self.links {
for (prop_name, target_ref) in ref_properties {
log::debug!(
"Linking {}.{prop_name} to {} ({pointer_ref} to {target_ref})",
dom.get_by_ref(pointer_ref).unwrap().name,
dom.get_by_ref(target_ref).unwrap().name,
);
let target_inst = dom
.get_by_ref_mut(target_ref)
.expect("Ref properties that aren't in DOM should be filtered");

let attributes = get_or_insert_attributes(target_inst)?;
if attributes.get(REF_ID_ATTRIBUTE_NAME).is_none() {
attributes.insert(
REF_ID_ATTRIBUTE_NAME.to_owned(),
Variant::String(target_ref.to_string()),
);
}

let target_id = attributes
.get(REF_ID_ATTRIBUTE_NAME)
.expect("every Instance to have an ID");
if let Variant::String(value) = target_id {
rewrites.push((prop_name, value.clone().into_bytes()));
} else if let Variant::BinaryString(value) = target_id {
rewrites.push((prop_name, value.clone().into_vec()))
}
}

let target_id = attributes
.get(REF_ID_ATTRIBUTE_NAME)
.expect("every Instance to have an ID");
if let Variant::String(value) = target_id {
rewrites.push((prop_name, value.clone().into_bytes()));
} else if let Variant::BinaryString(value) = target_id {
rewrites.push((prop_name, value.clone().into_vec()))
let inst = dom.get_by_ref_mut(pointer_ref).unwrap();
let attrs = get_or_insert_attributes(inst)?;
for (name, id) in rewrites.drain(..) {
attrs.insert(
format!("{REF_POINTER_ATTRIBUTE_PREFIX}{name}"),
String::from_utf8(id).unwrap().into(),
);
}
}

let inst = dom.get_by_ref_mut(pointer_ref).unwrap();
let attrs = get_or_insert_attributes(inst)?;
for (name, id) in rewrites.drain(..) {
attrs.insert(
format!("{REF_POINTER_ATTRIBUTE_PREFIX}{name}"),
String::from_utf8(id).unwrap().into(),
);
}
Ok(())
}

Ok(())
}

fn get_or_insert_attributes(inst: &mut Instance) -> anyhow::Result<&mut Attributes> {
Expand Down

0 comments on commit 84a96ec

Please sign in to comment.