krabka_client_streams/processor/
punctuation.rs1use std::{
14 any::Any,
15 marker::PhantomData,
16 sync::{
17 Arc,
18 atomic::{AtomicBool, Ordering},
19 },
20};
21
22use async_trait::async_trait;
23use krabka_units::prelude::*;
24
25use crate::processor::{api::ProcessorContext, erased::Dispatch};
26
27#[derive(Clone, Copy, Debug, PartialEq, Eq)]
30pub enum PunctuationType {
31 StreamTime,
33 WallClockTime,
35}
36
37#[async_trait]
43pub trait Punctuator<K: Send, V: Send>: Send + 'static {
44 async fn punctuate(&mut self, ctx: &mut ProcessorContext<'_, '_, K, V>, timestamp: i64);
48}
49
50#[derive(Clone)]
53pub struct Cancellable(Arc<AtomicBool>);
54impl Cancellable {
55 pub(crate) fn new(flag: Arc<AtomicBool>) -> Self {
56 Self(flag)
57 }
58 pub fn cancel(&self) {
60 self.0.store(true, Ordering::SeqCst);
61 }
62}
63
64#[async_trait]
67pub(crate) trait ErasedPunctuator: Send {
68 async fn fire(&mut self, dispatch: &mut Dispatch<'_>, timestamp: i64);
69}
70
71pub(crate) struct TypedPunctuator<K, V, P> {
74 inner: P,
75 _pd: PhantomData<fn(K, V)>,
76}
77impl<K, V, P> TypedPunctuator<K, V, P> {
78 pub(crate) fn new(inner: P) -> Self {
79 Self {
80 inner,
81 _pd: PhantomData,
82 }
83 }
84}
85#[async_trait]
86impl<K, V, P> ErasedPunctuator for TypedPunctuator<K, V, P>
87where
88 K: Any + Send + Clone,
89 V: Any + Send + Clone,
90 P: Punctuator<K, V>,
91{
92 async fn fire(&mut self, dispatch: &mut Dispatch<'_>, timestamp: i64) {
93 let mut ctx = ProcessorContext::<'_, '_, K, V>::new(dispatch);
94 self.inner.punctuate(&mut ctx, timestamp).await;
95 }
96}
97
98pub(crate) struct ScheduleEntry {
100 pub node_idx: usize,
101 pub interval: Time,
102 pub ty: PunctuationType,
103 pub next_time: i64,
108 pub punctuator: Box<dyn ErasedPunctuator>,
109 pub cancel: Arc<AtomicBool>,
110}
111impl ScheduleEntry {
112 pub fn is_cancelled(&self) -> bool {
113 self.cancel.load(Ordering::SeqCst)
114 }
115}
116
117#[cfg(test)]
118mod tests {
119 use assert2::check;
120
121 use super::*;
122
123 #[test]
124 fn cancellable_flips_the_flag() {
125 let flag = Arc::new(AtomicBool::new(false));
126 let c = Cancellable::new(flag.clone());
127 check!(!flag.load(Ordering::SeqCst));
128 c.cancel();
129 check!(flag.load(Ordering::SeqCst));
130 }
131
132 #[test]
133 fn schedule_entry_reports_cancelled() {
134 struct NoOp;
135 #[async_trait]
136 impl ErasedPunctuator for NoOp {
137 async fn fire(&mut self, _d: &mut Dispatch<'_>, _ts: i64) {}
138 }
139 let flag = Arc::new(AtomicBool::new(false));
140 let e = ScheduleEntry {
141 node_idx: 0,
142 interval: millis(10),
143 ty: PunctuationType::StreamTime,
144 next_time: 0,
145 punctuator: Box::new(NoOp),
146 cancel: flag.clone(),
147 };
148 check!(!e.is_cancelled());
149 flag.store(true, Ordering::SeqCst);
150 check!(e.is_cancelled());
151 }
152}