From b4963f4ff7afaf9fb432a8ff7d2d8241ba6faae4 Mon Sep 17 00:00:00 2001 From: Lucien Greathouse Date: Tue, 18 Feb 2020 22:42:31 -0800 Subject: [PATCH] Watching --- vfs/src/lib.rs | 24 +++++++++++++++++------- vfs/src/noop_backend.rs | 29 +++++++++++++++++++++++++---- vfs/src/std_backend.rs | 41 ++++++++++++++++++++++++++++++++++++----- 3 files changed, 78 insertions(+), 16 deletions(-) diff --git a/vfs/src/lib.rs b/vfs/src/lib.rs index 7246111f..836e4443 100644 --- a/vfs/src/lib.rs +++ b/vfs/src/lib.rs @@ -8,11 +8,23 @@ use std::sync::{Arc, Mutex}; pub use noop_backend::NoopBackend; pub use std_backend::StdBackend; -pub trait VfsBackend { - fn read(&self, path: &Path) -> io::Result>; - fn write(&self, path: &Path, data: &[u8]) -> io::Result<()>; - fn read_dir(&self, path: &Path) -> io::Result; - fn metadata(&self, path: &Path) -> io::Result; +mod sealed { + use super::*; + + pub trait Sealed {} + + impl Sealed for NoopBackend {} + impl Sealed for StdBackend {} +} + +pub trait VfsBackend: sealed::Sealed { + fn read(&mut self, path: &Path) -> io::Result>; + fn write(&mut self, path: &Path, data: &[u8]) -> io::Result<()>; + fn read_dir(&mut self, path: &Path) -> io::Result; + fn metadata(&mut self, path: &Path) -> io::Result; + + fn watch(&mut self, path: &Path) -> io::Result<()>; + fn unwatch(&mut self, path: &Path) -> io::Result<()>; } pub struct DirEntry { @@ -52,7 +64,6 @@ impl Metadata { } struct VfsLock { - data: (), backend: Box, } @@ -86,7 +97,6 @@ pub struct Vfs { impl Vfs { pub fn new(backend: B) -> Self { let lock = VfsLock { - data: (), backend: Box::new(backend), }; diff --git a/vfs/src/noop_backend.rs b/vfs/src/noop_backend.rs index 95e66205..7b210f28 100644 --- a/vfs/src/noop_backend.rs +++ b/vfs/src/noop_backend.rs @@ -3,31 +3,52 @@ use std::path::Path; use crate::{Metadata, ReadDir, VfsBackend}; +#[non_exhaustive] pub struct NoopBackend; +impl NoopBackend { + pub fn new() -> Self { + Self + } +} + impl VfsBackend for NoopBackend { - fn read(&self, path: &Path) -> io::Result> { + fn read(&mut self, _path: &Path) -> io::Result> { Err(io::Error::new( io::ErrorKind::Other, "NoopBackend doesn't do anything", )) } - fn write(&self, path: &Path, data: &[u8]) -> io::Result<()> { + fn write(&mut self, _path: &Path, _data: &[u8]) -> io::Result<()> { Err(io::Error::new( io::ErrorKind::Other, "NoopBackend doesn't do anything", )) } - fn read_dir(&self, path: &Path) -> io::Result { + fn read_dir(&mut self, _path: &Path) -> io::Result { Err(io::Error::new( io::ErrorKind::Other, "NoopBackend doesn't do anything", )) } - fn metadata(&self, path: &Path) -> io::Result { + fn metadata(&mut self, _path: &Path) -> io::Result { + Err(io::Error::new( + io::ErrorKind::Other, + "NoopBackend doesn't do anything", + )) + } + + fn watch(&mut self, _path: &Path) -> io::Result<()> { + Err(io::Error::new( + io::ErrorKind::Other, + "NoopBackend doesn't do anything", + )) + } + + fn unwatch(&mut self, _path: &Path) -> io::Result<()> { Err(io::Error::new( io::ErrorKind::Other, "NoopBackend doesn't do anything", diff --git a/vfs/src/std_backend.rs b/vfs/src/std_backend.rs index 1e2d4f6d..940b7b8f 100644 --- a/vfs/src/std_backend.rs +++ b/vfs/src/std_backend.rs @@ -1,21 +1,40 @@ use std::fs; use std::io; use std::path::Path; +use std::sync::mpsc; +use std::time::Duration; + +use notify::{watcher, DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher}; use crate::{DirEntry, Metadata, ReadDir, VfsBackend}; -pub struct StdBackend; +pub struct StdBackend { + watcher: RecommendedWatcher, + watcher_receiver: mpsc::Receiver, +} + +impl StdBackend { + pub fn new() -> StdBackend { + let (tx, rx) = mpsc::channel(); + let watcher = watcher(tx, Duration::from_millis(50)).unwrap(); + + Self { + watcher, + watcher_receiver: rx, + } + } +} impl VfsBackend for StdBackend { - fn read(&self, path: &Path) -> io::Result> { + fn read(&mut self, path: &Path) -> io::Result> { fs::read(path) } - fn write(&self, path: &Path, data: &[u8]) -> io::Result<()> { + fn write(&mut self, path: &Path, data: &[u8]) -> io::Result<()> { fs::write(path, data) } - fn read_dir(&self, path: &Path) -> io::Result { + fn read_dir(&mut self, path: &Path) -> io::Result { let inner = fs::read_dir(path)?.map(|entry| { Ok(DirEntry { path: entry?.path(), @@ -27,11 +46,23 @@ impl VfsBackend for StdBackend { }) } - fn metadata(&self, path: &Path) -> io::Result { + fn metadata(&mut self, path: &Path) -> io::Result { let inner = fs::metadata(path)?; Ok(Metadata { is_file: inner.is_file(), }) } + + fn watch(&mut self, path: &Path) -> io::Result<()> { + self.watcher + .watch(path, RecursiveMode::NonRecursive) + .map_err(|inner| io::Error::new(io::ErrorKind::Other, inner)) + } + + fn unwatch(&mut self, path: &Path) -> io::Result<()> { + self.watcher + .unwatch(path) + .map_err(|inner| io::Error::new(io::ErrorKind::Other, inner)) + } }