Compare commits

..

7 Commits

Author SHA1 Message Date
Lucien Greathouse
86875ab5f2 Git dependencies, skip dropping ServeSession 2022-05-27 19:39:44 -04:00
Lucien Greathouse
85f113fcad Use InstanceBuilder::empty to avoid extra name allocations 2022-05-27 19:17:07 -04:00
Lucien Greathouse
d666634330 Stop deferring property application in apply_patch_set 2022-05-27 19:04:53 -04:00
Lucien Greathouse
b2be0a513d Make compute_patch_set take snapshots by value 2022-05-27 18:47:34 -04:00
Lucien Greathouse
9767d4d8bd Use WeakDom::into_raw for faster snapshot generation from models 2022-05-27 18:39:36 -04:00
Lucien Greathouse
824cdc5dcd Annotate snapshot_rbxm for profiling 2022-05-27 18:13:07 -04:00
Lucien Greathouse
7aa7a35aa5 Add profiling info and optional profiling with Tracy 2022-05-27 03:08:54 -04:00
24 changed files with 318 additions and 208 deletions

189
Cargo.lock generated
View File

@@ -690,6 +690,19 @@ dependencies = [
"slab", "slab",
] ]
[[package]]
name = "generator"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1d9279ca822891c1a4dae06d185612cf8fc6acfe5dff37781b41297811b12ee"
dependencies = [
"cc",
"libc",
"log",
"rustversion",
"winapi 0.3.9",
]
[[package]] [[package]]
name = "generic-array" name = "generic-array"
version = "0.12.4" version = "0.12.4"
@@ -1029,6 +1042,19 @@ dependencies = [
"cfg-if 1.0.0", "cfg-if 1.0.0",
] ]
[[package]]
name = "loom"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5"
dependencies = [
"cfg-if 1.0.0",
"generator",
"scoped-tls",
"tracing",
"tracing-subscriber",
]
[[package]] [[package]]
name = "lz4" name = "lz4"
version = "1.23.3" version = "1.23.3"
@@ -1055,6 +1081,15 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
[[package]]
name = "matchers"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
dependencies = [
"regex-automata",
]
[[package]] [[package]]
name = "matches" name = "matches"
version = "0.1.9" version = "0.1.9"
@@ -1499,7 +1534,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f61dcf0b917cd75d4521d7343d1ffff3d1583054133c9b5cbea3375c703c40d" checksum = "2f61dcf0b917cd75d4521d7343d1ffff3d1583054133c9b5cbea3375c703c40d"
dependencies = [ dependencies = [
"profiling-procmacros", "profiling-procmacros",
"superluminal-perf", "tracy-client",
] ]
[[package]] [[package]]
@@ -1598,11 +1633,11 @@ dependencies = [
[[package]] [[package]]
name = "rbx_binary" name = "rbx_binary"
version = "0.6.4" version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/rojo-rbx/rbx-dom#4fa99b4190009f417ce63c86b2c6725e32c0090e"
checksum = "68f424adb7a0a24ab4bd153be141035f1404ae40affed902fd2721b42cca7f86"
dependencies = [ dependencies = [
"log", "log",
"lz4", "lz4",
"profiling",
"rbx_dom_weak", "rbx_dom_weak",
"rbx_reflection", "rbx_reflection",
"rbx_reflection_database", "rbx_reflection_database",
@@ -1612,8 +1647,7 @@ dependencies = [
[[package]] [[package]]
name = "rbx_dom_weak" name = "rbx_dom_weak"
version = "2.3.0" version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/rojo-rbx/rbx-dom#4fa99b4190009f417ce63c86b2c6725e32c0090e"
checksum = "6f7f524fb18f30d7065c82c4e87f747705679329810207e96169c6d4ec922d1f"
dependencies = [ dependencies = [
"rbx_types", "rbx_types",
"serde", "serde",
@@ -1622,8 +1656,7 @@ dependencies = [
[[package]] [[package]]
name = "rbx_reflection" name = "rbx_reflection"
version = "4.2.0" version = "4.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/rojo-rbx/rbx-dom#4fa99b4190009f417ce63c86b2c6725e32c0090e"
checksum = "a8915748c8a3b2a92540e4e35e99ebd548df2d62b0a6cf38ae5d0081f0e611d5"
dependencies = [ dependencies = [
"rbx_types", "rbx_types",
"serde", "serde",
@@ -1632,8 +1665,7 @@ dependencies = [
[[package]] [[package]]
name = "rbx_reflection_database" name = "rbx_reflection_database"
version = "0.2.4+roblox-504" version = "0.2.4+roblox-504"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/rojo-rbx/rbx-dom#4fa99b4190009f417ce63c86b2c6725e32c0090e"
checksum = "b41e8da85aa697cd04cef48e6dd7d96992786d2e322bafe1d3cc93045f4de1e1"
dependencies = [ dependencies = [
"lazy_static", "lazy_static",
"rbx_reflection", "rbx_reflection",
@@ -1644,8 +1676,7 @@ dependencies = [
[[package]] [[package]]
name = "rbx_types" name = "rbx_types"
version = "1.3.0" version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/rojo-rbx/rbx-dom#4fa99b4190009f417ce63c86b2c6725e32c0090e"
checksum = "d637383aa560cb675b7ea7a7778b945dab065ccc7c158f77b5455e27efadc6df"
dependencies = [ dependencies = [
"base64 0.11.0", "base64 0.11.0",
"bitflags", "bitflags",
@@ -1659,8 +1690,7 @@ dependencies = [
[[package]] [[package]]
name = "rbx_xml" name = "rbx_xml"
version = "0.12.3" version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/rojo-rbx/rbx-dom#4fa99b4190009f417ce63c86b2c6725e32c0090e"
checksum = "67387cd246cdec9251dd2451672541499ae6ce0a47c768b3ea9ee0a1becda9dd"
dependencies = [ dependencies = [
"base64 0.11.0", "base64 0.11.0",
"log", "log",
@@ -1706,6 +1736,9 @@ name = "regex-automata"
version = "0.1.10" version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
dependencies = [
"regex-syntax",
]
[[package]] [[package]]
name = "regex-syntax" name = "regex-syntax"
@@ -1816,15 +1849,7 @@ dependencies = [
] ]
[[package]] [[package]]
name = "rojo-insta-ext" name = "rojo"
version = "0.1.0"
dependencies = [
"serde",
"serde_yaml",
]
[[package]]
name = "rojo-smallstring"
version = "7.1.1" version = "7.1.1"
dependencies = [ dependencies = [
"anyhow", "anyhow",
@@ -1863,16 +1888,24 @@ dependencies = [
"serde", "serde",
"serde_json", "serde_json",
"serde_yaml", "serde_yaml",
"smol_str",
"tempfile", "tempfile",
"termcolor", "termcolor",
"thiserror", "thiserror",
"tokio", "tokio",
"tracy-client",
"uuid", "uuid",
"walkdir", "walkdir",
"winreg 0.10.1", "winreg 0.10.1",
] ]
[[package]]
name = "rojo-insta-ext"
version = "0.1.0"
dependencies = [
"serde",
"serde_yaml",
]
[[package]] [[package]]
name = "rustc-demangle" name = "rustc-demangle"
version = "0.1.21" version = "0.1.21"
@@ -1888,6 +1921,12 @@ dependencies = [
"semver", "semver",
] ]
[[package]]
name = "rustversion"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f"
[[package]] [[package]]
name = "ryu" name = "ryu"
version = "1.0.10" version = "1.0.10"
@@ -1913,6 +1952,12 @@ dependencies = [
"windows-sys", "windows-sys",
] ]
[[package]]
name = "scoped-tls"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"
[[package]] [[package]]
name = "scopeguard" name = "scopeguard"
version = "1.1.0" version = "1.1.0"
@@ -2025,6 +2070,15 @@ dependencies = [
"opaque-debug", "opaque-debug",
] ]
[[package]]
name = "sharded-slab"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31"
dependencies = [
"lazy_static",
]
[[package]] [[package]]
name = "similar" name = "similar"
version = "2.1.0" version = "2.1.0"
@@ -2038,13 +2092,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32"
[[package]] [[package]]
name = "smol_str" name = "smallvec"
version = "0.1.23" version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7475118a28b7e3a2e157ce0131ba8c5526ea96e90ee601d9f6bb2e286a35ab44" checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "snax" name = "snax"
@@ -2077,21 +2128,6 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" checksum = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee"
[[package]]
name = "superluminal-perf"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80ed8ddf5d2a4a849fa7dc75b3e0be740adb882fe7fee87e79584402ac9b1e60"
dependencies = [
"superluminal-perf-sys",
]
[[package]]
name = "superluminal-perf-sys"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0342a02bcc62538822a46f54294130677f026666c2e19d078fc213b7bc07ff16"
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.95" version = "1.0.95"
@@ -2171,6 +2207,15 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "thread_local"
version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180"
dependencies = [
"once_cell",
]
[[package]] [[package]]
name = "tinytemplate" name = "tinytemplate"
version = "1.2.1" version = "1.2.1"
@@ -2282,6 +2327,56 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f54c8ca710e81886d498c2fd3331b56c93aa248d49de2222ad2742247c60072f" checksum = "f54c8ca710e81886d498c2fd3331b56c93aa248d49de2222ad2742247c60072f"
dependencies = [ dependencies = [
"lazy_static", "lazy_static",
"valuable",
]
[[package]]
name = "tracing-log"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922"
dependencies = [
"lazy_static",
"log",
"tracing-core",
]
[[package]]
name = "tracing-subscriber"
version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4bc28f93baff38037f64e6f43d34cfa1605f27a49c34e8a04c5e78b0babf2596"
dependencies = [
"ansi_term",
"lazy_static",
"matchers",
"regex",
"sharded-slab",
"smallvec",
"thread_local",
"tracing",
"tracing-core",
"tracing-log",
]
[[package]]
name = "tracy-client"
version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42ebfe7a24c18b5ba86d8920c124b41b942352f863fbe0c84d3d63428fa1860f"
dependencies = [
"loom",
"once_cell",
"tracy-client-sys",
]
[[package]]
name = "tracy-client-sys"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9012b9dfeccaff16e93f5a8b02336125113a80a769902e679d334cbdd4d83f3b"
dependencies = [
"cc",
] ]
[[package]] [[package]]
@@ -2357,6 +2452,12 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "valuable"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
[[package]] [[package]]
name = "vcpkg" name = "vcpkg"
version = "0.2.15" version = "0.2.15"

View File

@@ -1,5 +1,5 @@
[package] [package]
name = "rojo-smallstring" name = "rojo"
version = "7.1.1" version = "7.1.1"
authors = ["Lucien Greathouse <me@lpghatguy.com>"] authors = ["Lucien Greathouse <me@lpghatguy.com>"]
description = "Enables professional-grade development tools for Roblox developers" description = "Enables professional-grade development tools for Roblox developers"
@@ -27,6 +27,8 @@ default = []
# Enable this feature to live-reload assets from the web UI. # Enable this feature to live-reload assets from the web UI.
dev_live_assets = [] dev_live_assets = []
profile-with-tracy = ["profiling/profile-with-tracy", "tracy-client"]
[workspace] [workspace]
members = ["crates/*"] members = ["crates/*"]
@@ -48,11 +50,17 @@ memofs = { version = "0.2.0", path = "crates/memofs" }
# rbx_reflection_database = { path = "../rbx-dom/rbx_reflection_database" } # rbx_reflection_database = { path = "../rbx-dom/rbx_reflection_database" }
# rbx_xml = { path = "../rbx-dom/rbx_xml" } # rbx_xml = { path = "../rbx-dom/rbx_xml" }
rbx_binary = "0.6.4" rbx_binary = { git = "https://github.com/rojo-rbx/rbx-dom" }
rbx_dom_weak = "2.3.0" rbx_dom_weak = { git = "https://github.com/rojo-rbx/rbx-dom" }
rbx_reflection = "4.2.0" rbx_reflection = { git = "https://github.com/rojo-rbx/rbx-dom" }
rbx_reflection_database = "0.2.2" rbx_reflection_database = { git = "https://github.com/rojo-rbx/rbx-dom" }
rbx_xml = "0.12.3" rbx_xml = { git = "https://github.com/rojo-rbx/rbx-dom" }
# rbx_binary = "0.6.4"
# rbx_dom_weak = "2.3.0"
# rbx_reflection = "4.2.0"
# rbx_reflection_database = "0.2.2"
# rbx_xml = "0.12.3"
anyhow = "1.0.44" anyhow = "1.0.44"
backtrace = "0.3.61" backtrace = "0.3.61"
@@ -80,8 +88,8 @@ thiserror = "1.0.30"
tokio = { version = "1.12.0", features = ["rt", "rt-multi-thread"] } tokio = { version = "1.12.0", features = ["rt", "rt-multi-thread"] }
uuid = { version = "1.0.0", features = ["v4", "serde"] } uuid = { version = "1.0.0", features = ["v4", "serde"] }
clap = { version = "3.1.18", features = ["derive"] } clap = { version = "3.1.18", features = ["derive"] }
smol_str = "0.1.23" profiling = "1.0.6"
profiling = { version = "1.0.6", features = ["profile-with-superluminal"] } tracy-client = { version = "0.13.2", optional = true }
[target.'cfg(windows)'.dependencies] [target.'cfg(windows)'.dependencies]
winreg = "0.10.1" winreg = "0.10.1"

View File

@@ -46,7 +46,6 @@ pub struct ChangeProcessor {
impl ChangeProcessor { impl ChangeProcessor {
/// Spin up the ChangeProcessor, connecting it to the given tree, VFS, and /// Spin up the ChangeProcessor, connecting it to the given tree, VFS, and
/// outbound message queue. /// outbound message queue.
#[profiling::function]
pub fn start( pub fn start(
tree: Arc<Mutex<RojoTree>>, tree: Arc<Mutex<RojoTree>>,
vfs: Arc<Vfs>, vfs: Arc<Vfs>,
@@ -292,7 +291,7 @@ fn compute_and_apply_changes(tree: &mut RojoTree, vfs: &Vfs, id: Ref) -> Option<
} }
}; };
let patch_set = compute_patch_set(snapshot.as_ref(), &tree, id); let patch_set = compute_patch_set(snapshot, &tree, id);
apply_patch_set(tree, patch_set) apply_patch_set(tree, patch_set)
} }
Ok(None) => { Ok(None) => {
@@ -335,7 +334,7 @@ fn compute_and_apply_changes(tree: &mut RojoTree, vfs: &Vfs, id: Ref) -> Option<
} }
}; };
let patch_set = compute_patch_set(snapshot.as_ref(), &tree, id); let patch_set = compute_patch_set(snapshot, &tree, id);
apply_patch_set(tree, patch_set) apply_patch_set(tree, patch_set)
} }
}; };

View File

@@ -1,5 +1,6 @@
use std::{ use std::{
io::{BufWriter, Write}, io::{BufWriter, Write},
mem::ManuallyDrop,
path::{Path, PathBuf}, path::{Path, PathBuf},
}; };
@@ -61,6 +62,14 @@ impl BuildCommand {
} }
} }
// Never drop ServeSession, because it's VERY expensive to drop and
// we're about to exit anyways.
//
// This is kind of evil; if this function is ever called outside of the
// context of a CLI, this will leak a large object forever. However, the
// performance benefits of leaking it outweigh the cost at this time.
let _session = ManuallyDrop::new(session);
Ok(()) Ok(())
} }
} }

View File

@@ -18,7 +18,6 @@ mod project;
mod resolution; mod resolution;
mod serve_session; mod serve_session;
mod session_id; mod session_id;
mod small_string;
mod snapshot; mod snapshot;
mod snapshot_middleware; mod snapshot_middleware;
mod web; mod web;

View File

@@ -6,7 +6,8 @@ use clap::Parser;
use librojo::cli::Options; use librojo::cli::Options;
fn main() { fn main() {
profiling::register_thread!("Main Thread"); #[cfg(feature = "profile-with-tracy")]
tracy_client::Client::start();
panic::set_hook(Box::new(|panic_info| { panic::set_hook(Box::new(|panic_info| {
// PanicInfo's payload is usually a &'static str or String. // PanicInfo's payload is usually a &'static str or String.

View File

@@ -96,7 +96,6 @@ impl ServeSession {
/// The project file is expected to be loaded out-of-band since it's /// The project file is expected to be loaded out-of-band since it's
/// currently loaded from the filesystem directly instead of through the /// currently loaded from the filesystem directly instead of through the
/// in-memory filesystem layer. /// in-memory filesystem layer.
#[profiling::function]
pub fn new<P: AsRef<Path>>(vfs: Vfs, start_path: P) -> Result<Self, ServeSessionError> { pub fn new<P: AsRef<Path>>(vfs: Vfs, start_path: P) -> Result<Self, ServeSessionError> {
let start_path = start_path.as_ref(); let start_path = start_path.as_ref();
let start_time = Instant::now(); let start_time = Instant::now();
@@ -131,7 +130,7 @@ impl ServeSession {
let snapshot = snapshot_from_vfs(&instance_context, &vfs, &start_path)?; let snapshot = snapshot_from_vfs(&instance_context, &vfs, &start_path)?;
log::trace!("Computing initial patch set"); log::trace!("Computing initial patch set");
let patch_set = compute_patch_set(snapshot.as_ref(), &tree, root_id); let patch_set = compute_patch_set(snapshot, &tree, root_id);
log::trace!("Applying initial patch set"); log::trace!("Applying initial patch set");
apply_patch_set(&mut tree, patch_set); apply_patch_set(&mut tree, patch_set);

View File

@@ -1 +0,0 @@
pub use smol_str::SmolStr as SmallString;

View File

@@ -1,15 +1,13 @@
//! Defines the structure of an instance snapshot. //! Defines the structure of an instance snapshot.
use std::collections::HashMap; use std::{borrow::Cow, collections::HashMap};
use rbx_dom_weak::{ use rbx_dom_weak::{
types::{Ref, Variant}, types::{Ref, Variant},
WeakDom, Instance, WeakDom,
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::small_string::SmallString;
use super::InstanceMetadata; use super::InstanceMetadata;
/// A lightweight description of what an instance should look like. /// A lightweight description of what an instance should look like.
@@ -27,13 +25,13 @@ pub struct InstanceSnapshot {
pub metadata: InstanceMetadata, pub metadata: InstanceMetadata,
/// Correpsonds to the Name property of the instance. /// Correpsonds to the Name property of the instance.
pub name: SmallString, pub name: Cow<'static, str>,
/// Corresponds to the ClassName property of the instance. /// Corresponds to the ClassName property of the instance.
pub class_name: SmallString, pub class_name: Cow<'static, str>,
/// All other properties of the instance, weakly-typed. /// All other properties of the instance, weakly-typed.
pub properties: HashMap<SmallString, Variant>, pub properties: HashMap<String, Variant>,
/// The children of the instance represented as more snapshots. /// The children of the instance represented as more snapshots.
/// ///
@@ -46,37 +44,37 @@ impl InstanceSnapshot {
Self { Self {
snapshot_id: None, snapshot_id: None,
metadata: InstanceMetadata::default(), metadata: InstanceMetadata::default(),
name: "DEFAULT".into(), name: Cow::Borrowed("DEFAULT"),
class_name: "DEFAULT".into(), class_name: Cow::Borrowed("DEFAULT"),
properties: HashMap::new(), properties: HashMap::new(),
children: Vec::new(), children: Vec::new(),
} }
} }
pub fn name(self, name: impl Into<SmallString>) -> Self { pub fn name(self, name: impl Into<String>) -> Self {
Self { Self {
name: name.into(), name: Cow::Owned(name.into()),
..self ..self
} }
} }
pub fn class_name(self, class_name: impl Into<SmallString>) -> Self { pub fn class_name(self, class_name: impl Into<String>) -> Self {
Self { Self {
class_name: class_name.into(), class_name: Cow::Owned(class_name.into()),
..self ..self
} }
} }
pub fn property<K, V>(mut self, key: K, value: V) -> Self pub fn property<K, V>(mut self, key: K, value: V) -> Self
where where
K: Into<SmallString>, K: Into<String>,
V: Into<Variant>, V: Into<Variant>,
{ {
self.properties.insert(key.into(), value.into()); self.properties.insert(key.into(), value.into());
self self
} }
pub fn properties(self, properties: impl Into<HashMap<SmallString, Variant>>) -> Self { pub fn properties(self, properties: impl Into<HashMap<String, Variant>>) -> Self {
Self { Self {
properties: properties.into(), properties: properties.into(),
..self ..self
@@ -104,28 +102,29 @@ impl InstanceSnapshot {
} }
} }
pub fn from_tree(tree: &WeakDom, id: Ref) -> Self { #[profiling::function]
let instance = tree.get_by_ref(id).expect("instance did not exist in tree"); pub fn from_tree(tree: WeakDom, id: Ref) -> Self {
let (_, mut raw_tree) = tree.into_raw();
Self::from_raw_tree(&mut raw_tree, id)
}
fn from_raw_tree(raw_tree: &mut HashMap<Ref, Instance>, id: Ref) -> Self {
let instance = raw_tree
.remove(&id)
.expect("instance did not exist in tree");
let children = instance let children = instance
.children() .children()
.iter() .iter()
.copied() .map(|&id| Self::from_raw_tree(raw_tree, id))
.map(|id| Self::from_tree(tree, id))
.collect();
let properties = instance
.properties
.iter()
.map(|(key, value)| (key.into(), value.clone()))
.collect(); .collect();
Self { Self {
snapshot_id: Some(id), snapshot_id: Some(id),
metadata: InstanceMetadata::default(), metadata: InstanceMetadata::default(),
name: SmallString::from(&instance.name), name: Cow::Owned(instance.name),
class_name: SmallString::from(&instance.class), class_name: Cow::Owned(instance.class),
properties, properties: instance.properties,
children, children,
} }
} }

View File

@@ -5,8 +5,6 @@ use std::collections::HashMap;
use rbx_dom_weak::types::{Ref, Variant}; use rbx_dom_weak::types::{Ref, Variant};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::small_string::SmallString;
use super::{InstanceMetadata, InstanceSnapshot}; use super::{InstanceMetadata, InstanceSnapshot};
/// A set of different kinds of patches that can be applied to an WeakDom. /// A set of different kinds of patches that can be applied to an WeakDom.
@@ -42,12 +40,12 @@ pub struct PatchAdd {
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct PatchUpdate { pub struct PatchUpdate {
pub id: Ref, pub id: Ref,
pub changed_name: Option<SmallString>, pub changed_name: Option<String>,
pub changed_class_name: Option<SmallString>, pub changed_class_name: Option<String>,
/// Contains all changed properties. If a property is assigned to `None`, /// Contains all changed properties. If a property is assigned to `None`,
/// then that property has been removed. /// then that property has been removed.
pub changed_properties: HashMap<SmallString, Option<Variant>>, pub changed_properties: HashMap<String, Option<Variant>>,
/// Changed Rojo-specific metadata, if any of it changed. /// Changed Rojo-specific metadata, if any of it changed.
pub changed_metadata: Option<InstanceMetadata>, pub changed_metadata: Option<InstanceMetadata>,
@@ -85,9 +83,9 @@ pub struct AppliedPatchUpdate {
pub id: Ref, pub id: Ref,
// TODO: Store previous values in order to detect application conflicts // TODO: Store previous values in order to detect application conflicts
pub changed_name: Option<SmallString>, pub changed_name: Option<String>,
pub changed_class_name: Option<SmallString>, pub changed_class_name: Option<String>,
pub changed_properties: HashMap<SmallString, Option<Variant>>, pub changed_properties: HashMap<String, Option<Variant>>,
pub changed_metadata: Option<InstanceMetadata>, pub changed_metadata: Option<InstanceMetadata>,
} }

View File

@@ -1,11 +1,12 @@
//! Defines the algorithm for applying generated patches. //! Defines the algorithm for applying generated patches.
use std::collections::HashMap; use std::{
collections::{HashMap, HashSet},
mem::take,
};
use rbx_dom_weak::types::{Ref, Variant}; use rbx_dom_weak::types::{Ref, Variant};
use crate::small_string::SmallString;
use super::{ use super::{
patch::{AppliedPatchSet, AppliedPatchUpdate, PatchSet, PatchUpdate}, patch::{AppliedPatchSet, AppliedPatchUpdate, PatchSet, PatchUpdate},
InstanceSnapshot, RojoTree, InstanceSnapshot, RojoTree,
@@ -18,18 +19,27 @@ use super::{
pub fn apply_patch_set(tree: &mut RojoTree, patch_set: PatchSet) -> AppliedPatchSet { pub fn apply_patch_set(tree: &mut RojoTree, patch_set: PatchSet) -> AppliedPatchSet {
let mut context = PatchApplyContext::default(); let mut context = PatchApplyContext::default();
for removed_id in patch_set.removed_instances { {
apply_remove_instance(&mut context, tree, removed_id); profiling::scope!("removals");
for removed_id in patch_set.removed_instances {
apply_remove_instance(&mut context, tree, removed_id);
}
} }
for add_patch in patch_set.added_instances { {
apply_add_child(&mut context, tree, add_patch.parent_id, add_patch.instance); profiling::scope!("additions");
for add_patch in patch_set.added_instances {
apply_add_child(&mut context, tree, add_patch.parent_id, add_patch.instance);
}
} }
// Updates need to be applied after additions, which reduces the complexity {
// of updates significantly. profiling::scope!("updates");
for update_patch in patch_set.updated_instances { // Updates need to be applied after additions, which reduces the complexity
apply_update_child(&mut context, tree, update_patch); // of updates significantly.
for update_patch in patch_set.updated_instances {
apply_update_child(&mut context, tree, update_patch);
}
} }
finalize_patch_application(context, tree) finalize_patch_application(context, tree)
@@ -58,20 +68,9 @@ struct PatchApplyContext {
/// eachother. /// eachother.
snapshot_id_to_instance_id: HashMap<Ref, Ref>, snapshot_id_to_instance_id: HashMap<Ref, Ref>,
/// The properties of instances added by the current `PatchSet`. /// Tracks all of the instances added by this patch that have refs that need
/// /// to be rewritten.
/// Instances added to the tree can refer to eachother via Ref properties, has_refs_to_rewrite: HashSet<Ref>,
/// but we need to make sure they're correctly transformed from snapshot
/// space into tree space (via `snapshot_id_to_instance_id`).
///
/// It's not possible to do that transformation for refs that refer to added
/// instances until all the instances have actually been inserted into the
/// tree. For simplicity, we defer application of _all_ properties on added
/// instances instead of just Refs.
///
/// This doesn't affect updated instances, since they're always applied
/// after we've added all the instances from the patch.
added_instance_properties: HashMap<Ref, HashMap<SmallString, Variant>>,
/// The current applied patch result, describing changes made to the tree. /// The current applied patch result, describing changes made to the tree.
applied_patch_set: AppliedPatchSet, applied_patch_set: AppliedPatchSet,
@@ -87,25 +86,22 @@ 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.
#[profiling::function]
fn finalize_patch_application(context: PatchApplyContext, tree: &mut RojoTree) -> AppliedPatchSet { fn finalize_patch_application(context: PatchApplyContext, tree: &mut RojoTree) -> AppliedPatchSet {
for (id, properties) in context.added_instance_properties { for id in context.has_refs_to_rewrite {
// This should always succeed since instances marked as added in our // This should always succeed since instances marked as added in our
// patch should be added without fail. // patch should be added without fail.
let mut instance = tree let mut instance = tree
.get_instance_mut(id) .get_instance_mut(id)
.expect("Invalid instance ID in deferred property map"); .expect("Invalid instance ID in deferred property map");
for (key, mut property_value) in properties { for value in instance.properties_mut().values_mut() {
if let Variant::Ref(referent) = property_value { if let Variant::Ref(referent) = value {
if let Some(&instance_referent) = context.snapshot_id_to_instance_id.get(&referent) if let Some(&instance_referent) = context.snapshot_id_to_instance_id.get(&referent)
{ {
property_value = Variant::Ref(instance_referent); *value = Variant::Ref(instance_referent);
} }
} }
instance
.properties_mut()
.insert(key.to_string(), property_value);
} }
} }
@@ -121,24 +117,24 @@ fn apply_add_child(
context: &mut PatchApplyContext, context: &mut PatchApplyContext,
tree: &mut RojoTree, tree: &mut RojoTree,
parent_id: Ref, parent_id: Ref,
snapshot: InstanceSnapshot, mut snapshot: InstanceSnapshot,
) { ) {
let snapshot_id = snapshot.snapshot_id; let snapshot_id = snapshot.snapshot_id;
let properties = snapshot.properties; let children = take(&mut snapshot.children);
let children = snapshot.children;
// Property application is deferred until after all children // If an object we're adding has a non-null referent, we'll note this
// are constructed. This helps apply referents correctly. // instance down as needing to be revisited later.
let remaining_snapshot = InstanceSnapshot::new() let has_refs = snapshot.properties.values().any(|value| match value {
.name(snapshot.name) Variant::Ref(value) => value.is_some(),
.class_name(snapshot.class_name) _ => false,
.metadata(snapshot.metadata) });
.snapshot_id(snapshot.snapshot_id);
let id = tree.insert_instance(parent_id, remaining_snapshot); let id = tree.insert_instance(parent_id, snapshot);
context.applied_patch_set.added.push(id); context.applied_patch_set.added.push(id);
context.added_instance_properties.insert(id, properties); if has_refs {
context.has_refs_to_rewrite.insert(id);
}
if let Some(snapshot_id) = snapshot_id { if let Some(snapshot_id) = snapshot_id {
context.snapshot_id_to_instance_id.insert(snapshot_id, id); context.snapshot_id_to_instance_id.insert(snapshot_id, id);
@@ -169,13 +165,13 @@ fn apply_update_child(context: &mut PatchApplyContext, tree: &mut RojoTree, patc
}; };
if let Some(name) = patch.changed_name { if let Some(name) = patch.changed_name {
*instance.name_mut() = name.to_string(); *instance.name_mut() = name.clone();
applied_patch.changed_name = Some(name.into()); applied_patch.changed_name = Some(name);
} }
if let Some(class_name) = patch.changed_class_name { if let Some(class_name) = patch.changed_class_name {
*instance.class_name_mut() = class_name.to_string(); *instance.class_name_mut() = class_name.clone();
applied_patch.changed_class_name = Some(class_name.into()); applied_patch.changed_class_name = Some(class_name);
} }
for (key, property_entry) in patch.changed_properties { for (key, property_entry) in patch.changed_properties {
@@ -200,15 +196,13 @@ fn apply_update_child(context: &mut PatchApplyContext, tree: &mut RojoTree, patc
instance instance
.properties_mut() .properties_mut()
.insert(key.to_string(), Variant::Ref(new_referent)); .insert(key.clone(), Variant::Ref(new_referent));
} }
Some(ref value) => { Some(ref value) => {
instance instance.properties_mut().insert(key.clone(), value.clone());
.properties_mut()
.insert(key.to_string(), value.clone());
} }
None => { None => {
instance.properties_mut().remove(key.as_str()); instance.properties_mut().remove(&key);
} }
} }

View File

@@ -1,7 +1,10 @@
//! Defines the algorithm for computing a roughly-minimal patch set given an //! Defines the algorithm for computing a roughly-minimal patch set given an
//! existing instance tree and an instance snapshot. //! existing instance tree and an instance snapshot.
use std::collections::{HashMap, HashSet}; use std::{
collections::{HashMap, HashSet},
mem::take,
};
use rbx_dom_weak::types::{Ref, Variant}; use rbx_dom_weak::types::{Ref, Variant};
@@ -11,11 +14,7 @@ use super::{
}; };
#[profiling::function] #[profiling::function]
pub fn compute_patch_set( pub fn compute_patch_set(snapshot: Option<InstanceSnapshot>, tree: &RojoTree, id: Ref) -> PatchSet {
snapshot: Option<&InstanceSnapshot>,
tree: &RojoTree,
id: Ref,
) -> PatchSet {
let mut patch_set = PatchSet::new(); let mut patch_set = PatchSet::new();
if let Some(snapshot) = snapshot { if let Some(snapshot) = snapshot {
@@ -75,7 +74,7 @@ fn rewrite_refs_in_snapshot(context: &ComputePatchContext, snapshot: &mut Instan
fn compute_patch_set_internal( fn compute_patch_set_internal(
context: &mut ComputePatchContext, context: &mut ComputePatchContext,
snapshot: &InstanceSnapshot, mut snapshot: InstanceSnapshot,
tree: &RojoTree, tree: &RojoTree,
id: Ref, id: Ref,
patch_set: &mut PatchSet, patch_set: &mut PatchSet,
@@ -88,12 +87,12 @@ fn compute_patch_set_internal(
.get_instance(id) .get_instance(id)
.expect("Instance did not exist in tree"); .expect("Instance did not exist in tree");
compute_property_patches(snapshot, &instance, patch_set); compute_property_patches(&mut snapshot, &instance, patch_set);
compute_children_patches(context, snapshot, tree, id, patch_set); compute_children_patches(context, &mut snapshot, tree, id, patch_set);
} }
fn compute_property_patches( fn compute_property_patches(
snapshot: &InstanceSnapshot, snapshot: &mut InstanceSnapshot,
instance: &InstanceWithMeta, instance: &InstanceWithMeta,
patch_set: &mut PatchSet, patch_set: &mut PatchSet,
) { ) {
@@ -103,32 +102,32 @@ fn compute_property_patches(
let changed_name = if snapshot.name == instance.name() { let changed_name = if snapshot.name == instance.name() {
None None
} else { } else {
Some(snapshot.name.clone()) Some(take(&mut snapshot.name).into_owned())
}; };
let changed_class_name = if snapshot.class_name == instance.class_name() { let changed_class_name = if snapshot.class_name == instance.class_name() {
None None
} else { } else {
Some(snapshot.class_name.clone()) Some(take(&mut snapshot.class_name).into_owned())
}; };
let changed_metadata = if &snapshot.metadata == instance.metadata() { let changed_metadata = if &snapshot.metadata == instance.metadata() {
None None
} else { } else {
Some(snapshot.metadata.clone()) Some(take(&mut snapshot.metadata))
}; };
for (name, snapshot_value) in &snapshot.properties { for (name, snapshot_value) in take(&mut snapshot.properties) {
visited_properties.insert(name.as_str()); visited_properties.insert(name.clone());
match instance.properties().get(name.as_str()) { match instance.properties().get(&name) {
Some(instance_value) => { Some(instance_value) => {
if snapshot_value != instance_value { if &snapshot_value != instance_value {
changed_properties.insert(name.clone(), Some(snapshot_value.clone())); changed_properties.insert(name, Some(snapshot_value));
} }
} }
None => { None => {
changed_properties.insert(name.clone(), Some(snapshot_value.clone())); changed_properties.insert(name, Some(snapshot_value));
} }
} }
} }
@@ -138,7 +137,7 @@ fn compute_property_patches(
continue; continue;
} }
changed_properties.insert(name.into(), None); changed_properties.insert(name.clone(), None);
} }
if changed_properties.is_empty() if changed_properties.is_empty()
@@ -160,7 +159,7 @@ fn compute_property_patches(
fn compute_children_patches( fn compute_children_patches(
context: &mut ComputePatchContext, context: &mut ComputePatchContext,
snapshot: &InstanceSnapshot, snapshot: &mut InstanceSnapshot,
tree: &RojoTree, tree: &RojoTree,
id: Ref, id: Ref,
patch_set: &mut PatchSet, patch_set: &mut PatchSet,
@@ -173,7 +172,7 @@ fn compute_children_patches(
let mut paired_instances = vec![false; instance_children.len()]; let mut paired_instances = vec![false; instance_children.len()];
for snapshot_child in snapshot.children.iter() { for snapshot_child in take(&mut snapshot.children) {
let matching_instance = let matching_instance =
instance_children instance_children
.iter() .iter()
@@ -210,7 +209,7 @@ fn compute_children_patches(
None => { None => {
patch_set.added_instances.push(PatchAdd { patch_set.added_instances.push(PatchAdd {
parent_id: id, parent_id: id,
instance: snapshot_child.clone(), instance: snapshot_child,
}); });
} }
} }
@@ -258,7 +257,7 @@ mod test {
children: Vec::new(), children: Vec::new(),
}; };
let patch_set = compute_patch_set(Some(&snapshot), &tree, root_id); let patch_set = compute_patch_set(Some(snapshot), &tree, root_id);
let expected_patch_set = PatchSet { let expected_patch_set = PatchSet {
updated_instances: vec![PatchUpdate { updated_instances: vec![PatchUpdate {
@@ -308,7 +307,7 @@ mod test {
class_name: Cow::Borrowed("foo"), class_name: Cow::Borrowed("foo"),
}; };
let patch_set = compute_patch_set(Some(&snapshot), &tree, root_id); let patch_set = compute_patch_set(Some(snapshot), &tree, root_id);
let expected_patch_set = PatchSet { let expected_patch_set = PatchSet {
added_instances: vec![PatchAdd { added_instances: vec![PatchAdd {

View File

@@ -23,7 +23,7 @@ fn set_name_and_class_name() {
children: Vec::new(), children: Vec::new(),
}; };
let patch_set = compute_patch_set(Some(&snapshot), &tree, tree.get_root_id()); let patch_set = compute_patch_set(Some(snapshot), &tree, tree.get_root_id());
let patch_value = redactions.redacted_yaml(patch_set); let patch_value = redactions.redacted_yaml(patch_set);
assert_yaml_snapshot!(patch_value); assert_yaml_snapshot!(patch_value);
@@ -47,7 +47,7 @@ fn set_property() {
children: Vec::new(), children: Vec::new(),
}; };
let patch_set = compute_patch_set(Some(&snapshot), &tree, tree.get_root_id()); let patch_set = compute_patch_set(Some(snapshot), &tree, tree.get_root_id());
let patch_value = redactions.redacted_yaml(patch_set); let patch_value = redactions.redacted_yaml(patch_set);
assert_yaml_snapshot!(patch_value); assert_yaml_snapshot!(patch_value);
@@ -78,7 +78,7 @@ fn remove_property() {
children: Vec::new(), children: Vec::new(),
}; };
let patch_set = compute_patch_set(Some(&snapshot), &tree, tree.get_root_id()); let patch_set = compute_patch_set(Some(snapshot), &tree, tree.get_root_id());
let patch_value = redactions.redacted_yaml(patch_set); let patch_value = redactions.redacted_yaml(patch_set);
assert_yaml_snapshot!(patch_value); assert_yaml_snapshot!(patch_value);
@@ -107,7 +107,7 @@ fn add_child() {
}], }],
}; };
let patch_set = compute_patch_set(Some(&snapshot), &tree, tree.get_root_id()); let patch_set = compute_patch_set(Some(snapshot), &tree, tree.get_root_id());
let patch_value = redactions.redacted_yaml(patch_set); let patch_value = redactions.redacted_yaml(patch_set);
assert_yaml_snapshot!(patch_value); assert_yaml_snapshot!(patch_value);
@@ -139,7 +139,7 @@ fn remove_child() {
children: Vec::new(), children: Vec::new(),
}; };
let patch_set = compute_patch_set(Some(&snapshot), &tree, tree.get_root_id()); let patch_set = compute_patch_set(Some(snapshot), &tree, tree.get_root_id());
let patch_value = redactions.redacted_yaml(patch_set); let patch_value = redactions.redacted_yaml(patch_set);
assert_yaml_snapshot!(patch_value); assert_yaml_snapshot!(patch_value);

View File

@@ -87,8 +87,9 @@ impl RojoTree {
} }
pub fn insert_instance(&mut self, parent_ref: Ref, snapshot: InstanceSnapshot) -> Ref { pub fn insert_instance(&mut self, parent_ref: Ref, snapshot: InstanceSnapshot) -> Ref {
let builder = InstanceBuilder::new(snapshot.class_name.to_owned()) let builder = InstanceBuilder::empty()
.with_name(snapshot.name.to_owned()) .with_class(snapshot.class_name.into_owned())
.with_name(snapshot.name.into_owned())
.with_properties(snapshot.properties); .with_properties(snapshot.properties);
let referent = self.inner.insert(parent_ref, builder); let referent = self.inner.insert(parent_ref, builder);

View File

@@ -30,7 +30,7 @@ pub fn snapshot_csv(
.name(name) .name(name)
.class_name("LocalizationTable") .class_name("LocalizationTable")
.properties(hashmap! { .properties(hashmap! {
"Contents".into() => table_contents.into(), "Contents".to_owned() => table_contents.into(),
}) })
.metadata( .metadata(
InstanceMetadata::new() InstanceMetadata::new()

View File

@@ -25,7 +25,7 @@ pub fn snapshot_json(
let as_lua = json_to_lua(value).to_string(); let as_lua = json_to_lua(value).to_string();
let properties = hashmap! { let properties = hashmap! {
"Source".into() => as_lua.into(), "Source".to_owned() => as_lua.into(),
}; };
let meta_path = path.with_file_name(format!("{}.meta.json", name)); let meta_path = path.with_file_name(format!("{}.meta.json", name));

View File

@@ -1,4 +1,4 @@
use std::{collections::HashMap, path::Path, str}; use std::{borrow::Cow, collections::HashMap, path::Path, str};
use anyhow::Context; use anyhow::Context;
use memofs::Vfs; use memofs::Vfs;
@@ -85,14 +85,14 @@ impl JsonModelCore {
let mut properties = HashMap::with_capacity(self.properties.len()); let mut properties = HashMap::with_capacity(self.properties.len());
for (key, unresolved) in self.properties { for (key, unresolved) in self.properties {
let value = unresolved.resolve(&class_name, &key)?; let value = unresolved.resolve(&class_name, &key)?;
properties.insert(key.into(), value); properties.insert(key, value);
} }
Ok(InstanceSnapshot { Ok(InstanceSnapshot {
snapshot_id: None, snapshot_id: None,
metadata: Default::default(), metadata: Default::default(),
name: name.into(), name: Cow::Owned(name),
class_name: class_name.into(), class_name: Cow::Owned(class_name),
properties, properties,
children, children,
}) })

View File

@@ -38,7 +38,7 @@ pub fn snapshot_lua(
.name(instance_name) .name(instance_name)
.class_name(class_name) .class_name(class_name)
.properties(hashmap! { .properties(hashmap! {
"Source".into() => contents_str.into(), "Source".to_owned() => contents_str.into(),
}) })
.metadata( .metadata(
InstanceMetadata::new() InstanceMetadata::new()

View File

@@ -1,4 +1,4 @@
use std::{collections::HashMap, path::PathBuf}; use std::{borrow::Cow, collections::HashMap, path::PathBuf};
use anyhow::{format_err, Context}; use anyhow::{format_err, Context};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@@ -49,7 +49,7 @@ impl AdjacentMetadata {
.resolve(&snapshot.class_name, &key) .resolve(&snapshot.class_name, &key)
.with_context(|| format!("error applying meta file {}", path.display()))?; .with_context(|| format!("error applying meta file {}", path.display()))?;
snapshot.properties.insert(key.into(), value); snapshot.properties.insert(key, value);
} }
Ok(()) Ok(())
@@ -116,7 +116,7 @@ impl DirectoryMetadata {
)); ));
} }
snapshot.class_name = class_name.into(); snapshot.class_name = Cow::Owned(class_name);
} }
Ok(()) Ok(())
@@ -136,7 +136,7 @@ impl DirectoryMetadata {
.resolve(&snapshot.class_name, &key) .resolve(&snapshot.class_name, &key)
.with_context(|| format!("error applying meta file {}", path.display()))?; .with_context(|| format!("error applying meta file {}", path.display()))?;
snapshot.properties.insert(key.into(), value); snapshot.properties.insert(key, value);
} }
Ok(()) Ok(())

View File

@@ -6,7 +6,6 @@ use rbx_reflection::ClassTag;
use crate::{ use crate::{
project::{PathNode, Project, ProjectNode}, project::{PathNode, Project, ProjectNode},
small_string::SmallString,
snapshot::{ snapshot::{
InstanceContext, InstanceMetadata, InstanceSnapshot, InstigatingSource, PathIgnoreRule, InstanceContext, InstanceMetadata, InstanceSnapshot, InstigatingSource, PathIgnoreRule,
}, },
@@ -68,10 +67,13 @@ pub fn snapshot_project_node(
) -> anyhow::Result<Option<InstanceSnapshot>> { ) -> anyhow::Result<Option<InstanceSnapshot>> {
let project_folder = project_path.parent().unwrap(); let project_folder = project_path.parent().unwrap();
let class_name_from_project = node.class_name.as_ref().map(|name| SmallString::from(name)); let class_name_from_project = node
.class_name
.as_ref()
.map(|name| Cow::Owned(name.clone()));
let mut class_name_from_path = None; let mut class_name_from_path = None;
let name = SmallString::from(instance_name); let name = Cow::Owned(instance_name.to_owned());
let mut properties = HashMap::new(); let mut properties = HashMap::new();
let mut children = Vec::new(); let mut children = Vec::new();
let mut metadata = InstanceMetadata::default(); let mut metadata = InstanceMetadata::default();
@@ -226,7 +228,7 @@ pub fn snapshot_project_node(
_ => {} _ => {}
} }
properties.insert(key.into(), value); properties.insert(key.clone(), value);
} }
// If the user specified $ignoreUnknownInstances, overwrite the existing // If the user specified $ignoreUnknownInstances, overwrite the existing
@@ -260,7 +262,7 @@ pub fn snapshot_project_node(
})) }))
} }
fn infer_class_name(name: &str, parent_class: Option<&str>) -> Option<SmallString> { fn infer_class_name(name: &str, parent_class: Option<&str>) -> Option<Cow<'static, str>> {
// If className wasn't defined from another source, we may be able // If className wasn't defined from another source, we may be able
// to infer one. // to infer one.
@@ -273,13 +275,13 @@ fn infer_class_name(name: &str, parent_class: Option<&str>) -> Option<SmallStrin
let descriptor = rbx_reflection_database::get().classes.get(name)?; let descriptor = rbx_reflection_database::get().classes.get(name)?;
if descriptor.tags.contains(&ClassTag::Service) { if descriptor.tags.contains(&ClassTag::Service) {
return Some(name.into()); return Some(Cow::Owned(name.to_owned()));
} }
} else if parent_class == "StarterPlayer" { } else if parent_class == "StarterPlayer" {
// StarterPlayer has two special members with their own classes. // StarterPlayer has two special members with their own classes.
if name == "StarterPlayerScripts" || name == "StarterCharacterScripts" { if name == "StarterPlayerScripts" || name == "StarterCharacterScripts" {
return Some(name.into()); return Some(Cow::Owned(name.to_owned()));
} }
} }

View File

@@ -7,6 +7,7 @@ use crate::snapshot::{InstanceContext, InstanceMetadata, InstanceSnapshot};
use super::util::PathExt; use super::util::PathExt;
#[profiling::function]
pub fn snapshot_rbxm( pub fn snapshot_rbxm(
context: &InstanceContext, context: &InstanceContext,
vfs: &Vfs, vfs: &Vfs,
@@ -21,7 +22,8 @@ pub fn snapshot_rbxm(
let children = root_instance.children(); let children = root_instance.children();
if children.len() == 1 { if children.len() == 1 {
let snapshot = InstanceSnapshot::from_tree(&temp_tree, children[0]) let child = children[0];
let snapshot = InstanceSnapshot::from_tree(temp_tree, child)
.name(name) .name(name)
.metadata( .metadata(
InstanceMetadata::new() InstanceMetadata::new()

View File

@@ -24,7 +24,8 @@ pub fn snapshot_rbxmx(
let children = root_instance.children(); let children = root_instance.children();
if children.len() == 1 { if children.len() == 1 {
let snapshot = InstanceSnapshot::from_tree(&temp_tree, children[0]) let child = children[0];
let snapshot = InstanceSnapshot::from_tree(temp_tree, child)
.name(name) .name(name)
.metadata( .metadata(
InstanceMetadata::new() InstanceMetadata::new()

View File

@@ -21,7 +21,7 @@ pub fn snapshot_txt(
.to_owned(); .to_owned();
let properties = hashmap! { let properties = hashmap! {
"Value".into() => contents_str.into(), "Value".to_owned() => contents_str.into(),
}; };
let meta_path = path.with_file_name(format!("{}.meta.json", name)); let meta_path = path.with_file_name(format!("{}.meta.json", name));

View File

@@ -12,7 +12,6 @@ use serde::{Deserialize, Serialize};
use crate::{ use crate::{
session_id::SessionId, session_id::SessionId,
small_string::SmallString,
snapshot::{ snapshot::{
AppliedPatchSet, InstanceMetadata as RojoInstanceMetadata, InstanceWithMeta, RojoTree, AppliedPatchSet, InstanceMetadata as RojoInstanceMetadata, InstanceWithMeta, RojoTree,
}, },
@@ -84,13 +83,13 @@ impl<'a> SubscribeMessage<'a> {
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct InstanceUpdate { pub struct InstanceUpdate {
pub id: Ref, pub id: Ref,
pub changed_name: Option<SmallString>, pub changed_name: Option<String>,
pub changed_class_name: Option<SmallString>, pub changed_class_name: Option<String>,
// TODO: Transform from HashMap<_, Option<_>> to something else, since // TODO: Transform from HashMap<String, Option<_>> to something else, since
// null will get lost when decoding from JSON in some languages. // null will get lost when decoding from JSON in some languages.
#[serde(default)] #[serde(default)]
pub changed_properties: HashMap<SmallString, Option<Variant>>, pub changed_properties: HashMap<String, Option<Variant>>,
pub changed_metadata: Option<InstanceMetadata>, pub changed_metadata: Option<InstanceMetadata>,
} }