Skip to main content

ifc_structural/model/
load_group.rs

1//! `IfcStructuralLoadGroup` projection.
2
3use ifc_model::EntityId;
4use ifc_schema::SchemaVersion;
5
6use crate::error::StructuralResult;
7use crate::view::Record;
8
9/// Borrowed projection of an `IfcStructuralLoadGroup`.
10#[derive(Debug, Clone, Copy)]
11pub struct LoadGroup<'m, 's> {
12    record: Record<'m, 's>,
13}
14
15impl<'m, 's> LoadGroup<'m, 's> {
16    pub(crate) fn from_record(record: Record<'m, 's>) -> Self {
17        Self { record }
18    }
19
20    #[must_use]
21    /// The `IfcStructuralLoadGroup` entity id.
22    pub fn id(&self) -> EntityId {
23        self.record.id
24    }
25
26    /// `Name`, inherited from `IfcRoot`. Legally absent.
27    pub fn name(&self) -> StructuralResult<Option<&'m str>> {
28        self.validate_semantics()?;
29        self.record.optional_text("Name")
30    }
31
32    /// `PredefinedType`, always mandatory.
33    pub fn predefined_type(&self) -> StructuralResult<&'m str> {
34        self.validate_semantics()?;
35        self.record.required_enum("PredefinedType")
36    }
37
38    /// `ActionType`, always mandatory.
39    pub fn action_type(&self) -> StructuralResult<&'m str> {
40        self.validate_semantics()?;
41        self.record.required_enum("ActionType")
42    }
43
44    /// `ActionSource`, always mandatory.
45    pub fn action_source(&self) -> StructuralResult<&'m str> {
46        self.validate_semantics()?;
47        self.record.required_enum("ActionSource")
48    }
49
50    /// `Coefficient`, a combination factor applied to this group's loads. Legally absent.
51    pub fn coefficient(&self) -> StructuralResult<Option<f64>> {
52        self.validate_semantics()?;
53        self.record.optional_number("Coefficient")
54    }
55
56    /// `Purpose`, a free-text description of the load group's role. Legally absent.
57    pub fn purpose(&self) -> StructuralResult<Option<&'m str>> {
58        self.validate_semantics()?;
59        self.record.optional_text("Purpose")
60    }
61
62    /// Validates the `USERDEFINED`-requires-`ObjectType` rule for IFC4/IFC4X3.
63    ///
64    /// Fails with [`crate::StructuralError::SemanticViolation`] if
65    /// `PredefinedType`, `ActionType`, or `ActionSource` is `USERDEFINED`
66    /// but `ObjectType` is unset. IFC2X3 declares no such constraint here.
67    fn validate_semantics(&self) -> StructuralResult<()> {
68        if self.record.schema.version() == Some(SchemaVersion::Ifc2x3) {
69            return Ok(());
70        }
71        let user_defined = ["PredefinedType", "ActionType", "ActionSource"]
72            .into_iter()
73            .try_fold(false, |found, attribute| {
74                self.record
75                    .required_enum(attribute)
76                    .map(|value| found || value.eq_ignore_ascii_case("USERDEFINED"))
77            })?;
78        self.record.require_object_type_if(
79            user_defined,
80            "USERDEFINED load group metadata requires ObjectType",
81        )
82    }
83}