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
//! EXPRESS `WHERE` rules: the schema's own correctness conditions.
//!
//! # Why these are worth implementing
//!
//! A file can parse and still describe impossible geometry: a 2D direction
//! on a 3D placement, a boolean between operands of different dimensionality,
//! an extrusion parallel to the plane it extrudes. The schema states these
//! conditions as `WHERE` rules, and they are the difference between "the
//! parser accepted it" and "a kernel can build it".
//!
//! Checking them **here** rather than in the kernel matters: the kernel would
//! discover the problem as a numerical failure deep in an algorithm, where the
//! diagnostic is a degenerate matrix rather than "RefDirection is parallel to
//! Axis in #4711".
//!
//! # Scope
//!
//! IFC4 declares 95 where-rules across 56 geometry entities, and all 95 are
//! implemented (`data/ifc4-where-rules.tsv`, asserted by
//! `tests/where_rule_inventory.rs`). A rule whose check cannot fail on a
//! parsed model would be kept as `inventoried`, with the reason beside the
//! code, rather than implemented as a check that always passes.
//!
//! Rules do not re-check what the parser and typed views already enforce
//! (declared types, attribute arity, SELECT membership); a rule states only
//! the schema's own `WHERE` condition. Numerical validation of a built shape
//! belongs to the kernel, not here.
//!
//! # Design
//!
//! A rule is a pure function from a resolved view to `Result<(), RuleViolation>`.
//! Rules never mutate, never allocate on the success path, and are grouped by
//! the entity they constrain. [`validate`] runs every rule that applies to an
//! entity, so a caller checks a whole model without knowing the rule list.
pub use ;
use ;
/// Run every implemented where-rule that applies to this entity.
///
/// Returns all violations rather than the first, because a consumer fixing a
/// file wants the whole list, and because one bad placement often implies
/// several related failures.
/// Validate every entity in a model.
///
/// Linear in model size and allocation-free unless a rule actually fails,
/// so it is cheap enough to run as an import-time check.