1 // This file is dual-licensed under the Artistic License 2.0 as per the
2 // LICENSE.ARTISTIC file, and the Creative Commons Zero 1.0 license.
3 //! The `Event` type and the hierarchical `EventKind` descriptor.
4 
5 use std::{
6     fmt,
7     hash::{Hash, Hasher},
8     path::PathBuf,
9 };
10 
11 #[cfg(feature = "serde")]
12 use serde::{Deserialize, Serialize};
13 
14 /// An event describing open or close operations on files.
15 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
16 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
17 #[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
18 pub enum AccessMode {
19     /// The catch-all case, to be used when the specific kind of event is unknown.
20     Any,
21 
22     /// An event emitted when the file is executed, or the folder opened.
23     Execute,
24 
25     /// An event emitted when the file is opened for reading.
26     Read,
27 
28     /// An event emitted when the file is opened for writing.
29     Write,
30 
31     /// An event which specific kind is known but cannot be represented otherwise.
32     Other,
33 }
34 
35 /// An event describing non-mutating access operations on files.
36 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
37 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
38 #[cfg_attr(feature = "serde", serde(tag = "kind", content = "mode"))]
39 #[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
40 pub enum AccessKind {
41     /// The catch-all case, to be used when the specific kind of event is unknown.
42     Any,
43 
44     /// An event emitted when the file is read.
45     Read,
46 
47     /// An event emitted when the file, or a handle to the file, is opened.
48     Open(AccessMode),
49 
50     /// An event emitted when the file, or a handle to the file, is closed.
51     Close(AccessMode),
52 
53     /// An event which specific kind is known but cannot be represented otherwise.
54     Other,
55 }
56 
57 /// An event describing creation operations on files.
58 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
59 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
60 #[cfg_attr(feature = "serde", serde(tag = "kind"))]
61 #[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
62 pub enum CreateKind {
63     /// The catch-all case, to be used when the specific kind of event is unknown.
64     Any,
65 
66     /// An event which results in the creation of a file.
67     File,
68 
69     /// An event which results in the creation of a folder.
70     Folder,
71 
72     /// An event which specific kind is known but cannot be represented otherwise.
73     Other,
74 }
75 
76 /// An event emitted when the data content of a file is changed.
77 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
78 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
79 #[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
80 pub enum DataChange {
81     /// The catch-all case, to be used when the specific kind of event is unknown.
82     Any,
83 
84     /// An event emitted when the size of the data is changed.
85     Size,
86 
87     /// An event emitted when the content of the data is changed.
88     Content,
89 
90     /// An event which specific kind is known but cannot be represented otherwise.
91     Other,
92 }
93 
94 /// An event emitted when the metadata of a file or folder is changed.
95 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
96 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
97 #[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
98 pub enum MetadataKind {
99     /// The catch-all case, to be used when the specific kind of event is unknown.
100     Any,
101 
102     /// An event emitted when the access time of the file or folder is changed.
103     AccessTime,
104 
105     /// An event emitted when the write or modify time of the file or folder is changed.
106     WriteTime,
107 
108     /// An event emitted when the permissions of the file or folder are changed.
109     Permissions,
110 
111     /// An event emitted when the ownership of the file or folder is changed.
112     Ownership,
113 
114     /// An event emitted when an extended attribute of the file or folder is changed.
115     ///
116     /// If the extended attribute's name or type is known, it should be provided in the
117     /// `Info` event attribute.
118     Extended,
119 
120     /// An event which specific kind is known but cannot be represented otherwise.
121     Other,
122 }
123 
124 /// An event emitted when the name of a file or folder is changed.
125 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
126 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
127 #[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
128 pub enum RenameMode {
129     /// The catch-all case, to be used when the specific kind of event is unknown.
130     Any,
131 
132     /// An event emitted on the file or folder resulting from a rename.
133     To,
134 
135     /// An event emitted on the file or folder that was renamed.
136     From,
137 
138     /// A single event emitted with both the `From` and `To` paths.
139     ///
140     /// This event should be emitted when both source and target are known. The paths should be
141     /// provided in this exact order (from, to).
142     Both,
143 
144     /// An event which specific kind is known but cannot be represented otherwise.
145     Other,
146 }
147 
148 /// An event describing mutation of content, name, or metadata.
149 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
150 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
151 #[cfg_attr(feature = "serde", serde(tag = "kind", content = "mode"))]
152 #[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
153 pub enum ModifyKind {
154     /// The catch-all case, to be used when the specific kind of event is unknown.
155     Any,
156 
157     /// An event emitted when the data content of a file is changed.
158     Data(DataChange),
159 
160     /// An event emitted when the metadata of a file or folder is changed.
161     Metadata(MetadataKind),
162 
163     /// An event emitted when the name of a file or folder is changed.
164     #[cfg_attr(feature = "serde", serde(rename = "rename"))]
165     Name(RenameMode),
166 
167     /// An event which specific kind is known but cannot be represented otherwise.
168     Other,
169 }
170 
171 /// An event describing removal operations on files.
172 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
173 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
174 #[cfg_attr(feature = "serde", serde(tag = "kind"))]
175 #[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
176 pub enum RemoveKind {
177     /// The catch-all case, to be used when the specific kind of event is unknown.
178     Any,
179 
180     /// An event emitted when a file is removed.
181     File,
182 
183     /// An event emitted when a folder is removed.
184     Folder,
185 
186     /// An event which specific kind is known but cannot be represented otherwise.
187     Other,
188 }
189 
190 /// Top-level event kind.
191 ///
192 /// This is arguably the most important classification for events. All subkinds below this one
193 /// represent details that may or may not be available for any particular backend, but most tools
194 /// and Notify systems will only care about which of these four general kinds an event is about.
195 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
196 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
197 #[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
198 pub enum EventKind {
199     /// The catch-all event kind, for unsupported/unknown events.
200     ///
201     /// This variant should be used as the "else" case when mapping native kernel bitmasks or
202     /// bitmaps, such that if the mask is ever extended with new event types the backend will not
203     /// gain bugs due to not matching new unknown event types.
204     ///
205     /// This variant is also the default variant used when Notify is in "imprecise" mode.
206     Any,
207 
208     /// An event describing non-mutating access operations on files.
209     ///
210     /// This event is about opening and closing file handles, as well as executing files, and any
211     /// other such event that is about accessing files, folders, or other structures rather than
212     /// mutating them.
213     ///
214     /// Only some platforms are capable of generating these.
215     Access(AccessKind),
216 
217     /// An event describing creation operations on files.
218     ///
219     /// This event is about the creation of files, folders, or other structures but not about e.g.
220     /// writing new content into them.
221     Create(CreateKind),
222 
223     /// An event describing mutation of content, name, or metadata.
224     ///
225     /// This event is about the mutation of files', folders', or other structures' content, name
226     /// (path), or associated metadata (attributes).
227     Modify(ModifyKind),
228 
229     /// An event describing removal operations on files.
230     ///
231     /// This event is about the removal of files, folders, or other structures but not e.g. erasing
232     /// content from them. This may also be triggered for renames/moves that move files _out of the
233     /// watched subpath_.
234     ///
235     /// Some editors also trigger Remove events when saving files as they may opt for removing (or
236     /// renaming) the original then creating a new file in-place.
237     Remove(RemoveKind),
238 
239     /// An event not fitting in any of the above four categories.
240     ///
241     /// This may be used for meta-events about the watch itself. In "imprecise" mode, it is, along
242     /// with `Any`, the only other event generated.
243     Other,
244 }
245 
246 impl EventKind {
247     /// Indicates whether an event is an Access variant.
is_access(&self) -> bool248     pub fn is_access(&self) -> bool {
249         matches!(self, EventKind::Access(_))
250     }
251 
252     /// Indicates whether an event is a Create variant.
is_create(&self) -> bool253     pub fn is_create(&self) -> bool {
254         matches!(self, EventKind::Create(_))
255     }
256 
257     /// Indicates whether an event is a Modify variant.
is_modify(&self) -> bool258     pub fn is_modify(&self) -> bool {
259         matches!(self, EventKind::Modify(_))
260     }
261 
262     /// Indicates whether an event is a Remove variant.
is_remove(&self) -> bool263     pub fn is_remove(&self) -> bool {
264         matches!(self, EventKind::Remove(_))
265     }
266 
267     /// Indicates whether an event is an Other variant.
is_other(&self) -> bool268     pub fn is_other(&self) -> bool {
269         matches!(self, EventKind::Other)
270     }
271 }
272 
273 impl Default for EventKind {
default() -> Self274     fn default() -> Self {
275         EventKind::Any
276     }
277 }
278 
279 /// Notify event.
280 #[derive(Clone)]
281 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
282 pub struct Event {
283     /// Kind or type of the event.
284     ///
285     /// This is a hierarchy of enums describing the event as precisely as possible. All enums in
286     /// the hierarchy have two variants always present, `Any` and `Other`, accompanied by one or
287     /// more specific variants.
288     ///
289     /// `Any` should be used when more detail about the event is not known beyond the variant
290     /// already selected. For example, `AccessMode::Any` means a file has been accessed, but that's
291     /// all we know.
292     ///
293     /// `Other` should be used when more detail _is_ available, but cannot be encoded as one of the
294     /// defined variants. When specifying `Other`, the event attributes should contain an `Info`
295     /// entry with a short string identifying this detail. That string is to be considered part of
296     /// the interface of the backend (i.e. a change should probably be breaking).
297     ///
298     /// For example, `CreateKind::Other` with an `Info("mount")` may indicate the binding of a
299     /// mount. The documentation of the particular backend should indicate if any `Other` events
300     /// are generated, and what their description means.
301     ///
302     /// The `EventKind::Any` variant should be used as the "else" case when mapping native kernel
303     /// bitmasks or bitmaps, such that if the mask is ever extended with new event types the
304     /// backend will not gain bugs due to not matching new unknown event types.
305     #[cfg_attr(feature = "serde", serde(rename = "type"))]
306     pub kind: EventKind,
307 
308     /// Paths the event is about, if known.
309     ///
310     /// If an event concerns two or more paths, and the paths are known at the time of event
311     /// creation, they should all go in this `Vec`. Otherwise, using the `Tracker` attr may be more
312     /// appropriate.
313     ///
314     /// The order of the paths is likely to be significant! For example, renames where both ends of
315     /// the name change are known will have the "source" path first, and the "target" path last.
316     pub paths: Vec<PathBuf>,
317 
318     // "What should be in the struct" and "what can go in the attrs" is an interesting question.
319     //
320     // Technically, the paths could go in the attrs. That would reduce the type size to 4 pointer
321     // widths, instead of 7 like it is now. Anything 8 and below is probably good — on x64 that's
322     // the size of an L1 cache line. The entire kind classification fits in 3 bytes, and an AnyMap
323     // is 3 pointers. A Vec<PathBuf> is another 3 pointers.
324     //
325     // Type size aside, what's behind these structures? A Vec and a PathBuf is stored on the heap.
326     // An AnyMap is stored on the heap. But a Vec is directly there, requiring about one access to
327     // get, while retrieving anything in the AnyMap requires some accesses as overhead.
328     //
329     // So things that are used often should be on the struct, and things that are used more rarely
330     // should go in the attrs. Additionally, arbitrary data can _only_ go in the attrs.
331     //
332     // The kind and the paths vie for first place on this scale, depending on how downstream wishes
333     // to use the information. Everything else is secondary. So far, that's why paths live here.
334     //
335     // In the future, it might be possible to have more data and to benchmark things properly, so
336     // the performance can be actually quantified. Also, it might turn out that I have no idea what
337     // I was talking about, so the above may be discarded or reviewed. We'll see!
338     //
339     /// Additional attributes of the event.
340     ///
341     /// Arbitrary data may be added to this field, without restriction beyond the `Sync` and
342     /// `Clone` properties. Some data added here is considered for comparing and hashing, but not
343     /// all: at this writing this is `Tracker`, `Flag`, `Info`, and `Source`.
344     #[cfg_attr(feature = "serde", serde(default))]
345     pub attrs: EventAttributes,
346 }
347 
348 /// Additional attributes of the event.
349 #[derive(Clone, Default)]
350 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
351 pub struct EventAttributes {
352     #[cfg_attr(feature = "serde", serde(flatten))]
353     inner: Option<Box<EventAttributesInner>>,
354 }
355 
356 #[derive(Clone, Default)]
357 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
358 struct EventAttributesInner {
359     /// Tracking ID for events that are related.
360     ///
361     /// For events generated by backends with the `TrackRelated` capability. Those backends _may_
362     /// emit events that are related to each other, and tag those with an identical "tracking id"
363     /// or "cookie". The value is normalised to `usize`.
364     #[cfg_attr(
365         feature = "serde",
366         serde(default, skip_serializing_if = "Option::is_none")
367     )]
368     tracker: Option<usize>,
369 
370     /// Special Notify flag on the event.
371     #[cfg_attr(
372         feature = "serde",
373         serde(default, skip_serializing_if = "Option::is_none")
374     )]
375     flag: Option<Flag>,
376 
377     /// Additional information on the event.
378     ///
379     /// This is to be used for all `Other` variants of the event kind hierarchy. The variant
380     /// indicates that a consumer should look into the `attrs` for an `Info` value; if that value
381     /// is missing it should be considered a backend bug.
382     ///
383     /// This attribute may also be present for non-`Other` variants of the event kind, if doing so
384     /// provides useful precision. For example, the `Modify(Metadata(Extended))` kind suggests
385     /// using this attribute when information about _what_ extended metadata changed is available.
386     ///
387     /// This should be a short string, and changes may be considered breaking.
388     #[cfg_attr(
389         feature = "serde",
390         serde(default, skip_serializing_if = "Option::is_none")
391     )]
392     info: Option<String>,
393 
394     /// The source of the event.
395     ///
396     /// In most cases this should be a short string, identifying the backend unambiguously. In some
397     /// cases this may be dynamically generated, but should contain a prefix to make it unambiguous
398     /// between backends.
399     #[cfg_attr(
400         feature = "serde",
401         serde(default, skip_serializing_if = "Option::is_none")
402     )]
403     source: Option<String>,
404 
405     /// The process ID of the originator of the event.
406     ///
407     /// This attribute is experimental and, while included in Notify itself, is not considered
408     /// stable or standard enough to be part of the serde, eq, hash, and debug representations.
409     #[cfg_attr(
410         feature = "serde",
411         serde(default, skip_serializing, skip_deserializing)
412     )]
413     process_id: Option<u32>,
414 }
415 
416 impl EventAttributes {
417     /// Creates a new `EventAttributes`.
new() -> Self418     pub fn new() -> Self {
419         Self { inner: None }
420     }
421 
422     /// Retrieves the tracker ID for an event directly, if present.
tracker(&self) -> Option<usize>423     pub fn tracker(&self) -> Option<usize> {
424         self.inner.as_ref().and_then(|inner| inner.tracker)
425     }
426 
427     /// Retrieves the Notify flag for an event directly, if present.
flag(&self) -> Option<Flag>428     pub fn flag(&self) -> Option<Flag> {
429         self.inner.as_ref().and_then(|inner| inner.flag.clone())
430     }
431 
432     /// Retrieves the additional info for an event directly, if present.
info(&self) -> Option<&str>433     pub fn info(&self) -> Option<&str> {
434         self.inner.as_ref().and_then(|inner| inner.info.as_deref())
435     }
436 
437     /// Retrieves the source for an event directly, if present.
source(&self) -> Option<&str>438     pub fn source(&self) -> Option<&str> {
439         self.inner
440             .as_ref()
441             .and_then(|inner| inner.source.as_deref())
442     }
443 
444     /// The process ID of the originator of the event.
445     ///
446     /// This attribute is experimental and, while included in Notify itself, is not considered
447     /// stable or standard enough to be part of the serde, eq, hash, and debug representations.
process_id(&self) -> Option<u32>448     pub fn process_id(&self) -> Option<u32> {
449         self.inner.as_ref().and_then(|inner| inner.process_id)
450     }
451 
452     /// Sets the tracker.
set_tracker(&mut self, tracker: usize)453     pub fn set_tracker(&mut self, tracker: usize) {
454         self.inner_mut().tracker = Some(tracker);
455     }
456 
457     /// Sets the Notify flag onto the event.
set_flag(&mut self, flag: Flag)458     pub fn set_flag(&mut self, flag: Flag) {
459         self.inner_mut().flag = Some(flag);
460     }
461 
462     /// Sets additional info onto the event.
set_info(&mut self, info: &str)463     pub fn set_info(&mut self, info: &str) {
464         self.inner_mut().info = Some(info.to_string());
465     }
466 
467     /// Sets the process id onto the event.
set_process_id(&mut self, process_id: u32)468     pub fn set_process_id(&mut self, process_id: u32) {
469         self.inner_mut().process_id = Some(process_id)
470     }
471 
inner_mut(&mut self) -> &mut EventAttributesInner472     fn inner_mut(&mut self) -> &mut EventAttributesInner {
473         self.inner
474             .get_or_insert_with(|| Box::new(Default::default()))
475     }
476 }
477 
478 /// Special Notify flag on the event.
479 ///
480 /// This attribute is used to flag certain kinds of events that Notify either marks or generates in
481 /// particular ways.
482 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
483 #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
484 pub enum Flag {
485     /*
486         /// Event notices are emitted by debounced watchers immediately after the _first_ event of that
487         /// kind is received on a path to indicate activity to a path within the interval of a debounce.
488         ///
489         /// Event notices are a runtime option and are disabled by default. (TODO)
490         Notice,
491 
492         /// Ongoing event notices are emitted by debounced watchers on a higher frequency than the
493         /// debouncing delay to indicate ongoing activity to a path within the interval of a debounce.
494         ///
495         /// Ongoing event notices are a runtime option and are disabled by default.
496         Ongoing,
497     */
498     /// Rescan notices are emitted by some platforms (and may also be emitted by Notify itself).
499     /// They indicate either a lapse in the events or a change in the filesystem such that events
500     /// received so far can no longer be relied on to represent the state of the filesystem now.
501     ///
502     /// An application that simply reacts to file changes may not care about this. An application
503     /// that keeps an in-memory representation of the filesystem will need to care, and will need
504     /// to refresh that representation directly from the filesystem.
505     Rescan,
506 }
507 
508 impl Event {
509     /// Retrieves the tracker ID for an event directly, if present.
tracker(&self) -> Option<usize>510     pub fn tracker(&self) -> Option<usize> {
511         self.attrs.tracker()
512     }
513 
514     /// Retrieves the Notify flag for an event directly, if present.
flag(&self) -> Option<Flag>515     pub fn flag(&self) -> Option<Flag> {
516         self.attrs.flag()
517     }
518 
519     /// Retrieves the additional info for an event directly, if present.
info(&self) -> Option<&str>520     pub fn info(&self) -> Option<&str> {
521         self.attrs.info()
522     }
523 
524     /// Retrieves the source for an event directly, if present.
source(&self) -> Option<&str>525     pub fn source(&self) -> Option<&str> {
526         self.attrs.source()
527     }
528 
529     /// Creates a new `Event` given a kind.
new(kind: EventKind) -> Self530     pub fn new(kind: EventKind) -> Self {
531         Self {
532             kind,
533             paths: Vec::new(),
534             attrs: EventAttributes::new(),
535         }
536     }
537 
538     /// Sets the kind.
set_kind(mut self, kind: EventKind) -> Self539     pub fn set_kind(mut self, kind: EventKind) -> Self {
540         self.kind = kind;
541         self
542     }
543 
544     /// Adds a path to the event.
add_path(mut self, path: PathBuf) -> Self545     pub fn add_path(mut self, path: PathBuf) -> Self {
546         self.paths.push(path);
547         self
548     }
549 
550     /// Adds a path to the event if the argument is Some.
add_some_path(self, path: Option<PathBuf>) -> Self551     pub fn add_some_path(self, path: Option<PathBuf>) -> Self {
552         if let Some(path) = path {
553             self.add_path(path)
554         } else {
555             self
556         }
557     }
558 
559     /// Sets the tracker.
set_tracker(mut self, tracker: usize) -> Self560     pub fn set_tracker(mut self, tracker: usize) -> Self {
561         self.attrs.set_tracker(tracker);
562         self
563     }
564 
565     /// Sets additional info onto the event.
set_info(mut self, info: &str) -> Self566     pub fn set_info(mut self, info: &str) -> Self {
567         self.attrs.set_info(info);
568         self
569     }
570 
571     /// Sets the Notify flag onto the event.
set_flag(mut self, flag: Flag) -> Self572     pub fn set_flag(mut self, flag: Flag) -> Self {
573         self.attrs.set_flag(flag);
574         self
575     }
576 
577     /// Sets the process id onto the event.
set_process_id(mut self, process_id: u32) -> Self578     pub fn set_process_id(mut self, process_id: u32) -> Self {
579         self.attrs.set_process_id(process_id);
580         self
581     }
582 }
583 
584 impl fmt::Debug for Event {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result585     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
586         f.debug_struct("Event")
587             .field("kind", &self.kind)
588             .field("paths", &self.paths)
589             .field("attr:tracker", &self.tracker())
590             .field("attr:flag", &self.flag())
591             .field("attr:info", &self.info())
592             .field("attr:source", &self.source())
593             .finish()
594     }
595 }
596 impl Default for Event {
default() -> Self597     fn default() -> Self {
598         Self {
599             kind: EventKind::default(),
600             paths: Vec::new(),
601             attrs: EventAttributes::new(),
602         }
603     }
604 }
605 
606 impl Eq for Event {}
607 impl PartialEq for Event {
eq(&self, other: &Self) -> bool608     fn eq(&self, other: &Self) -> bool {
609         self.kind.eq(&other.kind)
610             && self.paths.eq(&other.paths)
611             && self.tracker().eq(&other.tracker())
612             && self.flag().eq(&other.flag())
613             && self.info().eq(&other.info())
614             && self.source().eq(&other.source())
615     }
616 }
617 
618 impl Hash for Event {
hash<H: Hasher>(&self, state: &mut H)619     fn hash<H: Hasher>(&self, state: &mut H) {
620         self.kind.hash(state);
621         self.paths.hash(state);
622         self.tracker().hash(state);
623         self.flag().hash(state);
624         self.info().hash(state);
625         self.source().hash(state);
626     }
627 }
628