use std::sync::{Arc, OnceLock};
pub trait Clipboard: Send + Sync + 'static {
fn text(&self) -> Option<String>;
fn set_text(&self, text: &str);
}
static CLIPBOARD: OnceLock<Arc<dyn Clipboard>> = OnceLock::new();
pub fn set_clipboard(backend: Arc<dyn Clipboard>) {
let _ = CLIPBOARD.set(backend);
}
pub fn clipboard() -> Option<Arc<dyn Clipboard>> {
CLIPBOARD.get().cloned()
}
pub fn clipboard_text() -> Option<String> {
clipboard().and_then(|c| c.text())
}
pub fn set_clipboard_text(text: &str) {
if let Some(c) = clipboard() {
c.set_text(text);
}
}
#[cfg(test)]
mod tests {
use super::*;
struct Held(std::sync::Mutex<String>);
impl Clipboard for Held {
fn text(&self) -> Option<String> {
Some(self.0.lock().unwrap().clone())
}
fn set_text(&self, text: &str) {
*self.0.lock().unwrap() = text.to_owned();
}
}
#[test]
fn no_backend_is_an_answer_rather_than_a_panic() {
if clipboard().is_none() {
assert_eq!(clipboard_text(), None);
set_clipboard_text("dropped on the floor");
}
}
#[test]
fn an_installed_backend_round_trips() {
set_clipboard(Arc::new(Held(std::sync::Mutex::new(String::new()))));
set_clipboard_text("copied");
assert_eq!(clipboard_text().as_deref(), Some("copied"));
}
}