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