use std::{
fmt,
hash::{Hash, Hasher},
path::PathBuf,
};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
pub enum AccessMode {
Any,
Execute,
Read,
Write,
Other,
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "kind", content = "mode"))]
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
pub enum AccessKind {
Any,
Read,
Open(AccessMode),
Close(AccessMode),
Other,
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "kind"))]
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
pub enum CreateKind {
Any,
File,
Folder,
Other,
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
pub enum DataChange {
Any,
Size,
Content,
Other,
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
pub enum MetadataKind {
Any,
AccessTime,
WriteTime,
Permissions,
Ownership,
Extended,
Other,
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
pub enum RenameMode {
Any,
To,
From,
Both,
Other,
}
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "kind", content = "mode"))]
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
pub enum ModifyKind {
Any,
Data(DataChange),
Metadata(MetadataKind),
#[cfg_attr(feature = "serde", serde(rename = "rename"))]
Name(RenameMode),
Other,
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "kind"))]
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
pub enum RemoveKind {
Any,
File,
Folder,
Other,
}
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
pub enum EventKind {
Any,
Access(AccessKind),
Create(CreateKind),
Modify(ModifyKind),
Remove(RemoveKind),
Other,
}
impl EventKind {
pub fn is_access(&self) -> bool {
matches!(self, EventKind::Access(_))
}
pub fn is_create(&self) -> bool {
matches!(self, EventKind::Create(_))
}
pub fn is_modify(&self) -> bool {
matches!(self, EventKind::Modify(_))
}
pub fn is_remove(&self) -> bool {
matches!(self, EventKind::Remove(_))
}
pub fn is_other(&self) -> bool {
matches!(self, EventKind::Other)
}
}
impl Default for EventKind {
fn default() -> Self {
EventKind::Any
}
}
#[derive(Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Event {
#[cfg_attr(feature = "serde", serde(rename = "type"))]
pub kind: EventKind,
pub paths: Vec<PathBuf>,
#[cfg_attr(feature = "serde", serde(default))]
pub attrs: EventAttributes,
}
#[derive(Clone, Default, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct EventAttributes {
#[cfg_attr(feature = "serde", serde(flatten))]
inner: Option<Box<EventAttributesInner>>,
}
#[derive(Clone, Default, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
struct EventAttributesInner {
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
tracker: Option<usize>,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
flag: Option<Flag>,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
info: Option<String>,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
source: Option<String>,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing, skip_deserializing)
)]
process_id: Option<u32>,
}
impl EventAttributes {
pub fn new() -> Self {
Self { inner: None }
}
pub fn tracker(&self) -> Option<usize> {
self.inner.as_ref().and_then(|inner| inner.tracker)
}
pub fn flag(&self) -> Option<Flag> {
self.inner.as_ref().and_then(|inner| inner.flag)
}
pub fn info(&self) -> Option<&str> {
self.inner.as_ref().and_then(|inner| inner.info.as_deref())
}
pub fn source(&self) -> Option<&str> {
self.inner
.as_ref()
.and_then(|inner| inner.source.as_deref())
}
pub fn process_id(&self) -> Option<u32> {
self.inner.as_ref().and_then(|inner| inner.process_id)
}
pub fn set_tracker(&mut self, tracker: usize) {
self.inner_mut().tracker = Some(tracker);
}
pub fn set_flag(&mut self, flag: Flag) {
self.inner_mut().flag = Some(flag);
}
pub fn set_info(&mut self, info: &str) {
self.inner_mut().info = Some(info.to_string());
}
pub fn set_process_id(&mut self, process_id: u32) {
self.inner_mut().process_id = Some(process_id)
}
fn inner_mut(&mut self) -> &mut EventAttributesInner {
self.inner
.get_or_insert_with(|| Box::new(Default::default()))
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
pub enum Flag {
Rescan,
}
impl Event {
pub fn need_rescan(&self) -> bool {
matches!(self.flag(), Some(Flag::Rescan))
}
pub fn tracker(&self) -> Option<usize> {
self.attrs.tracker()
}
pub fn flag(&self) -> Option<Flag> {
self.attrs.flag()
}
pub fn info(&self) -> Option<&str> {
self.attrs.info()
}
pub fn source(&self) -> Option<&str> {
self.attrs.source()
}
pub fn new(kind: EventKind) -> Self {
Self {
kind,
paths: Vec::new(),
attrs: EventAttributes::new(),
}
}
pub fn set_kind(mut self, kind: EventKind) -> Self {
self.kind = kind;
self
}
pub fn add_path(mut self, path: PathBuf) -> Self {
self.paths.push(path);
self
}
pub fn add_some_path(self, path: Option<PathBuf>) -> Self {
if let Some(path) = path {
self.add_path(path)
} else {
self
}
}
pub fn set_tracker(mut self, tracker: usize) -> Self {
self.attrs.set_tracker(tracker);
self
}
pub fn set_info(mut self, info: &str) -> Self {
self.attrs.set_info(info);
self
}
pub fn set_flag(mut self, flag: Flag) -> Self {
self.attrs.set_flag(flag);
self
}
pub fn set_process_id(mut self, process_id: u32) -> Self {
self.attrs.set_process_id(process_id);
self
}
}
impl fmt::Debug for Event {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Event")
.field("kind", &self.kind)
.field("paths", &self.paths)
.field("attr:tracker", &self.tracker())
.field("attr:flag", &self.flag())
.field("attr:info", &self.info())
.field("attr:source", &self.source())
.finish()
}
}
impl Default for Event {
fn default() -> Self {
Self {
kind: EventKind::default(),
paths: Vec::new(),
attrs: EventAttributes::new(),
}
}
}
impl Eq for Event {}
impl PartialEq for Event {
fn eq(&self, other: &Self) -> bool {
self.kind.eq(&other.kind)
&& self.paths.eq(&other.paths)
&& self.tracker().eq(&other.tracker())
&& self.flag().eq(&other.flag())
&& self.info().eq(&other.info())
&& self.source().eq(&other.source())
}
}
impl Hash for Event {
fn hash<H: Hasher>(&self, state: &mut H) {
self.kind.hash(state);
self.paths.hash(state);
self.tracker().hash(state);
self.flag().hash(state);
self.info().hash(state);
self.source().hash(state);
}
}