1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
//! Structured alignment interpretation failures.
use ifc_model::EntityId;
/// Why an IFC alignment entity could not be read or lowered.
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq)]
pub enum AlignmentError {
/// A referenced entity id is not present in the model.
MissingEntity {
/// The id that resolved to nothing.
entity: EntityId,
},
/// An entity was not the IFC type the referencing slot requires.
WrongType {
/// The entity that was read.
entity: EntityId,
/// The IFC type the slot requires.
expected: &'static str,
/// The IFC type actually declared.
actual: String,
},
/// A mandatory attribute was absent, so the value cannot be inferred.
MissingAttribute {
/// The entity that was read.
entity: EntityId,
/// Zero-based slot index of the absent attribute.
index: usize,
/// Schema name of the attribute.
name: &'static str,
},
/// An attribute was present but held the wrong kind of value.
InvalidAttribute {
/// The entity that was read.
entity: EntityId,
/// Zero-based slot index of the offending attribute.
index: usize,
/// Schema name of the attribute.
name: &'static str,
},
/// The project's unit assignment does not resolve to usable lengths or angles.
InvalidUnits {
/// What expectation failed.
detail: &'static str,
},
/// A horizontal, vertical, or cant segment carries internally inconsistent data.
InvalidSegment {
/// The segment entity.
entity: EntityId,
/// What expectation failed.
detail: &'static str,
},
/// A segment type or configuration this crate deliberately does not lower.
///
/// Covers segment kinds that are legal IFC but require data this crate does
/// not yet combine (e.g. `VIENNESEBEND` needs the cant swing carried by a
/// separate `IfcAlignmentCant` layout) or that have no closed-form neutral
/// curve here (e.g. `CUBIC`).
Unsupported {
/// The unsupported entity.
entity: EntityId,
/// The IFC type or `PredefinedType` name actually declared.
type_name: String,
/// Why it is refused rather than approximated.
detail: &'static str,
},
/// The assembled neutral alignment graph violates a structural invariant.
Graph {
/// What expectation failed.
detail: String,
},
/// The model header declares no `FILE_SCHEMA` token.
MissingSchema,
/// More than one `FILE_SCHEMA` token was declared.
AmbiguousSchema {
/// Every schema token found in the header.
tokens: Vec<String>,
},
/// The declared schema is not one this crate can interpret.
///
/// Alignment entities (`IfcAlignment*`) were introduced in IFC4X3; IFC2X3
/// and IFC4 ADD2 TC1 do not declare them at all, so there is no version
/// dispatch here the way `ifc-resource`/`ifc-structural` have one --
/// exactly one profile is authoritative and anything else is refused.
UnsupportedSchema {
/// The rejected schema token.
token: String,
},
/// A relationship or nesting structure violates a stated invariant.
SemanticViolation {
/// The offending entity, when one could be identified.
entity: Option<EntityId>,
/// The invariant that was violated.
rule: &'static str,
},
/// An authored value was rejected before anything was staged (ADR 0011).
///
/// Distinct from [`Self::InvalidSegment`], which describes a segment that
/// already exists in a file. Here there is no entity yet and therefore no
/// id to report: the caller passed a value that could not be written.
InvalidAuthoredValue {
/// The IFC type being authored.
type_name: &'static str,
/// The attribute whose value was rejected.
attribute: &'static str,
/// Why it cannot be written.
detail: String,
},
/// A dangling reference: the target id is not present in the model.
DanglingReference {
/// The entity holding the dangling reference.
entity: EntityId,
/// The attribute that names the missing target.
attribute: &'static str,
/// The id that resolved to nothing.
target: EntityId,
},
/// Graph traversal exceeded an explicit depth or node-count bound.
BudgetExceeded {
/// The configured maximum traversal depth.
max_depth: usize,
/// The configured maximum node count.
max_nodes: usize,
},
}
/// Result of an alignment read, carrying [`AlignmentError`] on failure.
pub type AlignmentResult<T> = Result<T, AlignmentError>;
impl std::fmt::Display for AlignmentError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::MissingEntity { entity } => write!(f, "missing alignment entity {entity}"),
Self::WrongType {
entity,
expected,
actual,
} => write!(f, "{entity} is {actual}; expected {expected}"),
Self::MissingAttribute {
entity,
index,
name,
} => write!(f, "{entity} misses {name} at slot {index}"),
Self::InvalidAttribute {
entity,
index,
name,
} => write!(f, "{entity} has invalid {name} at slot {index}"),
Self::InvalidUnits { detail } => write!(f, "invalid alignment units: {detail}"),
Self::InvalidSegment { entity, detail } => {
write!(f, "invalid alignment segment {entity}: {detail}")
}
Self::Unsupported {
entity,
type_name,
detail,
} => write!(f, "unsupported {type_name} at {entity}: {detail}"),
Self::Graph { detail } => write!(f, "invalid neutral alignment graph: {detail}"),
Self::MissingSchema => write!(f, "no FILE_SCHEMA token was declared"),
Self::AmbiguousSchema { tokens } => {
write!(f, "ambiguous FILE_SCHEMA tokens: {tokens:?}")
}
Self::UnsupportedSchema { token } => write!(
f,
"unsupported schema {token}: alignment entities require IFC4X3 ADD2"
),
Self::SemanticViolation { entity, rule } => match entity {
Some(entity) => write!(f, "{entity} violates {rule}"),
None => write!(f, "violates {rule}"),
},
Self::InvalidAuthoredValue {
type_name,
attribute,
detail,
} => write!(f, "cannot author {type_name}.{attribute}: {detail}"),
Self::DanglingReference {
entity,
attribute,
target,
} => write!(f, "{entity}.{attribute} references missing {target}"),
Self::BudgetExceeded {
max_depth,
max_nodes,
} => write!(
f,
"traversal exceeded bounds (max_depth={max_depth}, max_nodes={max_nodes})"
),
}
}
}
impl std::error::Error for AlignmentError {}