use shape_value::{HeapKind, KindedSlot, NativeKind, ValueSlot};
use shape_value::heap_value::HeapValue;
use std::collections::{HashMap, HashSet};
use std::sync::Arc;
#[derive(Debug, Clone)]
pub enum TypedFieldValue {
F64(f64),
I64(i64),
I8(i8),
U8(u8),
I16(i16),
U16(u16),
I32(i32),
U32(u32),
U64(u64),
Bool(bool),
String(Arc<String>),
Heap(Arc<HeapValue>),
}
pub mod builtin_schemas;
pub mod current;
pub mod enum_support;
pub mod field_types;
pub mod intersection;
pub mod physical_binding;
pub mod registry;
pub mod schema;
pub use builtin_schemas::BuiltinSchemaIds;
pub use current::{
SyncRegistryScope, current_registry, default_registry, try_current_registry, with_async_scope,
};
pub use enum_support::{EnumInfo, EnumVariantInfo, EnumVariantKind};
pub use field_types::{FieldAnnotation, FieldDef, FieldType};
pub use physical_binding::PhysicalSchemaBinding;
pub use registry::{TypeSchemaBuilder, TypeSchemaRegistry};
pub use schema::{TypeBinding, TypeBindingError, TypeSchema};
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
pub enum SchemaError {
#[error("Field collision on '{field_name}': type '{type1}' vs '{type2}'")]
FieldCollision {
field_name: String,
type1: String,
type2: String,
},
#[error("Schema not found: {0}")]
NotFound(String),
}
pub type SchemaId = u32;
pub fn ensure_next_schema_id_above(max_existing_id: SchemaId) {
current_registry().ensure_next_id_above(max_existing_id);
}
pub fn register_predeclared_any_schema(fields: &[String]) -> SchemaId {
current_registry().register_predeclared_any_schema(fields)
}
fn lookup_predeclared_schema_by_id(id: SchemaId) -> Option<TypeSchema> {
current_registry().lookup_predeclared_by_id(id)
}
fn lookup_predeclared_schema_id(fields: &[&str]) -> Option<SchemaId> {
let reg = current_registry();
if let Some(id) = reg.lookup_predeclared_id_by_field_order(fields) {
return Some(id);
}
reg.type_names()
.filter_map(|name| reg.get(name))
.find(|schema| {
if schema.fields.len() != fields.len() {
return false;
}
schema
.fields
.iter()
.map(|f| f.name.as_str())
.eq(fields.iter().copied())
})
.map(|schema| schema.id)
}
fn lookup_schema_by_id(id: SchemaId) -> Option<TypeSchema> {
let reg = current_registry();
if let Some(schema) = reg.get_by_id(id).cloned() {
return Some(schema);
}
reg.lookup_predeclared_by_id(id)
}
pub fn lookup_schema_by_id_public(id: SchemaId) -> Option<TypeSchema> {
lookup_schema_by_id(id)
}
fn schema_matches_field_set(schema: &TypeSchema, fields: &[&str]) -> bool {
if schema.fields.len() != fields.len() {
return false;
}
let wanted: HashSet<&str> = fields.iter().copied().collect();
schema
.fields
.iter()
.all(|field| wanted.contains(field.name.as_str()))
}
fn lookup_schema_for_fields(fields: &[&str]) -> Option<TypeSchema> {
if let Some(id) = lookup_predeclared_schema_id(fields) {
return lookup_schema_by_id(id);
}
let reg = current_registry();
if let Some(schema) = reg
.type_names()
.filter_map(|name| reg.get(name))
.find(|schema| schema_matches_field_set(schema, fields))
{
return Some(schema.clone());
}
if let Some(schema) = reg.lookup_predeclared_by_field_set(fields) {
return Some(schema);
}
let owned: Vec<String> = fields.iter().map(|s| s.to_string()).collect();
let id = register_predeclared_any_schema(&owned);
lookup_predeclared_schema_by_id(id)
}
pub fn typed_object_from_pairs(fields: &[(&str, KindedSlot)]) -> KindedSlot {
let field_names: Vec<&str> = fields.iter().map(|(name, _)| *name).collect();
let schema = lookup_schema_for_fields(&field_names).unwrap_or_else(|| {
panic!(
"Missing predeclared schema for fields [{}]. Runtime schema synthesis is disabled.",
field_names.join(", ")
)
});
let value_by_name: HashMap<&str, &KindedSlot> =
fields.iter().map(|(name, value)| (*name, value)).collect();
let mut slots = Vec::with_capacity(schema.fields.len());
let mut field_kinds: Vec<NativeKind> = Vec::with_capacity(schema.fields.len());
let mut heap_mask: u64 = 0;
for (i, field_def) in schema.fields.iter().enumerate() {
let value = value_by_name
.get(field_def.name.as_str())
.unwrap_or_else(|| {
panic!(
"Missing field '{}' while materializing typed object",
field_def.name
)
});
let cloned = (*value).clone();
let bits = cloned.slot().raw();
let kind = cloned.kind();
let is_heap = match kind {
NativeKind::String | NativeKind::Ptr(_) => true,
_ => false,
};
std::mem::forget(cloned);
let slot = ValueSlot::from_raw(bits);
slots.push(slot);
field_kinds.push(kind);
if is_heap {
heap_mask |= 1u64 << i;
}
}
let ptr = shape_value::TypedObjectStorage::_new(
schema.id as u64,
slots.into_boxed_slice(),
heap_mask,
Arc::from(field_kinds.into_boxed_slice()),
);
KindedSlot::new(
ValueSlot::from_typed_object_raw(ptr),
NativeKind::Ptr(HeapKind::TypedObject),
)
}
#[cfg(test)]
mod tests {
}
pub fn typed_object_to_hashmap_nb(
_value: &KindedSlot,
) -> Option<HashMap<String, KindedSlot>> {
None
}