Skip to main content

ifc_classification/
error.rs

1//! Typed failures while interpreting or authoring IFC external references.
2
3use ifc_model::EntityId;
4use ifc_schema::SchemaVersion;
5use thiserror::Error;
6
7/// Failure decoding, cross-checking, or authoring classification/document/library records.
8#[derive(Debug, Clone, PartialEq, Error)]
9#[non_exhaustive]
10pub enum ClassificationError {
11    /// Entity did not have the expected IFC type.
12    #[error("expected {expected}, found {actual}")]
13    WrongEntityType {
14        /// IFC type name expected at this position.
15        expected: &'static str,
16        /// IFC type name actually found.
17        actual: String,
18    },
19    /// A required attribute was unset (`$` or `*`) or absent.
20    #[error("{entity} {id} is missing required attribute {attribute}")]
21    MissingAttribute {
22        /// IFC entity type of the offending instance.
23        entity: &'static str,
24        /// Id of the offending instance.
25        id: EntityId,
26        /// Name of the missing attribute.
27        attribute: &'static str,
28    },
29    /// An attribute was present but failed to decode as its expected shape.
30    #[error("{entity} {id} has invalid {attribute}: {value}")]
31    InvalidValue {
32        /// IFC entity type of the offending instance.
33        entity: &'static str,
34        /// Id of the offending instance.
35        id: EntityId,
36        /// Name of the invalid attribute.
37        attribute: &'static str,
38        /// Debug rendering of the offending value.
39        value: String,
40    },
41    /// A referenced entity id does not exist in the model.
42    #[error("entity {id} does not exist")]
43    UnknownEntity {
44        /// Id that could not be resolved.
45        id: EntityId,
46    },
47    /// An attribute reference points at an id that is not present in the model.
48    #[error("{entity} {id}.{attribute} reference {target} does not resolve")]
49    DanglingReference {
50        /// IFC entity type holding the dangling reference.
51        entity: &'static str,
52        /// Id of the entity holding the dangling reference.
53        id: EntityId,
54        /// Name of the attribute holding the dangling reference.
55        attribute: &'static str,
56        /// Id that could not be resolved.
57        target: EntityId,
58    },
59    /// An attribute reference resolves but the target entity has the wrong type for its select.
60    #[error("{entity} {id}.{attribute} reference {target} has type {actual}, expected {expected}")]
61    ReferenceType {
62        /// IFC entity type holding the mistyped reference.
63        entity: &'static str,
64        /// Id of the entity holding the mistyped reference.
65        id: EntityId,
66        /// Name of the attribute holding the mistyped reference.
67        attribute: &'static str,
68        /// Id of the mistyped target.
69        target: EntityId,
70        /// Select or type name the target was expected to satisfy.
71        expected: &'static str,
72        /// IFC type name the target actually has.
73        actual: String,
74    },
75    /// Following `ReferencedSource` links revisited an already-seen entity.
76    #[error("classification hierarchy contains a cycle: {path:?}")]
77    Cycle {
78        /// Entity ids on the cycle, in traversal order.
79        path: Vec<EntityId>,
80    },
81    /// Hierarchy traversal exceeded the caller-supplied node or depth budget.
82    #[error("classification hierarchy exceeded max_depth={max_depth} or max_nodes={max_nodes}")]
83    BudgetExceeded {
84        /// Maximum edge depth allowed.
85        max_depth: usize,
86        /// Maximum number of nodes allowed.
87        max_nodes: usize,
88    },
89    /// An occurrence object is related to more than one `IfcRelDefinesByType` type.
90    #[error("object {object} has {count} assigned IFC types")]
91    AmbiguousType {
92        /// The occurrence object with the ambiguous type assignment.
93        object: EntityId,
94        /// Number of types the object was found related to.
95        count: usize,
96    },
97    /// A draft value failed schema validation before staging.
98    #[error("cannot author {entity}.{attribute}: {value}")]
99    AuthoringInvalid {
100        /// IFC entity type being authored.
101        entity: &'static str,
102        /// Name of the offending attribute.
103        attribute: &'static str,
104        /// Description of why the value is invalid.
105        value: String,
106    },
107    /// A draft reference resolves to a staged or committed entity of the wrong type.
108    #[error("authoring reference {target} has type {actual}, expected {expected}")]
109    AuthoringReferenceType {
110        /// Id of the mistyped reference target.
111        target: EntityId,
112        /// Select or type name the target was expected to satisfy.
113        expected: &'static str,
114        /// IFC type name the target actually has.
115        actual: String,
116    },
117    /// The header declares several schemas, so no single release can be
118    /// bound to read or write the model against.
119    #[error("the header declares {schemas} schemas; classification reads bind to exactly one")]
120    MultipleSchemas {
121        /// Number of `FILE_SCHEMA` declarations.
122        schemas: usize,
123    },
124    /// The release the model is read against does not define this attribute
125    /// or record, for example `Description` on an IFC2X3 `IfcClassification`
126    /// or any `IfcExternalReferenceRelationship` in an IFC2X3 model. This is
127    /// never reported as an unset (`None`) value.
128    #[error("{entity} {id}.{attribute} is not defined by {schema:?}")]
129    NotInSchema {
130        /// IFC entity type of the instance.
131        entity: &'static str,
132        /// Id of the instance.
133        id: EntityId,
134        /// Attribute name, as this crate's accessor names it.
135        attribute: &'static str,
136        /// The release the model is read against.
137        schema: SchemaVersion,
138    },
139    /// A text accessor met an attribute the bound release types as an entity
140    /// record, such as an IFC2X3 `IfcCalendarDate` edition date. The value is
141    /// valid; read it structurally through `target`.
142    #[error("{entity} {id}.{attribute} is the record {target}, not text")]
143    StructuredValue {
144        /// IFC entity type of the instance.
145        entity: &'static str,
146        /// Id of the instance.
147        id: EntityId,
148        /// Attribute name.
149        attribute: &'static str,
150        /// The entity record holding the value.
151        target: EntityId,
152    },
153    /// The header declares one schema this crate has no bundled table for,
154    /// so no slot position can be trusted. Never read as IFC4.
155    #[error("the header declares {schema}, which has no bundled schema table")]
156    UnsupportedSchema {
157        /// The `FILE_SCHEMA` token as written.
158        schema: String,
159    },
160    /// An authoring call would write a record type the model's release
161    /// cannot instantiate, such as an `IfcExternalReferenceRelationship`
162    /// into an IFC2X3 model.
163    #[error("cannot author {entity}: not an instantiable entity of {schema:?}")]
164    EntityNotInSchema {
165        /// The IFC entity type name.
166        entity: &'static str,
167        /// The release the model is bound to.
168        schema: SchemaVersion,
169    },
170    /// An authoring call supplied a value for an attribute the model's
171    /// release does not declare, such as a `Description` for an IFC2X3
172    /// `IfcClassification`. The value is refused, never silently dropped.
173    #[error("cannot author {entity}.{attribute}: not defined by {schema:?}")]
174    AuthoringNotInSchema {
175        /// The IFC entity type name being authored.
176        entity: &'static str,
177        /// The attribute, as this crate names it (IFC4).
178        attribute: &'static str,
179        /// The release the model is bound to.
180        schema: SchemaVersion,
181    },
182    /// The model's release requires an attribute the authoring call leaves
183    /// unset, such as the IFC2X3 `IfcRoot.OwnerHistory` or the IFC2X3
184    /// `IfcClassification.Source`.
185    #[error("cannot author {entity}: {schema:?} requires {attribute}")]
186    AuthoringRequired {
187        /// The IFC entity type name being authored.
188        entity: &'static str,
189        /// The required attribute, as the release names it.
190        attribute: &'static str,
191        /// The release the model is bound to.
192        schema: SchemaVersion,
193    },
194    /// An authoring call supplied text for an attribute the model's release
195    /// types as an entity record, such as an IFC2X3 `IfcCalendarDate`
196    /// `EditionDate`. The text is refused rather than written into a slot
197    /// that cannot hold it.
198    #[error("cannot author {entity}.{attribute} as text: {schema:?} declares {declared}")]
199    AuthoringValueType {
200        /// The IFC entity type name being authored.
201        entity: &'static str,
202        /// The attribute, as this crate names it (IFC4).
203        attribute: &'static str,
204        /// The type the release declares for the attribute.
205        declared: &'static str,
206        /// The release the model is bound to.
207        schema: SchemaVersion,
208    },
209}
210
211/// Result of a classification/document/library query or authoring operation.
212pub type ClassificationResult<T> = Result<T, ClassificationError>;