Files
rojo/src/snapshot_middleware/rbxm.rs
Lucien Greathouse 82678235ab VFS Improvements (#259)
This PR refactors all of the methods on `Vfs` from accepting `&mut self` to
accepting `&self` and keeping data wrapped in a mutex. This builds on previous
changes to make reference count file contents and cleans up the last places
where we're returning borrowed data out of the VFS interface.

Once this change lands, there are two possible directions we can go that I see:
* Conservative: Refactor all remaining `&mut Vfs` handles to `&Vfs`
* Interesting: Embrace ref counting by changing `Vfs` methods to accept `self:
  Arc<Self>`, which makes the `VfsEntry` API no longer need an explicit `Vfs`
  argument for its operations.

* Change VfsFetcher to be immutable with internal locking
* Refactor Vfs::would_be_resident
* Refactor Vfs::read_if_not_exists
* Refactor Vfs::raise_file_removed
* Refactor Vfs::raise_file_changed
* Add Vfs::get_internal as bits of Vfs::get
* Switch Vfs to use internal locking
* Migrate all Vfs methods from &mut self to &self
* Make VfsEntry access Vfs immutably
* Remove outer VFS locking (#260)
* Refactor all snapshot middleware to accept &Vfs instead of &mut Vfs
* Remove outer VFS Mutex across the board
2019-10-16 15:45:23 -07:00

89 lines
2.9 KiB
Rust

use std::{borrow::Cow, collections::HashMap};
use rbx_dom_weak::{RbxInstanceProperties, RbxTree};
use crate::{
snapshot::InstanceSnapshot,
vfs::{Vfs, VfsEntry, VfsFetcher},
};
use super::{
context::InstanceSnapshotContext,
middleware::{SnapshotInstanceResult, SnapshotMiddleware},
util::match_file_name,
};
pub struct SnapshotRbxm;
impl SnapshotMiddleware for SnapshotRbxm {
fn from_vfs<F: VfsFetcher>(
_context: &mut InstanceSnapshotContext,
vfs: &Vfs<F>,
entry: &VfsEntry,
) -> SnapshotInstanceResult<'static> {
if entry.is_directory() {
return Ok(None);
}
let instance_name = match match_file_name(entry.path(), ".rbxm") {
Some(name) => name,
None => return Ok(None),
};
let mut temp_tree = RbxTree::new(RbxInstanceProperties {
name: "DataModel".to_owned(),
class_name: "DataModel".to_owned(),
properties: HashMap::new(),
});
let root_id = temp_tree.get_root_id();
rbx_binary::decode(&mut temp_tree, root_id, entry.contents(vfs)?.as_slice())
.expect("TODO: Handle rbx_binary errors");
let root_instance = temp_tree.get_instance(root_id).unwrap();
let children = root_instance.get_children_ids();
if children.len() == 1 {
let mut snapshot = InstanceSnapshot::from_tree(&temp_tree, children[0]);
snapshot.name = Cow::Owned(instance_name.to_owned());
snapshot.metadata.instigating_source = Some(entry.path().to_path_buf().into());
snapshot.metadata.relevant_paths = vec![entry.path().to_path_buf()];
Ok(Some(snapshot))
} else {
panic!("Rojo doesn't have support for model files with zero or more than one top-level instances yet.");
}
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::vfs::{NoopFetcher, VfsDebug, VfsSnapshot};
#[test]
fn model_from_vfs() {
let mut vfs = Vfs::new(NoopFetcher);
let file = VfsSnapshot::file(include_bytes!("../../assets/test-folder.rbxm").to_vec());
vfs.debug_load_snapshot("/foo.rbxm", file);
let entry = vfs.get("/foo.rbxm").unwrap();
let instance_snapshot =
SnapshotRbxm::from_vfs(&mut InstanceSnapshotContext::default(), &mut vfs, &entry)
.unwrap()
.unwrap();
assert_eq!(instance_snapshot.name, "foo");
assert_eq!(instance_snapshot.class_name, "Folder");
assert_eq!(instance_snapshot.children, Vec::new());
// We intentionally don't assert on properties. rbx_binary does not
// distinguish between String and BinaryString. The sample model was
// created by Roblox Studio and has an empty BinaryString "Tags"
// property that currently deserializes incorrectly.
// See: https://github.com/rojo-rbx/rbx-dom/issues/49
}
}