Skip to main content

bimifc_parser/
lib.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
5//! BIMIFC Parser - High-performance IFC parser
6//!
7//! This crate provides a fast, memory-efficient parser for IFC (STEP) files.
8//! It implements the traits defined in `bimifc-model` for a clean abstraction.
9//!
10//! # Features
11//!
12//! - **Fast tokenization** using `nom` combinators
13//! - **SIMD-accelerated scanning** using `memchr`
14//! - **Lazy entity decoding** - only parse entities when needed
15//! - **Arc-based caching** - efficient memory sharing
16//! - **Progress reporting** for large files
17//!
18//! # Example
19//!
20//! ```ignore
21//! use bimifc_parser::StepParser;
22//! use bimifc_model::IfcParser;
23//!
24//! let parser = StepParser::new();
25//! let model = parser.parse(ifc_content)?;
26//!
27//! // Access entities
28//! let walls = model.resolver().find_by_type_name("IFCWALL");
29//! println!("Found {} walls", walls.len());
30//! ```
31
32mod decoder;
33pub mod ifcx;
34pub mod lighting;
35mod model;
36mod properties;
37mod resolver;
38mod scanner;
39mod spatial;
40mod tokenizer;
41mod units;
42
43pub use decoder::EntityDecoder;
44pub use ifcx::{is_ifcx_format, IfcxGeometry, IfcxModel};
45pub use lighting::{
46    export_to_json, extract_lighting_data, goniometric_to_eulumdat, goniometric_to_ldt,
47    light_source_to_eulumdat, light_source_to_ldt, DistributionPlane, LightDistributionData,
48    LightFixtureData, LightSourceData, LightingExport,
49};
50pub use model::ParsedModel;
51pub use scanner::EntityScanner;
52pub use tokenizer::{parse_entity, Token};
53
54use bimifc_model::{IfcModel, IfcParser, ProgressCallback, Result};
55use std::sync::Arc;
56
57/// Main STEP/IFC parser implementing `IfcParser` trait
58///
59/// This is the entry point for parsing IFC files. It creates a `ParsedModel`
60/// that provides access to all IFC data through the trait interfaces.
61#[derive(Default)]
62pub struct StepParser {
63    /// Whether to build spatial tree during parsing
64    pub build_spatial_tree: bool,
65    /// Whether to extract properties during parsing
66    pub extract_properties: bool,
67}
68
69impl StepParser {
70    /// Create a new parser with default settings
71    pub fn new() -> Self {
72        Self {
73            build_spatial_tree: true,
74            extract_properties: true,
75        }
76    }
77
78    /// Create a parser optimized for geometry-only access
79    pub fn geometry_only() -> Self {
80        Self {
81            build_spatial_tree: false,
82            extract_properties: false,
83        }
84    }
85
86    /// Set whether to build spatial tree
87    pub fn with_spatial_tree(mut self, enabled: bool) -> Self {
88        self.build_spatial_tree = enabled;
89        self
90    }
91
92    /// Set whether to extract properties
93    pub fn with_properties(mut self, enabled: bool) -> Self {
94        self.extract_properties = enabled;
95        self
96    }
97}
98
99impl IfcParser for StepParser {
100    fn parse(&self, content: &str) -> Result<Arc<dyn IfcModel>> {
101        ParsedModel::parse(content, self.build_spatial_tree, self.extract_properties)
102            .map(|m| Arc::new(m) as Arc<dyn IfcModel>)
103    }
104
105    fn parse_with_progress(
106        &self,
107        content: &str,
108        on_progress: ProgressCallback,
109    ) -> Result<Arc<dyn IfcModel>> {
110        ParsedModel::parse_with_progress(
111            content,
112            self.build_spatial_tree,
113            self.extract_properties,
114            on_progress,
115        )
116        .map(|m| Arc::new(m) as Arc<dyn IfcModel>)
117    }
118}
119
120/// Quick parse function for simple use cases
121pub fn parse(content: &str) -> Result<Arc<dyn IfcModel>> {
122    StepParser::new().parse(content)
123}
124
125/// Parse with progress reporting
126pub fn parse_with_progress(
127    content: &str,
128    on_progress: impl Fn(&str, f32) + Send + 'static,
129) -> Result<Arc<dyn IfcModel>> {
130    StepParser::new().parse_with_progress(content, Box::new(on_progress))
131}
132
133/// Auto-detect format and parse (IFC4 STEP or IFC5 IFCX)
134///
135/// This is the recommended entry point for parsing IFC files when
136/// the format is not known in advance.
137pub fn parse_auto(content: &str) -> Result<Arc<dyn IfcModel>> {
138    if is_ifcx_format(content) {
139        IfcxModel::parse(content).map(|m| Arc::new(m) as Arc<dyn IfcModel>)
140    } else {
141        parse(content)
142    }
143}
144
145/// Unified parser that auto-detects format
146#[derive(Default)]
147pub struct UnifiedParser {
148    /// Settings for STEP parsing
149    pub step_settings: StepParser,
150}
151
152impl UnifiedParser {
153    pub fn new() -> Self {
154        Self::default()
155    }
156}
157
158impl IfcParser for UnifiedParser {
159    fn parse(&self, content: &str) -> Result<Arc<dyn IfcModel>> {
160        if is_ifcx_format(content) {
161            IfcxModel::parse(content).map(|m| Arc::new(m) as Arc<dyn IfcModel>)
162        } else {
163            self.step_settings.parse(content)
164        }
165    }
166
167    fn parse_with_progress(
168        &self,
169        content: &str,
170        on_progress: ProgressCallback,
171    ) -> Result<Arc<dyn IfcModel>> {
172        if is_ifcx_format(content) {
173            on_progress("Parsing IFCX JSON", 0.0);
174            let result = IfcxModel::parse(content).map(|m| Arc::new(m) as Arc<dyn IfcModel>);
175            on_progress("Done", 1.0);
176            result
177        } else {
178            self.step_settings.parse_with_progress(content, on_progress)
179        }
180    }
181}