Skip to main content

openbim_bcf/
lib.rs

1//! `openbim-bcf` — BIM Collaboration Format.
2//!
3//! # What this is
4//!
5//! The open issue-exchange format: a ZIP with one directory per topic, each
6//! holding the issue XML and optionally a viewpoint (camera plus component
7//! visibility) and a snapshot image. It is how findings from an audit leave
8//! this toolchain and land in any BCF-aware reviewer.
9//!
10//! # BCF is two standards
11//!
12//! **BCF-XML** is the file container this crate targets. **BCF-API** is a
13//! separate REST/JSON service specification for the same domain. They share a
14//! data model and nothing else; conflating them is why this crate is not
15//! simply named for the file extension.
16//!
17//! # 🚨 The reader must be tolerant, and that is evidence-based
18//!
19//! Measured over 33 real third-party archives in the sibling
20//! `../vendor/solibri` corpus:
21//!
22//! | Spec says | Corpus says |
23//! | --- | --- |
24//! | `project.bcfp` describes the project | **0 of 33** have one |
25//! | `bcf.version` declares the version | **20 of 33** have none |
26//! | `TopicStatus` comes from a known set | free text, e.g. `"Offen"` |
27//!
28//! A spec-strict reader rejects every file in that corpus — files every other
29//! BIM tool opens without complaint. So: reject only what cannot be
30//! interpreted at all, and keep status/type strings **verbatim** rather than
31//! mapping them onto an enum. `"Offen"` is not a parse failure; it is what the
32//! file says, and normalising it would corrupt a round-trip.
33//!
34//! # Status
35//!
36//! **Reserved — no implementation.** Published to establish the name.
37//! Read and write support are tracked separately and must never be inferred
38//! from one another.
39
40#![forbid(unsafe_code)]
41
42/// A BCF-XML container version.
43#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
44pub enum BcfVersion {
45    /// 2.0 — comment status in child elements; a back-reference `Topic`
46    /// element is nested inside each comment.
47    V2_0,
48    /// 2.1 — status moves onto a `Topic` attribute; the nested back-reference
49    /// is dropped.
50    V2_1,
51    /// 3.0.
52    V3_0,
53}
54
55impl BcfVersion {
56    /// Whether documents of this version nest a back-reference `Topic` element
57    /// inside each comment.
58    ///
59    /// A reader that does not expect this will mistake the back-reference for
60    /// a second topic declaration.
61    #[must_use]
62    pub fn nests_topic_in_comment(self) -> bool {
63        matches!(self, BcfVersion::V2_0)
64    }
65}
66
67#[cfg(test)]
68mod tests {
69    use super::*;
70
71    #[test]
72    fn only_2_0_nests_topic_backreferences() {
73        assert!(BcfVersion::V2_0.nests_topic_in_comment());
74        assert!(!BcfVersion::V2_1.nests_topic_in_comment());
75        assert!(!BcfVersion::V3_0.nests_topic_in_comment());
76    }
77
78    #[test]
79    fn versions_order_oldest_first() {
80        assert!(BcfVersion::V2_0 < BcfVersion::V2_1);
81        assert!(BcfVersion::V2_1 < BcfVersion::V3_0);
82    }
83}