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, one of them IFC2X3, so no single
118 /// release can be bound to read 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}
154
155/// Result of a classification/document/library query or authoring operation.
156pub type ClassificationResult<T> = Result<T, ClassificationError>;