openbim-ifcx
Lossless reader and writer for IFC5 / IFCX files, the layered JSON model.
| Crate | openbim-ifcx 0.1.1 on main |
|---|---|
| Latest release | 0.1.1 (2026-10-03) |
| Distributed as | crates.io openbim-ifcx |
| Install | cargo add openbim-ifcx |
| Requires | Rust 1.88.0 |
| License | MIT |
| API documentation | rustdoc · docs.rs |
| Source | crates/openbim-ifcx/ |
About
From the crate's README.md:
OpenBIM.rs crate for IFC5 / IFCX. It reads and writes ifcx_alpha files losslessly, composes layered nodes into a resolved tree as upstream does (flatten, then compose), and checks attribute values against the file's schemas, collecting every failure with its node path, attribute id, and JSON pointer (IfcxFile::validate, validate_flat, validate_attributes). It resolves imports into an ordered layer stack through a caller-supplied resolver (LayerStackBuilder::build for one main layer, build_all for several layers stacked as upstream's ifcx compose does), validates the stack against the schemas of all its layers (LayerStack::validate), and federates schemas and data with every layer after the layers it imports, so a layer overrides its imports (buildingSMART/IFC5-development#144). flatten_owned and LayerStack::into_federated move nodes and attribute values instead of copying them, which makes flattening large models several times faster than flatten over borrowed nodes. The composed tree shares sub-trees between instances instead of copying them, and reference cycles and unknown references are typed errors.
Features:
integrity(default): check SRI-stylesha256-<base64>(alsosha384,sha512)integrityvalues on imports, usingsha2andbase64. Without it, imports that carryintegrityare rejected.fs:FsResolver, which loads imports from local files. The crate never uses the network.
See the repository capabilities, the documentation with a Rust guide, and the viewer, which shows an IFCX file in the browser.
Licensed under MIT.
Public API
The crate root, as rustdoc shows it. Follow a name to its rustdoc entry.
| Module | Summary |
|---|---|
compose | Layer composition, following upstream src/ifcx-core/composition of buildingSMART/IFC5-development for the ifcx_alpha draft. |
layers | Layer stacks: loading a main layer and, recursively, its imports. |
validate | Checking attribute values against a file's schemas. |
| Item | Kind | Summary |
|---|---|---|
ArrayRestrictions | struct | |
compose | function | Composes flattened nodes into a tree, as upstream's LoadIfcxFile does after flattening. |
ComposedNode | struct | One node of the composed tree. Upstream calls this a post-composition node. |
ComposeError | enum | Why flattened nodes could not be composed. |
Composition | struct | The composed tree of a set of flattened nodes. |
DataType | enum | The dataType of a value description. Names this crate does not know read as DataType::Other and are written back unchanged. |
EnumRestrictions | struct | |
Extra | type alias | Fields this crate does not model, kept in input order for round trip. |
FailureKind | enum | What is wrong with one attribute value. |
FlatNode | struct | All opinions about one path, merged in layer order. |
flatten | function | Merges input nodes into one FlatNode per path. |
flatten_owned | function | flatten for nodes the caller no longer needs: the nodes are consumed and their paths, maps, and attribute values move into the result instead of being copied. |
IfcxFile | struct | One IFCX file: a single layer of a dataset. |
IfcxHeader | struct | |
IfcxNode | struct | One node opinion. children and inherits map a local name to a referenced path; a None value deletes that entry when layers merge. |
IfcxSchema | struct | Describes the values allowed for one attribute id. |
IfcxValueDescription | struct | |
ImportNode | struct | A reference to another IFCX file that this layer builds on. |
INTERNAL_ATTRIBUTE_PREFIX | constant | Attribute ids with this prefix are not validated, as upstream. |
JsonType | enum | The JSON type of a value, for failure messages. |
ObjectRestrictions | struct | |
ReadError | struct | A file that could not be read, with the 1-based location of the problem. |
ReadErrorKind | enum | Why a file could not be read. |
validate_attributes | function | Checks the attributes of nodes, given as (path, attributes) pairs, against schemas and collects every failure. |
validate_flat | function | Checks flattened nodes, as flatten or flatten_owned return them, against schemas. This is what upstream validates: one merged node per path, in the flattened order. |
validate_nodes | function | Checks the attributes of each node as it is, without merging nodes that share a path. Nodes without attributes are skipped. |
ValidationFailure | struct | One attribute value that does not match its schema. |
ValidationReport | struct | Every failure found in one validation run, in node and attribute order. |
WriteError | struct | A file that could not be written. |
Cargo features
| Feature | Default | Enables |
|---|---|---|
fs | — | |
integrity | yes | dep:base64, dep:sha2 |
Examples
compose-json:cargo run -p openbim-ifcx --example compose-json
Within the workspace
Changes
Unreleased, on main:
Changed
- Breaking: a layer now overrides the layers it imports, as agreed upstream in buildingSMART/IFC5-development#144 (2026-10-05): "imported data should come 'before' the main data".
LayerStackBuilderreturns the layers in federation order: every layer after its own imports, recursively; sibling imports in written order, so a later import overrides an earlier one; each layer once, where it is first reached; the main layer last.main → [a, b],a → [c]now givesc, a, b, main(wasmain, a, c, b), andmain → a → bgivesb, a, main(wasmain, a, b). Code relying on the old order, in which an import overrode its importer and the main layer had the lowest priority, now composes and validates differently whenever an import carriesdataor redefines a schema. Upstream's code at1a63082still uses the old order until a pending upstream pull request lands (#36). - Breaking:
LayerStack::layers,keysandinto_layersreturn the federation order, so the main layer is last, not first;LayerStack::mainstill returns the main layer. Forbuild_all,mainis now the last layer of the stack, the strongest named one (was the first named one), and the federated header is its header (#36). - Breaking:
federateandfederate_ownedtake the header of the last file, the strongest, instead of the first; schemas and data are merged as before.LayerStack::federateandinto_federatedthus keep the main layer's header (#36). LayerStackBuilder::allow_cycles(true)skips the import that closes a cycle, as before; under the new order the layer that import names comes after its importer, and the main layer stays last (main → a → maingivesa, main) (#36).LayerStackBuilderwalks imports without recursion, so a long import chain cannot overflow the stack.integrityis still checked on every import edge (#36).
Latest release, 0.1.1 (2026-10-03):
No breaking change: every addition below is new API, and existing functions and types keep their signatures.
Added
LayerStack::validatechecks a layer stack built with its imports: the schemas of every layer, merged asfederatedoes, against the attributes of every layer, merged per path asflattendoes. An attribute whose schema lives only in an imported file now validates.validate_flatchecks the output offlattenorflatten_owned(#42).LayerStackBuilder::build_allstacks several layers, weakest first, as the imports of a main layer without data, as upstream'sifcx composedoes (#42).flatten_owned,FlatNode::merge_owned,federate_owned, andLayerStack::into_federatedconsume their input and move nodes and attribute values instead of copying them. In the opt-inupstream_compositiontest (release build) flatteningTekla Housedrops from 88 ms to 18 ms andRailway_project_IFC5from 60 ms to 8 ms (#43).
Changed
IfcxFile::validatemerges attributes per path by reference instead of copying every value; the report is unchanged (#43).
Migration
- To flatten without copying, replace
flatten(&file.data)withflatten_owned(file.data)where the nodes are not needed afterwards, andstack.federate()withstack.into_federated().flattenover borrowed nodes still copies each attribute value, as before. - To validate a file with its imports, build its layer stack and call
stack.validate()instead offile.validate().
Fixed
IfcxFile::validateandvalidate_attributeswalk schemainheritswith an explicit stack and check each inherited schema once per value. A long inheritance chain overflowed the stack, and diamond-shaped inheritance doubled the work per level (22 levels took seconds and reported one failure four million times); a schema reached along several paths now reports its failures once. Found while fuzzing (#41).
Full history: crates/openbim-ifcx/CHANGELOG.md, and every release of every crate on the project changelog.