mirror of
https://github.com/rojo-rbx/rojo.git
synced 2026-04-24 14:45:56 +00:00
vfs: Expand documentation
This commit is contained in:
150
vfs/src/lib.rs
150
vfs/src/lib.rs
@@ -5,7 +5,7 @@ mod std_backend;
|
|||||||
|
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex, MutexGuard};
|
||||||
|
|
||||||
pub use memory_backend::MemoryBackend;
|
pub use memory_backend::MemoryBackend;
|
||||||
pub use noop_backend::NoopBackend;
|
pub use noop_backend::NoopBackend;
|
||||||
@@ -15,6 +15,7 @@ pub use std_backend::StdBackend;
|
|||||||
mod sealed {
|
mod sealed {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
/// Sealing trait for VfsBackend.
|
||||||
pub trait Sealed {}
|
pub trait Sealed {}
|
||||||
|
|
||||||
impl Sealed for MemoryBackend {}
|
impl Sealed for MemoryBackend {}
|
||||||
@@ -22,6 +23,9 @@ mod sealed {
|
|||||||
impl Sealed for StdBackend {}
|
impl Sealed for StdBackend {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Trait that transforms `io::Result<T>` into `io::Result<Option<T>>`.
|
||||||
|
///
|
||||||
|
/// `Ok(None)` takes the place of IO errors whose `io::ErrorKind` is `NotFound`.
|
||||||
pub trait IoResultExt<T> {
|
pub trait IoResultExt<T> {
|
||||||
fn with_not_found(self) -> io::Result<Option<T>>;
|
fn with_not_found(self) -> io::Result<Option<T>>;
|
||||||
}
|
}
|
||||||
@@ -57,6 +61,9 @@ pub trait VfsBackend: sealed::Sealed + Send + 'static {
|
|||||||
fn unwatch(&mut self, path: &Path) -> io::Result<()>;
|
fn unwatch(&mut self, path: &Path) -> io::Result<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Vfs equivalent to [`std::fs::DirEntry`][std::fs::DirEntry].
|
||||||
|
///
|
||||||
|
/// [std::fs::DirEntry]: https://doc.rust-lang.org/stable/std/fs/struct.DirEntry.html
|
||||||
pub struct DirEntry {
|
pub struct DirEntry {
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
}
|
}
|
||||||
@@ -67,6 +74,9 @@ impl DirEntry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Vfs equivalent to [`std::fs::ReadDir`][std::fs::ReadDir].
|
||||||
|
///
|
||||||
|
/// [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>>>,
|
inner: Box<dyn Iterator<Item = io::Result<DirEntry>>>,
|
||||||
}
|
}
|
||||||
@@ -79,6 +89,9 @@ impl Iterator for ReadDir {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Vfs equivalent to [`std::fs::Metadata`][std::fs::Metadata].
|
||||||
|
///
|
||||||
|
/// [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,
|
is_file: bool,
|
||||||
@@ -102,57 +115,55 @@ pub enum VfsEvent {
|
|||||||
Remove(PathBuf),
|
Remove(PathBuf),
|
||||||
}
|
}
|
||||||
|
|
||||||
struct VfsLock {
|
/// Contains implementation details of the Vfs, wrapped by `Vfs` and `VfsLock`,
|
||||||
|
/// the public interfaces to this type.
|
||||||
|
struct VfsInner {
|
||||||
backend: Box<dyn VfsBackend>,
|
backend: Box<dyn VfsBackend>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VfsLock {
|
impl VfsInner {
|
||||||
pub fn read<P: AsRef<Path>>(&mut self, path: P) -> io::Result<Arc<Vec<u8>>> {
|
fn read<P: AsRef<Path>>(&mut self, path: P) -> io::Result<Arc<Vec<u8>>> {
|
||||||
let path = path.as_ref();
|
let path = path.as_ref();
|
||||||
let contents = self.backend.read(path)?;
|
let contents = self.backend.read(path)?;
|
||||||
self.backend.watch(path)?;
|
self.backend.watch(path)?;
|
||||||
Ok(Arc::new(contents))
|
Ok(Arc::new(contents))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write<P: AsRef<Path>, C: AsRef<[u8]>>(
|
fn write<P: AsRef<Path>, C: AsRef<[u8]>>(&mut self, path: P, contents: C) -> io::Result<()> {
|
||||||
&mut self,
|
|
||||||
path: P,
|
|
||||||
contents: C,
|
|
||||||
) -> io::Result<()> {
|
|
||||||
let path = path.as_ref();
|
let path = path.as_ref();
|
||||||
let contents = contents.as_ref();
|
let contents = contents.as_ref();
|
||||||
self.backend.write(path, contents)
|
self.backend.write(path, contents)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_dir<P: AsRef<Path>>(&mut self, path: P) -> io::Result<ReadDir> {
|
fn read_dir<P: AsRef<Path>>(&mut self, path: P) -> io::Result<ReadDir> {
|
||||||
let path = path.as_ref();
|
let path = path.as_ref();
|
||||||
let dir = self.backend.read_dir(path)?;
|
let dir = self.backend.read_dir(path)?;
|
||||||
self.backend.watch(path)?;
|
self.backend.watch(path)?;
|
||||||
Ok(dir)
|
Ok(dir)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_file<P: AsRef<Path>>(&mut self, path: P) -> io::Result<()> {
|
fn remove_file<P: AsRef<Path>>(&mut self, path: P) -> io::Result<()> {
|
||||||
let path = path.as_ref();
|
let path = path.as_ref();
|
||||||
let _ = self.backend.unwatch(path);
|
let _ = self.backend.unwatch(path);
|
||||||
self.backend.remove_file(path)
|
self.backend.remove_file(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_dir_all<P: AsRef<Path>>(&mut self, path: P) -> io::Result<()> {
|
fn remove_dir_all<P: AsRef<Path>>(&mut self, path: P) -> io::Result<()> {
|
||||||
let path = path.as_ref();
|
let path = path.as_ref();
|
||||||
let _ = self.backend.unwatch(path);
|
let _ = self.backend.unwatch(path);
|
||||||
self.backend.remove_dir_all(path)
|
self.backend.remove_dir_all(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn metadata<P: AsRef<Path>>(&mut self, path: P) -> io::Result<Metadata> {
|
fn metadata<P: AsRef<Path>>(&mut self, path: P) -> io::Result<Metadata> {
|
||||||
let path = path.as_ref();
|
let path = path.as_ref();
|
||||||
self.backend.metadata(path)
|
self.backend.metadata(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn event_receiver(&self) -> crossbeam_channel::Receiver<VfsEvent> {
|
fn event_receiver(&self) -> crossbeam_channel::Receiver<VfsEvent> {
|
||||||
self.backend.event_receiver()
|
self.backend.event_receiver()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn commit_event(&mut self, event: &VfsEvent) -> io::Result<()> {
|
fn commit_event(&mut self, event: &VfsEvent) -> io::Result<()> {
|
||||||
match event {
|
match event {
|
||||||
VfsEvent::Remove(path) => {
|
VfsEvent::Remove(path) => {
|
||||||
let _ = self.backend.unwatch(&path);
|
let _ = self.backend.unwatch(&path);
|
||||||
@@ -166,7 +177,7 @@ impl VfsLock {
|
|||||||
|
|
||||||
/// A virtual filesystem with a configurable backend.
|
/// A virtual filesystem with a configurable backend.
|
||||||
pub struct Vfs {
|
pub struct Vfs {
|
||||||
inner: Mutex<VfsLock>,
|
inner: Mutex<VfsInner>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Vfs {
|
impl Vfs {
|
||||||
@@ -177,7 +188,7 @@ impl Vfs {
|
|||||||
|
|
||||||
/// Creates a new `Vfs` with the given backend.
|
/// Creates a new `Vfs` with the given backend.
|
||||||
pub fn new<B: VfsBackend>(backend: B) -> Self {
|
pub fn new<B: VfsBackend>(backend: B) -> Self {
|
||||||
let lock = VfsLock {
|
let lock = VfsInner {
|
||||||
backend: Box::new(backend),
|
backend: Box::new(backend),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -186,12 +197,19 @@ impl Vfs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn lock(&self) -> VfsLock<'_> {
|
||||||
|
VfsLock {
|
||||||
|
inner: self.inner.lock().unwrap(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Read a file from the VFS, or the underlying backend if it isn't
|
/// Read a file from the VFS, or the underlying backend if it isn't
|
||||||
/// resident.
|
/// resident.
|
||||||
///
|
///
|
||||||
/// Roughly equivalent to [`std::fs::read`][std::fs::read].
|
/// Roughly equivalent to [`std::fs::read`][std::fs::read].
|
||||||
///
|
///
|
||||||
/// [std::fs::read]: https://doc.rust-lang.org/stable/std/fs/fn.read.html
|
/// [std::fs::read]: https://doc.rust-lang.org/stable/std/fs/fn.read.html
|
||||||
|
#[inline]
|
||||||
pub fn read<P: AsRef<Path>>(&self, path: P) -> io::Result<Arc<Vec<u8>>> {
|
pub fn read<P: AsRef<Path>>(&self, path: P) -> io::Result<Arc<Vec<u8>>> {
|
||||||
let path = path.as_ref();
|
let path = path.as_ref();
|
||||||
self.inner.lock().unwrap().read(path)
|
self.inner.lock().unwrap().read(path)
|
||||||
@@ -202,6 +220,7 @@ impl Vfs {
|
|||||||
/// Roughly equivalent to [`std::fs::write`][std::fs::write].
|
/// Roughly equivalent to [`std::fs::write`][std::fs::write].
|
||||||
///
|
///
|
||||||
/// [std::fs::write]: https://doc.rust-lang.org/stable/std/fs/fn.write.html
|
/// [std::fs::write]: https://doc.rust-lang.org/stable/std/fs/fn.write.html
|
||||||
|
#[inline]
|
||||||
pub fn write<P: AsRef<Path>, C: AsRef<[u8]>>(&self, path: P, contents: C) -> io::Result<()> {
|
pub fn write<P: AsRef<Path>, C: AsRef<[u8]>>(&self, path: P, contents: C) -> io::Result<()> {
|
||||||
let path = path.as_ref();
|
let path = path.as_ref();
|
||||||
let contents = contents.as_ref();
|
let contents = contents.as_ref();
|
||||||
@@ -213,6 +232,7 @@ impl Vfs {
|
|||||||
/// Roughly equivalent to [`std::fs::read_dir`][std::fs::read_dir].
|
/// Roughly equivalent to [`std::fs::read_dir`][std::fs::read_dir].
|
||||||
///
|
///
|
||||||
/// [std::fs::read_dir]: https://doc.rust-lang.org/stable/std/fs/fn.read_dir.html
|
/// [std::fs::read_dir]: https://doc.rust-lang.org/stable/std/fs/fn.read_dir.html
|
||||||
|
#[inline]
|
||||||
pub fn read_dir<P: AsRef<Path>>(&self, path: P) -> io::Result<ReadDir> {
|
pub fn read_dir<P: AsRef<Path>>(&self, path: P) -> io::Result<ReadDir> {
|
||||||
let path = path.as_ref();
|
let path = path.as_ref();
|
||||||
self.inner.lock().unwrap().read_dir(path)
|
self.inner.lock().unwrap().read_dir(path)
|
||||||
@@ -223,6 +243,7 @@ impl Vfs {
|
|||||||
/// Roughly equivalent to [`std::fs::remove_file`][std::fs::remove_file].
|
/// Roughly equivalent to [`std::fs::remove_file`][std::fs::remove_file].
|
||||||
///
|
///
|
||||||
/// [std::fs::remove_file]: https://doc.rust-lang.org/stable/std/fs/fn.remove_file.html
|
/// [std::fs::remove_file]: https://doc.rust-lang.org/stable/std/fs/fn.remove_file.html
|
||||||
|
#[inline]
|
||||||
pub fn remove_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
|
pub fn remove_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
|
||||||
let path = path.as_ref();
|
let path = path.as_ref();
|
||||||
self.inner.lock().unwrap().remove_file(path)
|
self.inner.lock().unwrap().remove_file(path)
|
||||||
@@ -233,6 +254,7 @@ impl Vfs {
|
|||||||
/// Roughly equivalent to [`std::fs::remove_dir_all`][std::fs::remove_dir_all].
|
/// Roughly equivalent to [`std::fs::remove_dir_all`][std::fs::remove_dir_all].
|
||||||
///
|
///
|
||||||
/// [std::fs::remove_dir_all]: https://doc.rust-lang.org/stable/std/fs/fn.remove_dir_all.html
|
/// [std::fs::remove_dir_all]: https://doc.rust-lang.org/stable/std/fs/fn.remove_dir_all.html
|
||||||
|
#[inline]
|
||||||
pub fn remove_dir_all<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
|
pub fn remove_dir_all<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
|
||||||
let path = path.as_ref();
|
let path = path.as_ref();
|
||||||
self.inner.lock().unwrap().remove_dir_all(path)
|
self.inner.lock().unwrap().remove_dir_all(path)
|
||||||
@@ -243,18 +265,112 @@ impl Vfs {
|
|||||||
/// Roughly equivalent to [`std::fs::metadata`][std::fs::metadata].
|
/// Roughly equivalent to [`std::fs::metadata`][std::fs::metadata].
|
||||||
///
|
///
|
||||||
/// [std::fs::metadata]: https://doc.rust-lang.org/stable/std/fs/fn.metadata.html
|
/// [std::fs::metadata]: https://doc.rust-lang.org/stable/std/fs/fn.metadata.html
|
||||||
|
#[inline]
|
||||||
pub fn metadata<P: AsRef<Path>>(&self, path: P) -> io::Result<Metadata> {
|
pub fn metadata<P: AsRef<Path>>(&self, path: P) -> io::Result<Metadata> {
|
||||||
let path = path.as_ref();
|
let path = path.as_ref();
|
||||||
self.inner.lock().unwrap().metadata(path)
|
self.inner.lock().unwrap().metadata(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieve a handle to the event receiver for this `Vfs`.
|
/// Retrieve a handle to the event receiver for this `Vfs`.
|
||||||
|
#[inline]
|
||||||
pub fn event_receiver(&self) -> crossbeam_channel::Receiver<VfsEvent> {
|
pub fn event_receiver(&self) -> crossbeam_channel::Receiver<VfsEvent> {
|
||||||
self.inner.lock().unwrap().event_receiver()
|
self.inner.lock().unwrap().event_receiver()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Commit an event to this `Vfs`.
|
/// Commit an event to this `Vfs`.
|
||||||
|
#[inline]
|
||||||
pub fn commit_event(&self, event: &VfsEvent) -> io::Result<()> {
|
pub fn commit_event(&self, event: &VfsEvent) -> io::Result<()> {
|
||||||
self.inner.lock().unwrap().commit_event(event)
|
self.inner.lock().unwrap().commit_event(event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A locked handle to a `Vfs`, created by `Vfs::lock`.
|
||||||
|
pub struct VfsLock<'a> {
|
||||||
|
inner: MutexGuard<'a, VfsInner>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VfsLock<'_> {
|
||||||
|
/// Read a file from the VFS, or the underlying backend if it isn't
|
||||||
|
/// resident.
|
||||||
|
///
|
||||||
|
/// Roughly equivalent to [`std::fs::read`][std::fs::read].
|
||||||
|
///
|
||||||
|
/// [std::fs::read]: https://doc.rust-lang.org/stable/std/fs/fn.read.html
|
||||||
|
#[inline]
|
||||||
|
pub fn read<P: AsRef<Path>>(&mut self, path: P) -> io::Result<Arc<Vec<u8>>> {
|
||||||
|
let path = path.as_ref();
|
||||||
|
self.inner.read(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Write a file to the VFS and the underlying backend.
|
||||||
|
///
|
||||||
|
/// Roughly equivalent to [`std::fs::write`][std::fs::write].
|
||||||
|
///
|
||||||
|
/// [std::fs::write]: https://doc.rust-lang.org/stable/std/fs/fn.write.html
|
||||||
|
#[inline]
|
||||||
|
pub fn write<P: AsRef<Path>, C: AsRef<[u8]>>(
|
||||||
|
&mut self,
|
||||||
|
path: P,
|
||||||
|
contents: C,
|
||||||
|
) -> io::Result<()> {
|
||||||
|
let path = path.as_ref();
|
||||||
|
let contents = contents.as_ref();
|
||||||
|
self.inner.write(path, contents)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read all of the children of a directory.
|
||||||
|
///
|
||||||
|
/// Roughly equivalent to [`std::fs::read_dir`][std::fs::read_dir].
|
||||||
|
///
|
||||||
|
/// [std::fs::read_dir]: https://doc.rust-lang.org/stable/std/fs/fn.read_dir.html
|
||||||
|
#[inline]
|
||||||
|
pub fn read_dir<P: AsRef<Path>>(&mut self, path: P) -> io::Result<ReadDir> {
|
||||||
|
let path = path.as_ref();
|
||||||
|
self.inner.read_dir(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove a file.
|
||||||
|
///
|
||||||
|
/// Roughly equivalent to [`std::fs::remove_file`][std::fs::remove_file].
|
||||||
|
///
|
||||||
|
/// [std::fs::remove_file]: https://doc.rust-lang.org/stable/std/fs/fn.remove_file.html
|
||||||
|
#[inline]
|
||||||
|
pub fn remove_file<P: AsRef<Path>>(&mut self, path: P) -> io::Result<()> {
|
||||||
|
let path = path.as_ref();
|
||||||
|
self.inner.remove_file(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove a directory and all of its descendants.
|
||||||
|
///
|
||||||
|
/// Roughly equivalent to [`std::fs::remove_dir_all`][std::fs::remove_dir_all].
|
||||||
|
///
|
||||||
|
/// [std::fs::remove_dir_all]: https://doc.rust-lang.org/stable/std/fs/fn.remove_dir_all.html
|
||||||
|
#[inline]
|
||||||
|
pub fn remove_dir_all<P: AsRef<Path>>(&mut self, path: P) -> io::Result<()> {
|
||||||
|
let path = path.as_ref();
|
||||||
|
self.inner.remove_dir_all(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Query metadata about the given path.
|
||||||
|
///
|
||||||
|
/// Roughly equivalent to [`std::fs::metadata`][std::fs::metadata].
|
||||||
|
///
|
||||||
|
/// [std::fs::metadata]: https://doc.rust-lang.org/stable/std/fs/fn.metadata.html
|
||||||
|
#[inline]
|
||||||
|
pub fn metadata<P: AsRef<Path>>(&mut self, path: P) -> io::Result<Metadata> {
|
||||||
|
let path = path.as_ref();
|
||||||
|
self.inner.metadata(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieve a handle to the event receiver for this `Vfs`.
|
||||||
|
#[inline]
|
||||||
|
pub fn event_receiver(&self) -> crossbeam_channel::Receiver<VfsEvent> {
|
||||||
|
self.inner.event_receiver()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Commit an event to this `Vfs`.
|
||||||
|
#[inline]
|
||||||
|
pub fn commit_event(&mut self, event: &VfsEvent) -> io::Result<()> {
|
||||||
|
self.inner.commit_event(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ use std::path::{Path, PathBuf};
|
|||||||
|
|
||||||
use crate::{Metadata, ReadDir, VfsBackend, VfsEvent, VfsSnapshot};
|
use crate::{Metadata, ReadDir, VfsBackend, VfsEvent, VfsSnapshot};
|
||||||
|
|
||||||
/// `VfsBackend` that reads from an in-memory filesystem.
|
/// `VfsBackend` that reads from an in-memory filesystem, intended for setting
|
||||||
|
/// up testing scenarios quickly.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[non_exhaustive]
|
|
||||||
pub struct MemoryBackend {
|
pub struct MemoryBackend {
|
||||||
entries: HashMap<PathBuf, Entry>,
|
entries: HashMap<PathBuf, Entry>,
|
||||||
orphans: BTreeSet<PathBuf>,
|
orphans: BTreeSet<PathBuf>,
|
||||||
|
|||||||
Reference in New Issue
Block a user