notify/
config.rs

1//! Configuration types
2
3use std::time::Duration;
4
5/// Indicates how the path should be watched
6#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
7pub struct WatchMode {
8    /// Indicates whether to watch sub-directories as well
9    pub recursive_mode: RecursiveMode,
10    /// Indicates what happens when the relationship of the physical entity and the file path changes
11    pub target_mode: TargetMode,
12}
13
14impl WatchMode {
15    /// Creates a WatchMode that watches directories recursively and tracks the file path
16    #[must_use]
17    pub fn recursive() -> Self {
18        Self {
19            recursive_mode: RecursiveMode::Recursive,
20            target_mode: TargetMode::TrackPath,
21        }
22    }
23
24    /// Creates a WatchMode that watches only the provided directory and tracks the file path
25    #[must_use]
26    pub fn non_recursive() -> Self {
27        Self {
28            recursive_mode: RecursiveMode::NonRecursive,
29            target_mode: TargetMode::TrackPath,
30        }
31    }
32
33    pub(crate) fn upgrade_with(&mut self, other: WatchMode) {
34        self.recursive_mode = self.recursive_mode.upgraded_with(other.recursive_mode);
35        self.target_mode = self.target_mode.upgraded_with(other.target_mode);
36    }
37}
38
39/// Indicates whether only the provided directory or its sub-directories as well should be watched
40#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
41pub enum RecursiveMode {
42    /// Watch all sub-directories as well, including directories created after installing the watch
43    Recursive,
44
45    /// Watch only the provided directory
46    NonRecursive,
47}
48
49impl RecursiveMode {
50    #[expect(clippy::trivially_copy_pass_by_ref)]
51    pub(crate) fn is_recursive(&self) -> bool {
52        match *self {
53            RecursiveMode::Recursive => true,
54            RecursiveMode::NonRecursive => false,
55        }
56    }
57
58    pub(crate) fn upgraded_with(self, other: Self) -> Self {
59        match self {
60            RecursiveMode::Recursive => self,
61            RecursiveMode::NonRecursive => {
62                if other == RecursiveMode::Recursive {
63                    other
64                } else {
65                    self
66                }
67            }
68        }
69    }
70}
71
72/// Indicates what happens when the relationship of the physical entity and the file path changes
73#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
74pub enum TargetMode {
75    /// Tracks the file path.
76    ///
77    /// If the underlying physical entity (inode/File ID) at this path is replaced
78    /// (e.g., by a move/rename operation), the watch continues to monitor the new entity
79    /// that now occupies the path.
80    ///
81    /// TODO: watching nested non-existent paths is not implemented yet. <https://github.com/rolldown/notify/issues/32>
82    TrackPath,
83
84    /// Does not track the file path, nor the physical entity.
85    ///
86    /// If the underlying physical entity (inode/File ID) is replaced
87    /// (e.g., by a move/rename operation), the watch stops monitoring.
88    ///
89    /// TODO: fsevents backend and Windows backend and polling backend does not unwatch on physical entity change yet. <https://github.com/rolldown/notify/issues/33>
90    NoTrack,
91}
92
93impl TargetMode {
94    pub(crate) fn upgraded_with(self, other: Self) -> Self {
95        match self {
96            TargetMode::TrackPath => self,
97            TargetMode::NoTrack => {
98                if other == TargetMode::TrackPath {
99                    other
100                } else {
101                    self
102                }
103            }
104        }
105    }
106}
107
108/// Watcher Backend configuration
109///
110/// This contains multiple settings that may relate to only one specific backend,
111/// such as to correctly configure each backend regardless of what is selected during runtime.
112///
113/// ```rust
114/// # use std::time::Duration;
115/// # use notify::Config;
116/// let config = Config::default()
117///     .with_poll_interval(Duration::from_secs(2))
118///     .with_compare_contents(true);
119/// ```
120///
121/// Some options can be changed during runtime, others have to be set when creating the watcher backend.
122#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
123pub struct Config {
124    /// See [Config::with_poll_interval]
125    poll_interval: Option<Duration>,
126
127    /// See [Config::with_compare_contents]
128    compare_contents: bool,
129
130    follow_symlinks: bool,
131}
132
133impl Config {
134    /// For the [`PollWatcher`](crate::PollWatcher) backend.
135    ///
136    /// Interval between each re-scan attempt. This can be extremely expensive for large
137    /// file trees so it is recommended to measure and tune accordingly.
138    ///
139    /// The default poll frequency is 30 seconds.
140    ///
141    /// This will enable automatic polling, overwriting [`with_manual_polling()`](Config::with_manual_polling).
142    #[must_use]
143    pub fn with_poll_interval(mut self, dur: Duration) -> Self {
144        // TODO: v7.0 break signature to option
145        self.poll_interval = Some(dur);
146        self
147    }
148
149    /// Returns current setting
150    #[must_use]
151    pub fn poll_interval(&self) -> Option<Duration> {
152        // Changed Signature to Option
153        self.poll_interval
154    }
155
156    /// For the [`PollWatcher`](crate::PollWatcher) backend.
157    ///
158    /// Disable automatic polling. Requires calling [`crate::PollWatcher::poll()`] manually.
159    ///
160    /// This will disable automatic polling, overwriting [`with_poll_interval()`](Config::with_poll_interval).
161    #[must_use]
162    pub fn with_manual_polling(mut self) -> Self {
163        self.poll_interval = None;
164        self
165    }
166
167    /// For the [`PollWatcher`](crate::PollWatcher) backend.
168    ///
169    /// Optional feature that will evaluate the contents of changed files to determine if
170    /// they have indeed changed using a fast hashing algorithm.  This is especially important
171    /// for pseudo filesystems like those on Linux under /sys and /proc which are not obligated
172    /// to respect any other filesystem norms such as modification timestamps, file sizes, etc.
173    /// By enabling this feature, performance will be significantly impacted as all files will
174    /// need to be read and hashed at each `poll_interval`.
175    ///
176    /// This can't be changed during runtime. Off by default.
177    #[must_use]
178    pub fn with_compare_contents(mut self, compare_contents: bool) -> Self {
179        self.compare_contents = compare_contents;
180        self
181    }
182
183    /// Returns current setting
184    #[must_use]
185    pub fn compare_contents(&self) -> bool {
186        self.compare_contents
187    }
188
189    /// For the [INotifyWatcher](crate::INotifyWatcher), [KqueueWatcher](crate::KqueueWatcher),
190    /// and [PollWatcher](crate::PollWatcher).
191    ///
192    /// Determine if symbolic links should be followed when recursively watching a directory.
193    ///
194    /// This can't be changed during runtime. On by default.
195    #[must_use]
196    pub fn with_follow_symlinks(mut self, follow_symlinks: bool) -> Self {
197        self.follow_symlinks = follow_symlinks;
198        self
199    }
200
201    /// Returns current setting
202    #[must_use]
203    pub fn follow_symlinks(&self) -> bool {
204        self.follow_symlinks
205    }
206}
207
208impl Default for Config {
209    fn default() -> Self {
210        Self {
211            poll_interval: Some(Duration::from_secs(30)),
212            compare_contents: false,
213            follow_symlinks: true,
214        }
215    }
216}