pub trait AvroSchemaComponent {
// Required method
fn get_schema_in_ctxt(
named_schemas: &mut HashSet<Name>,
enclosing_namespace: &Namespace,
) -> Schema;
// Provided method
fn get_record_fields_in_ctxt(
first_field_position: usize,
named_schemas: &mut HashSet<Name>,
enclosing_namespace: &Namespace,
) -> Option<Vec<RecordField>> { ... }
}Expand description
Trait for types that serve as fully defined components inside an Avro data model.
This trait can be derived with #[derive(AvroSchema)] when the derive feature is enabled.
§Implementation guide
§Implementation for returning primitive types
When the schema you want to return is a primitive type (a type without a name), the function arguments can be ignored.
For example, you have a custom integer type:
// Make sure to implement `Serialize` and `Deserialize` to use the right serialization methods
pub struct U24([u8; 3]);
impl AvroSchemaComponent for U24 {
fn get_schema_in_ctxt(_: &mut HashSet<Name>, _: &Namespace) -> Schema {
Schema::Int
}
fn get_record_fields_in_ctxt(_: usize, _: &mut HashSet<Name>, _: &Namespace) -> Option<Vec<RecordField>> {
None // A Schema::Int is not a Schema::Record so there are no fields to return
}
}§Passthrough implementation
To construct a schema for a type is “transparent”, such as for smart pointers, simply pass through the arguments to the inner type:
#[derive(Serialize, Deserialize)]
#[serde(transparent)] // This attribute is important for all passthrough implementations!
pub struct Transparent<T>(T);
impl<T: AvroSchemaComponent> AvroSchemaComponent for Transparent<T> {
fn get_schema_in_ctxt(named_schemas: &mut HashSet<Name>, enclosing_namespace: &Namespace) -> Schema {
T::get_schema_in_ctxt(named_schemas, enclosing_namespace)
}
fn get_record_fields_in_ctxt(first_field_position: usize, named_schemas: &mut HashSet<Name>, enclosing_namespace: &Namespace) -> Option<Vec<RecordField>> {
T::get_record_fields_in_ctxt(first_field_position, named_schemas, enclosing_namespace)
}
}§Implementation for complex types
When the schema you want to return is a complex type (a type with a name), special care has to be taken to avoid duplicate type definitions and getting the correct namespace.
Things to keep in mind:
- If the fully qualified name already exists, return a
Schema::Ref - Use the
AvroSchemaComponentimplementations to get the schemas for the subtypes - The ordering of fields in the schema must match with the ordering in Serde
- Implement
get_record_fields_in_ctxtas the default implementation has to be implemented with backtracking and a lot of cloning.- Even if your schema is not a record, still implement the function and just return
None
- Even if your schema is not a record, still implement the function and just return
pub struct Foo {
one: String,
two: i32,
three: Option<Duration>
}
impl AvroSchemaComponent for Foo {
fn get_schema_in_ctxt(named_schemas: &mut HashSet<Name>, enclosing_namespace: &Namespace) -> Schema {
// Create the fully qualified name for your type given the enclosing namespace
let name = Name::new("Foo").unwrap().fully_qualified_name(enclosing_namespace);
if named_schemas.contains(&name) {
Schema::Ref { name }
} else {
let enclosing_namespace = &name.namespace;
// Do this before you start creating the schema, as otherwise recursive types will cause infinite recursion.
named_schemas.insert(name.clone());
let schema = Schema::Record(RecordSchema::builder()
.name(name.clone())
.fields(Self::get_record_fields_in_ctxt(0, named_schemas, enclosing_namespace).expect("Impossible!"))
.build()
);
schema
}
}
fn get_record_fields_in_ctxt(first_field_position: usize, named_schemas: &mut HashSet<Name>, enclosing_namespace: &Namespace) -> Option<Vec<RecordField>> {
Some(vec![
RecordField::builder()
.name("one")
.schema(String::get_schema_in_ctxt(named_schemas, enclosing_namespace))
.position(first_field_position)
.build(),
RecordField::builder()
.name("two")
.schema(i32::get_schema_in_ctxt(named_schemas, enclosing_namespace))
.position(first_field_position+1)
.build(),
RecordField::builder()
.name("three")
.schema(<Option<Duration>>::get_schema_in_ctxt(named_schemas, enclosing_namespace))
.position(first_field_position+2)
.build(),
])
}
}Required Methods§
Provided Methods§
Sourcefn get_record_fields_in_ctxt(
first_field_position: usize,
named_schemas: &mut HashSet<Name>,
enclosing_namespace: &Namespace,
) -> Option<Vec<RecordField>>
fn get_record_fields_in_ctxt( first_field_position: usize, named_schemas: &mut HashSet<Name>, enclosing_namespace: &Namespace, ) -> Option<Vec<RecordField>>
Get the fields of this schema if it is a record.
This returns None if the schema is not a record.
The default implementation has to do a lot of extra work, so it is strongly recommended to implement this function when manually implementing this trait.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.
Implementations on Foreign Types§
Source§impl AvroSchemaComponent for bool
impl AvroSchemaComponent for bool
Source§impl AvroSchemaComponent for char
impl AvroSchemaComponent for char
Source§impl AvroSchemaComponent for f32
impl AvroSchemaComponent for f32
Source§impl AvroSchemaComponent for f64
impl AvroSchemaComponent for f64
Source§impl AvroSchemaComponent for i8
impl AvroSchemaComponent for i8
Source§impl AvroSchemaComponent for i16
impl AvroSchemaComponent for i16
Source§impl AvroSchemaComponent for i32
impl AvroSchemaComponent for i32
Source§impl AvroSchemaComponent for i64
impl AvroSchemaComponent for i64
Source§impl AvroSchemaComponent for i128
impl AvroSchemaComponent for i128
Source§fn get_schema_in_ctxt(
named_schemas: &mut HashSet<Name>,
enclosing_namespace: &Namespace,
) -> Schema
fn get_schema_in_ctxt( named_schemas: &mut HashSet<Name>, enclosing_namespace: &Namespace, ) -> Schema
The schema is Schema::Fixed of size 16 with the name i128.
fn get_record_fields_in_ctxt( _: usize, _: &mut HashSet<Name>, _: &Namespace, ) -> Option<Vec<RecordField>>
Source§impl AvroSchemaComponent for str
impl AvroSchemaComponent for str
Source§impl AvroSchemaComponent for u8
impl AvroSchemaComponent for u8
Source§impl AvroSchemaComponent for u16
impl AvroSchemaComponent for u16
Source§impl AvroSchemaComponent for u32
impl AvroSchemaComponent for u32
Source§impl AvroSchemaComponent for u64
impl AvroSchemaComponent for u64
Source§fn get_schema_in_ctxt(
named_schemas: &mut HashSet<Name>,
enclosing_namespace: &Namespace,
) -> Schema
fn get_schema_in_ctxt( named_schemas: &mut HashSet<Name>, enclosing_namespace: &Namespace, ) -> Schema
The schema is Schema::Fixed of size 8 with the name u64.
fn get_record_fields_in_ctxt( _: usize, _: &mut HashSet<Name>, _: &Namespace, ) -> Option<Vec<RecordField>>
Source§impl AvroSchemaComponent for u128
impl AvroSchemaComponent for u128
Source§fn get_schema_in_ctxt(
named_schemas: &mut HashSet<Name>,
enclosing_namespace: &Namespace,
) -> Schema
fn get_schema_in_ctxt( named_schemas: &mut HashSet<Name>, enclosing_namespace: &Namespace, ) -> Schema
The schema is Schema::Fixed of size 16 with the name u128.
fn get_record_fields_in_ctxt( _: usize, _: &mut HashSet<Name>, _: &Namespace, ) -> Option<Vec<RecordField>>
Source§impl AvroSchemaComponent for String
impl AvroSchemaComponent for String
Source§impl AvroSchemaComponent for Duration
impl AvroSchemaComponent for Duration
Source§fn get_schema_in_ctxt(
named_schemas: &mut HashSet<Name>,
enclosing_namespace: &Namespace,
) -> Schema
fn get_schema_in_ctxt( named_schemas: &mut HashSet<Name>, enclosing_namespace: &Namespace, ) -> Schema
The schema is Schema::Duration with the name duration.
This is a lossy conversion as this Avro type does not store the amount of nanoseconds.