pub struct EntityDecoder<'a> { /* private fields */ }Expand description
Entity decoder for lazy parsing from raw IFC bytes.
String attributes are decoded lossily when tokens become AttributeValues;
structural scanning and byte offsets always use the original source bytes.
Implementations§
Source§impl<'a> EntityDecoder<'a>
impl<'a> EntityDecoder<'a>
Sourcepub fn with_index<T>(content: &'a T, index: EntityIndex) -> Self
pub fn with_index<T>(content: &'a T, index: EntityIndex) -> Self
Create decoder with pre-built index (faster for repeated lookups)
Sourcepub fn with_arc_index<T>(content: &'a T, index: Arc<EntityIndex>) -> Self
pub fn with_arc_index<T>(content: &'a T, index: Arc<EntityIndex>) -> Self
Create decoder with shared Arc index (for parallel processing)
Sourcepub fn decode_at(&mut self, start: usize, end: usize) -> Result<DecodedEntity>
pub fn decode_at(&mut self, start: usize, end: usize) -> Result<DecodedEntity>
Decode entity at byte offset Returns cached entity if already decoded
Validates the (start, end) span against self.content.len() before
slicing. Out-of-range or inverted spans return Error::parse instead
of panicking — callers (e.g. decode_and_cache, decode_at_with_id,
the streaming pre-pass shard mergers) hand us spans derived from
untrusted/streamed entity-index data, and a malformed span must not
take down the whole worker.
Sourcepub fn decode_at_with_id(
&mut self,
id: u32,
start: usize,
end: usize,
) -> Result<DecodedEntity>
pub fn decode_at_with_id( &mut self, id: u32, start: usize, end: usize, ) -> Result<DecodedEntity>
Decode entity at byte offset with known ID (faster - checks cache before parsing) Use this when the scanner provides the entity ID to avoid re-parsing cached entities
Sourcepub fn decode_by_id(&mut self, entity_id: u32) -> Result<DecodedEntity>
pub fn decode_by_id(&mut self, entity_id: u32) -> Result<DecodedEntity>
Decode entity by ID - O(1) lookup using entity index
Sourcepub fn plane_angle_to_radians(&mut self) -> f64
pub fn plane_angle_to_radians(&mut self) -> f64
Multiplier that converts file plane-angle units to radians.
Lazy-resolved on first call by scanning for IFCPROJECT and reading
its IFCUNITASSIGNMENT. Cached for subsequent calls. Returns 1.0
when no plane-angle unit is declared (IFC spec default = RADIAN).
Use this at curve-sampling time wherever an IfcParameterValue is
interpreted as an angle (IfcCircle / IfcEllipse trim parameters).
Without it, value.to_radians() is correct only for DEGREE files
and silently shrinks arcs on RADIAN files (issue #820).
Sourcepub fn length_unit_scale(&mut self) -> f64
pub fn length_unit_scale(&mut self) -> f64
Multiplier that converts file length units to metres (1.0 for metre
files, 0.001 for millimetre files, …). Lazy-resolved on first call by
scanning for IFCPROJECT and reading its IFCUNITASSIGNMENT, then cached.
Returns 1.0 when no length unit is declared.
Use this to express an absolute metric tolerance in file units — e.g. a curve-tessellation chord-deviation budget that stays constant in millimetres whether the file is authored in mm or m.
Sourcepub fn seed_unit_scales(
&mut self,
length_unit_scale: f64,
plane_angle_to_radians: f64,
)
pub fn seed_unit_scales( &mut self, length_unit_scale: f64, plane_angle_to_radians: f64, )
Pre-seed the unit-scale caches so Self::length_unit_scale and
Self::plane_angle_to_radians return immediately without the full-file
IFCPROJECT scan.
Both lazy resolvers walk the whole DATA section to locate the (singleton)
IFCPROJECT. That scan is O(file size) and IFCPROJECT legally sits
anywhere — IfcOpenShell emits it near the end, so on a large model the
scan touches tens of MB. The cache is per-decoder, and the parallel
geometry pipeline builds a fresh decoder per element, so without seeding
every arc-bearing element re-pays the scan (≈135 ms each on a 75 MB
file). The orchestrator resolves both scales once on a warm shared
decoder and seeds each worker decoder here.
Sourcepub fn resolve_ref(
&mut self,
attr: &AttributeValue,
) -> Result<Option<DecodedEntity>>
pub fn resolve_ref( &mut self, attr: &AttributeValue, ) -> Result<Option<DecodedEntity>>
Resolve entity reference (follow #ID) Returns None for null/derived values
Sourcepub fn resolve_ref_list(
&mut self,
attr: &AttributeValue,
) -> Result<Vec<DecodedEntity>>
pub fn resolve_ref_list( &mut self, attr: &AttributeValue, ) -> Result<Vec<DecodedEntity>>
Resolve list of entity references
Sourcepub fn get_cached(&self, entity_id: u32) -> Option<DecodedEntity>
pub fn get_cached(&self, entity_id: u32) -> Option<DecodedEntity>
Get cached entity (without decoding)
Sourcepub fn reserve_cache(&mut self, additional: usize)
pub fn reserve_cache(&mut self, additional: usize)
Reserve cache capacity to avoid HashMap resizing during processing. For a 487 MB file with 208 K building elements, the cache can grow to 300 K+ entries (elements + representation chains + placements). Pre-allocating avoids ~6 resize-and-rehash operations that each copy all entries, reducing both peak memory spikes and timing variance.
Inject a pre-warmed Arc-shared cache into this decoder’s local cache.
Used by the de-normalized parallel path: a serial pre-pass builds a
shared Arc<FxHashMap<u32, Arc<DecodedEntity>>> containing all
entities reachable from the jobs. Each rayon task then injects
that shared cache into its own decoder via this method, so the
per-task hot path hits in-WASM-heap Arc handles instead of
SAB-imported atomic memory.
Cost: one Arc::clone per cached entry (atomic refcount bump). For a typical 100K-entry cache × 9 rayon tasks = 900K atomics total, ~90 ms wall (incurred ONCE at task setup; the parallel hot path then runs lock-free against the populated cache).
Sourcepub fn decode_and_cache(
&mut self,
id: u32,
start: usize,
end: usize,
) -> Result<Arc<DecodedEntity>>
pub fn decode_and_cache( &mut self, id: u32, start: usize, end: usize, ) -> Result<Arc<DecodedEntity>>
Decode + cache without returning. Used by the pre-warm pass to populate a shared cache. Returns the cached Arc so the caller can chase references without re-decoding.
Sourcepub fn drain_cache(&mut self) -> FxHashMap<u32, Arc<DecodedEntity>>
pub fn drain_cache(&mut self) -> FxHashMap<u32, Arc<DecodedEntity>>
Drain the populated cache out of this decoder for sharing across rayon tasks. After calling this, the decoder is empty (cache moved out); callers typically then drop the decoder.
Sourcepub fn clear_cache(&mut self)
pub fn clear_cache(&mut self)
Clear all caches to free memory
Sourcepub fn clear_point_cache(&mut self)
pub fn clear_point_cache(&mut self)
Clear only the point coordinate cache (used after BREP preprocessing). The entity cache is preserved for subsequent geometry processing.
Sourcepub fn cache_size(&self) -> usize
pub fn cache_size(&self) -> usize
Get cache size
Sourcepub fn get_raw_bytes(&mut self, entity_id: u32) -> Option<&'a [u8]>
pub fn get_raw_bytes(&mut self, entity_id: u32) -> Option<&'a [u8]>
Get raw bytes for an entity (for direct/fast parsing) Returns the full entity line including type and attributes
Sourcepub fn get_first_entity_ref_fast(&mut self, entity_id: u32) -> Option<u32>
pub fn get_first_entity_ref_fast(&mut self, entity_id: u32) -> Option<u32>
Fast extraction of first entity ref from raw bytes Useful for BREP -> shell ID, Face -> FaceBound, etc. Returns the first entity reference ID found in the entity
Sourcepub fn get_entity_ref_list_fast(&mut self, entity_id: u32) -> Option<Vec<u32>>
pub fn get_entity_ref_list_fast(&mut self, entity_id: u32) -> Option<Vec<u32>>
Fast extraction of entity reference IDs from a list attribute in raw bytes Useful for getting face list from ClosedShell, bounds from Face, etc. Returns list of entity IDs
Sourcepub fn get_polyloop_point_ids_fast(
&mut self,
entity_id: u32,
) -> Option<Vec<u32>>
pub fn get_polyloop_point_ids_fast( &mut self, entity_id: u32, ) -> Option<Vec<u32>>
Fast extraction of PolyLoop point IDs directly from raw bytes Bypasses full entity decoding for BREP optimization Returns list of entity IDs for CartesianPoints
Sourcepub fn get_cartesian_point_fast(
&mut self,
entity_id: u32,
) -> Option<(f64, f64, f64)>
pub fn get_cartesian_point_fast( &mut self, entity_id: u32, ) -> Option<(f64, f64, f64)>
Fast extraction of CartesianPoint coordinates directly from raw bytes Bypasses full entity decoding for ~3x speedup on BREP-heavy files Returns (x, y, z) as f64 tuple
Sourcepub fn get_face_bound_fast(
&mut self,
entity_id: u32,
) -> Option<(u32, bool, bool)>
pub fn get_face_bound_fast( &mut self, entity_id: u32, ) -> Option<(u32, bool, bool)>
Fast extraction of FaceBound info directly from raw bytes Returns (loop_id, orientation, is_outer_bound) Bypasses full entity decoding for BREP optimization
Sourcepub fn get_polyloop_coords_fast(
&mut self,
entity_id: u32,
) -> Option<Vec<(f64, f64, f64)>>
pub fn get_polyloop_coords_fast( &mut self, entity_id: u32, ) -> Option<Vec<(f64, f64, f64)>>
Fast extraction of PolyLoop COORDINATES directly from raw bytes This is the ultimate fast path - extracts all coordinates in one go Avoids N+1 HashMap lookups by batching point extraction Returns Vec of (x, y, z) coordinate tuples