Skip to main content

ifc_schema/
version.rs

1//! Which IFC schema version a file declares.
2//!
3//! The token comes from the `FILE_SCHEMA` entry in a STEP header. Real files
4//! carry variants (`IFC4X3_ADD2` as well as `IFC4X3`), so matching is explicit
5//! rather than a prefix test.
6
7/// Which IFC schema version a table describes.
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum SchemaVersion {
10    /// IFC2x3 TC1 — 653 entities. Still the most common in the wild.
11    Ifc2x3,
12    /// IFC4 ADD2 TC1 — 776 entities. The ISO-standard release.
13    Ifc4,
14    /// IFC4x3 ADD2 — 876 entities. Adds alignment and civil infrastructure.
15    Ifc4x3,
16}
17
18impl SchemaVersion {
19    /// Exact published release identifier for the bundled structural table.
20    #[must_use]
21    pub const fn release_id(self) -> &'static str {
22        match self {
23            Self::Ifc2x3 => "IFC2X3_TC1",
24            Self::Ifc4 => "IFC4_ADD2_TC1",
25            Self::Ifc4x3 => "IFC4X3_ADD2",
26        }
27    }
28
29    /// Entity count asserted when the bundled artifact is generated.
30    #[must_use]
31    pub const fn expected_entity_count(self) -> usize {
32        match self {
33            Self::Ifc2x3 => 653,
34            Self::Ifc4 => 776,
35            Self::Ifc4x3 => 876,
36        }
37    }
38
39    /// Defined-type count asserted when the bundled artifact is generated.
40    #[must_use]
41    pub const fn expected_type_count(self) -> usize {
42        match self {
43            Self::Ifc2x3 => 327,
44            Self::Ifc4 => 397,
45            Self::Ifc4x3 => 436,
46        }
47    }
48
49    /// Header tokens accepted for this release, excluding case-only variants.
50    #[must_use]
51    pub const fn header_tokens(self) -> &'static [&'static str] {
52        match self {
53            Self::Ifc2x3 => &["IFC2X3"],
54            Self::Ifc4 => &["IFC4"],
55            Self::Ifc4x3 => &["IFC4X3", "IFC4X3_ADD2"],
56        }
57    }
58
59    /// Parse the token found in a STEP file's `FILE_SCHEMA` header entry.
60    pub fn from_header_token(token: &str) -> Option<Self> {
61        match token.trim().to_ascii_uppercase().as_str() {
62            "IFC2X3" => Some(Self::Ifc2x3),
63            "IFC4" => Some(Self::Ifc4),
64            "IFC4X3" | "IFC4X3_ADD2" => Some(Self::Ifc4x3),
65            _ => None,
66        }
67    }
68}
69
70#[cfg(test)]
71mod tests {
72    use super::*;
73
74    #[test]
75    fn recognizes_the_schema_tokens_our_fixtures_carry() {
76        assert_eq!(
77            SchemaVersion::from_header_token("IFC4"),
78            Some(SchemaVersion::Ifc4)
79        );
80        assert_eq!(
81            SchemaVersion::from_header_token("ifc2x3"),
82            Some(SchemaVersion::Ifc2x3)
83        );
84        assert_eq!(SchemaVersion::from_header_token("STEP"), None);
85    }
86}