openbim_ifcx/lib.rs
1//! OpenBIM.rs family for IFC5 / IFCX.
2//!
3//! IFCX is a layered, componentised JSON model with USD-like composition. It
4//! is not an EXPRESS schema release, so it lives here rather than as a
5//! `SchemaVersion` in `openbim-ifc` (see `docs/adr/0001`).
6//!
7//! This crate reads and writes single `ifcx_alpha` files losslessly, composes
8//! layered nodes into a resolved tree ([`flatten`], then [`compose()`]; see
9//! [`compose`](mod@compose)), and checks attribute values against a file's
10//! `schemas` ([`IfcxFile::validate`], [`validate_flat`],
11//! [`validate_attributes`]; rules in [`validate`](mod@validate)). [`layers`]
12//! loads a file with its imports through a caller-supplied resolver,
13//! validates the stack as a whole
14//! ([`LayerStack::validate`](layers::LayerStack::validate)), and federates
15//! it into one file, ready to flatten and compose.
16//!
17//! [`flatten_owned`] and [`layers::LayerStack::into_federated`] consume
18//! their input and move attribute values instead of copying them; use them
19//! when the nodes are not needed afterwards, which is the usual case after
20//! reading a file:
21//!
22//! ```
23//! use openbim_ifcx::{compose, flatten_owned, IfcxFile};
24//!
25//! let file = IfcxFile::from_json_str(r#"{
26//! "header": {"id": "demo", "ifcxVersion": "ifcx_alpha", "dataVersion": "1.0.0",
27//! "author": "someone", "timestamp": "2026-10-03"},
28//! "imports": [], "schemas": {},
29//! "data": [{"path": "site", "attributes": {"demo::name": "Site"}}]
30//! }"#)?;
31//! let composition = compose(&flatten_owned(file.data))?;
32//! assert_eq!(composition.roots(), ["site"]);
33//! # Ok::<(), Box<dyn std::error::Error>>(())
34//! ```
35//!
36//! # Features
37//!
38//! - `integrity` (default): check SHA-2 `integrity` values on imports. Without
39//! it, an import that carries `integrity` is rejected rather than loaded
40//! unchecked.
41//! - `fs`: [`layers::FsResolver`], which loads imports from local files. The
42//! crate does no filesystem access otherwise and never uses the network.
43//!
44//! ```
45//! use openbim_ifcx::IfcxFile;
46//!
47//! let file = IfcxFile::from_json_str(r#"{
48//! "header": {"id": "demo", "ifcxVersion": "ifcx_alpha", "dataVersion": "1.0.0",
49//! "author": "someone", "timestamp": "2026-10-03"},
50//! "imports": [],
51//! "schemas": {},
52//! "data": [{"path": "a1", "children": {"Wall": "b2", "Old": null}}]
53//! }"#)?;
54//! let children = file.data[0].children.as_ref().unwrap();
55//! assert_eq!(children["Wall"].as_deref(), Some("b2"));
56//! assert_eq!(children["Old"], None);
57//! # Ok::<(), openbim_ifcx::ReadError>(())
58//! ```
59
60#![forbid(unsafe_code)]
61
62pub mod compose;
63mod json;
64pub mod layers;
65mod model;
66pub mod validate;
67
68pub use compose::{
69 compose, flatten, flatten_owned, ComposeError, ComposedNode, Composition, FlatNode,
70};
71pub use json::{ReadError, ReadErrorKind, WriteError};
72pub use model::{
73 ArrayRestrictions, DataType, EnumRestrictions, Extra, IfcxFile, IfcxHeader, IfcxNode,
74 IfcxSchema, IfcxValueDescription, ImportNode, ObjectRestrictions,
75};
76pub use validate::{
77 validate_attributes, validate_flat, validate_nodes, FailureKind, JsonType, ValidationFailure,
78 ValidationReport, INTERNAL_ATTRIBUTE_PREFIX,
79};