use super::{
safe::SchemaNode as SafeSchemaNode,
union_variants_per_type_lookup::PerTypeLookup as UnionVariantsPerTypeLookup, Decimal, Fixed,
Name,
};
use std::collections::HashMap;
pub struct Schema {
nodes: Vec<SchemaNode<'static>>,
parsing_canonical_form: String,
fingerprint: [u8; 8],
}
impl Schema {
pub fn root<'a>(&'a self) -> &'a SchemaNode<'a> {
&self.nodes[0]
}
pub fn parsing_canonical_form(&self) -> &str {
self.parsing_canonical_form.as_str()
}
pub fn rabin_fingerprint(&self) -> &[u8; 8] {
&self.fingerprint
}
}
pub enum SchemaNode<'a> {
Null,
Boolean,
Int,
Long,
Float,
Double,
Bytes,
String,
Array(&'a SchemaNode<'a>),
Map(&'a SchemaNode<'a>),
Union(Union<'a>),
Record(Record<'a>),
Enum(Enum),
Fixed(Fixed),
Decimal(Decimal),
Uuid,
Date,
TimeMillis,
TimeMicros,
TimestampMillis,
TimestampMicros,
Duration,
}
pub struct Union<'a> {
pub variants: Vec<&'a SchemaNode<'a>>,
pub(crate) per_type_lookup: UnionVariantsPerTypeLookup<'a>,
}
impl std::fmt::Debug for Union<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Union")
.field("variants", &self.variants)
.finish()
}
}
pub struct Record<'a> {
pub fields: Vec<RecordField<'a>>,
pub name: Name,
pub per_name_lookup: HashMap<String, usize>,
}
impl<'a> std::fmt::Debug for Record<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Record")
.field("fields", &self.fields)
.field("name", &self.name)
.finish()
}
}
#[derive(Debug)]
pub struct RecordField<'a> {
pub name: String,
pub schema: &'a SchemaNode<'a>,
}
#[derive(Clone)]
pub struct Enum {
pub symbols: Vec<String>,
pub name: Name,
pub per_name_lookup: HashMap<String, usize>,
}
impl std::fmt::Debug for Enum {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Enum")
.field("name", &self.name)
.field("symbols", &self.symbols)
.finish()
}
}
impl From<super::safe::Schema> for Schema {
fn from(safe: super::safe::Schema) -> Self {
let mut ret = Self {
nodes: (0..safe.nodes.len()).map(|_| SchemaNode::Null).collect(),
parsing_canonical_form: safe.parsing_canonical_form,
fingerprint: safe.fingerprint,
};
let len = ret.nodes.len();
assert!(len > 0 && len == safe.nodes.len() && len <= (isize::MAX as usize));
let storage_start_ptr = ret.nodes.as_mut_ptr();
let key_to_node = |schema_key: super::safe::SchemaKey| -> &'static SchemaNode {
let idx = schema_key.idx;
assert!(idx < len);
unsafe { &*(storage_start_ptr.add(schema_key.idx)) }
};
let mut curr_storage_node_ptr = storage_start_ptr;
for safe_node in safe.nodes {
unsafe {
*curr_storage_node_ptr = match safe_node {
SafeSchemaNode::Null => SchemaNode::Null,
SafeSchemaNode::Boolean => SchemaNode::Boolean,
SafeSchemaNode::Int => SchemaNode::Int,
SafeSchemaNode::Long => SchemaNode::Long,
SafeSchemaNode::Float => SchemaNode::Float,
SafeSchemaNode::Double => SchemaNode::Double,
SafeSchemaNode::Bytes => SchemaNode::Bytes,
SafeSchemaNode::String => SchemaNode::String,
SafeSchemaNode::Array(schema_key) => SchemaNode::Array(key_to_node(schema_key)),
SafeSchemaNode::Map(schema_key) => SchemaNode::Map(key_to_node(schema_key)),
SafeSchemaNode::Union(union) => SchemaNode::Union({
Union {
variants: union
.variants
.into_iter()
.map(|schema_key| key_to_node(schema_key))
.collect(),
per_type_lookup: {
UnionVariantsPerTypeLookup::placeholder()
},
}
}),
SafeSchemaNode::Record(record) => SchemaNode::Record(Record {
per_name_lookup: record
.fields
.iter()
.enumerate()
.map(|(i, v)| (v.name.clone(), i))
.collect(),
fields: record
.fields
.into_iter()
.map(|f| RecordField {
name: f.name,
schema: key_to_node(f.schema),
})
.collect(),
name: record.name,
}),
SafeSchemaNode::Enum(enum_) => SchemaNode::Enum(Enum {
per_name_lookup: enum_
.symbols
.iter()
.enumerate()
.map(|(i, v)| (v.clone(), i))
.collect(),
symbols: enum_.symbols,
name: enum_.name,
}),
SafeSchemaNode::Fixed(fixed) => SchemaNode::Fixed(fixed),
SafeSchemaNode::Decimal(decimal) => SchemaNode::Decimal(decimal),
SafeSchemaNode::Uuid => SchemaNode::Uuid,
SafeSchemaNode::Date => SchemaNode::Date,
SafeSchemaNode::TimeMillis => SchemaNode::TimeMillis,
SafeSchemaNode::TimeMicros => SchemaNode::TimeMicros,
SafeSchemaNode::TimestampMillis => SchemaNode::TimestampMillis,
SafeSchemaNode::TimestampMicros => SchemaNode::TimestampMicros,
SafeSchemaNode::Duration => SchemaNode::Duration,
};
curr_storage_node_ptr = curr_storage_node_ptr.add(1);
};
}
curr_storage_node_ptr = storage_start_ptr;
for _ in 0..len {
unsafe {
match *curr_storage_node_ptr {
SchemaNode::Union(Union {
ref variants,
ref mut per_type_lookup,
}) => {
*per_type_lookup = UnionVariantsPerTypeLookup::new(variants);
}
_ => {}
}
curr_storage_node_ptr = curr_storage_node_ptr.add(1);
}
}
ret
}
}
impl std::fmt::Debug for Schema {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
<SchemaNode<'_> as std::fmt::Debug>::fmt(self.root(), f)
}
}
impl<'a> std::fmt::Debug for SchemaNode<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> ::std::fmt::Result {
use std::cell::Cell;
struct SchemaNodeRenderingDepthGuard;
thread_local! {
static DEPTH: Cell<u32> = Cell::new(0);
}
impl Drop for SchemaNodeRenderingDepthGuard {
fn drop(&mut self) {
DEPTH.with(|cell| cell.set(cell.get().checked_sub(1).unwrap()));
}
}
const MAX_DEPTH: u32 = 2;
let depth = DEPTH.with(|cell| {
let val = cell.get();
cell.set(val + 1);
val
});
let _decrement_depth_guard = SchemaNodeRenderingDepthGuard;
match *self {
SchemaNode::Null => f.debug_tuple("Null").finish(),
SchemaNode::Boolean => f.debug_tuple("Boolean").finish(),
SchemaNode::Int => f.debug_tuple("Int").finish(),
SchemaNode::Long => f.debug_tuple("Long").finish(),
SchemaNode::Float => f.debug_tuple("Float").finish(),
SchemaNode::Double => f.debug_tuple("Double").finish(),
SchemaNode::Bytes => f.debug_tuple("Bytes").finish(),
SchemaNode::String => f.debug_tuple("String").finish(),
SchemaNode::Array(inner) => {
let mut d = f.debug_tuple("Array");
if depth < MAX_DEPTH {
d.field(inner);
}
d.finish()
}
SchemaNode::Map(inner) => {
let mut d = f.debug_tuple("Map");
if depth < MAX_DEPTH {
d.field(inner);
}
d.finish()
}
SchemaNode::Union(ref inner) => {
let mut d = f.debug_tuple("Union");
if depth < MAX_DEPTH {
d.field(inner);
}
d.finish()
}
SchemaNode::Record(ref inner) => {
let mut d = f.debug_tuple("Record");
if depth < MAX_DEPTH {
d.field(inner);
}
d.finish()
}
SchemaNode::Enum(ref inner) => {
let mut d = f.debug_tuple("Enum");
if depth < MAX_DEPTH {
d.field(inner);
}
d.finish()
}
SchemaNode::Fixed(ref inner) => {
let mut d = f.debug_tuple("Fixed");
if depth < MAX_DEPTH {
d.field(inner);
}
d.finish()
}
SchemaNode::Decimal(ref inner) => {
let mut d = f.debug_tuple("Decimal");
if depth < MAX_DEPTH {
d.field(inner);
}
d.finish()
}
SchemaNode::Uuid => f.debug_tuple("Uuid").finish(),
SchemaNode::Date => f.debug_tuple("Date").finish(),
SchemaNode::TimeMillis => f.debug_tuple("TimeMillis").finish(),
SchemaNode::TimeMicros => f.debug_tuple("TimeMicros").finish(),
SchemaNode::TimestampMillis => f.debug_tuple("TimestampMillis").finish(),
SchemaNode::TimestampMicros => f.debug_tuple("TimestampMicros").finish(),
SchemaNode::Duration => f.debug_tuple("Duration").finish(),
}
}
}