use super::envelope::EnvelopeCase;
use crate::Envelope;
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub enum EdgeType {
None,
Subject,
Assertion,
Predicate,
Object,
Content,
}
impl EdgeType {
pub fn label(&self) -> Option<&'static str> {
match self {
EdgeType::Subject => Some("subj"),
EdgeType::Content => Some("cont"),
EdgeType::Predicate => Some("pred"),
EdgeType::Object => Some("obj"),
_ => None,
}
}
}
pub type Visitor<'a, State> =
dyn Fn(&Envelope, usize, EdgeType, State) -> (State, bool) + 'a;
impl Envelope {
pub fn walk<State: Clone>(
&self,
hide_nodes: bool,
state: State,
visit: &Visitor<'_, State>,
) {
if hide_nodes {
self.walk_tree(state, visit)
} else {
self.walk_structure(state, visit)
}
}
fn walk_structure<State: Clone>(
&self,
state: State,
visit: &Visitor<'_, State>,
) {
self._walk_structure(0, EdgeType::None, state, visit)
}
fn _walk_structure<State: Clone>(
&self,
level: usize,
incoming_edge: EdgeType,
state: State,
visit: &Visitor<'_, State>,
) {
let mut state = state;
let stop;
(state, stop) = visit(self, level, incoming_edge, state);
if stop {
return;
}
let next_level = level + 1;
match self.case() {
EnvelopeCase::Node { subject, assertions, .. } => {
subject._walk_structure(
next_level,
EdgeType::Subject,
state.clone(),
visit,
);
for assertion in assertions {
assertion._walk_structure(
next_level,
EdgeType::Assertion,
state.clone(),
visit,
);
}
}
EnvelopeCase::Wrapped { envelope, .. } => {
envelope._walk_structure(
next_level,
EdgeType::Content,
state,
visit,
);
}
EnvelopeCase::Assertion(assertion) => {
assertion.predicate()._walk_structure(
next_level,
EdgeType::Predicate,
state.clone(),
visit,
);
assertion.object()._walk_structure(
next_level,
EdgeType::Object,
state,
visit,
);
}
_ => {}
}
}
fn walk_tree<State: Clone>(
&self,
state: State,
visit: &Visitor<'_, State>,
) {
_ = self._walk_tree(0, EdgeType::None, state, visit)
}
fn _walk_tree<State: Clone>(
&self,
level: usize,
incoming_edge: EdgeType,
state: State,
visit: &Visitor<'_, State>,
) -> State {
let mut state = state;
let mut subject_level = level;
if !self.is_node() {
let stop;
(state, stop) = visit(self, level, incoming_edge, state);
if stop {
return state;
}
subject_level = level + 1;
}
match self.case() {
EnvelopeCase::Node { subject, assertions, .. } => {
let assertion_state = subject._walk_tree(
subject_level,
EdgeType::Subject,
state.clone(),
visit,
);
let assertion_level = subject_level + 1;
for assertion in assertions {
assertion._walk_tree(
assertion_level,
EdgeType::Assertion,
assertion_state.clone(),
visit,
);
}
}
EnvelopeCase::Wrapped { envelope, .. } => {
envelope._walk_tree(
subject_level,
EdgeType::Content,
state.clone(),
visit,
);
}
EnvelopeCase::Assertion(assertion) => {
assertion.predicate()._walk_tree(
subject_level,
EdgeType::Predicate,
state.clone(),
visit,
);
assertion.object()._walk_tree(
subject_level,
EdgeType::Object,
state.clone(),
visit,
);
}
_ => {}
}
state
}
}