ifc_resource/query/
allocation.rs1use ifc_model::EntityId;
4
5use crate::error::{ResourceError, ResourceResult};
6use crate::view::{validate_object_assignment, Record, ResourceView};
7
8#[derive(Debug, Clone, PartialEq, Eq)]
9pub struct ResourceAllocation {
12 relation: EntityId,
13 resource: EntityId,
14 related_objects: Vec<EntityId>,
15 related_objects_type: Option<String>,
16}
17
18impl ResourceAllocation {
19 #[must_use]
21 pub fn relation_id(&self) -> EntityId {
22 self.relation
23 }
24
25 #[must_use]
28 pub fn resource_id(&self) -> EntityId {
29 self.resource
30 }
31
32 #[must_use]
34 pub fn related_objects(&self) -> &[EntityId] {
35 &self.related_objects
36 }
37
38 #[must_use]
40 pub fn related_objects_type(&self) -> Option<&str> {
41 self.related_objects_type.as_deref()
42 }
43}
44
45impl<'m, 's> ResourceView<'m, 's> {
46 pub fn allocation(&self, id: EntityId) -> ResourceResult<ResourceAllocation> {
48 let record = self.record(id, "IfcRelAssignsToResource")?;
49 decode_allocation(record)
50 }
51
52 pub fn allocations_for(&self, resource: EntityId) -> ResourceResult<Vec<ResourceAllocation>> {
55 self.resource(resource)?;
56 let mut result = Vec::new();
57 for relation in self.ids_of_ancestor("IfcRelAssignsToResource") {
58 let allocation = self.allocation(relation)?;
59 if allocation.resource == resource {
60 result.push(allocation);
61 }
62 }
63 Ok(result)
64 }
65}
66
67fn decode_allocation(record: Record<'_, '_>) -> ResourceResult<ResourceAllocation> {
68 let resource = record.required_ref_select(
69 "RelatingResource",
70 "IfcResourceSelect",
71 &["IfcResource", "IfcTypeResource"],
72 )?;
73 let related_objects = record.refs("RelatedObjects", "IfcObjectDefinition", 1, false, true)?;
74 let related_objects_type = record.optional_enum("RelatedObjectsType")?;
75 validate_object_assignment(
76 record.model,
77 record.schema,
78 Some(record.id),
79 related_objects_type,
80 &related_objects,
81 )?;
82 if related_objects.contains(&resource) {
83 return Err(ResourceError::SemanticViolation {
84 entity: Some(record.id),
85 rule: "IfcRelAssignsToResource must not assign its resource to itself",
86 });
87 }
88 Ok(ResourceAllocation {
89 relation: record.id,
90 resource,
91 related_objects,
92 related_objects_type: related_objects_type.map(str::to_owned),
93 })
94}