use super::{Graph, GraphContext};
use crate::model::node::Node;
use crate::model::node::{NodeIter, NodePointer};
use crate::model::NodeId;
pub struct SquashIter<'a> {
id: NodeId,
depth: u8,
graph: &'a Graph,
resume_id: Option<NodeId>,
}
impl<'a> SquashIter<'a> {
#[allow(dead_code)]
pub fn new(graph: &'a Graph, id: NodeId, depth: u8) -> Self {
Self {
id,
depth,
graph,
resume_id: None,
}
}
fn next_referenced_id(&self) -> Option<NodeId> {
self.graph
.node(self.id)
.to_next()
.and_then(|n| n.ref_key())
.and_then(|key| self.graph.maybe_key(&key))
.and_then(|doc| doc.to_child())
.and_then(|node| node.id())
}
fn resume_next_referenced_id(&self) -> Option<NodeId> {
self.resume_id
.map(|id| self.graph.node(id))
.and_then(|n| n.to_next())
.and_then(|n| n.ref_key())
.and_then(|key| self.graph.maybe_key(&key))
.and_then(|doc| doc.to_child())
.and_then(|node| node.id())
}
fn resume_next_id(&self) -> Option<NodeId> {
self.resume_id
.and_then(|resume_id| self.graph.node(resume_id).to_next())
.and_then(|resume_next| resume_next.id())
}
fn child_referenced_id(&self) -> Option<NodeId> {
self.graph
.node(self.id)
.to_child()
.and_then(|n| n.ref_key())
.and_then(|key| self.graph.maybe_key(&key))
.and_then(|doc| doc.to_child())
.and_then(|node| node.id())
}
fn next_id(&self) -> Option<NodeId> {
self.graph.graph_node(self.id).next_id()
}
fn child_id(&self) -> Option<NodeId> {
self.graph.graph_node(self.id).child_id()
}
}
impl<'a> NodeIter<'a> for SquashIter<'a> {
fn next(&self) -> Option<Self> {
self.next_referenced_id()
.filter(|_| self.depth > 0)
.map(|id| SquashIter {
id,
depth: self.depth - 1,
resume_id: self.next_id(),
graph: self.graph,
})
.or(self
.resume_id
.filter(|_| self.next_id().is_none())
.and_then(|_| {
self.resume_next_referenced_id()
.filter(|_| self.depth > 0)
.map(|id| SquashIter {
id,
depth: self.depth + 1,
resume_id: self.resume_next_id(),
graph: self.graph,
})
.or(self.resume_next_id().map(|id| SquashIter {
id,
depth: self.depth + 1,
resume_id: None,
graph: self.graph,
}))
}))
.or(self.next_id().map(|id| SquashIter {
id,
depth: self.depth,
resume_id: self.resume_id,
graph: self.graph,
}))
}
fn child(&self) -> Option<Self> {
self.child_referenced_id()
.filter(|_| self.depth > 0)
.map(|id| SquashIter {
id,
depth: self.depth - 1,
resume_id: self.child_id(),
graph: self.graph,
})
.or(self.child_id().map(|id| SquashIter {
id,
depth: self.depth,
resume_id: None,
graph: self.graph,
}))
}
fn node(&self) -> Option<Node> {
{
let this = &self.graph;
let id = self.id;
this.node(id).node()
}
}
}