use std::fmt::{self, Display, Formatter};
use std::sync::Arc;
use crate::{ExecutionPlan, displayable, with_new_children_if_necessary};
use datafusion_common::Result;
use datafusion_common::tree_node::{ConcreteTreeNode, DynTreeNode};
impl DynTreeNode for dyn ExecutionPlan {
fn arc_children(&self) -> Vec<&Arc<Self>> {
self.children()
}
fn with_new_arc_children(
&self,
arc_self: Arc<Self>,
new_children: Vec<Arc<Self>>,
) -> Result<Arc<Self>> {
with_new_children_if_necessary(arc_self, new_children)
}
}
#[derive(Debug)]
pub struct PlanContext<T: Sized> {
pub plan: Arc<dyn ExecutionPlan>,
pub data: T,
pub children: Vec<Self>,
}
impl<T> PlanContext<T> {
pub fn new(plan: Arc<dyn ExecutionPlan>, data: T, children: Vec<Self>) -> Self {
Self {
plan,
data,
children,
}
}
pub fn update_plan_from_children(mut self) -> Result<Self> {
let children_plans = self.children.iter().map(|c| Arc::clone(&c.plan)).collect();
self.plan = with_new_children_if_necessary(self.plan, children_plans)?;
Ok(self)
}
}
impl<T: Default> PlanContext<T> {
pub fn new_default(plan: Arc<dyn ExecutionPlan>) -> Self {
let children = plan
.children()
.into_iter()
.cloned()
.map(Self::new_default)
.collect();
Self::new(plan, Default::default(), children)
}
}
impl<T: Display> Display for PlanContext<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let node_string = displayable(self.plan.as_ref()).one_line();
write!(f, "Node plan: {node_string}")?;
write!(f, "Node data: {}", self.data)?;
write!(f, "")
}
}
impl<T> ConcreteTreeNode for PlanContext<T> {
fn children(&self) -> &[Self] {
&self.children
}
fn take_children(mut self) -> (Self, Vec<Self>) {
let children = std::mem::take(&mut self.children);
(self, children)
}
fn with_new_children(mut self, children: Vec<Self>) -> Result<Self> {
self.children = children;
self.update_plan_from_children()
}
}