origin_platform/
watcher.rs1use crate::workspace::WorkspaceRoot;
7use async_trait::async_trait;
8use origin_domain::Result;
9use std::fmt::Debug;
10use tokio::sync::broadcast;
11
12pub(crate) const BUFFER_SIZE: usize = 64;
14
15#[derive(Debug, Clone, PartialEq, Eq)]
17pub enum WorkspaceChange {
18 Created { path: String },
19 Modified { path: String },
20 Removed { path: String },
21}
22
23impl WorkspaceChange {
24 pub fn created(path: impl Into<String>) -> Self {
25 Self::Created { path: path.into() }
26 }
27
28 pub fn modified(path: impl Into<String>) -> Self {
29 Self::Modified { path: path.into() }
30 }
31
32 pub fn removed(path: impl Into<String>) -> Self {
33 Self::Removed { path: path.into() }
34 }
35
36 pub fn path(&self) -> &str {
37 match self {
38 Self::Created { path } | Self::Modified { path } | Self::Removed { path } => path,
39 }
40 }
41}
42
43pub struct WatchHandle {
49 receiver: broadcast::Receiver<WorkspaceChange>,
50}
51
52impl Debug for WatchHandle {
53 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
54 f.debug_struct("WatchHandle").finish_non_exhaustive()
55 }
56}
57
58impl WatchHandle {
59 pub fn new(receiver: broadcast::Receiver<WorkspaceChange>) -> Self {
64 Self { receiver }
65 }
66
67 pub async fn recv(&mut self) -> Result<WorkspaceChange, broadcast::error::RecvError> {
69 self.receiver.recv().await
70 }
71
72 pub fn try_recv(&mut self) -> Result<WorkspaceChange, broadcast::error::TryRecvError> {
74 self.receiver.try_recv()
75 }
76}
77
78#[async_trait]
84pub trait WorkspaceWatcher: Debug + Send + Sync + 'static {
85 async fn watch(&self, root: &WorkspaceRoot) -> Result<WatchHandle>;
90}
91
92#[cfg(test)]
93mod tests {
94 use super::*;
95
96 #[test]
97 fn workspace_change_path_accessor() {
98 let change = WorkspaceChange::modified("src/main.rs");
99 assert_eq!(change.path(), "src/main.rs");
100 }
101}