openbim_ifcx_geometry/
attributes.rs

1//! Read access to one node's attributes, independent of where they come from.
2
3use indexmap::IndexMap;
4use openbim_ifcx::{ComposedNode, FlatNode, IfcxNode};
5use serde_json::{Map, Value};
6
7/// A node's attributes keyed by namespaced attribute id, as in a file's
8/// `schemas` (for example `points::array` or `gltf::material`).
9///
10/// Values are the attribute values as written, not the flattened
11/// `<id>::<component>` keys the upstream viewer builds. A JSON `null` counts
12/// as absent, because in IFCX it deletes an attribute when layers merge.
13///
14/// Implemented for a single [`IfcxNode`], a [`FlatNode`] from
15/// [`openbim_ifcx::flatten()`], a [`ComposedNode`] from
16/// [`openbim_ifcx::compose()`], plain attribute maps, and references to them.
17pub trait Attributes {
18    /// The raw value of attribute `id`, or `None` when absent.
19    fn raw_attribute(&self, id: &str) -> Option<&Value>;
20
21    /// The value of attribute `id`, or `None` when absent or `null`.
22    fn attribute(&self, id: &str) -> Option<&Value> {
23        self.raw_attribute(id).filter(|value| !value.is_null())
24    }
25}
26
27impl Attributes for IndexMap<String, Value> {
28    fn raw_attribute(&self, id: &str) -> Option<&Value> {
29        self.get(id)
30    }
31}
32
33impl Attributes for Map<String, Value> {
34    fn raw_attribute(&self, id: &str) -> Option<&Value> {
35        self.get(id)
36    }
37}
38
39impl Attributes for IfcxNode {
40    fn raw_attribute(&self, id: &str) -> Option<&Value> {
41        self.attributes.as_ref()?.get(id)
42    }
43}
44
45impl Attributes for FlatNode {
46    fn raw_attribute(&self, id: &str) -> Option<&Value> {
47        self.attributes.get(id).map(|value| &**value)
48    }
49}
50
51impl Attributes for ComposedNode {
52    fn raw_attribute(&self, id: &str) -> Option<&Value> {
53        self.attributes.get(id).map(|value| &**value)
54    }
55}
56
57impl<T: Attributes + ?Sized> Attributes for &T {
58    fn raw_attribute(&self, id: &str) -> Option<&Value> {
59        (**self).raw_attribute(id)
60    }
61}