use std::fmt::{Display, Formatter, Result as FmtResult};
use std::hash::Hash;
use crate::models::schema::{NamespaceId, SchemaId};
use super::Name;
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct TypeIdent {
pub ns: NamespaceId,
pub schema: SchemaId,
pub name: Name,
pub type_: TypeIdentType,
}
pub type TypeIdentType = IdentType;
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct PropertyIdent {
pub ns: NamespaceId,
pub name: Name,
}
pub type ElementIdent = PropertyIdent;
pub type AttributeIdent = PropertyIdent;
pub type EnumerationIdent = PropertyIdent;
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum IdentType {
Type = 0,
Group = 1,
Element = 2,
ElementType = 3,
Attribute = 4,
AttributeGroup = 5,
BuildIn = 6,
Enumeration = 7,
NillableContent = 8,
DynamicElement = 9,
}
#[allow(missing_docs)]
impl TypeIdent {
pub const UNKNOWN: Self = Self::type_("UNKNOWN");
pub const U8: Self = Self::build_in("u8");
pub const U16: Self = Self::build_in("u16");
pub const U32: Self = Self::build_in("u32");
pub const U64: Self = Self::build_in("u64");
pub const U128: Self = Self::build_in("u128");
pub const USIZE: Self = Self::build_in("usize");
pub const I8: Self = Self::build_in("i8");
pub const I16: Self = Self::build_in("i16");
pub const I32: Self = Self::build_in("i32");
pub const I64: Self = Self::build_in("i64");
pub const I128: Self = Self::build_in("i128");
pub const ISIZE: Self = Self::build_in("isize");
pub const F32: Self = Self::build_in("f32");
pub const F64: Self = Self::build_in("f64");
pub const BOOL: Self = Self::build_in("bool");
pub const STR: Self = Self::build_in("str");
pub const STRING: Self = Self::build_in("String");
pub const ANY_TYPE: Self = Self::type_("anyType");
pub const BUILD_IN: &[Self] = &[
Self::U8,
Self::U16,
Self::U32,
Self::U64,
Self::U128,
Self::USIZE,
Self::I8,
Self::I16,
Self::I32,
Self::I64,
Self::I128,
Self::ISIZE,
Self::F32,
Self::F64,
Self::BOOL,
Self::STR,
Self::STRING,
];
}
impl TypeIdent {
#[must_use]
pub const fn new(name: Name) -> Self {
Self {
ns: NamespaceId::UNKNOWN,
schema: SchemaId::UNKNOWN,
name,
type_: IdentType::Type,
}
}
#[must_use]
pub const fn type_(name: &'static str) -> Self {
Self {
ns: NamespaceId::UNKNOWN,
schema: SchemaId::UNKNOWN,
name: Name::named(name),
type_: IdentType::Type,
}
}
#[must_use]
pub const fn build_in(name: &'static str) -> Self {
Self {
ns: NamespaceId::ANONYMOUS,
schema: SchemaId::UNKNOWN,
name: Name::named(name),
type_: IdentType::BuildIn,
}
}
#[must_use]
pub const fn element(name: &'static str) -> Self {
Self {
ns: NamespaceId::UNKNOWN,
schema: SchemaId::UNKNOWN,
name: Name::named(name),
type_: IdentType::Element,
}
}
#[must_use]
pub fn with_ns(mut self, ns: NamespaceId) -> Self {
self.ns = ns;
self
}
#[must_use]
pub fn with_schema(mut self, schema: SchemaId) -> Self {
self.schema = schema;
self
}
#[must_use]
pub fn with_name(mut self, name: Name) -> Self {
self.name = name;
self
}
#[must_use]
pub fn with_type(mut self, type_: TypeIdentType) -> Self {
self.type_ = type_;
self
}
#[must_use]
pub fn matches(&self, other: &Self) -> bool {
let Self {
ns,
schema,
name,
type_,
} = self;
(ns.is_unknown() || other.ns.is_unknown() || ns.eq(&other.ns))
&& (schema.is_unknown() || other.schema.is_unknown() || schema.eq(&other.schema))
&& name.eq(&other.name)
&& type_.eq(&other.type_)
}
#[must_use]
pub fn to_property_ident(&self) -> PropertyIdent {
let Self {
ns,
schema: _,
name,
type_: _,
} = self;
PropertyIdent {
ns: *ns,
name: name.clone(),
}
}
#[must_use]
pub fn is_build_in(&self) -> bool {
TypeIdent::BUILD_IN.contains(self)
}
#[must_use]
pub fn is_fully_qualified(&self) -> bool {
!self.ns.is_unknown() && !self.schema.is_unknown()
}
}
impl Display for TypeIdent {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
fmt_ident(
f,
Some(self.ns),
Some(self.schema),
&self.name,
Some(self.type_),
)
}
}
impl PropertyIdent {
#[inline]
#[must_use]
pub const fn new(name: Name) -> Self {
Self {
ns: NamespaceId::UNKNOWN,
name,
}
}
#[inline]
#[must_use]
pub const fn named(name: &'static str) -> Self {
Self {
ns: NamespaceId::UNKNOWN,
name: Name::named(name),
}
}
#[inline]
#[must_use]
pub fn with_ns(mut self, ns: NamespaceId) -> Self {
self.ns = ns;
self
}
}
impl Display for PropertyIdent {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
fmt_ident(f, Some(self.ns), None, &self.name, None)
}
}
fn fmt_ident(
f: &mut Formatter<'_>,
ns: Option<NamespaceId>,
schema: Option<SchemaId>,
name: &Name,
type_: Option<IdentType>,
) -> FmtResult {
match type_ {
None => write!(f, "Ident(")?,
Some(IdentType::Type) => write!(f, "Type(")?,
Some(IdentType::Group) => write!(f, "Group(")?,
Some(IdentType::BuildIn) => write!(f, "BuildIn(")?,
Some(IdentType::Element) => write!(f, "Element(")?,
Some(IdentType::ElementType) => write!(f, "ElementType(")?,
Some(IdentType::Attribute) => write!(f, "Attribute(")?,
Some(IdentType::AttributeGroup) => write!(f, "AttributeGroup(")?,
Some(IdentType::Enumeration) => write!(f, "Enumeration(")?,
Some(IdentType::NillableContent) => write!(f, "NillableContent(")?,
Some(IdentType::DynamicElement) => write!(f, "DynamicElement(")?,
}
if f.sign_minus() {
write!(f, "{name})")?;
} else {
if let Some(SchemaId(schema)) = schema {
write!(f, "schema={schema}, ")?;
}
if let Some(ns) = ns {
write!(f, "ns={}, name={name})", ns.0)?;
} else {
write!(f, "ns=default, name={name})")?;
}
}
Ok(())
}