Skip to main content

openbim_core/
element_ref.rs

1//! Cross-document element references.
2
3/// A reference to one element, optionally inside a named document.
4///
5/// Cross-document referencing is the shared shape behind BCF viewpoint
6/// components and ICDD linkset endpoints. Both name a document and an element
7/// within it; only the vocabulary differs.
8#[derive(Debug, Clone, PartialEq, Eq, Hash)]
9pub struct ElementRef {
10    /// The document the element lives in, when the reference crosses one.
11    ///
12    /// `None` means "the current document" — an intra-document reference.
13    pub document: Option<String>,
14    /// The element's identifier within that document, verbatim.
15    ///
16    /// Kept as an opaque string on purpose: an IFC `GlobalId`, an ICDD URI and
17    /// a BCF component GUID are not the same syntax, and normalising them here
18    /// would lose information that only the owning standard can interpret.
19    pub id: String,
20}
21
22impl ElementRef {
23    /// A reference within the current document.
24    #[must_use]
25    pub fn local(id: impl Into<String>) -> Self {
26        Self {
27            document: None,
28            id: id.into(),
29        }
30    }
31
32    /// A reference into another document.
33    #[must_use]
34    pub fn in_document(document: impl Into<String>, id: impl Into<String>) -> Self {
35        Self {
36            document: Some(document.into()),
37            id: id.into(),
38        }
39    }
40
41    /// Whether this reference crosses a document boundary.
42    #[must_use]
43    pub fn is_cross_document(&self) -> bool {
44        self.document.is_some()
45    }
46}
47
48#[cfg(test)]
49mod tests {
50    use super::*;
51
52    #[test]
53    fn element_refs_distinguish_scope() {
54        let local = ElementRef::local("a");
55        assert_eq!(local.document, None);
56        assert!(!local.is_cross_document());
57
58        let remote = ElementRef::in_document("d.ifc", "a");
59        assert_eq!(remote.document.as_deref(), Some("d.ifc"));
60        assert!(remote.is_cross_document());
61    }
62
63    #[test]
64    fn same_id_in_different_documents_is_not_the_same_element() {
65        assert_ne!(
66            ElementRef::in_document("a.ifc", "x"),
67            ElementRef::in_document("b.ifc", "x")
68        );
69        assert_ne!(
70            ElementRef::local("x"),
71            ElementRef::in_document("a.ifc", "x")
72        );
73    }
74}