mirror of
https://github.com/rojo-rbx/rojo.git
synced 2026-10-23 22:11:38 +00:00
- Removed redundant Rojo reference attributes from snapshot comparisons to prevent spurious diffs during VFS events. - Updated the logic for interned instance additions to ensure deterministic ordering by redacted parent and name. These changes aim to improve the accuracy of snapshot comparisons and enhance the handling of interned instances.
142 lines
4.4 KiB
Rust
142 lines
4.4 KiB
Rust
use std::collections::HashMap;
|
|
|
|
use rbx_dom_weak::types::{Ref, Variant};
|
|
use serde::Serialize;
|
|
|
|
use librojo::web_api::{
|
|
Instance, InstanceUpdate, MessagesPacket, ReadResponse, SocketPacket, SocketPacketBody,
|
|
};
|
|
use rojo_insta_ext::RedactionMap;
|
|
|
|
/// A convenience method to store all of the redactable data from a piece of
|
|
/// data, then immediately redact it and return a serde_yaml Value.
|
|
pub trait InternAndRedact<T> {
|
|
fn intern_and_redact(&self, redactions: &mut RedactionMap, extra: T) -> serde_yaml::Value;
|
|
}
|
|
|
|
impl<I, T> InternAndRedact<T> for I
|
|
where
|
|
I: Serialize + Internable<T>,
|
|
{
|
|
fn intern_and_redact(&self, redactions: &mut RedactionMap, extra: T) -> serde_yaml::Value {
|
|
self.intern(redactions, extra);
|
|
redactions.redacted_yaml(self)
|
|
}
|
|
}
|
|
|
|
/// A trait to describe how to discover redactable data from an type.
|
|
///
|
|
/// The 'extra' parameter is a kludge to support types like Instance or
|
|
/// ReadResponse that need some additional information in order to be
|
|
/// deterministic.
|
|
pub trait Internable<T> {
|
|
fn intern(&self, redactions: &mut RedactionMap, extra: T);
|
|
}
|
|
|
|
impl Internable<Ref> for ReadResponse<'_> {
|
|
fn intern(&self, redactions: &mut RedactionMap, root_id: Ref) {
|
|
redactions.intern(root_id);
|
|
|
|
let root_instance = self.instances.get(&root_id).unwrap();
|
|
intern_variant_refs(
|
|
redactions,
|
|
root_instance.properties.values().map(|v| v.as_ref()),
|
|
);
|
|
|
|
for &child_id in root_instance.children.iter() {
|
|
self.intern(redactions, child_id);
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a> Internable<&'a HashMap<Ref, Instance<'_>>> for Instance<'a> {
|
|
fn intern(&self, redactions: &mut RedactionMap, other_instances: &HashMap<Ref, Instance<'_>>) {
|
|
redactions.intern(self.id);
|
|
|
|
intern_variant_refs(redactions, self.properties.values().map(|v| v.as_ref()));
|
|
|
|
for child_id in self.children.iter() {
|
|
let child = &other_instances[child_id];
|
|
child.intern(redactions, other_instances);
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Internable<()> for SocketPacket<'_> {
|
|
fn intern(&self, redactions: &mut RedactionMap, extra: ()) {
|
|
redactions.intern(self.session_id);
|
|
match &self.body {
|
|
SocketPacketBody::Messages(packet) => packet.intern(redactions, extra),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Internable<()> for MessagesPacket<'_> {
|
|
fn intern(&self, redactions: &mut RedactionMap, _extra: ()) {
|
|
for message in &self.messages {
|
|
intern_instance_updates(redactions, &message.updated);
|
|
intern_instance_additions(redactions, &message.added);
|
|
}
|
|
}
|
|
}
|
|
|
|
fn intern_instance_updates(redactions: &mut RedactionMap, updates: &[InstanceUpdate]) {
|
|
for update in updates {
|
|
redactions.intern(update.id);
|
|
intern_variant_refs(
|
|
redactions,
|
|
update
|
|
.changed_properties
|
|
.values()
|
|
.filter_map(|v| v.as_ref()),
|
|
);
|
|
}
|
|
}
|
|
|
|
fn intern_instance_additions(
|
|
redactions: &mut RedactionMap,
|
|
additions: &HashMap<Ref, Instance<'_>>,
|
|
) {
|
|
// This method redacts in a deterministic order from a HashMap by collecting
|
|
// all of the instances that are direct children of instances we've already
|
|
// interned.
|
|
let mut added_roots = Vec::new();
|
|
|
|
for (id, added) in additions {
|
|
let parent_id = added.parent;
|
|
let parent_redacted = match redactions.get_redacted_value(parent_id) {
|
|
Some(v) => v,
|
|
None => {
|
|
redactions.intern(parent_id);
|
|
redactions.get_redacted_value(parent_id).unwrap()
|
|
}
|
|
};
|
|
added_roots.push((id, parent_redacted));
|
|
}
|
|
|
|
// Sort by redacted parent, then by name for deterministic ordering when
|
|
// multiple children share the same parent.
|
|
added_roots.sort_unstable_by(|a, b| {
|
|
a.1.cmp(&b.1)
|
|
.then_with(|| additions[a.0].name.cmp(&additions[b.0].name))
|
|
});
|
|
|
|
for (root_id, _redacted_id) in added_roots {
|
|
additions[root_id].intern(redactions, additions);
|
|
}
|
|
}
|
|
|
|
/// Scan property values for Ref variants and intern them so they get redacted
|
|
/// to deterministic `id-N` values in snapshots.
|
|
fn intern_variant_refs<'a>(
|
|
redactions: &mut RedactionMap,
|
|
properties: impl Iterator<Item = &'a Variant>,
|
|
) {
|
|
for variant in properties {
|
|
if let Variant::Ref(r) = variant {
|
|
if !r.is_none() {
|
|
redactions.intern(*r);
|
|
}
|
|
}
|
|
}
|
|
}
|