mirror of
https://github.com/rojo-rbx/rojo.git
synced 2026-04-23 22:25:26 +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
|
/// [std::fs::DirEntry]: https://doc.rust-lang.org/stable/std/fs/struct.DirEntry.html
|
||||||
pub struct DirEntry {
|
pub struct DirEntry {
|
||||||
path: PathBuf,
|
pub(crate) path: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DirEntry {
|
impl DirEntry {
|
||||||
@@ -78,7 +78,7 @@ impl DirEntry {
|
|||||||
///
|
///
|
||||||
/// [std::fs::ReadDir]: https://doc.rust-lang.org/stable/std/fs/struct.ReadDir.html
|
/// [std::fs::ReadDir]: https://doc.rust-lang.org/stable/std/fs/struct.ReadDir.html
|
||||||
pub struct ReadDir {
|
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 {
|
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
|
/// [std::fs::Metadata]: https://doc.rust-lang.org/stable/std/fs/struct.Metadata.html
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Metadata {
|
pub struct Metadata {
|
||||||
is_file: bool,
|
pub(crate) is_file: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Metadata {
|
impl Metadata {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use std::collections::{BTreeSet, HashMap};
|
use std::collections::{BTreeSet, HashMap, VecDeque};
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::path::{Path, PathBuf};
|
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
|
/// `VfsBackend` that reads from an in-memory filesystem, intended for setting
|
||||||
/// up testing scenarios quickly.
|
/// 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();
|
let path = path.into();
|
||||||
|
|
||||||
if let Some(parent_path) = path.parent() {
|
if let Some(parent_path) = path.parent() {
|
||||||
@@ -28,10 +32,7 @@ impl MemoryBackend {
|
|||||||
if let Entry::Dir { children } = parent_entry {
|
if let Entry::Dir { children } = parent_entry {
|
||||||
children.insert(path.clone());
|
children.insert(path.clone());
|
||||||
} else {
|
} else {
|
||||||
panic!(
|
return must_be_dir(parent_path);
|
||||||
"Tried to load snapshot as child of file, {}",
|
|
||||||
parent_path.display()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.orphans.insert(path.clone());
|
self.orphans.insert(path.clone());
|
||||||
@@ -54,10 +55,25 @@ impl MemoryBackend {
|
|||||||
|
|
||||||
for (child_name, child) in children {
|
for (child_name, child) in children {
|
||||||
let full_path = path.join(child_name);
|
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 {
|
impl VfsBackend for MemoryBackend {
|
||||||
fn read(&mut self, _path: &Path) -> io::Result<Vec<u8>> {
|
fn read(&mut self, path: &Path) -> io::Result<Vec<u8>> {
|
||||||
Err(io::Error::new(
|
match self.entries.get(path) {
|
||||||
io::ErrorKind::Other,
|
Some(Entry::File { contents }) => Ok(contents.clone()),
|
||||||
"MemoryBackend doesn't do anything",
|
Some(Entry::Dir { .. }) => must_be_file(path),
|
||||||
))
|
None => not_found(path),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write(&mut self, _path: &Path, _data: &[u8]) -> io::Result<()> {
|
fn write(&mut self, path: &Path, data: &[u8]) -> io::Result<()> {
|
||||||
Err(io::Error::new(
|
self.load_snapshot(
|
||||||
io::ErrorKind::Other,
|
path,
|
||||||
"MemoryBackend doesn't do anything",
|
VfsSnapshot::File {
|
||||||
))
|
contents: data.to_owned(),
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_dir(&mut self, _path: &Path) -> io::Result<ReadDir> {
|
fn read_dir(&mut self, path: &Path) -> io::Result<ReadDir> {
|
||||||
Err(io::Error::new(
|
match self.entries.get(path) {
|
||||||
io::ErrorKind::Other,
|
Some(Entry::Dir { children }) => {
|
||||||
"MemoryBackend doesn't do anything",
|
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<()> {
|
fn remove_file(&mut self, path: &Path) -> io::Result<()> {
|
||||||
Err(io::Error::new(
|
match self.entries.get(path) {
|
||||||
io::ErrorKind::Other,
|
Some(Entry::File { .. }) => {
|
||||||
"MemoryBackend doesn't do anything",
|
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<()> {
|
fn remove_dir_all(&mut self, path: &Path) -> io::Result<()> {
|
||||||
Err(io::Error::new(
|
match self.entries.get(path) {
|
||||||
io::ErrorKind::Other,
|
Some(Entry::Dir { .. }) => {
|
||||||
"MemoryBackend doesn't do anything",
|
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> {
|
fn metadata(&mut self, path: &Path) -> io::Result<Metadata> {
|
||||||
Err(io::Error::new(
|
match self.entries.get(path) {
|
||||||
io::ErrorKind::Other,
|
Some(Entry::File { .. }) => Ok(Metadata { is_file: true }),
|
||||||
"MemoryBackend doesn't do anything",
|
Some(Entry::Dir { .. }) => Ok(Metadata { is_file: false }),
|
||||||
))
|
None => not_found(path),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn event_receiver(&self) -> crossbeam_channel::Receiver<VfsEvent> {
|
fn event_receiver(&self) -> crossbeam_channel::Receiver<VfsEvent> {
|
||||||
@@ -116,16 +154,37 @@ impl VfsBackend for MemoryBackend {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn watch(&mut self, _path: &Path) -> io::Result<()> {
|
fn watch(&mut self, _path: &Path) -> io::Result<()> {
|
||||||
Err(io::Error::new(
|
Ok(())
|
||||||
io::ErrorKind::Other,
|
|
||||||
"MemoryBackend doesn't do anything",
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unwatch(&mut self, _path: &Path) -> io::Result<()> {
|
fn unwatch(&mut self, _path: &Path) -> io::Result<()> {
|
||||||
Err(io::Error::new(
|
Ok(())
|
||||||
io::ErrorKind::Other,
|
|
||||||
"MemoryBackend doesn't do anything",
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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