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(crate) 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)
}
pub trait SchemaWithPartnerVisitor<P> {
type T;
fn before_struct_field(&mut self, _field: &NestedFieldRef, _partner: &P) -> Result<()> {
Ok(())
}
fn after_struct_field(&mut self, _field: &NestedFieldRef, _partner: &P) -> Result<()> {
Ok(())
}
fn before_list_element(&mut self, _field: &NestedFieldRef, _partner: &P) -> Result<()> {
Ok(())
}
fn after_list_element(&mut self, _field: &NestedFieldRef, _partner: &P) -> Result<()> {
Ok(())
}
fn before_map_key(&mut self, _field: &NestedFieldRef, _partner: &P) -> Result<()> {
Ok(())
}
fn after_map_key(&mut self, _field: &NestedFieldRef, _partner: &P) -> Result<()> {
Ok(())
}
fn before_map_value(&mut self, _field: &NestedFieldRef, _partner: &P) -> Result<()> {
Ok(())
}
fn after_map_value(&mut self, _field: &NestedFieldRef, _partner: &P) -> Result<()> {
Ok(())
}
fn schema(&mut self, schema: &Schema, partner: &P, value: Self::T) -> Result<Self::T>;
fn field(&mut self, field: &NestedFieldRef, partner: &P, value: Self::T) -> Result<Self::T>;
fn r#struct(
&mut self,
r#struct: &StructType,
partner: &P,
results: Vec<Self::T>,
) -> Result<Self::T>;
fn list(&mut self, list: &ListType, partner: &P, value: Self::T) -> Result<Self::T>;
fn map(
&mut self,
map: &MapType,
partner: &P,
key_value: Self::T,
value: Self::T,
) -> Result<Self::T>;
fn primitive(&mut self, p: &PrimitiveType, partner: &P) -> Result<Self::T>;
}
pub trait PartnerAccessor<P> {
fn struct_parner<'a>(&self, schema_partner: &'a P) -> Result<&'a P>;
fn field_partner<'a>(&self, struct_partner: &'a P, field: &NestedField) -> Result<&'a P>;
fn list_element_partner<'a>(&self, list_partner: &'a P) -> Result<&'a P>;
fn map_key_partner<'a>(&self, map_partner: &'a P) -> Result<&'a P>;
fn map_value_partner<'a>(&self, map_partner: &'a P) -> Result<&'a P>;
}
pub(crate) fn visit_type_with_partner<P, V: SchemaWithPartnerVisitor<P>, A: PartnerAccessor<P>>(
r#type: &Type,
partner: &P,
visitor: &mut V,
accessor: &A,
) -> Result<V::T> {
match r#type {
Type::Primitive(p) => visitor.primitive(p, partner),
Type::List(list) => {
let list_element_partner = accessor.list_element_partner(partner)?;
visitor.before_list_element(&list.element_field, list_element_partner)?;
let element_results = visit_type_with_partner(
&list.element_field.field_type,
list_element_partner,
visitor,
accessor,
)?;
visitor.after_list_element(&list.element_field, list_element_partner)?;
visitor.list(list, partner, element_results)
}
Type::Map(map) => {
let key_partner = accessor.map_key_partner(partner)?;
visitor.before_map_key(&map.key_field, key_partner)?;
let key_result =
visit_type_with_partner(&map.key_field.field_type, key_partner, visitor, accessor)?;
visitor.after_map_key(&map.key_field, key_partner)?;
let value_partner = accessor.map_value_partner(partner)?;
visitor.before_map_value(&map.value_field, value_partner)?;
let value_result = visit_type_with_partner(
&map.value_field.field_type,
value_partner,
visitor,
accessor,
)?;
visitor.after_map_value(&map.value_field, value_partner)?;
visitor.map(map, partner, key_result, value_result)
}
Type::Struct(s) => visit_struct_with_partner(s, partner, visitor, accessor),
}
}
pub fn visit_struct_with_partner<P, V: SchemaWithPartnerVisitor<P>, A: PartnerAccessor<P>>(
s: &StructType,
partner: &P,
visitor: &mut V,
accessor: &A,
) -> Result<V::T> {
let mut results = Vec::with_capacity(s.fields().len());
for field in s.fields() {
let field_partner = accessor.field_partner(partner, field)?;
visitor.before_struct_field(field, field_partner)?;
let result = visit_type_with_partner(&field.field_type, field_partner, visitor, accessor)?;
visitor.after_struct_field(field, field_partner)?;
let result = visitor.field(field, field_partner, result)?;
results.push(result);
}
visitor.r#struct(s, partner, results)
}
pub fn visit_schema_with_partner<P, V: SchemaWithPartnerVisitor<P>, A: PartnerAccessor<P>>(
schema: &Schema,
partner: &P,
visitor: &mut V,
accessor: &A,
) -> Result<V::T> {
let result = visit_struct_with_partner(
&schema.r#struct,
accessor.struct_parner(partner)?,
visitor,
accessor,
)?;
visitor.schema(schema, partner, result)
}