Skip to main content

ifc_material/
error.rs

1//! Typed failures while interpreting IFC material-resource entities.
2
3use ifc_model::EntityId;
4use ifc_schema::SchemaVersion;
5use thiserror::Error;
6
7/// A malformed, ambiguous, or unresolved material projection.
8#[derive(Debug, Clone, PartialEq, Error)]
9#[non_exhaustive]
10pub enum MaterialError {
11    /// A projection expected one entity type but the model holds another.
12    #[error("expected {expected}, found {actual}")]
13    WrongEntityType {
14        /// The IFC entity type name that was expected.
15        expected: &'static str,
16        /// The IFC entity type name actually found on the record.
17        actual: String,
18    },
19    /// A required attribute slot on the entity is absent (unset `$`).
20    #[error("{entity} {id} is missing required attribute {attribute}")]
21    MissingAttribute {
22        /// The IFC entity type name.
23        entity: &'static str,
24        /// The id of the entity missing the attribute.
25        id: EntityId,
26        /// The name of the missing attribute.
27        attribute: &'static str,
28    },
29    /// An attribute is present but its value violates a WHERE rule or type
30    /// constraint.
31    #[error("{entity} {id} has invalid {attribute}: {value}")]
32    InvalidValue {
33        /// The IFC entity type name.
34        entity: &'static str,
35        /// The id of the entity with the invalid attribute.
36        id: EntityId,
37        /// The name of the invalid attribute.
38        attribute: &'static str,
39        /// A rendering of the offending value.
40        value: String,
41    },
42    /// A value supplied to an authoring function cannot be written to the
43    /// named entity attribute.
44    #[error("cannot author {entity}.{attribute}: {value}")]
45    AuthoringInvalid {
46        /// The IFC entity type name being authored.
47        entity: &'static str,
48        /// The name of the attribute that rejected the value.
49        attribute: &'static str,
50        /// A rendering of the rejected value.
51        value: String,
52    },
53    /// An authoring-time reference points at an entity of the wrong type.
54    #[error("authoring reference {target} has type {actual}, expected {expected}")]
55    AuthoringReferenceType {
56        /// The id of the referenced entity.
57        target: EntityId,
58        /// The IFC entity type name that was expected.
59        expected: &'static str,
60        /// The IFC entity type name actually found at `target`.
61        actual: String,
62    },
63    /// A referenced entity id does not exist in the model.
64    #[error("entity {id} does not exist")]
65    UnknownEntity {
66        /// The id that could not be resolved.
67        id: EntityId,
68    },
69    /// A reference field points at an id absent from the model.
70    #[error("reference {target} from {source_id} does not resolve")]
71    DanglingReference {
72        /// The id of the entity holding the reference.
73        source_id: EntityId,
74        /// The unresolved target id.
75        target: EntityId,
76    },
77    /// A reference resolves to an entity, but of the wrong type.
78    #[error("reference {target} from {source_id} has type {actual}, expected {expected}")]
79    ReferenceType {
80        /// The id of the entity holding the reference.
81        source_id: EntityId,
82        /// The id of the referenced entity.
83        target: EntityId,
84        /// The IFC entity type name that was expected.
85        expected: &'static str,
86        /// The IFC entity type name actually found at `target`.
87        actual: String,
88    },
89    /// The object is directly related to more than one `IfcMaterial`
90    /// via `IfcRelAssociatesMaterial`, so the single active material cannot
91    /// be determined.
92    #[error("object {object} has {count} direct material assignments")]
93    AmbiguousAssignment {
94        /// The id of the object with conflicting assignments.
95        object: EntityId,
96        /// The number of direct material assignments found.
97        count: usize,
98    },
99    /// The object is typed by more than one `IfcTypeObject`, so its
100    /// inherited material cannot be determined unambiguously.
101    #[error("object {object} has {count} assigned IFC types")]
102    AmbiguousType {
103        /// The id of the object with conflicting type relationships.
104        object: EntityId,
105        /// The number of `IfcTypeObject` relationships found.
106        count: usize,
107    },
108    /// The header declares several schemas, so no single release can be
109    /// bound to read or write the model against.
110    #[error("the header declares {schemas} schemas; material reads bind to exactly one")]
111    MultipleSchemas {
112        /// Number of `FILE_SCHEMA` declarations.
113        schemas: usize,
114    },
115    /// The header declares one schema this crate has no bundled table for,
116    /// so no slot position can be trusted.
117    #[error("the header declares {schema}, which has no bundled schema table")]
118    UnsupportedSchema {
119        /// The `FILE_SCHEMA` token as written.
120        schema: String,
121    },
122    /// The release the model is read against does not declare this
123    /// attribute, for example `Category` on an IFC2X3 `IfcMaterial` or
124    /// `Name` on an IFC2X3 `IfcMaterialLayer`. This is never reported as an
125    /// unset (`None`) value, and no other slot is read in its place.
126    #[error("{entity} {id}.{attribute} is not defined by {schema:?}")]
127    NotInSchema {
128        /// IFC entity type of the instance.
129        entity: &'static str,
130        /// Id of the instance.
131        id: EntityId,
132        /// Attribute name, as this crate's accessor names it (IFC4).
133        attribute: &'static str,
134        /// The release the model is read against.
135        schema: SchemaVersion,
136    },
137    /// The release the model is bound to has no instantiable entity of this
138    /// type, for example an `IfcMaterialConstituentSet` or
139    /// `IfcMaterialProfileSet` in an IFC2X3 model, or the abstract IFC2X3
140    /// `IfcMaterialProperties`. Such a record is refused, not decoded with
141    /// another release's layout.
142    #[error("{entity} is not an instantiable entity of {schema:?}")]
143    EntityNotInSchema {
144        /// The IFC entity type name.
145        entity: &'static str,
146        /// The record, when one is being read; `None` when authoring.
147        id: Option<EntityId>,
148        /// The release the model is bound to.
149        schema: SchemaVersion,
150    },
151    /// An authoring call supplied a value for an attribute the model's
152    /// release does not declare, such as a layer `Name` for an IFC2X3
153    /// model. The value is refused rather than silently dropped.
154    #[error("cannot author {entity}.{attribute}: not defined by {schema:?}")]
155    AuthoringNotInSchema {
156        /// The IFC entity type name being authored.
157        entity: &'static str,
158        /// The attribute, as this crate names it (IFC4).
159        attribute: &'static str,
160        /// The release the model is bound to.
161        schema: SchemaVersion,
162    },
163    /// The model's release requires an attribute the authoring call leaves
164    /// unset, such as the IFC2X3 `IfcRoot.OwnerHistory`.
165    #[error("cannot author {entity}: {schema:?} requires {attribute}")]
166    AuthoringRequired {
167        /// The IFC entity type name being authored.
168        entity: &'static str,
169        /// The required attribute, as the release names it.
170        attribute: &'static str,
171        /// The release the model is bound to.
172        schema: SchemaVersion,
173    },
174}
175
176/// Convenience alias for results of material-projection operations.
177pub type MaterialResult<T> = Result<T, MaterialError>;