use std::hash::{Hash, Hasher};
use std::ops::{Deref, DerefMut};
use xsd_parser_types::xml::NamespacesShared;
use crate::models::{
meta::{MetaTypes, TypeEq},
schema::xs::{
FormChoiceType, NamespaceListType, NotNamespaceType, ProcessContentsType, QnameListAType,
Use,
},
AttributeIdent, TypeIdent,
};
#[derive(Debug, Clone)]
pub struct AttributeMeta {
pub ident: AttributeIdent,
pub variant: AttributeMetaVariant,
pub use_: Use,
pub form: FormChoiceType,
pub default: Option<String>,
pub display_name: Option<String>,
pub documentation: Vec<String>,
pub namespaces: Option<NamespacesShared<'static>>,
}
#[derive(Debug, Clone)]
pub enum AttributeMetaVariant {
Any(AnyAttributeMeta),
Type(TypeIdent),
}
#[allow(missing_docs)]
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct AnyAttributeMeta {
pub id: Option<String>,
pub namespace: Option<NamespaceListType>,
pub not_q_name: Option<QnameListAType>,
pub not_namespace: Option<NotNamespaceType>,
pub process_contents: ProcessContentsType,
}
#[derive(Default, Debug, Clone)]
pub struct AttributesMeta(Vec<AttributeMeta>);
impl AttributeMeta {
#[must_use]
pub fn new(ident: AttributeIdent, type_: TypeIdent, form: FormChoiceType) -> Self {
Self {
ident,
variant: AttributeMetaVariant::Type(type_),
use_: Use::Optional,
form,
default: None,
display_name: None,
documentation: Vec::new(),
namespaces: None,
}
}
#[must_use]
pub fn any(ident: AttributeIdent, any: AnyAttributeMeta) -> Self {
Self {
ident,
variant: AttributeMetaVariant::Any(any),
use_: Use::Required,
form: FormChoiceType::Unqualified,
default: None,
display_name: None,
documentation: Vec::new(),
namespaces: None,
}
}
#[must_use]
pub fn with_use(mut self, use_: Use) -> Self {
self.use_ = use_;
self
}
#[must_use]
pub fn is_any(&self) -> bool {
matches!(&self.variant, AttributeMetaVariant::Any(_))
}
#[must_use]
pub fn as_any(&self) -> Option<&AnyAttributeMeta> {
if let AttributeMetaVariant::Any(any) = &self.variant {
Some(any)
} else {
None
}
}
}
impl TypeEq for AttributeMeta {
fn type_hash<H: Hasher>(&self, hasher: &mut H, types: &MetaTypes) {
let Self {
ident,
variant,
use_,
form,
default,
display_name,
documentation,
namespaces,
} = self;
ident.hash(hasher);
variant.type_hash(hasher, types);
use_.hash(hasher);
form.hash(hasher);
default.hash(hasher);
display_name.hash(hasher);
documentation.hash(hasher);
namespaces.hash(hasher);
}
fn type_eq(&self, other: &Self, types: &MetaTypes) -> bool {
let Self {
ident,
variant: type_,
use_,
form,
default,
display_name,
documentation,
namespaces,
} = self;
ident.eq(&other.ident)
&& type_.type_eq(&other.variant, types)
&& use_.eq(&other.use_)
&& form.eq(&other.form)
&& default.eq(&other.default)
&& display_name.eq(&other.display_name)
&& documentation.eq(&other.documentation)
&& namespaces.eq(&other.namespaces)
}
}
impl Deref for AttributesMeta {
type Target = Vec<AttributeMeta>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for AttributesMeta {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl TypeEq for AttributesMeta {
fn type_hash<H: Hasher>(&self, hasher: &mut H, types: &MetaTypes) {
TypeEq::type_hash_slice(&self.0, hasher, types);
}
fn type_eq(&self, other: &Self, types: &MetaTypes) -> bool {
TypeEq::type_eq_iter(self.0.iter(), other.0.iter(), types)
}
}
impl TypeEq for AttributeMetaVariant {
fn type_hash<H: Hasher>(&self, hasher: &mut H, types: &MetaTypes) {
match self {
Self::Any(x) => {
hasher.write_u8(0);
x.hash(hasher);
}
Self::Type(x) => {
hasher.write_u8(1);
x.type_hash(hasher, types);
}
}
}
fn type_eq(&self, other: &Self, types: &MetaTypes) -> bool {
match (self, other) {
(Self::Any(a), Self::Any(b)) => a.eq(b),
(Self::Type(a), Self::Type(b)) => a.type_eq(b, types),
(_, _) => false,
}
}
}
impl Hash for AnyAttributeMeta {
fn hash<H: Hasher>(&self, hasher: &mut H) {
self.id.hash(hasher);
}
}