mac_watcher.rs

 1use crate::Watcher;
 2use anyhow::{Context as _, Result};
 3use collections::{BTreeMap, Bound};
 4use fsevent::EventStream;
 5use parking_lot::Mutex;
 6use std::{
 7    path::{Path, PathBuf},
 8    sync::Weak,
 9    time::Duration,
10};
11
12pub struct MacWatcher {
13    events_tx: smol::channel::Sender<Vec<fsevent::Event>>,
14    handles: Weak<Mutex<BTreeMap<PathBuf, fsevent::Handle>>>,
15    latency: Duration,
16}
17
18impl MacWatcher {
19    pub fn new(
20        events_tx: smol::channel::Sender<Vec<fsevent::Event>>,
21        handles: Weak<Mutex<BTreeMap<PathBuf, fsevent::Handle>>>,
22        latency: Duration,
23    ) -> Self {
24        Self {
25            events_tx,
26            handles,
27            latency,
28        }
29    }
30}
31
32impl Watcher for MacWatcher {
33    fn add(&self, path: &Path) -> Result<()> {
34        let handles = self
35            .handles
36            .upgrade()
37            .context("unable to watch path, receiver dropped")?;
38        let mut handles = handles.lock();
39
40        // Return early if an ancestor of this path was already being watched.
41        if let Some((watched_path, _)) = handles
42            .range::<Path, _>((Bound::Unbounded, Bound::Included(path)))
43            .next_back()
44        {
45            if path.starts_with(watched_path) {
46                return Ok(());
47            }
48        }
49
50        let (stream, handle) = EventStream::new(&[path], self.latency);
51        let tx = self.events_tx.clone();
52        std::thread::spawn(move || {
53            stream.run(move |events| smol::block_on(tx.send(events)).is_ok());
54        });
55        handles.insert(path.into(), handle);
56
57        Ok(())
58    }
59
60    fn remove(&self, path: &Path) -> anyhow::Result<()> {
61        let handles = self
62            .handles
63            .upgrade()
64            .context("unable to remove path, receiver dropped")?;
65
66        let mut handles = handles.lock();
67        handles.remove(path);
68        Ok(())
69    }
70}