use std::sync::Arc;
use std::sync::atomic::{AtomicU64, Ordering};
use crossbeam_channel as cbc;
use crate::config::Config;
use crate::errors::{Result, XcpError};
#[derive(Debug)]
pub enum StatusUpdate {
Copied(u64),
Size(u64),
Error(XcpError)
}
pub trait StatusUpdater: Sync + Send {
fn send(&self, update: StatusUpdate) -> Result<()>;
}
pub struct ChannelUpdater {
chan_tx: cbc::Sender<StatusUpdate>,
chan_rx: cbc::Receiver<StatusUpdate>,
config: Arc<Config>,
sent: AtomicU64,
}
impl ChannelUpdater {
pub fn new(config: &Arc<Config>) -> ChannelUpdater {
let (chan_tx, chan_rx) = cbc::unbounded();
ChannelUpdater {
chan_tx,
chan_rx,
config: config.clone(),
sent: AtomicU64::new(0),
}
}
pub fn rx_channel(&self) -> cbc::Receiver<StatusUpdate> {
self.chan_rx.clone()
}
}
impl StatusUpdater for ChannelUpdater {
fn send(&self, update: StatusUpdate) -> Result<()> {
if let StatusUpdate::Copied(bytes) = update {
let bsize = self.config.block_size;
let prev_written = self.sent.fetch_add(bytes, Ordering::Relaxed);
if ((prev_written + bytes) / bsize) > (prev_written / bsize) {
self.chan_tx.send(update)?;
}
} else {
self.chan_tx.send(update)?;
}
Ok(())
}
}
pub struct NoopUpdater;
impl StatusUpdater for NoopUpdater {
fn send(&self, _update: StatusUpdate) -> Result<()> {
Ok(())
}
}