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 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}