use crate::{AttributeValue, DecodedEntity, EntityId, IfcType};
use std::sync::Arc;
pub trait EntityResolver: Send + Sync {
fn get(&self, id: EntityId) -> Option<Arc<DecodedEntity>>;
fn resolve_ref(&self, attr: &AttributeValue) -> Option<Arc<DecodedEntity>> {
match attr {
AttributeValue::EntityRef(id) => self.get(*id),
_ => None,
}
}
fn resolve_ref_list(&self, attr: &AttributeValue) -> Vec<Arc<DecodedEntity>> {
match attr {
AttributeValue::List(items) => items
.iter()
.filter_map(|item| self.resolve_ref(item))
.collect(),
_ => Vec::new(),
}
}
fn entities_by_type(&self, ifc_type: &IfcType) -> Vec<Arc<DecodedEntity>>;
fn find_by_type_name(&self, type_name: &str) -> Vec<Arc<DecodedEntity>>;
fn count_by_type(&self, ifc_type: &IfcType) -> usize;
fn types_present(&self) -> Vec<IfcType> {
use std::collections::HashSet;
let mut seen: HashSet<String> = HashSet::new();
let mut out = Vec::new();
for id in self.all_ids() {
if let Some(e) = self.get(id) {
let key = format!("{:?}", e.ifc_type);
if seen.insert(key) {
out.push(e.ifc_type.clone());
}
}
}
out
}
fn all_ids(&self) -> Vec<EntityId>;
fn entity_count(&self) -> usize {
self.all_ids().len()
}
fn raw_bytes(&self, id: EntityId) -> Option<&[u8]>;
}
pub trait EntityResolverExt: EntityResolver {
fn get_by_u32(&self, id: u32) -> Option<Arc<DecodedEntity>> {
self.get(EntityId(id))
}
fn exists(&self, id: EntityId) -> bool {
self.get(id).is_some()
}
fn get_or_err(&self, id: EntityId) -> crate::Result<Arc<DecodedEntity>> {
self.get(id).ok_or(crate::ParseError::EntityNotFound(id))
}
fn resolve_ref_or_err(
&self,
entity_id: EntityId,
attr_index: usize,
attr: &AttributeValue,
) -> crate::Result<Arc<DecodedEntity>> {
self.resolve_ref(attr)
.ok_or(crate::ParseError::InvalidReference {
entity: entity_id,
attribute: attr_index,
})
}
}
impl<T: EntityResolver + ?Sized> EntityResolverExt for T {}