use bitflags::bitflags;
use crate::{kind, sdf};
use super::SchemaKind;
pub type InstanceRestriction<'a> = (&'a str, &'a [&'a str]);
#[derive(Debug, Clone, Copy)]
pub struct SchemaFamily<'a> {
pub(super) name: &'a str,
pub(super) schemas: &'a [SchemaDecl<'a>],
pub(super) metadata: &'a [MetadataDecl<'a>],
pub(super) kinds: &'a [kind::Decl<'a>],
}
#[derive(Debug, Clone, Copy)]
pub struct MetadataDecl<'a> {
pub(super) name: &'a str,
pub(super) type_name: &'a str,
pub(super) applies_to: MetadataTargets,
fallback: Option<FieldValue<'a>>,
}
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MetadataTargets: u8 {
const LAYERS = 1;
const PRIMS = 1 << 1;
const ATTRIBUTES = 1 << 2;
const RELATIONSHIPS = 1 << 3;
const PROPERTIES = Self::ATTRIBUTES.bits() | Self::RELATIONSHIPS.bits();
}
}
#[derive(Debug, Clone, Copy)]
pub struct SchemaDecl<'a> {
pub(super) identifier: &'a str,
pub(super) kind: SchemaKind,
pub(super) bases: &'a [&'a str],
pub(super) properties: &'a [PropertyDecl<'a>],
pub(super) fields: &'a [Field<'a>],
pub(super) applied_api_schemas: &'a [&'a str],
pub(super) override_property_names: &'a [&'a str],
pub(super) property_namespace_prefix: Option<&'a str>,
pub(super) auto_apply_to: &'a [&'a str],
pub(super) can_only_apply_to: &'a [&'a str],
pub(super) instance_restrictions: &'a [InstanceRestriction<'a>],
pub(super) allowed_instance_names: &'a [&'a str],
pub(super) fallback_types: &'a [&'a str],
}
#[derive(Debug, Clone, Copy)]
pub struct PropertyDecl<'a> {
pub(super) name: &'a str,
pub(super) kind: PropertyKind<'a>,
pub(super) variability: sdf::Variability,
pub(super) custom: bool,
pub(super) fields: &'a [Field<'a>],
}
#[derive(Debug, Clone, Copy)]
pub(super) enum PropertyKind<'a> {
Attribute(&'a str),
Relationship,
}
#[derive(Debug, Clone, Copy)]
pub struct Field<'a> {
pub(super) name: &'a str,
value: FieldValue<'a>,
}
#[derive(Debug, Clone, Copy)]
enum FieldValue<'a> {
Str(&'a str),
Strings(&'a [&'a str]),
Token(&'a str),
Tokens(&'a [&'a str]),
Built(fn() -> sdf::Value),
Ref(&'a sdf::Value),
}
impl<'a> SchemaFamily<'a> {
pub const fn new(name: &'a str, schemas: &'a [SchemaDecl<'a>]) -> Self {
Self {
name,
schemas,
metadata: &[],
kinds: &[],
}
}
pub const fn metadata(mut self, fields: &'a [MetadataDecl<'a>]) -> Self {
self.metadata = fields;
self
}
pub const fn declared_metadata(&self) -> &'a [MetadataDecl<'a>] {
self.metadata
}
pub const fn kinds(mut self, kinds: &'a [kind::Decl<'a>]) -> Self {
self.kinds = kinds;
self
}
pub const fn declared_kinds(&self) -> &'a [kind::Decl<'a>] {
self.kinds
}
pub const fn name(&self) -> &'a str {
self.name
}
pub const fn schemas(&self) -> &'a [SchemaDecl<'a>] {
self.schemas
}
}
impl<'a> MetadataDecl<'a> {
pub const fn new(name: &'a str, type_name: &'a str) -> Self {
Self {
name,
type_name,
applies_to: MetadataTargets::all(),
fallback: None,
}
}
pub const fn applies_to(mut self, targets: MetadataTargets) -> Self {
self.applies_to = targets;
self
}
pub const fn fallback(mut self, value: fn() -> sdf::Value) -> Self {
self.fallback = Some(FieldValue::Built(value));
self
}
pub const fn fallback_borrowed(mut self, value: &'a sdf::Value) -> Self {
self.fallback = Some(FieldValue::Ref(value));
self
}
pub const fn name(&self) -> &'a str {
self.name
}
pub const fn declared_type_name(&self) -> &'a str {
self.type_name
}
pub const fn declared_applies_to(&self) -> MetadataTargets {
self.applies_to
}
pub fn declared_fallback(&self) -> Option<sdf::Value> {
self.fallback.map(|value| value.to_value())
}
}
impl<'a> SchemaDecl<'a> {
pub const fn new(identifier: &'a str, kind: SchemaKind) -> Self {
Self {
identifier,
kind,
bases: &[],
properties: &[],
fields: &[],
applied_api_schemas: &[],
override_property_names: &[],
property_namespace_prefix: None,
auto_apply_to: &[],
can_only_apply_to: &[],
instance_restrictions: &[],
allowed_instance_names: &[],
fallback_types: &[],
}
}
pub const fn bases(mut self, bases: &'a [&'a str]) -> Self {
self.bases = bases;
self
}
pub const fn properties(mut self, properties: &'a [PropertyDecl<'a>]) -> Self {
self.properties = properties;
self
}
pub const fn fields(mut self, fields: &'a [Field<'a>]) -> Self {
self.fields = fields;
self
}
pub const fn applied_api_schemas(mut self, schemas: &'a [&'a str]) -> Self {
self.applied_api_schemas = schemas;
self
}
pub const fn override_property_names(mut self, names: &'a [&'a str]) -> Self {
self.override_property_names = names;
self
}
pub const fn property_namespace_prefix(mut self, prefix: &'a str) -> Self {
self.property_namespace_prefix = Some(prefix);
self
}
pub const fn auto_apply_to(mut self, targets: &'a [&'a str]) -> Self {
self.auto_apply_to = targets;
self
}
pub const fn can_only_apply_to(mut self, targets: &'a [&'a str]) -> Self {
self.can_only_apply_to = targets;
self
}
pub const fn instance_restrictions(mut self, restrictions: &'a [InstanceRestriction<'a>]) -> Self {
self.instance_restrictions = restrictions;
self
}
pub const fn allowed_instance_names(mut self, names: &'a [&'a str]) -> Self {
self.allowed_instance_names = names;
self
}
pub const fn fallback_types(mut self, types: &'a [&'a str]) -> Self {
self.fallback_types = types;
self
}
pub const fn identifier(&self) -> &'a str {
self.identifier
}
pub const fn kind(&self) -> SchemaKind {
self.kind
}
pub const fn declared_bases(&self) -> &'a [&'a str] {
self.bases
}
pub const fn declared_properties(&self) -> &'a [PropertyDecl<'a>] {
self.properties
}
pub const fn declared_fields(&self) -> &'a [Field<'a>] {
self.fields
}
pub const fn declared_applied_api_schemas(&self) -> &'a [&'a str] {
self.applied_api_schemas
}
pub const fn declared_override_property_names(&self) -> &'a [&'a str] {
self.override_property_names
}
pub const fn declared_property_namespace_prefix(&self) -> Option<&'a str> {
self.property_namespace_prefix
}
pub const fn declared_auto_apply_to(&self) -> &'a [&'a str] {
self.auto_apply_to
}
pub const fn declared_can_only_apply_to(&self) -> &'a [&'a str] {
self.can_only_apply_to
}
pub const fn declared_instance_restrictions(&self) -> &'a [InstanceRestriction<'a>] {
self.instance_restrictions
}
pub const fn declared_allowed_instance_names(&self) -> &'a [&'a str] {
self.allowed_instance_names
}
pub const fn declared_fallback_types(&self) -> &'a [&'a str] {
self.fallback_types
}
}
impl<'a> PropertyDecl<'a> {
pub const fn attribute(name: &'a str, type_name: &'a str) -> Self {
Self {
name,
kind: PropertyKind::Attribute(type_name),
variability: sdf::Variability::Varying,
custom: false,
fields: &[],
}
}
pub const fn relationship(name: &'a str) -> Self {
Self {
name,
kind: PropertyKind::Relationship,
variability: sdf::Variability::Uniform,
custom: false,
fields: &[],
}
}
pub const fn uniform(mut self) -> Self {
self.variability = sdf::Variability::Uniform;
self
}
pub const fn varying(mut self) -> Self {
self.variability = sdf::Variability::Varying;
self
}
pub const fn custom(mut self) -> Self {
self.custom = true;
self
}
pub const fn fields(mut self, fields: &'a [Field<'a>]) -> Self {
self.fields = fields;
self
}
pub const fn name(&self) -> &'a str {
self.name
}
pub const fn type_name(&self) -> Option<&'a str> {
match self.kind {
PropertyKind::Attribute(type_name) => Some(type_name),
PropertyKind::Relationship => None,
}
}
pub const fn is_uniform(&self) -> bool {
matches!(self.variability, sdf::Variability::Uniform)
}
pub const fn is_custom(&self) -> bool {
self.custom
}
pub const fn spec_type(&self) -> sdf::SpecType {
match self.kind {
PropertyKind::Attribute(_) => sdf::SpecType::Attribute,
PropertyKind::Relationship => sdf::SpecType::Relationship,
}
}
pub const fn declared_fields(&self) -> &'a [Field<'a>] {
self.fields
}
}
impl<'a> Field<'a> {
pub const fn string(name: &'a str, text: &'a str) -> Self {
Self {
name,
value: FieldValue::Str(text),
}
}
pub const fn token(name: &'a str, token: &'a str) -> Self {
Self {
name,
value: FieldValue::Token(token),
}
}
pub const fn strings(name: &'a str, texts: &'a [&'a str]) -> Self {
Self {
name,
value: FieldValue::Strings(texts),
}
}
pub const fn tokens(name: &'a str, tokens: &'a [&'a str]) -> Self {
Self {
name,
value: FieldValue::Tokens(tokens),
}
}
pub const fn new(name: &'a str, value: fn() -> sdf::Value) -> Self {
Self {
name,
value: FieldValue::Built(value),
}
}
pub const fn borrowed(name: &'a str, value: &'a sdf::Value) -> Self {
Self {
name,
value: FieldValue::Ref(value),
}
}
pub const fn name(&self) -> &'a str {
self.name
}
pub fn value(&self) -> sdf::Value {
self.value.to_value()
}
}
impl FieldValue<'_> {
fn to_value(self) -> sdf::Value {
match self {
FieldValue::Str(text) => sdf::Value::String(text.to_owned()),
FieldValue::Strings(texts) => sdf::Value::StringVec(texts.iter().map(|text| (*text).to_owned()).collect()),
FieldValue::Token(token) => sdf::Value::token(token),
FieldValue::Tokens(tokens) => sdf::Value::token_vec(tokens.iter().copied()),
FieldValue::Built(build) => build(),
FieldValue::Ref(value) => value.clone(),
}
}
}