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
5use std::{
6 fmt,
7 hash::{Hash, Hasher},
8 path::PathBuf,
9};
10
11#[cfg(feature = "serde")]
12use serde::{Deserialize, Serialize};
13
14/// An event describing open or close operations on files.
15#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
16#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
17#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
18pub 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, Copy, 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"))]
40pub 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, Copy, 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"))]
62pub 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, Copy, Debug, Eq, Hash, PartialEq)]
78#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
79#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
80pub 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, Copy, Debug, Eq, Hash, PartialEq)]
96#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
97#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
98pub 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, Copy, Debug, Eq, Hash, PartialEq)]
126#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
127#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
128pub 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, Copy, 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"))]
153pub 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, Copy, 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"))]
176pub 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, Copy, Debug, Eq, Hash, PartialEq)]
196#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
197#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
198pub 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.
242 Other,
243}
244
245impl EventKind {
246 /// Indicates whether an event is an Access variant.
247 pub fn is_access(&self) -> bool {
248 matches!(self, EventKind::Access(_))
249 }
250
251 /// Indicates whether an event is a Create variant.
252 pub fn is_create(&self) -> bool {
253 matches!(self, EventKind::Create(_))
254 }
255
256 /// Indicates whether an event is a Modify variant.
257 pub fn is_modify(&self) -> bool {
258 matches!(self, EventKind::Modify(_))
259 }
260
261 /// Indicates whether an event is a Remove variant.
262 pub fn is_remove(&self) -> bool {
263 matches!(self, EventKind::Remove(_))
264 }
265
266 /// Indicates whether an event is an Other variant.
267 pub fn is_other(&self) -> bool {
268 matches!(self, EventKind::Other)
269 }
270}
271
272impl Default for EventKind {
273 fn default() -> Self {
274 EventKind::Any
275 }
276}
277
278/// Notify event.
279///
280/// You might want to check [`Event::need_rescan`] to make sure no event was missed before you
281/// received this one.
282#[derive(Clone)]
283#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
284pub struct Event {
285 /// Kind or type of the event.
286 ///
287 /// This is a hierarchy of enums describing the event as precisely as possible. All enums in
288 /// the hierarchy have two variants always present, `Any` and `Other`, accompanied by one or
289 /// more specific variants.
290 ///
291 /// `Any` should be used when more detail about the event is not known beyond the variant
292 /// already selected. For example, `AccessMode::Any` means a file has been accessed, but that's
293 /// all we know.
294 ///
295 /// `Other` should be used when more detail _is_ available, but cannot be encoded as one of the
296 /// defined variants. When specifying `Other`, the event attributes should contain an `Info`
297 /// entry with a short string identifying this detail. That string is to be considered part of
298 /// the interface of the backend (i.e. a change should probably be breaking).
299 ///
300 /// For example, `CreateKind::Other` with an `Info("mount")` may indicate the binding of a
301 /// mount. The documentation of the particular backend should indicate if any `Other` events
302 /// are generated, and what their description means.
303 ///
304 /// The `EventKind::Any` variant should be used as the "else" case when mapping native kernel
305 /// bitmasks or bitmaps, such that if the mask is ever extended with new event types the
306 /// backend will not gain bugs due to not matching new unknown event types.
307 #[cfg_attr(feature = "serde", serde(rename = "type"))]
308 pub kind: EventKind,
309
310 /// Paths the event is about, if known.
311 ///
312 /// If an event concerns two or more paths, and the paths are known at the time of event
313 /// creation, they should all go in this `Vec`. Otherwise, using the `Tracker` attr may be more
314 /// appropriate.
315 ///
316 /// The order of the paths is likely to be significant! For example, renames where both ends of
317 /// the name change are known will have the "source" path first, and the "target" path last.
318 pub paths: Vec<PathBuf>,
319
320 // "What should be in the struct" and "what can go in the attrs" is an interesting question.
321 //
322 // Technically, the paths could go in the attrs. That would reduce the type size to 4 pointer
323 // widths, instead of 7 like it is now. Anything 8 and below is probably good — on x64 that's
324 // the size of an L1 cache line. The entire kind classification fits in 3 bytes, and an AnyMap
325 // is 3 pointers. A Vec<PathBuf> is another 3 pointers.
326 //
327 // Type size aside, what's behind these structures? A Vec and a PathBuf is stored on the heap.
328 // An AnyMap is stored on the heap. But a Vec is directly there, requiring about one access to
329 // get, while retrieving anything in the AnyMap requires some accesses as overhead.
330 //
331 // So things that are used often should be on the struct, and things that are used more rarely
332 // should go in the attrs. Additionally, arbitrary data can _only_ go in the attrs.
333 //
334 // The kind and the paths vie for first place on this scale, depending on how downstream wishes
335 // to use the information. Everything else is secondary. So far, that's why paths live here.
336 //
337 // In the future, it might be possible to have more data and to benchmark things properly, so
338 // the performance can be actually quantified. Also, it might turn out that I have no idea what
339 // I was talking about, so the above may be discarded or reviewed. We'll see!
340 //
341 /// Additional attributes of the event.
342 ///
343 /// Arbitrary data may be added to this field, without restriction beyond the `Sync` and
344 /// `Clone` properties. Some data added here is considered for comparing and hashing, but not
345 /// all: at this writing this is `Tracker`, `Flag`, `Info`, and `Source`.
346 #[cfg_attr(feature = "serde", serde(default))]
347 pub attrs: EventAttributes,
348}
349
350/// Additional attributes of the event.
351#[derive(Clone, Default, Debug)]
352#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
353pub struct EventAttributes {
354 #[cfg_attr(feature = "serde", serde(flatten))]
355 inner: Option<Box<EventAttributesInner>>,
356}
357
358#[derive(Clone, Default, Debug)]
359#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
360struct EventAttributesInner {
361 /// Tracking ID for events that are related.
362 ///
363 /// For events generated by backends with the `TrackRelated` capability. Those backends _may_
364 /// emit events that are related to each other, and tag those with an identical "tracking id"
365 /// or "cookie". The value is normalised to `usize`.
366 #[cfg_attr(
367 feature = "serde",
368 serde(default, skip_serializing_if = "Option::is_none")
369 )]
370 tracker: Option<usize>,
371
372 /// Special Notify flag on the event.
373 #[cfg_attr(
374 feature = "serde",
375 serde(default, skip_serializing_if = "Option::is_none")
376 )]
377 flag: Option<Flag>,
378
379 /// Additional information on the event.
380 ///
381 /// This is to be used for all `Other` variants of the event kind hierarchy. The variant
382 /// indicates that a consumer should look into the `attrs` for an `Info` value; if that value
383 /// is missing it should be considered a backend bug.
384 ///
385 /// This attribute may also be present for non-`Other` variants of the event kind, if doing so
386 /// provides useful precision. For example, the `Modify(Metadata(Extended))` kind suggests
387 /// using this attribute when information about _what_ extended metadata changed is available.
388 ///
389 /// This should be a short string, and changes may be considered breaking.
390 #[cfg_attr(
391 feature = "serde",
392 serde(default, skip_serializing_if = "Option::is_none")
393 )]
394 info: Option<String>,
395
396 /// The source of the event.
397 ///
398 /// In most cases this should be a short string, identifying the backend unambiguously. In some
399 /// cases this may be dynamically generated, but should contain a prefix to make it unambiguous
400 /// between backends.
401 #[cfg_attr(
402 feature = "serde",
403 serde(default, skip_serializing_if = "Option::is_none")
404 )]
405 source: Option<String>,
406
407 /// The process ID of the originator of the event.
408 ///
409 /// This attribute is experimental and, while included in Notify itself, is not considered
410 /// stable or standard enough to be part of the serde, eq, hash, and debug representations.
411 #[cfg_attr(
412 feature = "serde",
413 serde(default, skip_serializing, skip_deserializing)
414 )]
415 process_id: Option<u32>,
416}
417
418impl EventAttributes {
419 /// Creates a new `EventAttributes`.
420 pub fn new() -> Self {
421 Self { inner: None }
422 }
423
424 /// Retrieves the tracker ID for an event directly, if present.
425 pub fn tracker(&self) -> Option<usize> {
426 self.inner.as_ref().and_then(|inner| inner.tracker)
427 }
428
429 /// Retrieves the Notify flag for an event directly, if present.
430 pub fn flag(&self) -> Option<Flag> {
431 self.inner.as_ref().and_then(|inner| inner.flag)
432 }
433
434 /// Retrieves the additional info for an event directly, if present.
435 pub fn info(&self) -> Option<&str> {
436 self.inner.as_ref().and_then(|inner| inner.info.as_deref())
437 }
438
439 /// Retrieves the source for an event directly, if present.
440 pub fn source(&self) -> Option<&str> {
441 self.inner
442 .as_ref()
443 .and_then(|inner| inner.source.as_deref())
444 }
445
446 /// The process ID of the originator of the event.
447 ///
448 /// This attribute is experimental and, while included in Notify itself, is not considered
449 /// stable or standard enough to be part of the serde, eq, hash, and debug representations.
450 pub fn process_id(&self) -> Option<u32> {
451 self.inner.as_ref().and_then(|inner| inner.process_id)
452 }
453
454 /// Sets the tracker.
455 pub fn set_tracker(&mut self, tracker: usize) {
456 self.inner_mut().tracker = Some(tracker);
457 }
458
459 /// Sets the Notify flag onto the event.
460 pub fn set_flag(&mut self, flag: Flag) {
461 self.inner_mut().flag = Some(flag);
462 }
463
464 /// Sets additional info onto the event.
465 pub fn set_info(&mut self, info: &str) {
466 self.inner_mut().info = Some(info.to_string());
467 }
468
469 /// Sets the process id onto the event.
470 pub fn set_process_id(&mut self, process_id: u32) {
471 self.inner_mut().process_id = Some(process_id)
472 }
473
474 fn inner_mut(&mut self) -> &mut EventAttributesInner {
475 self.inner
476 .get_or_insert_with(|| Box::new(Default::default()))
477 }
478}
479
480/// Special Notify flag on the event.
481///
482/// This attribute is used to flag certain kinds of events that Notify either marks or generates in
483/// particular ways.
484#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
485#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
486pub enum Flag {
487 /// Rescan notices are emitted by some platforms (and may also be emitted by Notify itself).
488 /// They indicate either a lapse in the events or a change in the filesystem such that events
489 /// received so far can no longer be relied on to represent the state of the filesystem now.
490 ///
491 /// An application that simply reacts to file changes may not care about this. An application
492 /// that keeps an in-memory representation of the filesystem will need to care, and will need
493 /// to refresh that representation directly from the filesystem.
494 Rescan,
495}
496
497impl Event {
498 /// Returns whether some events may have been missed. If true, you should assume any file or
499 /// folder might have been modified.
500 ///
501 /// See [`Flag::Rescan`] for more information.
502 pub fn need_rescan(&self) -> bool {
503 matches!(self.flag(), Some(Flag::Rescan))
504 }
505 /// Retrieves the tracker ID for an event directly, if present.
506 pub fn tracker(&self) -> Option<usize> {
507 self.attrs.tracker()
508 }
509
510 /// Retrieves the Notify flag for an event directly, if present.
511 pub fn flag(&self) -> Option<Flag> {
512 self.attrs.flag()
513 }
514
515 /// Retrieves the additional info for an event directly, if present.
516 pub fn info(&self) -> Option<&str> {
517 self.attrs.info()
518 }
519
520 /// Retrieves the source for an event directly, if present.
521 pub fn source(&self) -> Option<&str> {
522 self.attrs.source()
523 }
524
525 /// Creates a new `Event` given a kind.
526 pub fn new(kind: EventKind) -> Self {
527 Self {
528 kind,
529 paths: Vec::new(),
530 attrs: EventAttributes::new(),
531 }
532 }
533
534 /// Sets the kind.
535 pub fn set_kind(mut self, kind: EventKind) -> Self {
536 self.kind = kind;
537 self
538 }
539
540 /// Adds a path to the event.
541 pub fn add_path(mut self, path: PathBuf) -> Self {
542 self.paths.push(path);
543 self
544 }
545
546 /// Adds a path to the event if the argument is Some.
547 pub fn add_some_path(self, path: Option<PathBuf>) -> Self {
548 if let Some(path) = path {
549 self.add_path(path)
550 } else {
551 self
552 }
553 }
554
555 /// Sets the tracker.
556 pub fn set_tracker(mut self, tracker: usize) -> Self {
557 self.attrs.set_tracker(tracker);
558 self
559 }
560
561 /// Sets additional info onto the event.
562 pub fn set_info(mut self, info: &str) -> Self {
563 self.attrs.set_info(info);
564 self
565 }
566
567 /// Sets the Notify flag onto the event.
568 pub fn set_flag(mut self, flag: Flag) -> Self {
569 self.attrs.set_flag(flag);
570 self
571 }
572
573 /// Sets the process id onto the event.
574 pub fn set_process_id(mut self, process_id: u32) -> Self {
575 self.attrs.set_process_id(process_id);
576 self
577 }
578}
579
580impl fmt::Debug for Event {
581 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
582 f&mut DebugStruct<'_, '_>.debug_struct("Event")
583 .field("kind", &self.kind)
584 .field("paths", &self.paths)
585 .field("attr:tracker", &self.tracker())
586 .field("attr:flag", &self.flag())
587 .field("attr:info", &self.info())
588 .field(name:"attr:source", &self.source())
589 .finish()
590 }
591}
592impl Default for Event {
593 fn default() -> Self {
594 Self {
595 kind: EventKind::default(),
596 paths: Vec::new(),
597 attrs: EventAttributes::new(),
598 }
599 }
600}
601
602impl Eq for Event {}
603impl PartialEq for Event {
604 fn eq(&self, other: &Self) -> bool {
605 self.kind.eq(&other.kind)
606 && self.paths.eq(&other.paths)
607 && self.tracker().eq(&other.tracker())
608 && self.flag().eq(&other.flag())
609 && self.info().eq(&other.info())
610 && self.source().eq(&other.source())
611 }
612}
613
614impl Hash for Event {
615 fn hash<H: Hasher>(&self, state: &mut H) {
616 self.kind.hash(state);
617 self.paths.hash(state);
618 self.tracker().hash(state);
619 self.flag().hash(state);
620 self.info().hash(state);
621 self.source().hash(state);
622 }
623}
624