ifc_resource/resource/
base.rs1use ifc_model::EntityId;
4
5use crate::error::{ResourceError, ResourceResult};
6use crate::usage::ResourceTime;
7use crate::view::Record;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12#[non_exhaustive]
13pub enum ResourceKind {
14 Labor,
16 Equipment,
18 Crew,
20 Material,
22 Product,
24 Subcontract,
26}
27
28impl ResourceKind {
29 fn from_type(type_name: &str) -> Option<Self> {
30 if type_name.eq_ignore_ascii_case("IfcLaborResource") {
31 Some(Self::Labor)
32 } else if type_name.eq_ignore_ascii_case("IfcConstructionEquipmentResource") {
33 Some(Self::Equipment)
34 } else if type_name.eq_ignore_ascii_case("IfcCrewResource") {
35 Some(Self::Crew)
36 } else if type_name.eq_ignore_ascii_case("IfcConstructionMaterialResource") {
37 Some(Self::Material)
38 } else if type_name.eq_ignore_ascii_case("IfcConstructionProductResource") {
39 Some(Self::Product)
40 } else if type_name.eq_ignore_ascii_case("IfcSubContractResource") {
41 Some(Self::Subcontract)
42 } else {
43 None
44 }
45 }
46}
47
48#[derive(Debug, Clone, Copy)]
49pub struct ConstructionResource<'m, 's> {
51 record: Record<'m, 's>,
52 kind: ResourceKind,
53}
54
55impl<'m, 's> ConstructionResource<'m, 's> {
56 pub(crate) fn from_record(record: Record<'m, 's>) -> ResourceResult<Self> {
57 let kind = ResourceKind::from_type(&record.entity.type_name).ok_or_else(|| {
58 ResourceError::WrongType {
59 id: record.id,
60 expected: "concrete IfcConstructionResource occurrence",
61 actual: record.entity.type_name.to_string(),
62 }
63 })?;
64 Ok(Self { record, kind })
65 }
66
67 #[must_use]
69 pub fn id(&self) -> EntityId {
70 self.record.id
71 }
72
73 #[must_use]
75 pub fn kind(&self) -> ResourceKind {
76 self.kind
77 }
78
79 pub fn name(&self) -> ResourceResult<Option<&'m str>> {
81 self.record.optional_text("Name")
82 }
83
84 pub fn identification(&self) -> ResourceResult<Option<&'m str>> {
86 self.record.optional_text("Identification")
87 }
88
89 pub fn long_description(&self) -> ResourceResult<Option<&'m str>> {
91 self.record.optional_text("LongDescription")
92 }
93
94 pub fn predefined_type(&self) -> ResourceResult<Option<&'m str>> {
99 let value = self.record.optional_enum("PredefinedType")?;
100 self.record.require_object_type_if(
101 value.is_some_and(|value| value.eq_ignore_ascii_case("USERDEFINED")),
102 "USERDEFINED resource PredefinedType requires ObjectType",
103 )?;
104 Ok(value)
105 }
106
107 pub fn usage(&self) -> ResourceResult<Option<ResourceTime<'m, 's>>> {
109 self.record
110 .optional_ref("Usage", "IfcResourceTime")?
111 .map(|id| Record::new(self.record.model, self.record.schema, id, "IfcResourceTime"))
112 .transpose()
113 .map(|record| record.map(ResourceTime::from_record))
114 }
115
116 pub fn base_costs(&self) -> ResourceResult<Vec<EntityId>> {
118 self.record
119 .refs("BaseCosts", "IfcAppliedValue", 1, true, false)
120 }
121
122 pub fn base_quantity(&self) -> ResourceResult<Option<EntityId>> {
125 self.record
126 .optional_ref("BaseQuantity", "IfcPhysicalQuantity")
127 }
128}