1use crate::TextError;
12use dyn_clone::{clone_box, DynClone};
13use std::error::Error;
14use std::fmt::{Debug, Display, Formatter};
15use std::sync::{Arc, Mutex, OnceLock};
16
17#[derive(Debug)]
18pub struct ClipboardError;
19
20impl Display for ClipboardError {
21 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
22 write!(f, "{:?}", self)
23 }
24}
25
26impl Error for ClipboardError {}
27
28impl From<ClipboardError> for TextError {
29 fn from(_value: ClipboardError) -> Self {
30 TextError::Clipboard
31 }
32}
33
34pub trait Clipboard: DynClone + Debug {
36 fn get_string(&self) -> Result<String, ClipboardError>;
38
39 fn set_string(&self, s: &str) -> Result<(), ClipboardError>;
41}
42
43static GLOBAL_CLIPBOARD: OnceLock<StaticClipboard> = OnceLock::new();
44
45pub fn global_clipboard() -> Box<dyn Clipboard> {
47 let c = GLOBAL_CLIPBOARD.get_or_init(StaticClipboard::default);
48 Box::new(c.clone())
49}
50
51pub fn set_global_clipboard(clipboard: impl Clipboard + Send + 'static) {
53 let c = GLOBAL_CLIPBOARD.get_or_init(StaticClipboard::default);
54 c.replace(clipboard);
55}
56
57#[derive(Debug, Clone)]
61struct StaticClipboard {
62 clip: Arc<Mutex<Box<dyn Clipboard + Send>>>,
63}
64
65impl Default for StaticClipboard {
66 fn default() -> Self {
67 Self {
68 clip: Arc::new(Mutex::new(Box::new(LocalClipboard::new()))),
69 }
70 }
71}
72
73impl StaticClipboard {
74 fn replace(&self, clipboard: impl Clipboard + Send + 'static) {
76 let mut clip = self.clip.lock().expect("clipboard-lock");
77 *clip = Box::new(clipboard);
78 }
79}
80
81impl Clipboard for StaticClipboard {
82 fn get_string(&self) -> Result<String, ClipboardError> {
83 self.clip.lock().expect("clipboard-lock").get_string()
84 }
85
86 fn set_string(&self, s: &str) -> Result<(), ClipboardError> {
87 self.clip.lock().expect("clipboard-lock").set_string(s)
88 }
89}
90
91#[derive(Debug, Default, Clone)]
94pub struct LocalClipboard {
95 text: Arc<Mutex<String>>,
96}
97
98impl LocalClipboard {
99 pub fn new() -> Self {
100 Self::default()
101 }
102}
103
104impl Clipboard for LocalClipboard {
105 fn get_string(&self) -> Result<String, ClipboardError> {
106 match self.text.lock() {
107 Ok(v) => Ok(v.clone()),
108 Err(_) => Err(ClipboardError),
109 }
110 }
111
112 fn set_string(&self, s: &str) -> Result<(), ClipboardError> {
113 match self.text.lock() {
114 Ok(mut v) => {
115 *v = s.to_string();
116 Ok(())
117 }
118 Err(_) => Err(ClipboardError),
119 }
120 }
121}
122
123impl Clone for Box<dyn Clipboard> {
124 fn clone(&self) -> Self {
125 clone_box(self.as_ref())
126 }
127}
128
129impl Clipboard for Box<dyn Clipboard> {
130 fn get_string(&self) -> Result<String, ClipboardError> {
131 self.as_ref().get_string()
132 }
133
134 fn set_string(&self, s: &str) -> Result<(), ClipboardError> {
135 self.as_ref().set_string(s)
136 }
137}