unistore_watcher/
event.rs

1//! 【文件事件】- 文件系统事件定义
2//!
3//! 职责:
4//! - 定义标准化的文件事件类型
5//! - 从 notify 事件转换
6
7use crate::deps::{EventKind, NotifyEvent, PathBuf};
8
9/// 文件系统事件
10#[derive(Debug, Clone)]
11pub enum FileEvent {
12    /// 文件/目录创建
13    Created(PathBuf),
14
15    /// 文件修改
16    Modified(PathBuf),
17
18    /// 文件/目录删除
19    Deleted(PathBuf),
20
21    /// 文件/目录重命名(旧路径,新路径)
22    Renamed { from: PathBuf, to: PathBuf },
23
24    /// 访问(读取)
25    Accessed(PathBuf),
26
27    /// 其他事件
28    Other { kind: String, paths: Vec<PathBuf> },
29}
30
31impl FileEvent {
32    /// 从 notify 事件转换
33    pub fn from_notify(event: NotifyEvent) -> Option<Self> {
34        let paths = event.paths;
35
36        match event.kind {
37            EventKind::Create(_) => paths.into_iter().next().map(FileEvent::Created),
38
39            EventKind::Modify(_) => paths.into_iter().next().map(FileEvent::Modified),
40
41            EventKind::Remove(_) => paths.into_iter().next().map(FileEvent::Deleted),
42
43            EventKind::Access(_) => paths.into_iter().next().map(FileEvent::Accessed),
44
45            EventKind::Other => Some(FileEvent::Other {
46                kind: "other".to_string(),
47                paths,
48            }),
49
50            _ => None,
51        }
52    }
53
54    /// 获取主要路径
55    pub fn path(&self) -> Option<&PathBuf> {
56        match self {
57            FileEvent::Created(p) => Some(p),
58            FileEvent::Modified(p) => Some(p),
59            FileEvent::Deleted(p) => Some(p),
60            FileEvent::Renamed { to, .. } => Some(to),
61            FileEvent::Accessed(p) => Some(p),
62            FileEvent::Other { paths, .. } => paths.first(),
63        }
64    }
65
66    /// 获取所有相关路径
67    pub fn paths(&self) -> Vec<&PathBuf> {
68        match self {
69            FileEvent::Created(p) => vec![p],
70            FileEvent::Modified(p) => vec![p],
71            FileEvent::Deleted(p) => vec![p],
72            FileEvent::Renamed { from, to } => vec![from, to],
73            FileEvent::Accessed(p) => vec![p],
74            FileEvent::Other { paths, .. } => paths.iter().collect(),
75        }
76    }
77
78    /// 检查是否是创建事件
79    pub fn is_created(&self) -> bool {
80        matches!(self, FileEvent::Created(_))
81    }
82
83    /// 检查是否是修改事件
84    pub fn is_modified(&self) -> bool {
85        matches!(self, FileEvent::Modified(_))
86    }
87
88    /// 检查是否是删除事件
89    pub fn is_deleted(&self) -> bool {
90        matches!(self, FileEvent::Deleted(_))
91    }
92
93    /// 检查是否是重命名事件
94    pub fn is_renamed(&self) -> bool {
95        matches!(self, FileEvent::Renamed { .. })
96    }
97}
98
99impl std::fmt::Display for FileEvent {
100    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
101        match self {
102            FileEvent::Created(p) => write!(f, "创建: {}", p.display()),
103            FileEvent::Modified(p) => write!(f, "修改: {}", p.display()),
104            FileEvent::Deleted(p) => write!(f, "删除: {}", p.display()),
105            FileEvent::Renamed { from, to } => {
106                write!(f, "重命名: {} -> {}", from.display(), to.display())
107            }
108            FileEvent::Accessed(p) => write!(f, "访问: {}", p.display()),
109            FileEvent::Other { kind, paths } => {
110                write!(f, "其他({}): {:?}", kind, paths)
111            }
112        }
113    }
114}
115
116#[cfg(test)]
117mod tests {
118    use super::*;
119
120    #[test]
121    fn test_event_path() {
122        let event = FileEvent::Created(PathBuf::from("/tmp/test.txt"));
123        assert_eq!(event.path(), Some(&PathBuf::from("/tmp/test.txt")));
124        assert!(event.is_created());
125    }
126
127    #[test]
128    fn test_renamed_paths() {
129        let event = FileEvent::Renamed {
130            from: PathBuf::from("/tmp/old.txt"),
131            to: PathBuf::from("/tmp/new.txt"),
132        };
133        assert_eq!(event.paths().len(), 2);
134        assert!(event.is_renamed());
135    }
136
137    #[test]
138    fn test_display() {
139        let event = FileEvent::Modified(PathBuf::from("/tmp/test.txt"));
140        let display = format!("{}", event);
141        assert!(display.contains("修改"));
142    }
143}