use crate::ids::{AttributeGroupKey, ModelGroupKey, NameId};
use crate::parser::location::SourceRef;
use crate::types::complex::{AttributeUse, AttributeWildcard, Compositor, ContentParticle};
#[derive(Debug, Clone)]
pub struct ModelGroupDef {
pub name: Option<NameId>,
pub target_namespace: Option<NameId>,
pub source: Option<SourceRef>,
pub compositor: Compositor,
pub particles: Vec<ContentParticle>,
pub id: Option<String>,
}
impl ModelGroupDef {
pub fn new(name: NameId, compositor: Compositor) -> Self {
Self {
name: Some(name),
target_namespace: None,
source: None,
compositor,
particles: Vec::new(),
id: None,
}
}
pub fn anonymous(compositor: Compositor) -> Self {
Self {
name: None,
target_namespace: None,
source: None,
compositor,
particles: Vec::new(),
id: None,
}
}
pub fn is_named(&self) -> bool {
self.name.is_some()
}
pub fn is_empty(&self) -> bool {
self.particles.is_empty()
}
pub fn add_particle(&mut self, particle: ContentParticle) {
self.particles.push(particle);
}
}
#[derive(Debug, Clone)]
pub enum ModelGroupRef {
Resolved(ModelGroupKey),
Unresolved {
namespace: Option<NameId>,
local_name: NameId,
},
}
#[derive(Debug, Clone)]
pub struct AttributeGroupDef {
pub name: Option<NameId>,
pub target_namespace: Option<NameId>,
pub source: Option<SourceRef>,
pub attributes: Vec<AttributeUse>,
pub attribute_group_refs: Vec<AttributeGroupRef>,
pub attribute_wildcard: Option<AttributeWildcard>,
pub id: Option<String>,
}
impl AttributeGroupDef {
pub fn new(name: NameId) -> Self {
Self {
name: Some(name),
target_namespace: None,
source: None,
attributes: Vec::new(),
attribute_group_refs: Vec::new(),
attribute_wildcard: None,
id: None,
}
}
pub fn anonymous() -> Self {
Self {
name: None,
target_namespace: None,
source: None,
attributes: Vec::new(),
attribute_group_refs: Vec::new(),
attribute_wildcard: None,
id: None,
}
}
pub fn is_named(&self) -> bool {
self.name.is_some()
}
pub fn is_empty(&self) -> bool {
self.attributes.is_empty()
&& self.attribute_group_refs.is_empty()
&& self.attribute_wildcard.is_none()
}
pub fn add_attribute(&mut self, attr_use: AttributeUse) {
self.attributes.push(attr_use);
}
pub fn add_attribute_group_ref(&mut self, ref_: AttributeGroupRef) {
self.attribute_group_refs.push(ref_);
}
}
#[derive(Debug, Clone)]
pub enum AttributeGroupRef {
Resolved(AttributeGroupKey),
Unresolved {
namespace: Option<NameId>,
local_name: NameId,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Occurrence {
pub min: u32,
pub max: Option<u32>,
}
impl Occurrence {
pub const ONCE: Occurrence = Occurrence {
min: 1,
max: Some(1),
};
pub const OPTIONAL: Occurrence = Occurrence {
min: 0,
max: Some(1),
};
pub const UNBOUNDED: Occurrence = Occurrence { min: 0, max: None };
pub const ONE_OR_MORE: Occurrence = Occurrence { min: 1, max: None };
pub fn new(min: u32, max: Option<u32>) -> Self {
Self { min, max }
}
pub fn is_optional(&self) -> bool {
self.min == 0
}
pub fn is_unbounded(&self) -> bool {
self.max.is_none()
}
pub fn allows_multiple(&self) -> bool {
self.max.is_none_or(|m| m > 1)
}
pub fn is_once(&self) -> bool {
self.min == 1 && self.max == Some(1)
}
}
impl Default for Occurrence {
fn default() -> Self {
Self::ONCE
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_model_group_def() {
let group = ModelGroupDef::new(NameId(1), Compositor::Sequence);
assert!(group.is_named());
assert!(group.is_empty());
assert_eq!(group.compositor, Compositor::Sequence);
}
#[test]
fn test_anonymous_model_group() {
let group = ModelGroupDef::anonymous(Compositor::Choice);
assert!(!group.is_named());
assert_eq!(group.compositor, Compositor::Choice);
}
#[test]
fn test_attribute_group_def() {
let group = AttributeGroupDef::new(NameId(1));
assert!(group.is_named());
assert!(group.is_empty());
}
#[test]
fn test_anonymous_attribute_group() {
let group = AttributeGroupDef::anonymous();
assert!(!group.is_named());
assert!(group.is_empty());
}
#[test]
fn test_occurrence_constants() {
assert!(Occurrence::ONCE.is_once());
assert!(!Occurrence::ONCE.is_optional());
assert!(!Occurrence::ONCE.is_unbounded());
assert!(Occurrence::OPTIONAL.is_optional());
assert!(!Occurrence::OPTIONAL.allows_multiple());
assert!(Occurrence::UNBOUNDED.is_unbounded());
assert!(Occurrence::UNBOUNDED.allows_multiple());
assert!(!Occurrence::ONE_OR_MORE.is_optional());
assert!(Occurrence::ONE_OR_MORE.is_unbounded());
}
#[test]
fn test_occurrence_custom() {
let occ = Occurrence::new(2, Some(5));
assert!(!occ.is_optional());
assert!(!occ.is_unbounded());
assert!(occ.allows_multiple());
}
}