use std::sync::{Mutex, OnceLock};
static CLIPBOARD: OnceLock<Mutex<Option<arboard::Clipboard>>> = OnceLock::new();
fn with_clipboard<F, R>(f: F) -> Option<R>
where
F: FnOnce(&mut arboard::Clipboard) -> R,
{
let mutex = CLIPBOARD.get_or_init(|| Mutex::new(arboard::Clipboard::new().ok()));
let mut guard = mutex.lock().ok()?;
guard.as_mut().map(f)
}
pub(crate) fn system_clipboard_set(text: &str) {
with_clipboard(|cb| {
let _ = cb.set_text(text);
});
}
pub(crate) fn system_clipboard_get() -> Option<String> {
with_clipboard(|cb| cb.get_text().ok())
.flatten()
.filter(|s| !s.is_empty())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_clipboard_set_does_not_panic() {
system_clipboard_set("test");
}
#[test]
fn test_clipboard_get_does_not_panic() {
let _ = system_clipboard_get();
}
#[test]
fn test_clipboard_roundtrip() {
system_clipboard_set("roundtrip_test");
let _ = system_clipboard_get();
}
#[test]
fn test_with_clipboard_returns_none_gracefully() {
let result = with_clipboard(|cb| cb.get_text().ok());
let _ = result;
}
#[test]
fn test_repeated_access_same_thread() {
for _ in 0..100 {
system_clipboard_set("repeated");
let _ = system_clipboard_get();
}
}
}