xsd_parser/models/meta/
reference.rs

1//! Contains the [`ReferenceMeta`] type information and all related types.
2
3use std::hash::{Hash, Hasher};
4
5use crate::models::{
6    schema::{MaxOccurs, MinOccurs},
7    Ident,
8};
9
10use super::{MetaTypes, TypeEq};
11
12/// Type information that defines a reference to another type.
13#[derive(Debug, Clone)]
14pub struct ReferenceMeta {
15    /// Type that is referenced.
16    pub type_: Ident,
17
18    /// Whether the referenced type is nillable or not.
19    pub nillable: bool,
20
21    /// Minimum occurrence of the referenced type.
22    pub min_occurs: MinOccurs,
23
24    /// Maximum occurrence of the referenced type.
25    pub max_occurs: MaxOccurs,
26}
27
28impl ReferenceMeta {
29    /// Create a new [`ReferenceMeta`] instance from the passed `type_`.
30    #[must_use]
31    pub fn new<T>(type_: T) -> Self
32    where
33        T: Into<Ident>,
34    {
35        Self {
36            type_: type_.into(),
37            nillable: false,
38            min_occurs: 1,
39            max_occurs: MaxOccurs::Bounded(1),
40        }
41    }
42
43    /// Returns `true` if this references a single type, `false` otherwise.
44    ///
45    /// This means that the target type is used exactly once in this reference.
46    #[must_use]
47    pub fn is_single(&self) -> bool {
48        self.min_occurs == 1 && self.max_occurs == MaxOccurs::Bounded(1)
49    }
50
51    /// Returns `true` if this references a simple type, `false` otherwise.
52    ///
53    /// This means that it is more or less just a type definition or renaming of an
54    /// existing type.
55    #[must_use]
56    pub fn is_simple(&self) -> bool {
57        self.is_single() && !self.nillable
58    }
59
60    /// Sets the minimum occurrence of the referenced type.
61    #[must_use]
62    pub fn min_occurs(mut self, min: MinOccurs) -> Self {
63        self.min_occurs = min;
64
65        self
66    }
67
68    /// Sets the maximum occurrence of the referenced type.
69    #[must_use]
70    pub fn max_occurs(mut self, max: MaxOccurs) -> Self {
71        self.max_occurs = max;
72
73        self
74    }
75
76    /// Returns `true` if this type is emptiable, `false` otherwise.
77    ///
78    /// Emptiable means that the type may not have any element.
79    #[must_use]
80    pub fn is_emptiable(&self, types: &MetaTypes) -> bool {
81        if self.min_occurs == 0 {
82            return true;
83        }
84
85        types
86            .items
87            .get(&self.type_)
88            .is_none_or(|ty| ty.is_emptiable(types))
89    }
90
91    /// Returns `true` if this type is mixed, `false` otherwise.
92    ///
93    /// Mixed means, that the type also accepts text intermixed with it's elements.
94    #[must_use]
95    pub fn is_mixed(&self, types: &MetaTypes) -> bool {
96        types
97            .items
98            .get(&self.type_)
99            .is_some_and(|ty| ty.is_mixed(types))
100    }
101}
102
103impl TypeEq for ReferenceMeta {
104    fn type_hash<H: Hasher>(&self, hasher: &mut H, types: &MetaTypes) {
105        let Self {
106            type_,
107            nillable,
108            min_occurs,
109            max_occurs,
110        } = self;
111
112        type_.type_hash(hasher, types);
113        nillable.hash(hasher);
114        min_occurs.hash(hasher);
115        max_occurs.hash(hasher);
116    }
117
118    fn type_eq(&self, other: &Self, types: &MetaTypes) -> bool {
119        let Self {
120            type_,
121            nillable,
122            min_occurs,
123            max_occurs,
124        } = self;
125
126        type_.type_eq(&other.type_, types)
127            && nillable.eq(&other.nillable)
128            && min_occurs.eq(&other.min_occurs)
129            && max_occurs.eq(&other.max_occurs)
130    }
131}