Skip to content
This repository was archived by the owner on Jan 7, 2025. It is now read-only.

Commit bbcc22d

Browse files
authored
refactor: add data type to define_plan_node macro (#136)
Add data type to `define_plan_node`. The benefits include: - Pass actual data type in `new` instead of converting it to `Value` outside first to reduce boilerplate code. - Aggregate the serialization and deserialization to one place, to ensure serialization and deserialization use the same format - Data type is clear from the macro invocation
1 parent 3ebe94e commit bbcc22d

File tree

2 files changed

+52
-51
lines changed

2 files changed

+52
-51
lines changed

optd-datafusion-repr/src/plan_nodes.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -208,8 +208,17 @@ pub trait OptRelNode: 'static + Clone {
208208
}
209209
}
210210

211-
pub trait ExplainData: OptRelNode {
212-
fn explain_data(data: &Value) -> Vec<(&'static str, Pretty<'static>)>;
211+
/// Plan nodes that are defined through `define_plan_node` macro with data
212+
/// field should implement this trait. Since data is stored as `Value` in
213+
/// `RelNode`, we need to now how to convert between `Value` and the actual
214+
/// data type.
215+
///
216+
/// For reasons why `explain_data`` needs to be explicitly implemented, see
217+
/// `define_plan_node`.
218+
pub trait ExplainData<T>: OptRelNode {
219+
fn data_to_value(data: &T) -> Value;
220+
fn value_to_data(value: &Value) -> T;
221+
fn explain_data(data: &T) -> Vec<(&'static str, Pretty<'static>)>;
213222
}
214223

215224
#[derive(Clone, Debug)]

optd-datafusion-repr/src/plan_nodes/macros.rs

Lines changed: 41 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,19 @@
1-
/// Plan nodes with data fields must implement `ExplainData` trait. An example:
1+
/// Plan nodes with data fields must implement `ExplainData` trait.
22
///
3-
/// ```ignore
4-
/// #[derive(Clone, Debug)]
5-
/// struct PhysicalDummy(PlanNode);
6-
///
7-
/// // Implement `OptRelNode` using `define_plan_node!`...
8-
///
9-
/// impl ExplainData for PhysicalDummy {
10-
/// fn explain_data(data: &Value) -> Vec<(&'static str, Pretty<'static>)> {
11-
/// if let Value::Int32(i) = data {
12-
/// vec![("primitive_data", i.to_string().into())]
13-
/// } else {
14-
/// unreachable!()
15-
/// }
16-
/// }
17-
/// }
18-
/// ```
3+
/// The generated `dispatch_explain` method delegates explaining data to
4+
/// rel node implementations of `ExplainData` trait instead of just debug
5+
/// printing it, because for complex data type (struct), derived debug printing
6+
/// displays struct name which should be hidden from the user. It also wraps
7+
/// the fields in braces, unlike the rest of the fields as children.
8+
199
macro_rules! define_plan_node {
2010
(
2111
$struct_name:ident : $meta_typ:tt,
2212
$variant:ident,
2313
[ $({ $child_id:literal, $child_name:ident : $child_meta_typ:ty }),* ] ,
2414
[ $({ $attr_id:literal, $attr_name:ident : $attr_meta_typ:ty }),* ]
2515
$(, { $inner_name:ident : $inner_typ:ty })?
26-
$(, $data_name:ident)?
16+
$(, $data_name:ident: $data_typ: ty )?
2717
) => {
2818
impl OptRelNode for $struct_name {
2919
fn into_rel_node(self) -> OptRelNodeRef {
@@ -49,7 +39,7 @@ macro_rules! define_plan_node {
4939
if let Some(meta_map) = meta_map {
5040
fields = fields.with_meta(self.0.get_meta(meta_map));
5141
};
52-
define_plan_node!(@expand_fields self, $struct_name, fields $(, $data_name)?);
42+
define_plan_node!(@expand_data_fields self, $struct_name, fields $(, $data_name)?);
5343

5444
pretty_xmlish::Pretty::simple_record(
5545
stringify!($struct_name),
@@ -65,13 +55,13 @@ macro_rules! define_plan_node {
6555
pub fn new(
6656
$($child_name : $child_meta_typ,)*
6757
$($attr_name : $attr_meta_typ),*
68-
$($data_name: Value)?
58+
$($data_name: $data_typ)?
6959
$(, $inner_name : $inner_typ)?
7060
) -> $struct_name {
7161
#[allow(unused_mut, unused)]
7262
let mut data = None;
7363
$(
74-
data = Some($data_name);
64+
data = Some($struct_name::data_to_value(&$data_name));
7565
)*
7666
$struct_name($meta_typ(
7767
optd_core::rel_node::RelNode {
@@ -111,11 +101,11 @@ macro_rules! define_plan_node {
111101
}
112102
};
113103
// Dummy branch that does nothing when data is `None`.
114-
(@expand_fields $self:ident, $struct_name:ident, $fields:ident) => {};
104+
(@expand_data_fields $self:ident, $struct_name:ident, $fields:ident) => {};
115105
// Expand explain fields with data.
116-
(@expand_fields $self:ident, $struct_name:ident, $fields:ident, $data_name:ident) => {
117-
let data = $self.0 .0.data.as_ref().unwrap();
118-
$fields.extend($struct_name::explain_data(data));
106+
(@expand_data_fields $self:ident, $struct_name:ident, $fields:ident, $data_name:ident) => {
107+
let value = $self.0 .0.data.as_ref().unwrap();
108+
$fields.extend($struct_name::explain_data(&$struct_name::value_to_data(&value)));
119109
};
120110
}
121111

@@ -151,40 +141,42 @@ mod test {
151141
#[derive(Clone, Debug)]
152142
struct PhysicalComplexDummy(PlanNode);
153143

154-
impl ExplainData for PhysicalComplexDummy {
155-
fn explain_data(data: &Value) -> Vec<(&'static str, Pretty<'static>)> {
156-
if let Value::Serialized(serialized_data) = data {
157-
let data: ComplexData = bincode::deserialize(serialized_data).unwrap();
158-
vec![
159-
("a", data.a.to_string().into()),
160-
("b", data.b.to_string().into()),
161-
]
162-
} else {
163-
unreachable!()
164-
}
165-
}
166-
}
167-
168144
define_plan_node!(
169145
PhysicalComplexDummy: PlanNode,
170146
PhysicalScan, [
171147
{ 0, child: PlanNode }
172148
], [
173149
],
174-
complex_data
150+
complex_data: ComplexData
175151
);
176152

153+
impl ExplainData<ComplexData> for PhysicalComplexDummy {
154+
fn data_to_value(data: &ComplexData) -> Value {
155+
Value::Serialized(bincode::serialize(data).unwrap().into_iter().collect())
156+
}
157+
158+
fn value_to_data(value: &Value) -> ComplexData {
159+
if let Value::Serialized(serialized_data) = value {
160+
bincode::deserialize(serialized_data).unwrap()
161+
} else {
162+
unreachable!()
163+
}
164+
}
165+
166+
fn explain_data(data: &ComplexData) -> Vec<(&'static str, Pretty<'static>)> {
167+
vec![
168+
("a", data.a.to_string().into()),
169+
("b", data.b.to_string().into()),
170+
]
171+
}
172+
}
173+
177174
let node = PhysicalComplexDummy::new(
178175
LogicalScan::new("a".to_string()).0,
179-
Value::Serialized(
180-
bincode::serialize(&ComplexData {
181-
a: 1,
182-
b: "a".to_string(),
183-
})
184-
.unwrap()
185-
.into_iter()
186-
.collect(),
187-
),
176+
ComplexData {
177+
a: 1,
178+
b: "a".to_string(),
179+
},
188180
);
189181
let pretty = node.dispatch_explain(None);
190182
println!("{}", get_explain_str(&pretty));

0 commit comments

Comments
 (0)