Skip to main content

EntityDecoder

Struct EntityDecoder 

Source
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>

Source

pub fn new<T>(content: &'a T) -> Self
where T: AsRef<[u8]> + ?Sized,

Create new decoder

Source

pub fn with_index<T>(content: &'a T, index: EntityIndex) -> Self
where T: AsRef<[u8]> + ?Sized,

Create decoder with pre-built index (faster for repeated lookups)

Source

pub fn with_arc_index<T>(content: &'a T, index: Arc<EntityIndex>) -> Self
where T: AsRef<[u8]> + ?Sized,

Create decoder with shared Arc index (for parallel processing)

Source

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.

Source

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

Source

pub fn decode_by_id(&mut self, entity_id: u32) -> Result<DecodedEntity>

Decode entity by ID - O(1) lookup using entity index

Source

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).

Source

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.

Source

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.

Source

pub fn resolve_ref( &mut self, attr: &AttributeValue, ) -> Result<Option<DecodedEntity>>

Resolve entity reference (follow #ID) Returns None for null/derived values

Source

pub fn resolve_ref_list( &mut self, attr: &AttributeValue, ) -> Result<Vec<DecodedEntity>>

Resolve list of entity references

Source

pub fn get_cached(&self, entity_id: u32) -> Option<DecodedEntity>

Get cached entity (without decoding)

Source

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.

Source

pub fn inject_shared_cache( &mut self, shared: &FxHashMap<u32, Arc<DecodedEntity>>, )

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).

Source

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.

Source

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.

Source

pub fn clear_cache(&mut self)

Clear all caches to free memory

Source

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.

Source

pub fn cache_size(&self) -> usize

Get cache size

Source

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

Source

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

Source

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

Source

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

Source

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

Source

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

Source

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

Source

pub fn get_polyloop_coords_cached( &mut self, entity_id: u32, ) -> Option<Vec<(f64, f64, f64)>>

Fast extraction of PolyLoop COORDINATES with point caching Uses a cache to avoid re-parsing the same cartesian points For files with many faces sharing points, this can be 2-3x faster

Auto Trait Implementations§

§

impl<'a> Freeze for EntityDecoder<'a>

§

impl<'a> RefUnwindSafe for EntityDecoder<'a>

§

impl<'a> Send for EntityDecoder<'a>

§

impl<'a> Sync for EntityDecoder<'a>

§

impl<'a> Unpin for EntityDecoder<'a>

§

impl<'a> UnsafeUnpin for EntityDecoder<'a>

§

impl<'a> UnwindSafe for EntityDecoder<'a>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.