fret_runtime/
clipboard_diagnostics.rs1use std::collections::HashMap;
2
3use fret_core::{AppWindowId, ClipboardToken, FrameId};
4
5#[derive(Debug, Clone, PartialEq, Eq)]
6pub struct ClipboardReadDiagnostics {
7 pub token: ClipboardToken,
8 pub unavailable: bool,
9 pub message: Option<String>,
10}
11
12#[derive(Debug, Clone, PartialEq, Eq)]
13pub struct ClipboardWriteDiagnostics {
14 pub unavailable: bool,
15 pub message: Option<String>,
16}
17
18#[derive(Debug, Default)]
19pub struct WindowClipboardDiagnosticsStore {
20 per_window: HashMap<AppWindowId, WindowClipboardDiagnosticsFrame>,
21}
22
23#[derive(Debug, Default)]
24struct WindowClipboardDiagnosticsFrame {
25 frame_id: FrameId,
26 last_read: Option<ClipboardReadDiagnostics>,
27 last_write: Option<ClipboardWriteDiagnostics>,
28}
29
30impl WindowClipboardDiagnosticsStore {
31 pub fn record_read_ok(
32 &mut self,
33 window: AppWindowId,
34 frame_id: FrameId,
35 token: ClipboardToken,
36 ) {
37 let entry = self.per_window.entry(window).or_default();
38 if entry.frame_id != frame_id {
39 entry.frame_id = frame_id;
40 entry.last_read = None;
41 entry.last_write = None;
42 }
43 entry.last_read = Some(ClipboardReadDiagnostics {
44 token,
45 unavailable: false,
46 message: None,
47 });
48 }
49
50 pub fn record_read_unavailable(
51 &mut self,
52 window: AppWindowId,
53 frame_id: FrameId,
54 token: ClipboardToken,
55 message: Option<String>,
56 ) {
57 let entry = self.per_window.entry(window).or_default();
58 if entry.frame_id != frame_id {
59 entry.frame_id = frame_id;
60 entry.last_read = None;
61 entry.last_write = None;
62 }
63 entry.last_read = Some(ClipboardReadDiagnostics {
64 token,
65 unavailable: true,
66 message,
67 });
68 }
69
70 pub fn record_write_ok(&mut self, window: AppWindowId, frame_id: FrameId) {
71 let entry = self.per_window.entry(window).or_default();
72 if entry.frame_id != frame_id {
73 entry.frame_id = frame_id;
74 entry.last_read = None;
75 entry.last_write = None;
76 }
77 entry.last_write = Some(ClipboardWriteDiagnostics {
78 unavailable: false,
79 message: None,
80 });
81 }
82
83 pub fn record_write_unavailable(
84 &mut self,
85 window: AppWindowId,
86 frame_id: FrameId,
87 message: Option<String>,
88 ) {
89 let entry = self.per_window.entry(window).or_default();
90 if entry.frame_id != frame_id {
91 entry.frame_id = frame_id;
92 entry.last_read = None;
93 entry.last_write = None;
94 }
95 entry.last_write = Some(ClipboardWriteDiagnostics {
96 unavailable: true,
97 message,
98 });
99 }
100
101 pub fn last_read_for_window(
102 &self,
103 window: AppWindowId,
104 frame_id: FrameId,
105 ) -> Option<&ClipboardReadDiagnostics> {
106 self.per_window
107 .get(&window)
108 .filter(|entry| entry.frame_id == frame_id)
109 .and_then(|entry| entry.last_read.as_ref())
110 }
111
112 pub fn last_write_for_window(
113 &self,
114 window: AppWindowId,
115 frame_id: FrameId,
116 ) -> Option<&ClipboardWriteDiagnostics> {
117 self.per_window
118 .get(&window)
119 .filter(|entry| entry.frame_id == frame_id)
120 .and_then(|entry| entry.last_write.as_ref())
121 }
122}
123
124#[cfg(test)]
125mod tests {
126 use super::*;
127
128 #[test]
129 fn write_diagnostics_reset_per_frame_and_coexist_with_read() {
130 let window = AppWindowId::default();
131 let token = ClipboardToken::default();
132 let frame_1 = FrameId(1);
133 let frame_2 = FrameId(2);
134
135 let mut store = WindowClipboardDiagnosticsStore::default();
136 store.record_write_unavailable(window, frame_1, Some("nope".to_string()));
137
138 let write_1 = store
139 .last_write_for_window(window, frame_1)
140 .expect("last_write frame 1");
141 assert!(write_1.unavailable);
142 assert_eq!(write_1.message.as_deref(), Some("nope"));
143
144 assert!(store.last_write_for_window(window, frame_2).is_none());
145
146 store.record_write_ok(window, frame_2);
147 let write_2 = store
148 .last_write_for_window(window, frame_2)
149 .expect("last_write frame 2");
150 assert!(!write_2.unavailable);
151 assert!(write_2.message.is_none());
152
153 store.record_read_ok(window, frame_2, token);
155 assert!(store.last_read_for_window(window, frame_2).is_some());
156 assert!(store.last_write_for_window(window, frame_2).is_some());
157 }
158}