use std::any::Any;
use std::marker::PhantomData;
use std::sync::{Arc, Mutex};
use async_trait::async_trait;
use tinyflow_api::error::StreamResult;
use tinyflow_api::functions::SourceFunction;
use super::{
ChainSegmentFactory, ChainSourceSegment, ChainStepKindInner, NamedStep,
impl_chain_segment_lifecycle,
};
struct SourceChainSegment<T, S>
where
T: Send,
S: SourceFunction<T>,
{
function: S,
task_id: u32,
input_cnt: u64,
output_cnt: u64,
last_input_cnt: u64,
last_output_cnt: u64,
_marker: PhantomData<T>,
}
impl<T, S> SourceChainSegment<T, S>
where
T: Send + 'static,
S: SourceFunction<T> + Send,
{
fn new(function: S) -> Self {
Self {
function,
task_id: 0,
input_cnt: 0,
output_cnt: 0,
last_input_cnt: 0,
last_output_cnt: 0,
_marker: PhantomData,
}
}
}
impl_chain_segment_lifecycle! {
impl<T, S>
ChainSegment for SourceChainSegment<T, S>,
with_metrics
where
T: Send + 'static,
S: SourceFunction<T> + Send,
}
#[async_trait]
impl<T, S> ChainSourceSegment for SourceChainSegment<T, S>
where
T: Send + 'static,
S: SourceFunction<T> + Send,
{
async fn poll_next(&mut self) -> StreamResult<Option<Box<dyn Any + Send>>> {
let result = self.function.poll_next().await?;
if result.is_some() {
self.input_cnt += 1;
self.output_cnt += 1;
}
Ok(result.map(|v| Box::new(v) as Box<dyn Any + Send>))
}
}
pub fn source_chain_factory<T, S, F>(factory: Arc<Mutex<F>>) -> ChainSegmentFactory
where
T: Send + 'static,
S: SourceFunction<T> + Send + 'static,
F: Fn() -> S + Send + 'static,
{
Box::new(move || {
let source = factory.lock().expect("source factory lock poisoned")();
NamedStep {
name: "Source".into(),
kind: ChainStepKindInner::Source(Box::new(SourceChainSegment::new(source))),
}
})
}