use super::BatchStreamData;
use std::sync::atomic::{AtomicI64, Ordering};
use std::sync::{Arc, Condvar, Mutex};
use std::time::Duration;
static NEXT_SEQUENCE_ID: AtomicI64 = AtomicI64::new(1);
type Continuation = Box<dyn FnOnce() + Send>;
#[derive(Default)]
pub struct BatchCompletion {
state: Mutex<CompletionState>,
completed: Condvar,
}
#[derive(Default)]
struct CompletionState {
completed: bool,
continuations: Vec<Continuation>,
}
impl BatchCompletion {
pub fn is_completed(&self) -> bool {
self.state.lock().unwrap_or_else(|e| e.into_inner()).completed
}
pub fn on_completed(&self, continuation: impl FnOnce() + Send + 'static) {
{
let mut state = self.state.lock().unwrap_or_else(|e| e.into_inner());
if !state.completed {
state.continuations.push(Box::new(continuation));
return;
}
}
continuation();
}
pub fn wait(&self) {
let mut state = self.state.lock().unwrap_or_else(|e| e.into_inner());
while !state.completed {
state = self.completed.wait(state).unwrap_or_else(|e| e.into_inner());
}
}
pub(crate) fn try_set(&self) {
let continuations = {
let mut state = self.state.lock().unwrap_or_else(|e| e.into_inner());
if state.completed {
return;
}
state.completed = true;
std::mem::take(&mut state.continuations)
};
self.completed.notify_all();
for continuation in continuations {
continuation();
}
}
}
pub struct CompositionBatch {
sequence_id: i64,
processed: BatchCompletion,
rendered: BatchCompletion,
}
impl CompositionBatch {
pub(crate) fn new() -> Arc<CompositionBatch> {
Arc::new(CompositionBatch {
sequence_id: NEXT_SEQUENCE_ID.fetch_add(1, Ordering::SeqCst) + 1,
processed: BatchCompletion::default(),
rendered: BatchCompletion::default(),
})
}
pub fn sequence_id(&self) -> i64 {
self.sequence_id
}
pub fn processed(&self) -> &BatchCompletion {
&self.processed
}
pub fn rendered(&self) -> &BatchCompletion {
&self.rendered
}
pub(crate) fn notify_processed(&self) {
self.processed.try_set();
}
pub(crate) fn notify_rendered(&self) {
self.rendered.try_set();
}
}
pub struct CommittedBatch {
pub(crate) batch: Arc<CompositionBatch>,
pub(crate) changes: BatchStreamData,
pub(crate) committed_at: Duration,
}
const _: fn() = || {
fn sent<T: Send>() {}
sent::<CommittedBatch>();
};