use ifc_model::{Entity, EntityId, Model};
use ifc_schema::{for_version, Schema, SchemaVersion};
use super::refs::require_exact_slots;
use super::ExactPropertyError;
use std::sync::Arc;
#[derive(Clone, Copy)]
pub(super) struct Release {
pub(super) version: SchemaVersion,
pub(super) schema: &'static Schema,
}
impl Release {
pub(super) fn require_exact_slots(
self,
entity_id: EntityId,
entity: &Entity,
) -> Result<(), ExactPropertyError> {
if self.schema.entity(entity.type_name.as_ref()).is_none() {
return Err(self.not_in_schema(entity_id, entity.type_name.clone()));
}
require_exact_slots(self.schema, entity_id, entity)
}
pub(super) fn not_in_schema(self, entity: EntityId, name: Arc<str>) -> ExactPropertyError {
ExactPropertyError::NotInSchema {
entity,
name,
schema: self.version,
}
}
pub(super) fn slot_accepts(self, entity: &str, slot: usize, candidate: &str) -> bool {
self.schema
.attributes(entity)
.get(slot)
.is_some_and(|attribute| self.schema.accepts_type(&attribute.type_name, candidate))
}
}
pub(super) fn validate_model(model: &Model) -> Result<Release, ExactPropertyError> {
if !model.diagnostics().is_empty() {
return Err(ExactPropertyError::IncompleteModel {
diagnostics: model.diagnostics().len(),
});
}
match model.header().schema.as_slice() {
[] => Err(ExactPropertyError::MissingSchema),
[token] => match SchemaVersion::from_header_token(token) {
Some(version @ (SchemaVersion::Ifc2x3 | SchemaVersion::Ifc4)) => Ok(Release {
version,
schema: for_version(version).expect("IFC2X3 and IFC4 are bundled"),
}),
_ => Err(ExactPropertyError::UnsupportedSchema {
schema: token.clone(),
}),
},
schemas => Err(ExactPropertyError::MultipleSchemas {
schemas: schemas.len(),
}),
}
}