use async_trait::async_trait;
use crate::models::{CosmosResponse, FeedRange};
use super::{context::PipelineContext, snapshot::PipelineNodeState};
#[must_use = "a PageResult carries the next page, drain signal, or a split request that the caller must act on"]
#[allow(clippy::large_enum_variant)]
pub(crate) enum PageResult {
Page {
response: CosmosResponse,
is_terminal: bool,
},
Drained,
SplitRequired {
replacement_nodes: Vec<Box<dyn PipelineNode>>,
},
}
impl std::fmt::Debug for PageResult {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
PageResult::Page { is_terminal, .. } => {
write!(f, "Page(terminal={is_terminal})")
}
PageResult::Drained => f.write_str("Drained"),
PageResult::SplitRequired {
replacement_nodes, ..
} => write!(f, "SplitRequired({} nodes)", replacement_nodes.len()),
}
}
}
#[async_trait]
pub(crate) trait PipelineNode: Send + std::any::Any {
async fn next_page(
&mut self,
context: &mut PipelineContext<'_>,
) -> crate::error::Result<PageResult>;
#[cfg(test)]
fn into_children(self) -> Vec<Box<dyn PipelineNode>>;
fn snapshot_state(&self) -> crate::error::Result<PipelineNodeState>;
fn topology_can_change(&self) -> bool;
fn feed_range(&self) -> Option<&FeedRange> {
None
}
}
#[cfg(test)]
impl dyn PipelineNode {
pub(crate) fn downcast_ref<T: PipelineNode>(&self) -> Option<&T> {
(self as &dyn std::any::Any).downcast_ref::<T>()
}
pub(crate) fn downcast<T: PipelineNode>(self: Box<Self>) -> Option<Box<T>> {
(self as Box<dyn std::any::Any>).downcast::<T>().ok()
}
}