mirror of
https://github.com/rojo-rbx/rojo.git
synced 2026-04-20 12:45:05 +00:00
vfs: Flesh out MemoryBackend
This commit is contained in:
@@ -65,7 +65,7 @@ pub trait VfsBackend: sealed::Sealed + Send + 'static {
|
||||
///
|
||||
/// [std::fs::DirEntry]: https://doc.rust-lang.org/stable/std/fs/struct.DirEntry.html
|
||||
pub struct DirEntry {
|
||||
path: PathBuf,
|
||||
pub(crate) path: PathBuf,
|
||||
}
|
||||
|
||||
impl DirEntry {
|
||||
@@ -78,7 +78,7 @@ impl DirEntry {
|
||||
///
|
||||
/// [std::fs::ReadDir]: https://doc.rust-lang.org/stable/std/fs/struct.ReadDir.html
|
||||
pub struct ReadDir {
|
||||
inner: Box<dyn Iterator<Item = io::Result<DirEntry>>>,
|
||||
pub(crate) inner: Box<dyn Iterator<Item = io::Result<DirEntry>>>,
|
||||
}
|
||||
|
||||
impl Iterator for ReadDir {
|
||||
@@ -94,7 +94,7 @@ impl Iterator for ReadDir {
|
||||
/// [std::fs::Metadata]: https://doc.rust-lang.org/stable/std/fs/struct.Metadata.html
|
||||
#[derive(Debug)]
|
||||
pub struct Metadata {
|
||||
is_file: bool,
|
||||
pub(crate) is_file: bool,
|
||||
}
|
||||
|
||||
impl Metadata {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use std::collections::{BTreeSet, HashMap};
|
||||
use std::collections::{BTreeSet, HashMap, VecDeque};
|
||||
use std::io;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use crate::{Metadata, ReadDir, VfsBackend, VfsEvent, VfsSnapshot};
|
||||
use crate::{DirEntry, Metadata, ReadDir, VfsBackend, VfsEvent, VfsSnapshot};
|
||||
|
||||
/// `VfsBackend` that reads from an in-memory filesystem, intended for setting
|
||||
/// up testing scenarios quickly.
|
||||
@@ -20,7 +20,11 @@ impl MemoryBackend {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_snapshot<P: Into<PathBuf>>(&mut self, path: P, snapshot: VfsSnapshot) {
|
||||
pub fn load_snapshot<P: Into<PathBuf>>(
|
||||
&mut self,
|
||||
path: P,
|
||||
snapshot: VfsSnapshot,
|
||||
) -> io::Result<()> {
|
||||
let path = path.into();
|
||||
|
||||
if let Some(parent_path) = path.parent() {
|
||||
@@ -28,10 +32,7 @@ impl MemoryBackend {
|
||||
if let Entry::Dir { children } = parent_entry {
|
||||
children.insert(path.clone());
|
||||
} else {
|
||||
panic!(
|
||||
"Tried to load snapshot as child of file, {}",
|
||||
parent_path.display()
|
||||
);
|
||||
return must_be_dir(parent_path);
|
||||
}
|
||||
} else {
|
||||
self.orphans.insert(path.clone());
|
||||
@@ -54,10 +55,25 @@ impl MemoryBackend {
|
||||
|
||||
for (child_name, child) in children {
|
||||
let full_path = path.join(child_name);
|
||||
self.load_snapshot(full_path, child);
|
||||
self.load_snapshot(full_path, child)?;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn remove(&mut self, root_path: PathBuf) {
|
||||
self.orphans.remove(&root_path);
|
||||
|
||||
let mut to_remove = VecDeque::new();
|
||||
to_remove.push_back(root_path);
|
||||
|
||||
while let Some(path) = to_remove.pop_front() {
|
||||
if let Some(Entry::Dir { children }) = self.entries.remove(&path) {
|
||||
to_remove.extend(children);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,46 +85,68 @@ enum Entry {
|
||||
}
|
||||
|
||||
impl VfsBackend for MemoryBackend {
|
||||
fn read(&mut self, _path: &Path) -> io::Result<Vec<u8>> {
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"MemoryBackend doesn't do anything",
|
||||
))
|
||||
fn read(&mut self, path: &Path) -> io::Result<Vec<u8>> {
|
||||
match self.entries.get(path) {
|
||||
Some(Entry::File { contents }) => Ok(contents.clone()),
|
||||
Some(Entry::Dir { .. }) => must_be_file(path),
|
||||
None => not_found(path),
|
||||
}
|
||||
}
|
||||
|
||||
fn write(&mut self, _path: &Path, _data: &[u8]) -> io::Result<()> {
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"MemoryBackend doesn't do anything",
|
||||
))
|
||||
fn write(&mut self, path: &Path, data: &[u8]) -> io::Result<()> {
|
||||
self.load_snapshot(
|
||||
path,
|
||||
VfsSnapshot::File {
|
||||
contents: data.to_owned(),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn read_dir(&mut self, _path: &Path) -> io::Result<ReadDir> {
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"MemoryBackend doesn't do anything",
|
||||
))
|
||||
fn read_dir(&mut self, path: &Path) -> io::Result<ReadDir> {
|
||||
match self.entries.get(path) {
|
||||
Some(Entry::Dir { children }) => {
|
||||
let iter = children
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(|path| Ok(DirEntry { path }));
|
||||
|
||||
Ok(ReadDir {
|
||||
inner: Box::new(iter),
|
||||
})
|
||||
}
|
||||
Some(Entry::File { .. }) => must_be_dir(path),
|
||||
None => not_found(path),
|
||||
}
|
||||
}
|
||||
|
||||
fn remove_file(&mut self, _path: &Path) -> io::Result<()> {
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"MemoryBackend doesn't do anything",
|
||||
))
|
||||
fn remove_file(&mut self, path: &Path) -> io::Result<()> {
|
||||
match self.entries.get(path) {
|
||||
Some(Entry::File { .. }) => {
|
||||
self.remove(path.to_owned());
|
||||
Ok(())
|
||||
}
|
||||
Some(Entry::Dir { .. }) => must_be_file(path),
|
||||
None => not_found(path),
|
||||
}
|
||||
}
|
||||
|
||||
fn remove_dir_all(&mut self, _path: &Path) -> io::Result<()> {
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"MemoryBackend doesn't do anything",
|
||||
))
|
||||
fn remove_dir_all(&mut self, path: &Path) -> io::Result<()> {
|
||||
match self.entries.get(path) {
|
||||
Some(Entry::Dir { .. }) => {
|
||||
self.remove(path.to_owned());
|
||||
Ok(())
|
||||
}
|
||||
Some(Entry::File { .. }) => must_be_dir(path),
|
||||
None => not_found(path),
|
||||
}
|
||||
}
|
||||
|
||||
fn metadata(&mut self, _path: &Path) -> io::Result<Metadata> {
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"MemoryBackend doesn't do anything",
|
||||
))
|
||||
fn metadata(&mut self, path: &Path) -> io::Result<Metadata> {
|
||||
match self.entries.get(path) {
|
||||
Some(Entry::File { .. }) => Ok(Metadata { is_file: true }),
|
||||
Some(Entry::Dir { .. }) => Ok(Metadata { is_file: false }),
|
||||
None => not_found(path),
|
||||
}
|
||||
}
|
||||
|
||||
fn event_receiver(&self) -> crossbeam_channel::Receiver<VfsEvent> {
|
||||
@@ -116,16 +154,37 @@ impl VfsBackend for MemoryBackend {
|
||||
}
|
||||
|
||||
fn watch(&mut self, _path: &Path) -> io::Result<()> {
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"MemoryBackend doesn't do anything",
|
||||
))
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn unwatch(&mut self, _path: &Path) -> io::Result<()> {
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"MemoryBackend doesn't do anything",
|
||||
))
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn must_be_file<T>(path: &Path) -> io::Result<T> {
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!(
|
||||
"path {} was a directory, but must be a file",
|
||||
path.display()
|
||||
),
|
||||
))
|
||||
}
|
||||
|
||||
fn must_be_dir<T>(path: &Path) -> io::Result<T> {
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!(
|
||||
"path {} was a file, but must be a directory",
|
||||
path.display()
|
||||
),
|
||||
))
|
||||
}
|
||||
|
||||
fn not_found<T>(path: &Path) -> io::Result<T> {
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::NotFound,
|
||||
format!("path {} not found", path.display()),
|
||||
))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user