Update rbx-dom (#1023)

This commit is contained in:
Micah
2025-04-02 11:32:27 -07:00
committed by GitHub
parent 0d6ff8ef8a
commit 833320de64
30 changed files with 8815 additions and 2249 deletions

View File

@@ -1,10 +1,10 @@
//! Defines the structure of an instance snapshot.
use std::{borrow::Cow, collections::HashMap};
use std::borrow::Cow;
use rbx_dom_weak::{
types::{Ref, Variant},
Instance, WeakDom,
ustr, AHashMap, HashMapExt as _, Instance, Ustr, UstrMap, WeakDom,
};
use serde::{Deserialize, Serialize};
@@ -27,10 +27,10 @@ pub struct InstanceSnapshot {
pub name: Cow<'static, str>,
/// Corresponds to the ClassName property of the instance.
pub class_name: Cow<'static, str>,
pub class_name: Ustr,
/// All other properties of the instance, weakly-typed.
pub properties: HashMap<String, Variant>,
pub properties: UstrMap<Variant>,
/// The children of the instance represented as more snapshots.
///
@@ -44,8 +44,8 @@ impl InstanceSnapshot {
snapshot_id: Ref::none(),
metadata: InstanceMetadata::default(),
name: Cow::Borrowed("DEFAULT"),
class_name: Cow::Borrowed("DEFAULT"),
properties: HashMap::new(),
class_name: ustr("DEFAULT"),
properties: UstrMap::new(),
children: Vec::new(),
}
}
@@ -57,23 +57,23 @@ impl InstanceSnapshot {
}
}
pub fn class_name(self, class_name: impl Into<String>) -> Self {
pub fn class_name<S: Into<Ustr>>(self, class_name: S) -> Self {
Self {
class_name: Cow::Owned(class_name.into()),
class_name: class_name.into(),
..self
}
}
pub fn property<K, V>(mut self, key: K, value: V) -> Self
where
K: Into<String>,
K: Into<Ustr>,
V: Into<Variant>,
{
self.properties.insert(key.into(), value.into());
self
}
pub fn properties(self, properties: impl Into<HashMap<String, Variant>>) -> Self {
pub fn properties(self, properties: impl Into<UstrMap<Variant>>) -> Self {
Self {
properties: properties.into(),
..self
@@ -107,7 +107,7 @@ impl InstanceSnapshot {
Self::from_raw_tree(&mut raw_tree, id)
}
fn from_raw_tree(raw_tree: &mut HashMap<Ref, Instance>, id: Ref) -> Self {
fn from_raw_tree(raw_tree: &mut AHashMap<Ref, Instance>, id: Ref) -> Self {
let instance = raw_tree
.remove(&id)
.expect("instance did not exist in tree");
@@ -122,7 +122,7 @@ impl InstanceSnapshot {
snapshot_id: id,
metadata: InstanceMetadata::default(),
name: Cow::Owned(instance.name),
class_name: Cow::Owned(instance.class),
class_name: instance.class,
properties: instance.properties,
children,
}

View File

@@ -1,8 +1,9 @@
//! Defines the data structures used for describing instance patches.
use std::collections::HashMap;
use rbx_dom_weak::types::{Ref, Variant};
use rbx_dom_weak::{
types::{Ref, Variant},
HashMapExt as _, Ustr, UstrMap,
};
use serde::{Deserialize, Serialize};
use super::{InstanceMetadata, InstanceSnapshot};
@@ -41,11 +42,11 @@ pub struct PatchAdd {
pub struct PatchUpdate {
pub id: Ref,
pub changed_name: Option<String>,
pub changed_class_name: Option<String>,
pub changed_class_name: Option<Ustr>,
/// Contains all changed properties. If a property is assigned to `None`,
/// then that property has been removed.
pub changed_properties: HashMap<String, Option<Variant>>,
pub changed_properties: UstrMap<Option<Variant>>,
/// Changed Rojo-specific metadata, if any of it changed.
pub changed_metadata: Option<InstanceMetadata>,
@@ -88,8 +89,8 @@ pub struct AppliedPatchUpdate {
// TODO: Store previous values in order to detect application conflicts
pub changed_name: Option<String>,
pub changed_class_name: Option<String>,
pub changed_properties: HashMap<String, Option<Variant>>,
pub changed_class_name: Option<Ustr>,
pub changed_properties: UstrMap<Option<Variant>>,
pub changed_metadata: Option<InstanceMetadata>,
}
@@ -99,7 +100,7 @@ impl AppliedPatchUpdate {
id,
changed_name: None,
changed_class_name: None,
changed_properties: HashMap::new(),
changed_properties: UstrMap::new(),
changed_metadata: None,
}
}

View File

@@ -5,7 +5,10 @@ use std::{
mem::take,
};
use rbx_dom_weak::types::{Ref, Variant};
use rbx_dom_weak::{
types::{Ref, Variant},
ustr, Ustr,
};
use super::{
patch::{AppliedPatchSet, AppliedPatchUpdate, PatchSet, PatchUpdate},
@@ -76,7 +79,7 @@ struct PatchApplyContext {
/// Tracks all ref properties that were specified using attributes. This has
/// to be handled after everything else is done just like normal referent
/// properties.
attribute_refs_to_rewrite: MultiMap<Ref, (String, String)>,
attribute_refs_to_rewrite: MultiMap<Ref, (Ustr, String)>,
/// The current applied patch result, describing changes made to the tree.
applied_patch_set: AppliedPatchSet,
@@ -193,7 +196,7 @@ fn apply_update_child(context: &mut PatchApplyContext, tree: &mut RojoTree, patc
}
if let Some(class_name) = patch.changed_class_name {
*instance.class_name_mut() = class_name.clone();
instance.set_class_name(class_name);
applied_patch.changed_class_name = Some(class_name);
}
@@ -219,10 +222,10 @@ fn apply_update_child(context: &mut PatchApplyContext, tree: &mut RojoTree, patc
instance
.properties_mut()
.insert(key.clone(), Variant::Ref(new_referent));
.insert(key, Variant::Ref(new_referent));
}
Some(ref value) => {
instance.properties_mut().insert(key.clone(), value.clone());
instance.properties_mut().insert(key, value.clone());
}
None => {
instance.properties_mut().remove(&key);
@@ -247,7 +250,7 @@ fn defer_ref_properties(tree: &mut RojoTree, id: Ref, context: &mut PatchApplyCo
let instance = tree
.get_instance(id)
.expect("Instances should exist when calculating deferred refs");
let attributes = match instance.properties().get("Attributes") {
let attributes = match instance.properties().get(&ustr("Attributes")) {
Some(Variant::Attributes(attrs)) => attrs,
_ => return,
};
@@ -275,12 +278,12 @@ fn defer_ref_properties(tree: &mut RojoTree, id: Ref, context: &mut PatchApplyCo
if let Variant::String(prop_value) = attr_value {
context
.attribute_refs_to_rewrite
.insert(id, (prop_name.to_owned(), prop_value.clone()));
.insert(id, (ustr(prop_name), prop_value.clone()));
} else if let Variant::BinaryString(prop_value) = attr_value {
if let Ok(str) = std::str::from_utf8(prop_value.as_ref()) {
context
.attribute_refs_to_rewrite
.insert(id, (prop_name.to_owned(), str.to_string()));
.insert(id, (ustr(prop_name), str.to_string()));
} else {
log::error!("IDs specified by referent property attributes must be valid UTF-8 strings.")
}
@@ -304,7 +307,7 @@ mod test {
use std::borrow::Cow;
use rbx_dom_weak::types::Variant;
use rbx_dom_weak::{types::Variant, UstrMap};
use super::super::PatchAdd;
@@ -320,8 +323,8 @@ mod test {
snapshot_id: Ref::none(),
metadata: Default::default(),
name: Cow::Borrowed("Foo"),
class_name: Cow::Borrowed("Bar"),
properties: [("Baz".to_owned(), Variant::Int32(5))].into(),
class_name: ustr("Bar"),
properties: UstrMap::from_iter([(ustr("Baz"), Variant::Int32(5))]),
children: Vec::new(),
};
@@ -340,7 +343,7 @@ mod test {
let child_instance = tree.get_instance(child_id).unwrap();
assert_eq!(child_instance.name(), &snapshot.name);
assert_eq!(child_instance.class_name(), &snapshot.class_name);
assert_eq!(child_instance.class_name(), snapshot.class_name);
assert_eq!(child_instance.properties(), &snapshot.properties);
assert!(child_instance.children().is_empty());
}
@@ -363,16 +366,15 @@ mod test {
let patch = PatchUpdate {
id: root_id,
changed_name: Some("Foo".to_owned()),
changed_class_name: Some("NewClassName".to_owned()),
changed_properties: [
changed_class_name: Some(ustr("NewClassName")),
changed_properties: UstrMap::from_iter([
// The value of Foo has changed
("Foo".to_owned(), Some(Variant::Int32(8))),
(ustr("Foo"), Some(Variant::Int32(8))),
// Bar has been deleted
("Bar".to_owned(), None),
(ustr("Bar"), None),
// Baz has been added
("Baz".to_owned(), Some(Variant::Int32(10))),
]
.into(),
(ustr("Baz"), Some(Variant::Int32(10))),
]),
changed_metadata: None,
};
@@ -383,12 +385,11 @@ mod test {
apply_patch_set(&mut tree, patch_set);
let expected_properties = [
("Foo".to_owned(), Variant::Int32(8)),
("Baz".to_owned(), Variant::Int32(10)),
("Unchanged".to_owned(), Variant::Int32(-5)),
]
.into();
let expected_properties = UstrMap::from_iter([
(ustr("Foo"), Variant::Int32(8)),
(ustr("Baz"), Variant::Int32(10)),
(ustr("Unchanged"), Variant::Int32(-5)),
]);
let root_instance = tree.get_instance(root_id).unwrap();
assert_eq!(root_instance.name(), "Foo");

View File

@@ -1,12 +1,12 @@
//! Defines the algorithm for computing a roughly-minimal patch set given an
//! existing instance tree and an instance snapshot.
use std::{
collections::{HashMap, HashSet},
mem::take,
};
use std::{collections::HashMap, mem::take};
use rbx_dom_weak::types::{Ref, Variant};
use rbx_dom_weak::{
types::{Ref, Variant},
ustr, HashMapExt as _, UstrMap, UstrSet,
};
use crate::{RojoRef, REF_POINTER_ATTRIBUTE_PREFIX};
@@ -99,8 +99,8 @@ fn compute_property_patches(
patch_set: &mut PatchSet,
tree: &RojoTree,
) {
let mut visited_properties = HashSet::new();
let mut changed_properties = HashMap::new();
let mut visited_properties = UstrSet::default();
let mut changed_properties = UstrMap::new();
let attribute_ref_properties = compute_ref_properties(snapshot, tree);
@@ -113,7 +113,7 @@ fn compute_property_patches(
let changed_class_name = if snapshot.class_name == instance.class_name() {
None
} else {
Some(take(&mut snapshot.class_name).into_owned())
Some(take(&mut snapshot.class_name))
};
let changed_metadata = if &snapshot.metadata == instance.metadata() {
@@ -123,7 +123,7 @@ fn compute_property_patches(
};
for (name, snapshot_value) in take(&mut snapshot.properties) {
visited_properties.insert(name.clone());
visited_properties.insert(name);
match instance.properties().get(&name) {
Some(instance_value) => {
@@ -138,11 +138,11 @@ fn compute_property_patches(
}
for name in instance.properties().keys() {
if visited_properties.contains(name.as_str()) {
if visited_properties.contains(name) {
continue;
}
changed_properties.insert(name.clone(), None);
changed_properties.insert(*name, None);
}
for (name, ref_value) in attribute_ref_properties {
@@ -250,9 +250,9 @@ fn compute_children_patches(
fn compute_ref_properties(
snapshot: &InstanceSnapshot,
tree: &RojoTree,
) -> HashMap<String, Option<Variant>> {
let mut map = HashMap::new();
let attributes = match snapshot.properties.get("Attributes") {
) -> UstrMap<Option<Variant>> {
let mut map = UstrMap::new();
let attributes = match snapshot.properties.get(&ustr("Attributes")) {
Some(Variant::Attributes(attrs)) => attrs,
_ => return map,
};
@@ -284,9 +284,9 @@ fn compute_ref_properties(
}
};
if let Some(target_id) = tree.get_specified_id(&rojo_ref) {
map.insert(prop_name.to_string(), Some(Variant::Ref(target_id)));
map.insert(ustr(prop_name), Some(Variant::Ref(target_id)));
} else {
map.insert(prop_name.to_string(), None);
map.insert(ustr(prop_name), None);
}
}
@@ -314,11 +314,11 @@ mod test {
let snapshot_id = Ref::new();
let snapshot = InstanceSnapshot {
snapshot_id,
properties: [("Self".to_owned(), Variant::Ref(snapshot_id))].into(),
properties: UstrMap::from_iter([(ustr("Self"), Variant::Ref(snapshot_id))]),
metadata: Default::default(),
name: Cow::Borrowed("foo"),
class_name: Cow::Borrowed("foo"),
class_name: ustr("foo"),
children: Vec::new(),
};
@@ -329,7 +329,10 @@ mod test {
id: root_id,
changed_name: None,
changed_class_name: None,
changed_properties: [("Self".to_owned(), Some(Variant::Ref(root_id)))].into(),
changed_properties: UstrMap::from_iter([(
ustr("Self"),
Some(Variant::Ref(root_id)),
)]),
changed_metadata: None,
}],
added_instances: Vec::new(),
@@ -353,19 +356,19 @@ mod test {
let snapshot = InstanceSnapshot {
snapshot_id,
children: vec![InstanceSnapshot {
properties: [("Self".to_owned(), Variant::Ref(snapshot_id))].into(),
properties: UstrMap::from_iter([(ustr("Self"), Variant::Ref(snapshot_id))]),
snapshot_id: Ref::none(),
metadata: Default::default(),
name: Cow::Borrowed("child"),
class_name: Cow::Borrowed("child"),
class_name: ustr("child"),
children: Vec::new(),
}],
metadata: Default::default(),
properties: HashMap::new(),
properties: UstrMap::new(),
name: Cow::Borrowed("foo"),
class_name: Cow::Borrowed("foo"),
class_name: ustr("foo"),
};
let patch_set = compute_patch_set(Some(snapshot), &tree, root_id);
@@ -376,9 +379,9 @@ mod test {
instance: InstanceSnapshot {
snapshot_id: Ref::none(),
metadata: Default::default(),
properties: [("Self".to_owned(), Variant::Ref(root_id))].into(),
properties: UstrMap::from_iter([(ustr("Self"), Variant::Ref(root_id))]),
name: Cow::Borrowed("child"),
class_name: Cow::Borrowed("child"),
class_name: ustr("child"),
children: Vec::new(),
},
}],

View File

@@ -1,5 +1,6 @@
use insta::assert_yaml_snapshot;
use rbx_dom_weak::{ustr, UstrMap};
use rojo_insta_ext::RedactionMap;
use crate::{
@@ -18,7 +19,7 @@ fn set_name_and_class_name() {
updated_instances: vec![PatchUpdate {
id: tree.get_root_id(),
changed_name: Some("Hello, world!".to_owned()),
changed_class_name: Some("Folder".to_owned()),
changed_class_name: Some(ustr("Folder")),
changed_properties: Default::default(),
changed_metadata: None,
}],
@@ -46,7 +47,7 @@ fn add_property() {
id: tree.get_root_id(),
changed_name: None,
changed_class_name: None,
changed_properties: [("Foo".to_owned(), Some("Value of Foo".into()))].into(),
changed_properties: UstrMap::from_iter([(ustr("Foo"), Some("Value of Foo".into()))]),
changed_metadata: None,
}],
..Default::default()
@@ -74,7 +75,7 @@ fn remove_property() {
root_instance
.properties_mut()
.insert("Foo".to_owned(), "Should be removed".into());
.insert(ustr("Foo"), "Should be removed".into());
}
let tree_view = view_tree(&tree, &mut redactions);
@@ -85,7 +86,7 @@ fn remove_property() {
id: tree.get_root_id(),
changed_name: None,
changed_class_name: None,
changed_properties: [("Foo".to_owned(), None)].into(),
changed_properties: UstrMap::from_iter([(ustr("Foo"), None)]),
changed_metadata: None,
}],
..Default::default()

View File

@@ -2,7 +2,7 @@ use std::borrow::Cow;
use insta::assert_yaml_snapshot;
use rbx_dom_weak::types::Ref;
use rbx_dom_weak::{types::Ref, ustr, UstrMap};
use rojo_insta_ext::RedactionMap;
use crate::snapshot::{compute_patch_set, InstanceSnapshot, RojoTree};
@@ -18,7 +18,7 @@ fn set_name_and_class_name() {
snapshot_id: Ref::none(),
metadata: Default::default(),
name: Cow::Borrowed("Some Folder"),
class_name: Cow::Borrowed("Folder"),
class_name: ustr("Folder"),
properties: Default::default(),
children: Vec::new(),
};
@@ -40,8 +40,8 @@ fn set_property() {
snapshot_id: Ref::none(),
metadata: Default::default(),
name: Cow::Borrowed("ROOT"),
class_name: Cow::Borrowed("ROOT"),
properties: [("PropertyName".into(), "Hello, world!".into())].into(),
class_name: ustr("ROOT"),
properties: UstrMap::from_iter([(ustr("PropertyName"), "Hello, world!".into())]),
children: Vec::new(),
};
@@ -61,17 +61,16 @@ fn remove_property() {
{
let root_id = tree.get_root_id();
let mut root_instance = tree.get_instance_mut(root_id).unwrap();
root_instance.properties_mut().insert(
"Foo".to_owned(),
"This should be removed by the patch.".into(),
);
root_instance
.properties_mut()
.insert(ustr("Foo"), "This should be removed by the patch.".into());
}
let snapshot = InstanceSnapshot {
snapshot_id: Ref::none(),
metadata: Default::default(),
name: Cow::Borrowed("ROOT"),
class_name: Cow::Borrowed("ROOT"),
class_name: ustr("ROOT"),
properties: Default::default(),
children: Vec::new(),
};
@@ -93,13 +92,13 @@ fn add_child() {
snapshot_id: Ref::none(),
metadata: Default::default(),
name: Cow::Borrowed("ROOT"),
class_name: Cow::Borrowed("ROOT"),
class_name: ustr("ROOT"),
properties: Default::default(),
children: vec![InstanceSnapshot {
snapshot_id: Ref::none(),
metadata: Default::default(),
name: Cow::Borrowed("New"),
class_name: Cow::Borrowed("Folder"),
class_name: ustr("Folder"),
properties: Default::default(),
children: Vec::new(),
}],
@@ -132,7 +131,7 @@ fn remove_child() {
snapshot_id: Ref::none(),
metadata: Default::default(),
name: Cow::Borrowed("ROOT"),
class_name: Cow::Borrowed("ROOT"),
class_name: ustr("ROOT"),
properties: Default::default(),
children: Vec::new(),
};

View File

@@ -5,7 +5,7 @@ use std::{
use rbx_dom_weak::{
types::{Ref, Variant},
Instance, InstanceBuilder, WeakDom,
ustr, Instance, InstanceBuilder, Ustr, UstrMap, WeakDom,
};
use crate::{multimap::MultiMap, RojoRef};
@@ -95,7 +95,7 @@ impl RojoTree {
pub fn insert_instance(&mut self, parent_ref: Ref, snapshot: InstanceSnapshot) -> Ref {
let builder = InstanceBuilder::empty()
.with_class(snapshot.class_name.into_owned())
.with_class(snapshot.class_name)
.with_name(snapshot.name.into_owned())
.with_properties(snapshot.properties);
@@ -283,11 +283,11 @@ impl<'a> InstanceWithMeta<'a> {
&self.instance.name
}
pub fn class_name(&self) -> &'a str {
&self.instance.class
pub fn class_name(&self) -> Ustr {
self.instance.class
}
pub fn properties(&self) -> &'a HashMap<String, Variant> {
pub fn properties(&self) -> &'a UstrMap<Variant> {
&self.instance.properties
}
@@ -328,15 +328,15 @@ impl InstanceWithMetaMut<'_> {
&self.instance.class
}
pub fn class_name_mut(&mut self) -> &mut String {
&mut self.instance.class
pub fn set_class_name<'a, S: Into<&'a str>>(&mut self, new_class: S) {
self.instance.class = ustr(new_class.into());
}
pub fn properties(&self) -> &HashMap<String, Variant> {
pub fn properties(&self) -> &UstrMap<Variant> {
&self.instance.properties
}
pub fn properties_mut(&mut self) -> &mut HashMap<String, Variant> {
pub fn properties_mut(&mut self) -> &mut UstrMap<Variant> {
&mut self.instance.properties
}