vortex_array/expr/analysis/
annotation.rs1use std::hash::Hash;
5
6use vortex_error::VortexExpect;
7use vortex_error::VortexResult;
8use vortex_utils::aliases::hash_map::HashMap;
9use vortex_utils::aliases::hash_set::HashSet;
10
11use crate::expr::BoundExpression;
12use crate::expr::ExactBoundExpr;
13use crate::expr::traversal::NodeExt;
14use crate::expr::traversal::NodeVisitor;
15use crate::expr::traversal::TraversalOrder;
16
17pub trait Annotation: Clone + Hash + Eq {}
19
20impl<A> Annotation for A where A: Clone + Hash + Eq {}
21
22pub trait AnnotationFn<N = BoundExpression>: Fn(&N) -> Vec<Self::Annotation> {
24 type Annotation: Annotation;
26}
27
28impl<N, A, F> AnnotationFn<N> for F
29where
30 A: Annotation,
31 F: Fn(&N) -> Vec<A>,
32{
33 type Annotation = A;
34}
35
36pub type BoundAnnotations<A> = HashMap<ExactBoundExpr, HashSet<A>>;
41
42pub fn descendent_bound_annotations<A>(
46 expr: &BoundExpression,
47 annotate: A,
48) -> BoundAnnotations<A::Annotation>
49where
50 A: AnnotationFn<BoundExpression>,
51{
52 bound_annotations(expr, annotate, true)
53}
54
55pub fn direct_bound_annotations<A>(
59 expr: &BoundExpression,
60 annotate: A,
61) -> BoundAnnotations<A::Annotation>
62where
63 A: AnnotationFn<BoundExpression>,
64{
65 bound_annotations(expr, annotate, false)
66}
67
68fn bound_annotations<A>(
69 expr: &BoundExpression,
70 annotate: A,
71 propagate_up: bool,
72) -> BoundAnnotations<A::Annotation>
73where
74 A: AnnotationFn<BoundExpression>,
75{
76 let mut visitor = BoundAnnotationVisitor {
77 annotations: Default::default(),
78 annotate,
79 propagate_up,
80 };
81 expr.accept(&mut visitor).vortex_expect("Infallible");
82 visitor.annotations
83}
84
85struct BoundAnnotationVisitor<A>
86where
87 A: AnnotationFn<BoundExpression>,
88{
89 annotations: BoundAnnotations<A::Annotation>,
90 annotate: A,
91 propagate_up: bool,
92}
93
94impl<'a, A> NodeVisitor<'a> for BoundAnnotationVisitor<A>
95where
96 A: AnnotationFn<BoundExpression>,
97{
98 type NodeTy = BoundExpression;
99
100 fn visit_down(&mut self, node: &'a Self::NodeTy) -> VortexResult<TraversalOrder> {
101 let annotations = (self.annotate)(node);
102 if annotations.is_empty() {
103 return Ok(TraversalOrder::Continue);
104 }
105
106 self.annotations
107 .entry(ExactBoundExpr(node.clone()))
108 .or_default()
109 .extend(annotations);
110 Ok(TraversalOrder::Skip)
111 }
112
113 fn visit_up(&mut self, node: &'a Self::NodeTy) -> VortexResult<TraversalOrder> {
114 if !self.propagate_up {
115 return Ok(TraversalOrder::Continue);
116 }
117
118 let child_annotations = node
119 .children()
120 .iter()
121 .filter_map(|child| {
122 self.annotations
123 .get(&ExactBoundExpr(child.clone()))
124 .cloned()
125 })
126 .collect::<Vec<_>>();
127 let annotations = self
128 .annotations
129 .entry(ExactBoundExpr(node.clone()))
130 .or_default();
131 child_annotations
132 .into_iter()
133 .for_each(|child| annotations.extend(child));
134
135 Ok(TraversalOrder::Continue)
136 }
137}