EntityScanner

Struct EntityScanner 

Source
pub struct EntityScanner<'a> { /* private fields */ }
Expand description

Fast entity scanner over raw IFC bytes without full parsing. O(n) performance for finding entities by type Uses memchr for SIMD-accelerated byte searching

Implementations§

Source§

impl<'a> EntityScanner<'a>

Source

pub fn skipped_oversized_ids(&self) -> usize

How many records this scanner has skipped because their instance name does not fit u32 (issue #3395).

ISO 10303-21 puts no upper bound on #<digits>, but every express-id column in this workspace is u32 (ColumnarIndex::ids, MeshData::express_id, the wasm express_ids buffers), so a wider id cannot be represented — it used to wrap, making #4294967297 indistinguishable from #1. The record is dropped instead, and this counter is the other half of that guard: callers report it rather than letting the model come back quietly short.

Source

pub fn skipped_oversized_id_starts(&self) -> &[usize]

The line_start byte offset of every record this scanner refused, strictly increasing.

A whole-file scan only needs the count above. A SHARDED scan needs the offsets, and the difference is not cosmetic: shard i > 0 starts at an arbitrary byte, so it can begin inside a quoted value and parse a string literal such as '…#4294967297=IFCWALL(…' as a record — and refuse it. That refusal is an artefact of where the shard started, not a record the file declares, so a count alone would let a file with NOTHING oversized in it be reported as incomplete. The offset lets the stitch keep only the refusals inside the byte region it actually retained from that shard (issue #3395/#3430).

Source

pub fn malformed_record_start(&self) -> Option<usize>

The first record this scan dropped for having no terminator of its own, or None. See Self::malformed_record_starts.

Source

pub fn malformed_record_starts(&self) -> &[usize]

The line_start of EVERY record this scan dropped for having no terminator of its own, strictly increasing.

A REPORT, not a stop signal: a record merely missing its ; is dropped and the scan CONTINUES past the ) closing its parameter list (#4179). Ask position, not this, whether a scan finished.

A Vec for the reason skipped_oversized_id_starts is one, which recovery made load-bearing: a SHARDED scan can now hit a speculative drop inside a quoted value AND a real one after it, and keeping only the first made the stitch’s “inside my retained region” filter test the speculative offset and discard the real report with it.

Source§

impl<'a> EntityScanner<'a>

Source

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

Create a new scanner.

Positions past the STEP HEADER section when one is present so that a stray # inside a header string (e.g. a CATIA FILE_NAME like '…\X0\2#.ifc') can’t be mistaken for an entity start and corrupt quote-parity for the rest of the file (issue #654).

Source

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

Create a scanner positioned at a specific byte offset.

Used by the sharded-scan pre-pass: each shard scans the full file (so byte offsets returned are GLOBAL, not relative to the shard’s range) but starts walking at its assigned start offset. Callers are expected to rewind position to a known entity boundary (typically the byte after a ;\n terminator) before calling next_entity.

Does NOT auto-skip the HEADER section — that’s the caller’s responsibility, since shards expect the exact offset they were given.

Source

pub fn position(&self) -> usize

Current byte offset of the scanner (start of the next entity to scan).

Source

pub fn next_entity(&mut self) -> Option<(u32, &'a str, usize, usize)>

Next (entity_id, keyword, line_start, line_end). The keyword is the RAW slice as the file wrote it (IfcWall stays IfcWall); STEP keyword case is not significant, so compare it with super::keyword_eq, never ==.

Source

pub fn find_by_type(&mut self, target_type: &str) -> Vec<(u32, usize, usize)>

Find all entities of a specific type

Source

pub fn count_by_type(&mut self) -> FxHashMap<String, usize>

Count entities by type

Source

pub fn count(&mut self) -> usize

Count the entities remaining from the scanner’s current position, without allocating anything per entity.

Unlike count_by_type (which builds a per-keyword map) or build_entity_index (which retains a span per entity, ~20 B each), this walks the byte stream and increments a single counter: O(scan) time, O(1) memory. It is the cheap primitive for a downstream entity-count DoS guard on a file too large to index (issue #1517). Advances the scanner to the end of the data section.

Source

pub fn reset(&mut self)

Reset scanner to beginning (re-applies the HEADER skip).

Auto Trait Implementations§

§

impl<'a> Freeze for EntityScanner<'a>

§

impl<'a> RefUnwindSafe for EntityScanner<'a>

§

impl<'a> Send for EntityScanner<'a>

§

impl<'a> Sync for EntityScanner<'a>

§

impl<'a> Unpin for EntityScanner<'a>

§

impl<'a> UnwindSafe for EntityScanner<'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.