mod assignment;
mod complex;
mod composite;
mod enumerate;
mod material;
mod measure;
mod predefined;
mod quantity;
mod refs;
mod release;
mod set;
mod unit;
mod value;
mod values;
use std::{fmt, sync::Arc};
use ifc_model::{EntityId, Model};
use ifc_schema::SchemaVersion;
use assignment::assigned_sets;
pub use enumerate::{
exact_properties, exact_properties_where, exact_property_sets_where, ExactPropertyEntry,
ExactPropertySetEntry,
};
pub use material::{
exact_material_properties_where, exact_material_property, exact_material_property_sets_where,
};
pub use predefined::{exact_predefined_sets, ExactPredefinedSet};
use release::validate_model;
use set::find_property;
pub use unit::{exact_unit, ExactUnit, ExactUnitError};
pub use values::{
ExactBoundedValue, ExactComplexMember, ExactComplexValue, ExactEntityRef, ExactEnumeratedValue,
ExactEnumeration, ExactReferenceValue, ExactTableRow, ExactTableValue, ExactTypedValue,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum ExactSource {
Occurrence,
Type(EntityId),
Material(EntityId),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ExactLogical {
False,
Unknown,
True,
}
#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
pub enum ExactValue {
Null,
Bool(bool),
Logical(ExactLogical),
Binary(Arc<str>),
Integer(i64),
Real(f64),
Text(Arc<str>),
Enumerated(ExactEnumeratedValue),
List(Vec<ExactTypedValue>),
Bounded(Box<ExactBoundedValue>),
Table(ExactTableValue),
Reference(ExactReferenceValue),
Enum(Arc<str>),
Entity(ExactEntityRef),
Complex(ExactComplexValue),
}
#[derive(Debug, Clone, PartialEq)]
pub struct ExactProperty {
pub source: ExactSource,
pub property_set: Arc<str>,
pub set_id: EntityId,
pub property_id: EntityId,
pub value_type: Option<Arc<str>>,
pub unit_id: Option<EntityId>,
pub value: ExactValue,
}
#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
pub enum ExactResolution {
Present(ExactProperty),
Absent,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum ExactPropertyError {
IncompleteModel {
diagnostics: usize,
},
MissingSchema,
MultipleSchemas {
schemas: usize,
},
UnsupportedSchema {
schema: String,
},
MissingReference {
from: EntityId,
to: EntityId,
},
MalformedAggregate {
entity: EntityId,
attribute: &'static str,
},
MultipleTypeAssignments {
object: EntityId,
first: EntityId,
second: EntityId,
},
InvalidOccurrenceTarget {
relationship: EntityId,
object: EntityId,
},
InvalidTypeTarget {
relationship: EntityId,
object: EntityId,
},
InvalidQueryObject {
object: EntityId,
type_name: Arc<str>,
},
DuplicateAggregateMember {
entity: EntityId,
attribute: &'static str,
member: EntityId,
},
DuplicateMatchingSets {
source: ExactSource,
first: EntityId,
second: EntityId,
},
DuplicateMatchingProperties {
set: EntityId,
first: EntityId,
second: EntityId,
},
MalformedName {
entity: EntityId,
attribute: &'static str,
},
UnsupportedDefinition {
entity: EntityId,
type_name: Arc<str>,
},
UnsupportedProperty {
entity: EntityId,
type_name: Arc<str>,
},
MissingValueSlot {
property: EntityId,
},
MalformedEntitySlots {
entity: EntityId,
type_name: Arc<str>,
expected: usize,
actual: usize,
},
UnsupportedUnit {
property: EntityId,
},
UnsupportedValue {
property: EntityId,
},
NonFiniteReal {
property: EntityId,
},
NotInSchema {
entity: EntityId,
name: Arc<str>,
schema: SchemaVersion,
},
InconsistentValues {
entity: EntityId,
rule: &'static str,
},
NotAPredefinedSet {
name: Arc<str>,
schema: SchemaVersion,
},
UnsupportedRelationship {
relationship: EntityId,
type_name: Arc<str>,
},
ComplexCycle {
complex: EntityId,
member: EntityId,
},
ComplexTooDeep {
complex: EntityId,
limit: usize,
},
ComplexBudgetExceeded {
complex: EntityId,
limit: usize,
},
}
impl fmt::Display for ExactPropertyError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "exact IFC property resolution failed: {self:?}")
}
}
pub fn exact_schema(model: &Model) -> Result<SchemaVersion, ExactPropertyError> {
validate_model(model).map(|release| release.version)
}
impl std::error::Error for ExactPropertyError {}
pub fn exact_property(
model: &Model,
object: EntityId,
set_name: Option<&str>,
property_name: &str,
) -> Result<ExactResolution, ExactPropertyError> {
let release = validate_model(model)?;
let assigned = assigned_sets(model, release, object)?;
let occurrence = find_property(
model,
release,
&assigned.occurrence_sets,
ExactSource::Occurrence,
set_name,
property_name,
)?;
let inherited = match &assigned.type_sets {
Some((type_id, sets)) => find_property(
model,
release,
sets,
ExactSource::Type(*type_id),
set_name,
property_name,
)?,
None => None,
};
Ok(occurrence
.or(inherited)
.map_or(ExactResolution::Absent, ExactResolution::Present))
}