use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::time::Duration;
use parking_lot::Mutex;
#[derive(Debug)]
pub struct VocabSyncHandle {
completed: Arc<AtomicBool>,
error: Arc<Mutex<Option<String>>>,
}
impl VocabSyncHandle {
pub(super) fn already_synced() -> Self {
Self {
completed: Arc::new(AtomicBool::new(true)),
error: Arc::new(Mutex::new(None)),
}
}
pub fn is_synced(&self) -> bool {
self.completed.load(Ordering::Acquire)
}
pub fn wait(&self) -> std::result::Result<(), String> {
let mut backoff_us = 10;
while !self.completed.load(Ordering::Acquire) {
std::thread::sleep(Duration::from_micros(backoff_us));
backoff_us = (backoff_us * 2).min(10_000); }
let error_guard = self.error.lock();
if let Some(ref e) = *error_guard {
Err(e.clone())
} else {
Ok(())
}
}
pub fn wait_timeout(&self, timeout: Duration) -> std::result::Result<bool, String> {
let start = std::time::Instant::now();
let mut backoff_us = 10;
while !self.completed.load(Ordering::Acquire) {
if start.elapsed() >= timeout {
return Ok(false); }
std::thread::sleep(Duration::from_micros(backoff_us));
backoff_us = (backoff_us * 2).min(10_000);
}
let error_guard = self.error.lock();
if let Some(ref e) = *error_guard {
Err(e.clone())
} else {
Ok(true)
}
}
}
impl Clone for VocabSyncHandle {
fn clone(&self) -> Self {
Self {
completed: Arc::clone(&self.completed),
error: Arc::clone(&self.error),
}
}
}