use super::*;
use {
serde::ser::*,
std::{borrow::Cow, cell::Cell},
};
impl SchemaMut {
pub(crate) fn serialize_to_json(&self) -> Result<String, SchemaError> {
serde_json::to_string(self).map_err(SchemaError::serde_json)
}
}
impl Serialize for SchemaMut {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let node_traversal_state = vec![Cell::new(0); self.nodes.len()];
let n_written_names = Cell::new(1);
SerializeSchema {
schema_nodes: self.nodes(),
key: SchemaKey::from_idx(0),
parent_namespace: None,
n_written_names: &n_written_names,
node_traversal_state: node_traversal_state.as_slice(),
}
.serialize(serializer)
}
}
struct SerializeSchema<'a, K> {
schema_nodes: &'a [SchemaNode],
key: K,
n_written_names: &'a Cell<u64>,
node_traversal_state: &'a [Cell<u64>],
parent_namespace: Option<&'a str>,
}
impl<'a, K> SerializeSchema<'a, K> {
fn serializable<NK>(&self, key: NK) -> SerializeSchema<'a, NK> {
SerializeSchema {
key,
schema_nodes: self.schema_nodes,
n_written_names: self.n_written_names,
node_traversal_state: self.node_traversal_state,
parent_namespace: self.parent_namespace,
}
}
fn serializable_with_namespace<NK>(
&self,
key: NK,
namespace: Option<&'a str>,
) -> SerializeSchema<'a, NK> {
SerializeSchema {
key,
schema_nodes: self.schema_nodes,
n_written_names: self.n_written_names,
node_traversal_state: self.node_traversal_state,
parent_namespace: namespace,
}
}
}
impl<'a> SerializeSchema<'a, SchemaKey> {
fn no_cycle_guard<E: serde::ser::Error>(&self) -> Result<NoCycleGuard<'_>, E> {
let cell = &self.node_traversal_state[self.key.idx];
let n_written_names = self.n_written_names.get();
let prev_n_written_names = cell.replace(n_written_names);
if prev_n_written_names >= n_written_names {
Err(E::custom(
"Schema contains a cycle that can't be avoided using named references",
))
} else {
Ok(NoCycleGuard {
node_traversal_state: cell,
})
}
}
fn should_write_as_ref(&self) -> bool {
let key_generation = &self.node_traversal_state[self.key.idx];
if key_generation.get() > 0 {
true
} else {
let generation = self.n_written_names.get();
key_generation.set(generation);
self.n_written_names.set(generation + 1);
false
}
}
fn str_for_ref(&self, name: &'a Name) -> Cow<'a, str> {
if self.parent_namespace == name.namespace() {
Cow::Borrowed(name.name())
} else if name.namespace().is_none() {
Cow::Owned(format!(".{}", name.fully_qualified_name()))
} else {
Cow::Borrowed(name.fully_qualified_name())
}
}
fn serialize_name<M: SerializeMap>(&self, map: &mut M, name: &'a Name) -> Result<(), M::Error> {
if self.parent_namespace == name.namespace() {
map.serialize_entry("name", name.name())?;
} else if name.namespace().is_none() {
map.serialize_entry("namespace", "")?;
map.serialize_entry("name", name.name())?;
} else {
map.serialize_entry("name", name.fully_qualified_name())?;
}
Ok(())
}
}
#[must_use]
struct NoCycleGuard<'a> {
node_traversal_state: &'a Cell<u64>,
}
impl NoCycleGuard<'_> {
fn release(self) {
self.node_traversal_state.set(0);
}
}
impl Serialize for SerializeSchema<'_, SchemaKey> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let node = self
.schema_nodes
.get(self.key.idx)
.ok_or_else(|| S::Error::custom("SchemaKey refers to non-existing node"))?;
let serialize_type_and_logical_type = |type_: &str, map: &mut S::SerializeMap| {
if let Some(logical_type) = &node.logical_type {
map.serialize_entry("logicalType", logical_type.as_str())?;
map.serialize_entry("type", type_)?;
match logical_type {
LogicalType::Decimal(decimal) => {
map.serialize_entry("scale", &decimal.scale)?;
map.serialize_entry("precision", &decimal.precision)?;
}
LogicalType::Uuid
| LogicalType::Date
| LogicalType::TimeMillis
| LogicalType::TimeMicros
| LogicalType::TimestampMillis
| LogicalType::TimestampMicros
| LogicalType::Duration
| LogicalType::BigDecimal => {}
LogicalType::Unknown(_) => {}
}
} else {
map.serialize_entry("type", type_)?;
}
Ok(())
};
let serialize_primitive_type = |type_: &str, serializer: S| match node.logical_type {
None => serializer.serialize_str(type_),
Some(_) => {
let mut map = serializer.serialize_map(None)?;
serialize_type_and_logical_type(type_, &mut map)?;
map.end()
}
};
match node.type_ {
RegularType::Null => serialize_primitive_type("null", serializer),
RegularType::Boolean => serialize_primitive_type("boolean", serializer),
RegularType::Int => serialize_primitive_type("int", serializer),
RegularType::Long => serialize_primitive_type("long", serializer),
RegularType::Float => serialize_primitive_type("float", serializer),
RegularType::Double => serialize_primitive_type("double", serializer),
RegularType::Bytes => serialize_primitive_type("bytes", serializer),
RegularType::String => serialize_primitive_type("string", serializer),
RegularType::Array(Array { items }) => {
let no_cycle_guard = self.no_cycle_guard()?;
let mut map = serializer.serialize_map(None)?;
serialize_type_and_logical_type("array", &mut map)?;
map.serialize_entry("items", &self.serializable(items))?;
let res = map.end();
no_cycle_guard.release();
res
}
RegularType::Map(Map { values }) => {
let no_cycle_guard = self.no_cycle_guard()?;
let mut map = serializer.serialize_map(None)?;
serialize_type_and_logical_type("map", &mut map)?;
map.serialize_entry("values", &self.serializable(values))?;
let res = map.end();
no_cycle_guard.release();
res
}
RegularType::Union(Union { ref variants }) => {
if node.logical_type.is_some() {
return Err(S::Error::custom("Union type can't have a logical type"));
}
let no_cycle_guard = self.no_cycle_guard()?;
let mut seq = serializer.serialize_seq(Some(variants.len()))?;
for &union_variant_key in variants {
seq.serialize_element(&self.serializable(union_variant_key))?;
}
let res = seq.end();
no_cycle_guard.release();
res
}
RegularType::Record(Record {
ref name,
ref fields,
}) => {
if self.should_write_as_ref() {
serializer.serialize_str(&self.str_for_ref(name))
} else {
let mut map = serializer.serialize_map(None)?;
serialize_type_and_logical_type("record", &mut map)?;
self.serialize_name(&mut map, name)?;
map.serialize_entry(
"fields",
&self.serializable_with_namespace(fields.as_slice(), name.namespace()),
)?;
map.end()
}
}
RegularType::Enum(Enum {
ref name,
ref symbols,
}) => {
if self.should_write_as_ref() {
serializer.serialize_str(&self.str_for_ref(name))
} else {
let mut map = serializer.serialize_map(None)?;
serialize_type_and_logical_type("enum", &mut map)?;
self.serialize_name(&mut map, name)?;
map.serialize_entry("symbols", symbols)?;
map.end()
}
}
RegularType::Fixed(Fixed { ref name, ref size }) => {
if self.should_write_as_ref() {
serializer.serialize_str(&self.str_for_ref(name))
} else {
let mut map = serializer.serialize_map(None)?;
serialize_type_and_logical_type("fixed", &mut map)?;
self.serialize_name(&mut map, name)?;
map.serialize_entry("size", size)?;
map.end()
}
}
}
}
}
impl Serialize for SerializeSchema<'_, &[RecordField]> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut seq = serializer.serialize_seq(Some(self.key.len()))?;
for field in self.key {
seq.serialize_element(&self.serializable(field))?;
}
seq.end()
}
}
impl Serialize for SerializeSchema<'_, &RecordField> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut map = serializer.serialize_map(Some(2))?;
map.serialize_entry("name", &self.key.name)?;
map.serialize_entry("type", &self.serializable(self.key.type_))?;
map.end()
}
}