1#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
16#[non_exhaustive]
17pub enum SchemaVersion {
18 Ifc2x3,
20 Ifc4,
22 Ifc4x1,
25 Ifc4x2,
28 Ifc4x3,
30}
31
32impl SchemaVersion {
33 pub const ALL: [Self; 5] = [
38 Self::Ifc2x3,
39 Self::Ifc4,
40 Self::Ifc4x1,
41 Self::Ifc4x2,
42 Self::Ifc4x3,
43 ];
44
45 #[must_use]
47 pub const fn release_id(self) -> &'static str {
48 match self {
49 Self::Ifc2x3 => "IFC2X3_TC1",
50 Self::Ifc4 => "IFC4_ADD2_TC1",
51 Self::Ifc4x1 => "IFC4X1_FINAL",
52 Self::Ifc4x2 => "IFC4X2_FINAL",
53 Self::Ifc4x3 => "IFC4X3_ADD2",
54 }
55 }
56
57 #[must_use]
59 pub const fn expected_entity_count(self) -> usize {
60 match self {
61 Self::Ifc2x3 => 653,
62 Self::Ifc4 => 776,
63 Self::Ifc4x1 => 801,
64 Self::Ifc4x2 => 816,
65 Self::Ifc4x3 => 876,
66 }
67 }
68
69 #[must_use]
71 pub const fn expected_type_count(self) -> usize {
72 match self {
73 Self::Ifc2x3 => 327,
74 Self::Ifc4 => 397,
75 Self::Ifc4x1 => 400,
76 Self::Ifc4x2 => 407,
77 Self::Ifc4x3 => 436,
78 }
79 }
80
81 #[must_use]
83 pub const fn header_tokens(self) -> &'static [&'static str] {
84 match self {
85 Self::Ifc2x3 => &["IFC2X3"],
86 Self::Ifc4 => &["IFC4"],
87 Self::Ifc4x1 => &["IFC4X1"],
88 Self::Ifc4x2 => &["IFC4X2"],
89 Self::Ifc4x3 => &["IFC4X3", "IFC4X3_ADD2"],
90 }
91 }
92
93 #[must_use]
95 pub const fn feature_name(self) -> &'static str {
96 match self {
97 Self::Ifc2x3 => "ifc2x3",
98 Self::Ifc4 => "ifc4",
99 Self::Ifc4x1 => "ifc4x1",
100 Self::Ifc4x2 => "ifc4x2",
101 Self::Ifc4x3 => "ifc4x3",
102 }
103 }
104
105 #[must_use]
108 pub const fn is_bundled(self) -> bool {
109 match self {
110 Self::Ifc2x3 => cfg!(feature = "ifc2x3"),
111 Self::Ifc4 => cfg!(feature = "ifc4"),
112 Self::Ifc4x1 => cfg!(feature = "ifc4x1"),
113 Self::Ifc4x2 => cfg!(feature = "ifc4x2"),
114 Self::Ifc4x3 => cfg!(feature = "ifc4x3"),
115 }
116 }
117
118 pub fn from_header_token(token: &str) -> Option<Self> {
120 match token.trim().to_ascii_uppercase().as_str() {
121 "IFC2X3" => Some(Self::Ifc2x3),
122 "IFC4" => Some(Self::Ifc4),
123 "IFC4X1" => Some(Self::Ifc4x1),
124 "IFC4X2" => Some(Self::Ifc4x2),
125 "IFC4X3" | "IFC4X3_ADD2" => Some(Self::Ifc4x3),
126 _ => None,
127 }
128 }
129}
130
131#[cfg(test)]
132mod tests {
133 use super::*;
134
135 #[test]
136 fn recognizes_the_schema_tokens_our_fixtures_carry() {
137 assert_eq!(
138 SchemaVersion::from_header_token("IFC4"),
139 Some(SchemaVersion::Ifc4)
140 );
141 assert_eq!(
142 SchemaVersion::from_header_token("ifc2x3"),
143 Some(SchemaVersion::Ifc2x3)
144 );
145 assert_eq!(SchemaVersion::from_header_token("STEP"), None);
146 }
147
148 #[test]
152 fn header_tokens_and_release_ids_round_trip_for_every_version() {
153 for version in SchemaVersion::ALL {
154 for token in version.header_tokens() {
155 assert_eq!(SchemaVersion::from_header_token(token), Some(version));
156 assert_eq!(
157 SchemaVersion::from_header_token(&token.to_ascii_lowercase()),
158 Some(version)
159 );
160 }
161 }
162 assert_eq!(
163 SchemaVersion::from_header_token("IFC4X1"),
164 Some(SchemaVersion::Ifc4x1)
165 );
166 assert_eq!(
167 SchemaVersion::from_header_token(" ifc4x2 "),
168 Some(SchemaVersion::Ifc4x2)
169 );
170 assert_eq!(SchemaVersion::Ifc4x1.release_id(), "IFC4X1_FINAL");
171 assert_eq!(SchemaVersion::Ifc4x2.release_id(), "IFC4X2_FINAL");
172 let ids: std::collections::BTreeSet<_> =
173 SchemaVersion::ALL.iter().map(|v| v.release_id()).collect();
174 assert_eq!(ids.len(), SchemaVersion::ALL.len());
175 }
176}