use crate::types::PIPELINE_PRODUCE_SIZE;
use crate::{
engine::{context::GraphCtx, traverser::Traverser},
types::error::StoreError,
};
use smallvec::SmallVec;
use std::{cell::RefCell, collections::VecDeque, rc::Rc};
#[derive(Debug, Clone)]
pub(crate) struct ExplainNode {
pub(crate) name: &'static str,
pub(crate) params: Vec<(&'static str, String)>,
pub(crate) children: Vec<(String, ExplainNode)>,
}
impl ExplainNode {
pub(crate) fn new(name: &'static str) -> Self {
ExplainNode { name, params: vec![], children: vec![] }
}
pub(crate) fn with_params(mut self, params: Vec<(&'static str, String)>) -> Self {
self.params = params;
self
}
pub(crate) fn with_children(mut self, children: Vec<(String, ExplainNode)>) -> Self {
self.children = children;
self
}
}
pub type StepRef = Rc<dyn GremlinStep>;
pub trait GremlinStep: std::fmt::Debug {
fn next(&self, ctx: &mut dyn GraphCtx) -> Result<Option<Rc<Traverser>>, StoreError>;
fn reset(&self);
fn add_upper(&self, upstream: StepRef);
fn upper(&self) -> Option<StepRef>;
fn explain(&self) -> ExplainNode;
}
pub trait CoreStep: std::fmt::Debug {
fn add_upper(&mut self, upstream: StepRef);
fn produce(
&mut self,
ctx: &mut dyn GraphCtx,
) -> Result<Option<SmallVec<[Rc<Traverser>; PIPELINE_PRODUCE_SIZE]>>, StoreError>;
fn reset(&mut self);
fn upper(&self) -> Option<StepRef> {
None
}
fn explain(&self) -> ExplainNode;
}
pub(crate) struct StepInner<T: CoreStep> {
pub(crate) core: T,
buffer: VecDeque<Rc<Traverser>>,
}
pub struct BufferedStep<T: CoreStep> {
pub(crate) inner: RefCell<StepInner<T>>,
}
impl<T: CoreStep + 'static> BufferedStep<T> {
pub fn new(core: T) -> Rc<Self> {
Rc::new(Self {
inner: RefCell::new(StepInner { core, buffer: VecDeque::with_capacity(PIPELINE_PRODUCE_SIZE + 1) }),
})
}
}
impl<T: CoreStep + 'static> std::fmt::Debug for BufferedStep<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.inner.borrow().core.fmt(f)
}
}
impl<T: CoreStep + 'static> GremlinStep for BufferedStep<T> {
fn next(&self, ctx: &mut dyn GraphCtx) -> Result<Option<Rc<Traverser>>, StoreError> {
let mut inner = self.inner.borrow_mut();
if inner.buffer.is_empty() {
let Some(items) = inner.core.produce(ctx)? else { return Ok(None) };
#[cfg(feature = "tracing")]
tracing::trace!(target: "rocksgraph::pipeline", "{:?} produced {} items", self, items.len());
inner.buffer.extend(items);
}
Ok(inner.buffer.pop_front())
}
fn reset(&self) {
let mut inner = self.inner.borrow_mut();
inner.buffer.clear();
inner.core.reset();
}
fn add_upper(&self, upstream: StepRef) {
self.inner.borrow_mut().core.add_upper(upstream);
}
fn upper(&self) -> Option<StepRef> {
self.inner.borrow().core.upper()
}
fn explain(&self) -> ExplainNode {
self.inner.borrow().core.explain()
}
}