pub mod rewritable;
pub mod visitable;
use datafusion_common::Result;
pub trait TreeNodeVisitor: Sized {
type N: TreeNodeVisitable;
fn pre_visit(&mut self, node: &Self::N) -> Result<VisitRecursion>;
fn post_visit(&mut self, _node: &Self::N) -> Result<()> {
Ok(())
}
}
pub trait TreeNodeVisitable: Sized {
fn get_children(&self) -> Vec<Self>;
fn accept<V: TreeNodeVisitor<N = Self>>(&self, visitor: &mut V) -> Result<()> {
match visitor.pre_visit(self)? {
VisitRecursion::Continue => {}
VisitRecursion::Stop => return Ok(()),
};
for child in self.get_children() {
child.accept(visitor)?;
}
visitor.post_visit(self)
}
}
pub enum VisitRecursion {
Continue,
Stop,
}
pub trait TreeNodeRewritable: Clone {
fn transform<F>(self, op: &F) -> Result<Self>
where
F: Fn(Self) -> Result<Option<Self>>,
{
self.transform_up(op)
}
fn transform_down<F>(self, op: &F) -> Result<Self>
where
F: Fn(Self) -> Result<Option<Self>>,
{
let node_cloned = self.clone();
let after_op = match op(node_cloned)? {
Some(value) => value,
None => self,
};
after_op.map_children(|node| node.transform_down(op))
}
fn transform_up<F>(self, op: &F) -> Result<Self>
where
F: Fn(Self) -> Result<Option<Self>>,
{
let after_op_children = self.map_children(|node| node.transform_up(op))?;
let after_op_children_clone = after_op_children.clone();
let new_node = match op(after_op_children)? {
Some(value) => value,
None => after_op_children_clone,
};
Ok(new_node)
}
fn transform_using<R: TreeNodeRewriter<N = Self>>(
self,
rewriter: &mut R,
) -> Result<Self> {
let need_mutate = match rewriter.pre_visit(&self)? {
RewriteRecursion::Mutate => return rewriter.mutate(self),
RewriteRecursion::Stop => return Ok(self),
RewriteRecursion::Continue => true,
RewriteRecursion::Skip => false,
};
let after_op_children =
self.map_children(|node| node.transform_using(rewriter))?;
if need_mutate {
rewriter.mutate(after_op_children)
} else {
Ok(after_op_children)
}
}
fn map_children<F>(self, transform: F) -> Result<Self>
where
F: FnMut(Self) -> Result<Self>;
}
pub trait TreeNodeRewriter: Sized {
type N: TreeNodeRewritable;
fn pre_visit(&mut self, _node: &Self::N) -> Result<RewriteRecursion> {
Ok(RewriteRecursion::Continue)
}
fn mutate(&mut self, node: Self::N) -> Result<Self::N>;
}
#[allow(dead_code)]
pub enum RewriteRecursion {
Continue,
Mutate,
Stop,
Skip,
}