mirror of
https://github.com/rojo-rbx/rojo.git
synced 2026-04-25 07:06:12 +00:00
Start MapSet work
This commit is contained in:
@@ -14,6 +14,7 @@ pub mod project;
|
|||||||
|
|
||||||
mod auth_cookie;
|
mod auth_cookie;
|
||||||
mod imfs;
|
mod imfs;
|
||||||
|
mod mapset;
|
||||||
mod message_queue;
|
mod message_queue;
|
||||||
mod path_map;
|
mod path_map;
|
||||||
mod path_serializer;
|
mod path_serializer;
|
||||||
|
|||||||
69
src/mapset.rs
Normal file
69
src/mapset.rs
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
use std::{
|
||||||
|
borrow::Borrow,
|
||||||
|
collections::HashMap,
|
||||||
|
fmt::{self, Debug},
|
||||||
|
hash::Hash,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A map whose value contains a set of multiple values.
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct MapSet<K, V> {
|
||||||
|
inner: HashMap<K, Vec<V>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)] // This is a core library-ish struct, unused stuff is ok
|
||||||
|
impl<K: Hash + Eq, V: Eq> MapSet<K, V> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
MapSet {
|
||||||
|
inner: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get<Q: Borrow<K>>(&mut self, k: Q) -> &[V] {
|
||||||
|
self.inner.get(k.borrow()).map(Vec::as_slice).unwrap_or(&[])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert(&mut self, k: K, v: V) {
|
||||||
|
let bucket = self.inner.entry(k).or_default();
|
||||||
|
|
||||||
|
for value in &*bucket {
|
||||||
|
if &*value == &v {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bucket.push(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove<Q: Borrow<K>, U: Borrow<V>>(&mut self, k: Q, v: U) -> Option<V> {
|
||||||
|
let b = v.borrow();
|
||||||
|
|
||||||
|
if let Some(bucket) = self.inner.get_mut(k.borrow()) {
|
||||||
|
let mut removed_value = None;
|
||||||
|
|
||||||
|
if let Some(index) = bucket.iter().position(|value| value == b) {
|
||||||
|
removed_value = Some(bucket.swap_remove(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
if bucket.len() == 0 {
|
||||||
|
self.inner.remove(k.borrow());
|
||||||
|
}
|
||||||
|
|
||||||
|
removed_value
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K: Debug + Hash + Eq, V: Debug + Eq> Debug for MapSet<K, V> {
|
||||||
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
self.inner.fmt(formatter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K: Hash + Eq, V: Eq> PartialEq for MapSet<K, V> {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.inner == other.inner
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,4 @@
|
|||||||
use std::{collections::HashMap, path::PathBuf};
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use rbx_dom_weak::{RbxId, RbxInstance, RbxInstanceProperties, RbxTree};
|
|
||||||
|
|
||||||
use crate::project::ProjectNode;
|
use crate::project::ProjectNode;
|
||||||
|
|
||||||
@@ -39,89 +37,3 @@ impl Default for InstanceMetadata {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct InstancePropertiesWithMeta {
|
|
||||||
pub inner: RbxInstanceProperties,
|
|
||||||
pub metadata: InstanceMetadata,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct InstanceWithMeta<'a> {
|
|
||||||
pub inner: &'a RbxInstance,
|
|
||||||
pub metadata: &'a InstanceMetadata,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct InstanceWithMetaMut<'a> {
|
|
||||||
pub inner: &'a mut RbxInstance,
|
|
||||||
pub metadata: &'a mut InstanceMetadata,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct TreeWithMetadata {
|
|
||||||
inner: RbxTree,
|
|
||||||
metadata: HashMap<RbxId, InstanceMetadata>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TreeWithMetadata {
|
|
||||||
pub fn new(root: InstancePropertiesWithMeta) -> TreeWithMetadata {
|
|
||||||
let inner = RbxTree::new(root.inner);
|
|
||||||
let mut metadata = HashMap::new();
|
|
||||||
metadata.insert(inner.get_root_id(), root.metadata);
|
|
||||||
|
|
||||||
TreeWithMetadata { inner, metadata }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_root_id(&self) -> RbxId {
|
|
||||||
self.inner.get_root_id()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_instance(&self, id: RbxId) -> Option<InstanceWithMeta> {
|
|
||||||
if let Some(inner) = self.inner.get_instance(id) {
|
|
||||||
let metadata = self.metadata.get(&id).unwrap();
|
|
||||||
|
|
||||||
Some(InstanceWithMeta { inner, metadata })
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_instance_mut(&mut self, id: RbxId) -> Option<InstanceWithMetaMut> {
|
|
||||||
if let Some(inner) = self.inner.get_instance_mut(id) {
|
|
||||||
let metadata = self.metadata.get_mut(&id).unwrap();
|
|
||||||
|
|
||||||
Some(InstanceWithMetaMut { inner, metadata })
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn insert_instance(
|
|
||||||
&mut self,
|
|
||||||
properties: InstancePropertiesWithMeta,
|
|
||||||
parent_id: RbxId,
|
|
||||||
) -> RbxId {
|
|
||||||
let id = self.inner.insert_instance(properties.inner, parent_id);
|
|
||||||
self.metadata.insert(id, properties.metadata);
|
|
||||||
id
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn remove_instance(&mut self, id: RbxId) -> Option<TreeWithMetadata> {
|
|
||||||
if let Some(inner) = self.inner.remove_instance(id) {
|
|
||||||
let mut metadata = HashMap::new();
|
|
||||||
|
|
||||||
let root_meta = self.metadata.remove(&id).unwrap();
|
|
||||||
metadata.insert(id, root_meta);
|
|
||||||
|
|
||||||
for instance in inner.descendants(id) {
|
|
||||||
let instance_meta = self.metadata.remove(&instance.get_id()).unwrap();
|
|
||||||
metadata.insert(instance.get_id(), instance_meta);
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(TreeWithMetadata { inner, metadata })
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -23,9 +23,11 @@ mod metadata;
|
|||||||
mod patch;
|
mod patch;
|
||||||
mod patch_apply;
|
mod patch_apply;
|
||||||
mod patch_compute;
|
mod patch_compute;
|
||||||
|
mod tree;
|
||||||
|
|
||||||
pub use instance_snapshot::InstanceSnapshot;
|
pub use instance_snapshot::InstanceSnapshot;
|
||||||
pub use metadata::*;
|
pub use metadata::*;
|
||||||
pub use patch::*;
|
pub use patch::*;
|
||||||
pub use patch_apply::apply_patch_set;
|
pub use patch_apply::apply_patch_set;
|
||||||
pub use patch_compute::compute_patch_set;
|
pub use patch_compute::compute_patch_set;
|
||||||
|
pub use tree::*;
|
||||||
|
|||||||
120
src/snapshot/tree.rs
Normal file
120
src/snapshot/tree.rs
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
use std::{collections::HashMap, path::PathBuf};
|
||||||
|
|
||||||
|
use rbx_dom_weak::{RbxId, RbxInstance, RbxInstanceProperties, RbxTree};
|
||||||
|
|
||||||
|
use crate::mapset::MapSet;
|
||||||
|
|
||||||
|
use super::InstanceMetadata;
|
||||||
|
|
||||||
|
/// An expanded variant of rbx_dom_weak's `RbxTree` that tracks additional
|
||||||
|
/// metadata per instance that's Rojo-specific.
|
||||||
|
///
|
||||||
|
/// This tree is also optimized for doing fast incremental updates and patches.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct RojoTree {
|
||||||
|
/// Contains the instances without their Rojo-specific metadata.
|
||||||
|
inner: RbxTree,
|
||||||
|
|
||||||
|
/// Metadata associated with each instance that is kept up-to-date with the
|
||||||
|
/// set of actual instances.
|
||||||
|
metadata: HashMap<RbxId, InstanceMetadata>,
|
||||||
|
|
||||||
|
/// A multimap from source paths to all of the root instances that were
|
||||||
|
/// constructed from that path.
|
||||||
|
///
|
||||||
|
/// Descendants of those instances should not be contained in the set, the
|
||||||
|
/// value portion of the map is also a set in order to support the same path
|
||||||
|
/// appearing multiple times in the same Rojo project. This is sometimes
|
||||||
|
/// called "path aliasing" in various Rojo documentation.
|
||||||
|
path_to_id: MapSet<PathBuf, RbxId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RojoTree {
|
||||||
|
pub fn new(root: InstancePropertiesWithMeta) -> RojoTree {
|
||||||
|
let inner = RbxTree::new(root.inner);
|
||||||
|
let mut metadata = HashMap::new();
|
||||||
|
metadata.insert(inner.get_root_id(), root.metadata);
|
||||||
|
|
||||||
|
RojoTree {
|
||||||
|
inner,
|
||||||
|
metadata,
|
||||||
|
path_to_id: MapSet::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_root_id(&self) -> RbxId {
|
||||||
|
self.inner.get_root_id()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_instance(&self, id: RbxId) -> Option<InstanceWithMeta> {
|
||||||
|
if let Some(inner) = self.inner.get_instance(id) {
|
||||||
|
let metadata = self.metadata.get(&id).unwrap();
|
||||||
|
|
||||||
|
Some(InstanceWithMeta { inner, metadata })
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_instance_mut(&mut self, id: RbxId) -> Option<InstanceWithMetaMut> {
|
||||||
|
if let Some(inner) = self.inner.get_instance_mut(id) {
|
||||||
|
let metadata = self.metadata.get_mut(&id).unwrap();
|
||||||
|
|
||||||
|
Some(InstanceWithMetaMut { inner, metadata })
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert_instance(
|
||||||
|
&mut self,
|
||||||
|
properties: InstancePropertiesWithMeta,
|
||||||
|
parent_id: RbxId,
|
||||||
|
) -> RbxId {
|
||||||
|
let id = self.inner.insert_instance(properties.inner, parent_id);
|
||||||
|
self.metadata.insert(id, properties.metadata);
|
||||||
|
id
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove_instance(&mut self, id: RbxId) -> Option<RojoTree> {
|
||||||
|
if let Some(inner) = self.inner.remove_instance(id) {
|
||||||
|
let mut metadata = HashMap::new();
|
||||||
|
let mut path_to_id = MapSet::new(); // TODO
|
||||||
|
|
||||||
|
let root_meta = self.metadata.remove(&id).unwrap();
|
||||||
|
|
||||||
|
metadata.insert(id, root_meta);
|
||||||
|
|
||||||
|
for instance in inner.descendants(id) {
|
||||||
|
let instance_meta = self.metadata.remove(&instance.get_id()).unwrap();
|
||||||
|
metadata.insert(instance.get_id(), instance_meta);
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(RojoTree {
|
||||||
|
inner,
|
||||||
|
metadata,
|
||||||
|
path_to_id,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct InstancePropertiesWithMeta {
|
||||||
|
pub inner: RbxInstanceProperties,
|
||||||
|
pub metadata: InstanceMetadata,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct InstanceWithMeta<'a> {
|
||||||
|
pub inner: &'a RbxInstance,
|
||||||
|
pub metadata: &'a InstanceMetadata,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct InstanceWithMetaMut<'a> {
|
||||||
|
pub inner: &'a mut RbxInstance,
|
||||||
|
pub metadata: &'a mut InstanceMetadata,
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user