avoid boxing

This commit is contained in:
Bernardo 2019-01-21 19:11:39 +01:00 committed by Aleksey Kladov
parent 277e0f1baa
commit 2a1afad3ed
3 changed files with 44 additions and 34 deletions

View File

@ -9,26 +9,27 @@ use crossbeam_channel::{Receiver, Sender};
use parking_lot::Mutex;
use relative_path::RelativePathBuf;
use thread_worker::WorkerHandle;
use walkdir::{DirEntry, WalkDir};
use walkdir::WalkDir;
mod watcher;
use watcher::Watcher;
pub use watcher::WatcherChange;
use crate::VfsRoot;
use crate::{RootFilter, VfsRoot};
pub(crate) enum Task {
AddRoot {
root: VfsRoot,
path: PathBuf,
filter: Box<Fn(&DirEntry) -> bool + Send>,
root_filter: Arc<RootFilter>,
nested_roots: Vec<PathBuf>,
},
/// this variant should only be created by the watcher
HandleChange(WatcherChange),
LoadChange(WatcherChange),
Watch {
dir: PathBuf,
filter: Box<Fn(&DirEntry) -> bool + Send>,
root_filter: Arc<RootFilter>,
},
}
@ -109,7 +110,7 @@ impl Worker {
fn watch(
watcher: &Arc<Mutex<Option<Watcher>>>,
dir: &Path,
filter_entry: impl Fn(&DirEntry) -> bool,
filter_entry: &RootFilter,
emit_for_existing: bool,
) {
let mut watcher = watcher.lock();
@ -125,10 +126,19 @@ fn watch(
fn handle_task(task: Task, watcher: &Arc<Mutex<Option<Watcher>>>) -> TaskResult {
match task {
Task::AddRoot { root, path, filter } => {
watch(watcher, &path, &*filter, false);
Task::AddRoot {
root,
path,
root_filter,
nested_roots,
} => {
watch(watcher, &path, &*root_filter, false);
log::debug!("loading {} ...", path.as_path().display());
let files = load_root(path.as_path(), &*filter);
let files = load_root(
path.as_path(),
root_filter.as_ref(),
nested_roots.as_slice(),
);
log::debug!("... loaded {}", path.as_path().display());
TaskResult::AddRoot(AddRootResult { root, files })
}
@ -143,16 +153,27 @@ fn handle_task(task: Task, watcher: &Arc<Mutex<Option<Watcher>>>) -> TaskResult
None => TaskResult::NoOp,
}
}
Task::Watch { dir, filter } => {
watch(watcher, &dir, &*filter, true);
Task::Watch { dir, root_filter } => {
watch(watcher, &dir, root_filter.as_ref(), true);
TaskResult::NoOp
}
}
}
fn load_root(root: &Path, filter: &dyn Fn(&DirEntry) -> bool) -> Vec<(RelativePathBuf, String)> {
fn load_root(
root: &Path,
root_filter: &RootFilter,
nested_roots: &[PathBuf],
) -> Vec<(RelativePathBuf, String)> {
let mut res = Vec::new();
for entry in WalkDir::new(root).into_iter().filter_entry(filter) {
for entry in WalkDir::new(root).into_iter().filter_entry(|entry| {
if entry.file_type().is_dir() && nested_roots.iter().any(|it| it == entry.path()) {
// do not load files of a nested root
false
} else {
root_filter.can_contain(entry.path()).is_some()
}
}) {
let entry = match entry {
Ok(entry) => entry,
Err(e) => {

View File

@ -1,4 +1,4 @@
use crate::io;
use crate::{io, RootFilter};
use crossbeam_channel::Sender;
use drop_bomb::DropBomb;
use notify::{DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher as NotifyWatcher};
@ -8,7 +8,7 @@ use std::{
thread,
time::Duration,
};
use walkdir::{DirEntry, WalkDir};
use walkdir::WalkDir;
#[derive(Debug)]
pub enum WatcherChange {
@ -83,13 +83,11 @@ impl Watcher {
})
}
pub fn watch_recursive(
&mut self,
dir: &Path,
filter_entry: impl Fn(&DirEntry) -> bool,
emit_for_contents: bool,
) {
for res in WalkDir::new(dir).into_iter().filter_entry(filter_entry) {
pub fn watch_recursive(&mut self, dir: &Path, filter: &RootFilter, emit_for_contents: bool) {
for res in WalkDir::new(dir)
.into_iter()
.filter_entry(|entry| filter.can_contain(entry.path()).is_some())
{
match res {
Ok(entry) => {
if entry.path().is_dir() {

View File

@ -28,7 +28,6 @@ use crossbeam_channel::Receiver;
use ra_arena::{impl_arena_id, Arena, RawId};
use relative_path::RelativePathBuf;
use rustc_hash::{FxHashMap, FxHashSet};
use walkdir::DirEntry;
pub use crate::io::TaskResult as VfsTask;
use io::{Task, TaskResult, WatcherChange, WatcherChangeData, Worker};
@ -128,23 +127,17 @@ impl Vfs {
let root = res.roots.alloc(root_filter.clone());
res.root2files.insert(root, Default::default());
let nested = roots[..i]
let nested_roots = roots[..i]
.iter()
.filter(|it| it.starts_with(path))
.map(|it| it.clone())
.collect::<Vec<_>>();
let filter = move |entry: &DirEntry| {
if entry.file_type().is_dir() && nested.iter().any(|it| it == entry.path()) {
false
} else {
root_filter.can_contain(entry.path()).is_some()
}
};
let task = io::Task::AddRoot {
root,
path: path.clone(),
filter: Box::new(filter),
root_filter,
nested_roots,
};
res.worker.sender().send(task).unwrap();
}
@ -232,13 +225,11 @@ impl Vfs {
WatcherChange::Create(path) if path.is_dir() => {
if let Some((root, _path, _file)) = self.find_root(&path) {
let root_filter = self.roots[root].clone();
let filter =
move |entry: &DirEntry| root_filter.can_contain(entry.path()).is_some();
self.worker
.sender()
.send(Task::Watch {
dir: path.to_path_buf(),
filter: Box::new(filter),
root_filter,
})
.unwrap()
}