use crate::graph::GraphStorage;
use crate::traversal::optimizer::path_analysis::{PathAnalysis, PathRequirement};
use crate::value::Operator;
use crate::*;
pub(crate) mod reason {
pub(crate) const TOO_MANY: &str = "Sack step can only have one by modulator";
}
struct StepSackValue<'g, S: GraphStorage + 'g> {
operator: Operator,
by: Option<By<'g, S>>,
by_check: ByModulatorCheck,
}
impl<'g, S: GraphStorage + 'g> Clone for StepSackValue<'g, S> {
fn clone(&self) -> Self {
Self {
operator: self.operator,
by: self.by.clone(),
by_check: self.by_check.clone(),
}
}
}
impl<'g, S: GraphStorage + 'g> fmt::Display for StepSackValue<'g, S> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "sack(Operator.{})", self.operator)?;
match &self.by {
None => Ok(()),
Some(by) => f.write_str(&crate::traversal::render_by(by)),
}
}
}
fn sack_step<'g, S: GraphStorage + 'g>(operator: Operator) -> GraphStep<'g, S> {
GraphStep::FlatMap(
"sack",
Box::new(StepSackValue {
operator,
by: None,
by_check: ByModulatorCheck::default(),
}),
)
}
impl<'g, S: GraphStorage + 'g> GraphTraversalSource<'g, S> {
pub fn sack_with(self, operator: Operator) -> Self {
self.push_step(sack_step(operator))
}
}
impl __ {
pub fn sack_with<'g, S: GraphStorage + 'g>(operator: Operator) -> AnonymousTraversal<'g, S> {
AnonymousTraversal::new().sack_with(operator)
}
}
impl<'g, S: GraphStorage + 'g> AnonymousTraversal<'g, S> {
pub fn sack_with(self, operator: Operator) -> Self {
self.push_step(sack_step(operator))
}
}
impl<'g, S: GraphStorage + 'g> GraphStepFlatMap<'g, S> for StepSackValue<'g, S> {
fn process(
&self,
context: &mut TraverserContext<'_, S>,
mut source: Traverser<S>,
output: &mut Vec<Traverser<S>>,
) -> TraverserResult<()> {
self.by_check.check("sack")?;
let resolved = match &self.by {
Some(by) => {
TraverserValue::fetch_traverser_value_by(context, &source, &source.value, by)?
}
None => Some(source.value.clone()),
};
let Some(resolved) = resolved else {
return Ok(());
};
let storage: &S = context.storage;
let operand = resolved.into_node_property(storage)?;
let current = context.sacks.get(source.sack).clone();
let updated = self.operator.apply_owned(current, operand)?;
source.sack = context.sacks.intern(updated)?;
output.push(source);
Ok(())
}
fn extends_path(&self) -> bool {
false
}
fn push_modulator_by(&mut self, args: By<'g, S>, _modulator_name: &str) -> ByModulation {
self.by_check.observe(&args);
if self.by.is_some() {
self.by_check.reject_last(reason::TOO_MANY);
}
self.by = Some(args);
ByModulation::Accepted
}
fn child_traversals_mut(&mut self) -> Vec<&mut crate::traversal::AnonymousTraversal<'g, S>> {
self.by
.as_mut()
.and_then(By::traversal_mut)
.into_iter()
.collect()
}
fn analyze_nested_paths(
&mut self,
analysis: &PathAnalysis,
_downstream: &PathRequirement,
) -> PathRequirement {
match &mut self.by {
Some(by) => by.analyze_paths(analysis),
None => PathRequirement::None,
}
}
fn clone_box(&self) -> Box<dyn GraphStepFlatMap<'g, S> + 'g> {
Box::new(self.clone())
}
}