use crate::ids::{ElementKey, IdentityConstraintKey, NameId, SimpleTypeKey, TypeKey};
use crate::parser::location::SourceRef;
use crate::schema::model::DerivationSet;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DeclarationScope {
Global,
Local,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ValueConstraint {
Default(String),
Fixed(String),
}
impl ValueConstraint {
pub fn value(&self) -> &str {
match self {
ValueConstraint::Default(v) => v,
ValueConstraint::Fixed(v) => v,
}
}
pub fn is_fixed(&self) -> bool {
matches!(self, ValueConstraint::Fixed(_))
}
}
#[derive(Debug, Clone)]
pub enum TypeReference {
Resolved(TypeKey),
Unresolved {
namespace: Option<NameId>,
local_name: NameId,
},
}
#[derive(Debug, Clone)]
pub struct ElementDecl {
pub name: NameId,
pub target_namespace: Option<NameId>,
pub source: Option<SourceRef>,
pub scope: DeclarationScope,
pub type_def: Option<TypeReference>,
pub value_constraint: Option<ValueConstraint>,
pub nillable: bool,
pub is_abstract: bool,
pub substitution_group: Option<ElementRef>,
pub disallowed_substitutions: DerivationSet,
pub substitution_group_exclusions: DerivationSet,
pub identity_constraints: Vec<IdentityConstraintKey>,
pub id: Option<String>,
pub type_alternatives: Vec<TypeAlternative>,
pub form: Option<FormKind>,
}
#[derive(Debug, Clone)]
pub enum ElementRef {
Resolved(ElementKey),
Unresolved {
namespace: Option<NameId>,
local_name: NameId,
},
}
#[derive(Debug, Clone)]
pub struct TypeAlternative {
pub test: Option<String>,
pub type_def: TypeReference,
pub source: Option<SourceRef>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FormKind {
Qualified,
Unqualified,
}
impl ElementDecl {
pub fn new_global(name: NameId, target_namespace: Option<NameId>) -> Self {
Self {
name,
target_namespace,
source: None,
scope: DeclarationScope::Global,
type_def: None,
value_constraint: None,
nillable: false,
is_abstract: false,
substitution_group: None,
disallowed_substitutions: DerivationSet::empty(),
substitution_group_exclusions: DerivationSet::empty(),
identity_constraints: Vec::new(),
id: None,
type_alternatives: Vec::new(),
form: None,
}
}
pub fn new_local(name: NameId, target_namespace: Option<NameId>) -> Self {
Self {
name,
target_namespace,
source: None,
scope: DeclarationScope::Local,
type_def: None,
value_constraint: None,
nillable: false,
is_abstract: false,
substitution_group: None,
disallowed_substitutions: DerivationSet::empty(),
substitution_group_exclusions: DerivationSet::empty(),
identity_constraints: Vec::new(),
id: None,
type_alternatives: Vec::new(),
form: None,
}
}
pub fn is_global(&self) -> bool {
self.scope == DeclarationScope::Global
}
pub fn is_local(&self) -> bool {
self.scope == DeclarationScope::Local
}
pub fn is_substitutable(&self) -> bool {
!self.is_abstract && self.substitution_group_exclusions.is_empty()
}
}
#[derive(Debug, Clone)]
pub struct AttributeDecl {
pub name: NameId,
pub target_namespace: Option<NameId>,
pub source: Option<SourceRef>,
pub scope: DeclarationScope,
pub type_def: Option<SimpleTypeReference>,
pub value_constraint: Option<ValueConstraint>,
pub id: Option<String>,
pub form: Option<FormKind>,
pub inheritable: bool,
}
#[derive(Debug, Clone)]
pub enum SimpleTypeReference {
Resolved(SimpleTypeKey),
BuiltIn(crate::types::simple::BuiltInType),
Unresolved {
namespace: Option<NameId>,
local_name: NameId,
},
}
impl AttributeDecl {
pub fn new_global(name: NameId, target_namespace: Option<NameId>) -> Self {
Self {
name,
target_namespace,
source: None,
scope: DeclarationScope::Global,
type_def: None,
value_constraint: None,
id: None,
form: None,
inheritable: false,
}
}
pub fn new_local(name: NameId, target_namespace: Option<NameId>) -> Self {
Self {
name,
target_namespace,
source: None,
scope: DeclarationScope::Local,
type_def: None,
value_constraint: None,
id: None,
form: None,
inheritable: false,
}
}
pub fn is_global(&self) -> bool {
self.scope == DeclarationScope::Global
}
pub fn is_local(&self) -> bool {
self.scope == DeclarationScope::Local
}
pub fn has_default(&self) -> bool {
matches!(self.value_constraint, Some(ValueConstraint::Default(_)))
}
pub fn has_fixed(&self) -> bool {
matches!(self.value_constraint, Some(ValueConstraint::Fixed(_)))
}
}
#[derive(Debug, Clone)]
pub struct NotationDecl {
pub name: NameId,
pub target_namespace: Option<NameId>,
pub public: String,
pub system: Option<String>,
pub source: Option<SourceRef>,
pub id: Option<String>,
}
impl NotationDecl {
pub fn new(name: NameId, public: String) -> Self {
Self {
name,
target_namespace: None,
public,
system: None,
source: None,
id: None,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_element_decl_global() {
let elem = ElementDecl::new_global(NameId(1), Some(NameId(2)));
assert!(elem.is_global());
assert!(!elem.is_local());
assert_eq!(elem.scope, DeclarationScope::Global);
}
#[test]
fn test_element_decl_local() {
let elem = ElementDecl::new_local(NameId(1), None);
assert!(elem.is_local());
assert!(!elem.is_global());
assert_eq!(elem.scope, DeclarationScope::Local);
}
#[test]
fn test_element_substitutable() {
let mut elem = ElementDecl::new_global(NameId(1), None);
assert!(elem.is_substitutable());
elem.is_abstract = true;
assert!(!elem.is_substitutable());
}
#[test]
fn test_attribute_decl_global() {
let attr = AttributeDecl::new_global(NameId(1), Some(NameId(2)));
assert!(attr.is_global());
assert!(!attr.is_local());
}
#[test]
fn test_attribute_decl_local() {
let attr = AttributeDecl::new_local(NameId(1), None);
assert!(attr.is_local());
assert!(!attr.is_global());
}
#[test]
fn test_value_constraint() {
let default_val = ValueConstraint::Default("foo".to_string());
assert!(!default_val.is_fixed());
assert_eq!(default_val.value(), "foo");
let fixed_val = ValueConstraint::Fixed("bar".to_string());
assert!(fixed_val.is_fixed());
assert_eq!(fixed_val.value(), "bar");
}
#[test]
fn test_attribute_value_constraint() {
let mut attr = AttributeDecl::new_local(NameId(1), None);
assert!(!attr.has_default());
assert!(!attr.has_fixed());
attr.value_constraint = Some(ValueConstraint::Default("test".to_string()));
assert!(attr.has_default());
assert!(!attr.has_fixed());
attr.value_constraint = Some(ValueConstraint::Fixed("test".to_string()));
assert!(!attr.has_default());
assert!(attr.has_fixed());
}
#[test]
fn test_notation_decl() {
let notation = NotationDecl::new(NameId(1), "http://example.com/public".to_string());
assert_eq!(notation.name, NameId(1));
assert_eq!(notation.public, "http://example.com/public");
assert!(notation.system.is_none());
}
}