pub struct Model { /* private fields */ }Expand description
A parsed IFC file: header, entities, and indices over them.
Implementations§
Source§impl Model
impl Model
Sourcepub fn with_source(source: Arc<dyn EntitySource>) -> Self
pub fn with_source(source: Arc<dyn EntitySource>) -> Self
An empty model whose entities a codec registers with
Model::insert_lazy and source decodes on first access.
Sourcepub fn header_mut(&mut self) -> &mut Header
pub fn header_mut(&mut self) -> &mut Header
Mutable access to the header, for writers and editors.
Sourcepub fn diagnostics(&self) -> &[Diagnostic]
pub fn diagnostics(&self) -> &[Diagnostic]
Non-fatal problems reported by the codec that read this model.
Empty for a clean file. A non-empty slice means the model is incomplete relative to its source: the codec recovered from damage and each entry says exactly what was dropped, so a consumer can surface “loaded, 1 record skipped” instead of pretending the read was lossless.
Sourcepub fn is_complete(&self) -> bool
pub fn is_complete(&self) -> bool
Whether the read that produced this model dropped anything.
Sourcepub fn push_diagnostic(&mut self, diagnostic: Diagnostic)
pub fn push_diagnostic(&mut self, diagnostic: Diagnostic)
Attaches a codec diagnostic. Called by codecs during a recovered read.
Sourcepub fn insert(&mut self, id: EntityId, entity: Entity)
pub fn insert(&mut self, id: EntityId, entity: Entity)
Insert an entity under a specific id, replacing any previous occupant.
Codecs use this to preserve file ids exactly.
Sourcepub fn insert_lazy(&mut self, id: EntityId, type_name: &str, span: Range<usize>)
pub fn insert_lazy(&mut self, id: EntityId, type_name: &str, span: Range<usize>)
Register the entity stored at span of this model’s source under
id, without decoding it; it is decoded on first access. Replaces
any previous occupant exactly as Model::insert does.
type_name must be the type the span decodes to, which lets
Model::ids_of_type answer without decoding. Only a codec that
validated the span may register it (see EntitySource).
§Panics
When the model has no source (Model::with_source).
Sourcepub fn reserve(&mut self, additional: usize)
pub fn reserve(&mut self, additional: usize)
Reserve room for additional more entities; a codec that knows the
record count up front avoids regrowing the storage while it loads.
Sourcepub fn push(&mut self, entity: Entity) -> EntityId
pub fn push(&mut self, entity: Entity) -> EntityId
Append an entity, allocating the next free id.
Sourcepub fn revision(&self) -> u64
pub fn revision(&self) -> u64
How many structural changes this model has seen.
Starts at zero and increases; the absolute value carries no meaning
beyond comparison. See Transaction.
Sourcepub fn next_id(&self) -> EntityId
pub fn next_id(&self) -> EntityId
The id Model::push would allocate next.
A transaction reserves ids from here so several creates in one batch cannot collide with each other or with existing entities.
Sourcepub fn get(&self, id: EntityId) -> Option<&Entity>
pub fn get(&self, id: EntityId) -> Option<&Entity>
Look up one entity, decoding it first if it was loaded lazily.
Sourcepub fn decoded_len(&self) -> usize
pub fn decoded_len(&self) -> usize
How many entities have been decoded. Equals Model::len for a
model built from decoded entities; for a lazily loaded one it counts
the entities accessed so far.
Sourcepub fn decode_all(&self, threads: usize)
pub fn decode_all(&self, threads: usize)
Decode every entity now, on up to threads threads.
A lazily loaded model decodes on first access, one entity at a time. A consumer about to touch most of the model – a writer, a full validation, a geometry pass – can decode everything up front in parallel instead. Idempotent, and a no-op on a decoded model.
Sourcepub fn iter(&self) -> impl Iterator<Item = (EntityId, &Entity)> + '_
pub fn iter(&self) -> impl Iterator<Item = (EntityId, &Entity)> + '_
Entities in original file order.
Sourcepub fn ids_of_type(&self, type_name: &str) -> &[EntityId]
pub fn ids_of_type(&self, type_name: &str) -> &[EntityId]
Ids of every entity with this exact type name, case-insensitive.
This is an exact-type query and does not include subtypes: asking
for IfcElement will not return walls. Subtype queries need the schema,
which this crate does not depend on. The facade’s
ifc::ids_of_type_including_subtypes (feature schema) joins the two.
Sourcepub fn of_type<'a>(
&'a self,
type_name: &str,
) -> impl Iterator<Item = (EntityId, &'a Entity)>
pub fn of_type<'a>( &'a self, type_name: &str, ) -> impl Iterator<Item = (EntityId, &'a Entity)>
Entities with this exact type name.
Sourcepub fn type_histogram(&self) -> Vec<(&str, usize)>
pub fn type_histogram(&self) -> Vec<(&str, usize)>
Every distinct type name present, with its instance count.
Useful as a cheap file summary and as the basis for a coverage report of what a given build can and cannot interpret.
Sourcepub fn dangling_references(&self) -> Vec<(EntityId, EntityId)>
pub fn dangling_references(&self) -> Vec<(EntityId, EntityId)>
Ids that are referenced by some entity but do not exist.
A dangling reference is the most common corruption in real files, and it is a structural question, so it belongs here rather than in a validation crate.
Source§impl Model
impl Model
Sourcepub fn set_attribute(
&mut self,
id: EntityId,
index: usize,
value: Value,
) -> Option<Value>
pub fn set_attribute( &mut self, id: EntityId, index: usize, value: Value, ) -> Option<Value>
Set one positional attribute on an existing entity.
Returns the value previously at that slot, or None if id does not
name an entity in this model. Growing past the entity’s current
attribute count pads with Value::Null, matching how STEP itself
treats a missing trailing optional attribute.
Does not touch type_name, so the by-type index stays correct without
needing to run the same reindex logic Model::insert does. Renaming
an entity’s type is a structural change, not an attribute edit: use
Model::retype.
use ifc_model::{Entity, EntityId, Model, Value};
let mut model = Model::new();
let id = model.push(Entity::new("IFCCARTESIANPOINT", vec![Value::List(vec![
Value::Real(0.0), Value::Real(0.0),
])]));
let previous = model.set_attribute(id, 0, Value::List(vec![
Value::Real(10.0), Value::Real(20.0),
]));
assert!(previous.is_some());
let coords = model.get(id).unwrap().attribute(0).unwrap().as_list().unwrap();
assert_eq!(coords[0].as_f64(), Some(10.0));Sourcepub fn set_attributes(
&mut self,
id: EntityId,
edits: impl IntoIterator<Item = (usize, Value)>,
) -> Option<Vec<Value>>
pub fn set_attributes( &mut self, id: EntityId, edits: impl IntoIterator<Item = (usize, Value)>, ) -> Option<Vec<Value>>
Apply several attribute edits to one entity as a single unit.
edits are applied in order; a later edit to the same slot wins. This
exists because a caller updating several attributes wants to do it in
one lookup rather than repeating Model::set_attribute’s entity
lookup per field — the practical difference for callers is that this
is one indexmap probe instead of N, not a transactional guarantee
(there is nothing to roll back: slot writes cannot themselves fail).
Returns the previous values in edits order, or None if id does
not name an entity.
Sourcepub fn retype(
&mut self,
id: EntityId,
type_name: impl Into<Arc<str>>,
) -> Option<Arc<str>>
pub fn retype( &mut self, id: EntityId, type_name: impl Into<Arc<str>>, ) -> Option<Arc<str>>
Change an entity’s type in place, keeping its id and attributes.
Reindexes by_type so ids_of_type reflects the new type immediately
– the operation Model::insert already performs when an id is
reused with a different type, exposed here without requiring the
caller to reconstruct the whole entity.
Returns the previous type name, or None if id does not name an
entity.
Sourcepub fn remove(&mut self, id: EntityId) -> Option<Entity>
pub fn remove(&mut self, id: EntityId) -> Option<Entity>
Remove an entity entirely.
Returns the removed entity, or None if id was not present. Leaves
every reference to id from other entities dangling – detect those
with Model::dangling_references after a batch of removals, the
same way a codec would detect them in a hand-edited file.