pub mod barrier;
pub mod branch;
pub mod filter;
pub mod flatmap;
pub mod map;
pub mod sideeffect;
pub mod source;
pub mod traverser;
pub use barrier::{
BarrierStep, CollectingBarrierStep, FoldStep, GroupStep, OrderStep, ReducingBarrierStep,
};
pub use branch::{BranchStep, ChooseStep, OptionalStep, RepeatStep, UnionStep};
pub use filter::{DedupStep, FilterStep, HasStep, LimitStep, Predicate, RangeStep, WhereStep};
pub use flatmap::{BothStep, Direction, EdgeStep, FlatMapStep, InStep, OutStep, VertexStep};
pub use map::{IdStep, MapStep, PathStep, ProjectStep, SelectStep, ValueMapStep};
pub use sideeffect::{AggregateStep, PropertyStep, SideEffectStep, StoreStep};
pub use source::{EdgeSourceStep, SourceStep, VertexSourceStep};
pub use traverser::{
LoopState, Path, Traverser, TraverserGenerator, TraverserRequirement, TraverserValue,
};
use std::any::Any;
use std::fmt::Debug;
pub trait Step: Send + Sync + Debug {
fn id(&self) -> &str;
fn name(&self) -> &str;
fn labels(&self) -> &[String];
fn add_label(&mut self, label: String);
fn requirements(&self) -> &[TraverserRequirement];
fn process_traverser(&self, traverser: Traverser) -> StepResult;
fn reset(&mut self);
fn clone_step(&self) -> Box<dyn Step>;
fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any;
}
#[derive(Debug, Clone)]
pub enum StepResult {
Emit(Vec<Traverser>),
Filter,
Hold(Vec<Traverser>),
Error(String),
}
impl StepResult {
pub fn emit_one(traverser: Traverser) -> Self {
StepResult::Emit(vec![traverser])
}
pub fn emit_many(traversers: Vec<Traverser>) -> Self {
if traversers.is_empty() {
StepResult::Filter
} else {
StepResult::Emit(traversers)
}
}
pub fn is_filter(&self) -> bool {
matches!(self, StepResult::Filter)
}
pub fn has_traversers(&self) -> bool {
match self {
StepResult::Emit(t) => !t.is_empty(),
StepResult::Hold(t) => !t.is_empty(),
_ => false,
}
}
pub fn into_traversers(self) -> Vec<Traverser> {
match self {
StepResult::Emit(t) | StepResult::Hold(t) => t,
_ => Vec::new(),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ExecutionMode {
Standard,
Computer,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum StepPosition {
Start,
Middle,
End,
}
pub trait TraversalParent: Send + Sync {
fn global_children(&self) -> Vec<&dyn Traversal>;
fn local_children(&self) -> Vec<&dyn Traversal>;
fn children(&self) -> Vec<&dyn Traversal> {
let mut all = self.global_children();
all.extend(self.local_children());
all
}
}
pub trait Traversal: Send + Sync + Debug {
fn steps(&self) -> &[Box<dyn Step>];
fn steps_mut(&mut self) -> &mut Vec<Box<dyn Step>>;
fn add_step(&mut self, step: Box<dyn Step>);
fn insert_step(&mut self, index: usize, step: Box<dyn Step>);
fn remove_step(&mut self, index: usize) -> Box<dyn Step>;
fn get_step(&self, index: usize) -> Option<&dyn Step>;
fn find_step(&self, id: &str) -> Option<&dyn Step>;
fn requirements(&self) -> Vec<TraverserRequirement>;
fn reset(&mut self);
}
#[derive(Debug)]
pub struct BasicTraversal {
steps: Vec<Box<dyn Step>>,
requirements_cache: Option<Vec<TraverserRequirement>>,
}
impl BasicTraversal {
pub fn new() -> Self {
Self {
steps: Vec::new(),
requirements_cache: None,
}
}
pub fn with_steps(steps: Vec<Box<dyn Step>>) -> Self {
Self {
steps,
requirements_cache: None,
}
}
fn invalidate_cache(&mut self) {
self.requirements_cache = None;
}
}
impl Default for BasicTraversal {
fn default() -> Self {
Self::new()
}
}
impl Clone for BasicTraversal {
fn clone(&self) -> Self {
Self {
steps: self.steps.iter().map(|s| s.clone_step()).collect(),
requirements_cache: self.requirements_cache.clone(),
}
}
}
impl Traversal for BasicTraversal {
fn steps(&self) -> &[Box<dyn Step>] {
&self.steps
}
fn steps_mut(&mut self) -> &mut Vec<Box<dyn Step>> {
self.invalidate_cache();
&mut self.steps
}
fn add_step(&mut self, step: Box<dyn Step>) {
self.invalidate_cache();
self.steps.push(step);
}
fn insert_step(&mut self, index: usize, step: Box<dyn Step>) {
self.invalidate_cache();
self.steps.insert(index, step);
}
fn remove_step(&mut self, index: usize) -> Box<dyn Step> {
self.invalidate_cache();
self.steps.remove(index)
}
fn get_step(&self, index: usize) -> Option<&dyn Step> {
self.steps.get(index).map(|s| s.as_ref())
}
fn find_step(&self, id: &str) -> Option<&dyn Step> {
self.steps.iter().find(|s| s.id() == id).map(|s| s.as_ref())
}
fn requirements(&self) -> Vec<TraverserRequirement> {
if let Some(ref cached) = self.requirements_cache {
return cached.clone();
}
let mut reqs: Vec<TraverserRequirement> = Vec::new();
for step in &self.steps {
for req in step.requirements() {
if !reqs.contains(req) {
reqs.push(req.clone());
}
}
}
reqs
}
fn reset(&mut self) {
for step in &mut self.steps {
step.reset();
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_step_result_emit_one() {
let traverser = Traverser::new("test");
let result = StepResult::emit_one(traverser);
assert!(result.has_traversers());
}
#[test]
fn test_step_result_filter() {
let result = StepResult::Filter;
assert!(result.is_filter());
assert!(!result.has_traversers());
}
#[test]
fn test_step_result_into_traversers() {
let t1 = Traverser::new("a");
let t2 = Traverser::new("b");
let result = StepResult::emit_many(vec![t1, t2]);
let traversers = result.into_traversers();
assert_eq!(traversers.len(), 2);
}
#[test]
fn test_basic_traversal() {
let traversal = BasicTraversal::new();
assert_eq!(traversal.steps().len(), 0);
}
}