use super::*;
pub trait SchemaVisitor {
type T;
fn before_struct_field(&mut self, _field: &NestedFieldRef) -> Result<()> {
Ok(())
}
fn after_struct_field(&mut self, _field: &NestedFieldRef) -> Result<()> {
Ok(())
}
fn before_list_element(&mut self, _field: &NestedFieldRef) -> Result<()> {
Ok(())
}
fn after_list_element(&mut self, _field: &NestedFieldRef) -> Result<()> {
Ok(())
}
fn before_map_key(&mut self, _field: &NestedFieldRef) -> Result<()> {
Ok(())
}
fn after_map_key(&mut self, _field: &NestedFieldRef) -> Result<()> {
Ok(())
}
fn before_map_value(&mut self, _field: &NestedFieldRef) -> Result<()> {
Ok(())
}
fn after_map_value(&mut self, _field: &NestedFieldRef) -> Result<()> {
Ok(())
}
fn schema(&mut self, schema: &Schema, value: Self::T) -> Result<Self::T>;
fn field(&mut self, field: &NestedFieldRef, value: Self::T) -> Result<Self::T>;
fn r#struct(&mut self, r#struct: &StructType, results: Vec<Self::T>) -> Result<Self::T>;
fn list(&mut self, list: &ListType, value: Self::T) -> Result<Self::T>;
fn map(&mut self, map: &MapType, key_value: Self::T, value: Self::T) -> Result<Self::T>;
fn primitive(&mut self, p: &PrimitiveType) -> Result<Self::T>;
}
pub fn visit_type<V: SchemaVisitor>(r#type: &Type, visitor: &mut V) -> Result<V::T> {
match r#type {
Type::Primitive(p) => visitor.primitive(p),
Type::List(list) => {
visitor.before_list_element(&list.element_field)?;
let value = visit_type(&list.element_field.field_type, visitor)?;
visitor.after_list_element(&list.element_field)?;
visitor.list(list, value)
}
Type::Map(map) => {
let key_result = {
visitor.before_map_key(&map.key_field)?;
let ret = visit_type(&map.key_field.field_type, visitor)?;
visitor.after_map_key(&map.key_field)?;
ret
};
let value_result = {
visitor.before_map_value(&map.value_field)?;
let ret = visit_type(&map.value_field.field_type, visitor)?;
visitor.after_map_value(&map.value_field)?;
ret
};
visitor.map(map, key_result, value_result)
}
Type::Struct(s) => visit_struct(s, visitor),
}
}
pub fn visit_struct<V: SchemaVisitor>(s: &StructType, visitor: &mut V) -> Result<V::T> {
let mut results = Vec::with_capacity(s.fields().len());
for field in s.fields() {
visitor.before_struct_field(field)?;
let result = visit_type(&field.field_type, visitor)?;
visitor.after_struct_field(field)?;
let result = visitor.field(field, result)?;
results.push(result);
}
visitor.r#struct(s, results)
}
pub fn visit_schema<V: SchemaVisitor>(schema: &Schema, visitor: &mut V) -> Result<V::T> {
let result = visit_struct(&schema.r#struct, visitor)?;
visitor.schema(schema, result)
}