avro-schema 0.3.0

Apache Avro specification
Documentation
use serde::ser::{SerializeMap, SerializeSeq};
use serde::{Serialize, Serializer};

use super::*;

impl Serialize for Schema {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        match self {
            Schema::Null => serializer.serialize_str("null"),
            Schema::Boolean => serializer.serialize_str("boolean"),
            Schema::Int(logical) => match logical {
                None => serializer.serialize_str("int"),
                Some(logical) => {
                    let mut map = serializer.serialize_map(Some(2))?;
                    map.serialize_entry("type", "int")?;
                    let name = match logical {
                        IntLogical::Date => "date",
                        IntLogical::Time => "time-millis",
                    };
                    map.serialize_entry("logicalType", name)?;
                    map.end()
                }
            },
            Schema::Long(logical) => match logical {
                None => serializer.serialize_str("long"),
                Some(logical) => {
                    let mut map = serializer.serialize_map(Some(2))?;
                    map.serialize_entry("type", "long")?;
                    let name = match logical {
                        LongLogical::Time => "time-micros",
                        LongLogical::TimestampMillis => "timestamp-millis",
                        LongLogical::TimestampMicros => "timestamp-micros",
                        LongLogical::LocalTimestampMillis => "local-timestamp-millis",
                        LongLogical::LocalTimestampMicros => "local-timestamp-micros",
                    };
                    map.serialize_entry("logicalType", name)?;
                    map.end()
                }
            },
            Schema::Float => serializer.serialize_str("float"),
            Schema::Double => serializer.serialize_str("double"),
            Schema::Bytes(logical) => match logical {
                None => serializer.serialize_str("bytes"),
                Some(logical) => match logical {
                    BytesLogical::Decimal(precision, scale) => {
                        let mut map = serializer.serialize_map(Some(4))?;
                        map.serialize_entry("type", "bytes")?;
                        map.serialize_entry("logicalType", "decimal")?;
                        map.serialize_entry("precision", precision)?;
                        if *scale > 0 {
                            map.serialize_entry("scale", scale)?;
                        }
                        map.end()
                    }
                },
            },
            Schema::String(logical) => match logical {
                None => serializer.serialize_str("string"),
                Some(logical) => match logical {
                    StringLogical::Uuid => {
                        let mut map = serializer.serialize_map(Some(1))?;
                        map.serialize_entry("type", "string")?;
                        map.serialize_entry("logicalType", "uuid")?;
                        map.end()
                    }
                },
            },
            Schema::Record(record) => {
                let Record {
                    name,
                    namespace,
                    doc,
                    aliases,
                    fields,
                } = record;
                let mut map = serializer.serialize_map(Some(3))?;
                map.serialize_entry("type", "record")?;
                map.serialize_entry("name", name)?;
                if let Some(namespace) = namespace {
                    map.serialize_entry("namespace", namespace)?;
                }
                if !aliases.is_empty() {
                    map.serialize_entry("aliases", aliases)?;
                }
                if let Some(doc) = doc {
                    map.serialize_entry("doc", doc)?;
                }
                map.serialize_entry("fields", fields)?;
                map.end()
            }
            Schema::Enum(enum_) => {
                let Enum {
                    name,
                    namespace,
                    aliases,
                    doc,
                    symbols,
                    default,
                } = enum_;
                let mut map = serializer.serialize_map(Some(3))?;
                map.serialize_entry("type", "enum")?;
                map.serialize_entry("name", name)?;
                if let Some(namespace) = namespace {
                    map.serialize_entry("namespace", namespace)?;
                }
                if !aliases.is_empty() {
                    map.serialize_entry("aliases", aliases)?;
                }
                if let Some(doc) = doc {
                    map.serialize_entry("doc", doc)?;
                }
                if let Some(default) = default {
                    map.serialize_entry("default", default)?;
                }
                map.serialize_entry("symbols", symbols)?;
                map.end()
            }
            Schema::Array(schema) => {
                let mut map = serializer.serialize_map(Some(2))?;
                map.serialize_entry("type", "array")?;
                map.serialize_entry("items", schema.as_ref())?;
                map.end()
            }
            Schema::Map(schema) => {
                let mut map = serializer.serialize_map(Some(2))?;
                map.serialize_entry("type", "map")?;
                map.serialize_entry("values", schema.as_ref())?;
                map.end()
            }
            Schema::Union(schemas) => {
                let mut seq = serializer.serialize_seq(Some(schemas.len()))?;
                for schema in schemas {
                    seq.serialize_element(schema)?;
                }
                seq.end()
            }
            Schema::Fixed(fixed) => {
                let Fixed {
                    name,
                    namespace,
                    doc,
                    aliases,
                    size,
                    logical,
                } = fixed;

                let mut map = serializer.serialize_map(None)?;
                map.serialize_entry("type", "fixed")?;
                map.serialize_entry("name", name)?;
                if let Some(namespace) = namespace {
                    map.serialize_entry("namespace", namespace)?;
                }
                if !aliases.is_empty() {
                    map.serialize_entry("aliases", aliases)?;
                }
                if let Some(doc) = doc {
                    map.serialize_entry("doc", doc)?;
                }
                map.serialize_entry("size", size)?;

                if let Some(logical) = logical {
                    match logical {
                        FixedLogical::Decimal(precision, scale) => {
                            map.serialize_entry("logicalType", "decimal")?;
                            map.serialize_entry("precision", precision)?;
                            if *scale > 0 {
                                map.serialize_entry("scale", scale)?;
                            }
                        }
                        FixedLogical::Duration => map.serialize_entry("logicalType", "duration")?,
                    }
                }

                map.end()
            }
        }
    }
}

impl Serialize for Field {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let Field {
            name,
            doc,
            schema,
            default,
            order,
            aliases,
        } = self;

        let mut map = serializer.serialize_map(None)?;
        map.serialize_entry("name", name)?;
        if !aliases.is_empty() {
            map.serialize_entry("aliases", aliases)?;
        }
        if let Some(doc) = doc {
            map.serialize_entry("doc", doc)?;
        }
        if let Some(default) = default {
            map.serialize_entry("default", default)?;
        }
        map.serialize_entry("type", schema)?;
        if let Some(order) = order {
            let order = match order {
                Order::Ascending => "ascending",
                Order::Descending => "descending",
                Order::Ignore => "ignore",
            };
            map.serialize_entry("order", order)?;
        }

        map.end()
    }
}