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::{export_to_json, extract_lighting_data, LightFixtureData, LightingExport};
46pub use model::ParsedModel;
47pub use scanner::EntityScanner;
48pub use tokenizer::{parse_entity, Token};
49
50use bimifc_model::{IfcModel, IfcParser, ProgressCallback, Result};
51use std::sync::Arc;
52
53/// Main STEP/IFC parser implementing `IfcParser` trait
54///
55/// This is the entry point for parsing IFC files. It creates a `ParsedModel`
56/// that provides access to all IFC data through the trait interfaces.
57#[derive(Default)]
58pub struct StepParser {
59    /// Whether to build spatial tree during parsing
60    pub build_spatial_tree: bool,
61    /// Whether to extract properties during parsing
62    pub extract_properties: bool,
63}
64
65impl StepParser {
66    /// Create a new parser with default settings
67    pub fn new() -> Self {
68        Self {
69            build_spatial_tree: true,
70            extract_properties: true,
71        }
72    }
73
74    /// Create a parser optimized for geometry-only access
75    pub fn geometry_only() -> Self {
76        Self {
77            build_spatial_tree: false,
78            extract_properties: false,
79        }
80    }
81
82    /// Set whether to build spatial tree
83    pub fn with_spatial_tree(mut self, enabled: bool) -> Self {
84        self.build_spatial_tree = enabled;
85        self
86    }
87
88    /// Set whether to extract properties
89    pub fn with_properties(mut self, enabled: bool) -> Self {
90        self.extract_properties = enabled;
91        self
92    }
93}
94
95impl IfcParser for StepParser {
96    fn parse(&self, content: &str) -> Result<Arc<dyn IfcModel>> {
97        ParsedModel::parse(content, self.build_spatial_tree, self.extract_properties)
98            .map(|m| Arc::new(m) as Arc<dyn IfcModel>)
99    }
100
101    fn parse_with_progress(
102        &self,
103        content: &str,
104        on_progress: ProgressCallback,
105    ) -> Result<Arc<dyn IfcModel>> {
106        ParsedModel::parse_with_progress(
107            content,
108            self.build_spatial_tree,
109            self.extract_properties,
110            on_progress,
111        )
112        .map(|m| Arc::new(m) as Arc<dyn IfcModel>)
113    }
114}
115
116/// Quick parse function for simple use cases
117pub fn parse(content: &str) -> Result<Arc<dyn IfcModel>> {
118    StepParser::new().parse(content)
119}
120
121/// Parse with progress reporting
122pub fn parse_with_progress(
123    content: &str,
124    on_progress: impl Fn(&str, f32) + Send + 'static,
125) -> Result<Arc<dyn IfcModel>> {
126    StepParser::new().parse_with_progress(content, Box::new(on_progress))
127}
128
129/// Auto-detect format and parse (IFC4 STEP or IFC5 IFCX)
130///
131/// This is the recommended entry point for parsing IFC files when
132/// the format is not known in advance.
133pub fn parse_auto(content: &str) -> Result<Arc<dyn IfcModel>> {
134    if is_ifcx_format(content) {
135        IfcxModel::parse(content).map(|m| Arc::new(m) as Arc<dyn IfcModel>)
136    } else {
137        parse(content)
138    }
139}
140
141/// Unified parser that auto-detects format
142#[derive(Default)]
143pub struct UnifiedParser {
144    /// Settings for STEP parsing
145    pub step_settings: StepParser,
146}
147
148impl UnifiedParser {
149    pub fn new() -> Self {
150        Self::default()
151    }
152}
153
154impl IfcParser for UnifiedParser {
155    fn parse(&self, content: &str) -> Result<Arc<dyn IfcModel>> {
156        if is_ifcx_format(content) {
157            IfcxModel::parse(content).map(|m| Arc::new(m) as Arc<dyn IfcModel>)
158        } else {
159            self.step_settings.parse(content)
160        }
161    }
162
163    fn parse_with_progress(
164        &self,
165        content: &str,
166        on_progress: ProgressCallback,
167    ) -> Result<Arc<dyn IfcModel>> {
168        if is_ifcx_format(content) {
169            on_progress("Parsing IFCX JSON", 0.0);
170            let result = IfcxModel::parse(content).map(|m| Arc::new(m) as Arc<dyn IfcModel>);
171            on_progress("Done", 1.0);
172            result
173        } else {
174            self.step_settings.parse_with_progress(content, on_progress)
175        }
176    }
177}