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
193
//! Which representations this build can turn into points, and how to add more.
//!
//! # Why a registry rather than a match
//!
//! Reading a representation used to be one `match` over five type names. That
//! works until somebody needs a sixth - and the somebody is not always in this
//! repository. An application with its own RESQML extension, a build that wants
//! IJK grids before this crate ships them, a version whose spelling nobody here
//! has seen: each of those is a reader to add, and none of them should require
//! editing the function every other reader goes through.
//!
//! So it is the same arrangement as `ArrayBackend` in the storage layer:
//! a trait, a registry, the built-ins pushed in by default, and anything the
//! caller adds tried **first**.
//!
//! ```no_run
//! # use energyml_geometry::readers::{Readers, RepresentationReader};
//! # fn example(mine: Box<dyn RepresentationReader>) {
//! let mut readers = Readers::builtin();
//! readers.push(mine); // tried before the built-ins
//! # }
//! ```
//!
//! # What "another version" costs
//!
//! Nothing, in the ordinary case - and that is by design rather than by luck.
//! Readers are keyed on [`TypeInfo::type_key`], the name of the *concept*,
//! which the generator makes identical across versions: RESQML 2.0.1's
//! `obj_PointSetRepresentation` and RESQML 2.2's `PointSetRepresentation` are
//! both `PointSetRepresentation`. A new release that keeps the concept is read
//! by the reader that already exists.
//!
//! What costs something is a new release that *respells the insides* - and that
//! has happened twice already, both times silently: 2.2 dropped the patch
//! wrapper (`NodePatchGeometry` rather than `NodePatch` → `Geometry`), and
//! renamed a lattice's `Offset` to `Dimension`. Those live inside the readers,
//! which accept both spellings. A reader added here can do the same, or a
//! caller can push one that replaces it entirely.
//!
//! [`TypeInfo::type_key`]: energyml_core::reflect::TypeInfo::type_key
use Reflect;
use crateResult;
use cratePatch;
use crateValueSource;
/// Turns one kind of representation into patches of points.
///
/// Implement this to teach a build a representation it does not know. The
/// contract is the one the whole crate follows: **what cannot be evaluated is
/// an error naming it**, never an empty list of patches. A caller cannot tell
/// "nothing to draw" from "I did not understand this", and the difference
/// matters more than any individual reader.
/// The readers a build will try, in order.
/// The registry used when a caller does not supply one.
///
/// Public as [`default_registry`], for a caller that wants the built-ins
/// without building a second copy of them.
///
/// Built once. A caller that needs its own readers builds a [`Readers`] and
/// calls [`crate::geometry::of_with`]; nothing here is global mutable state,
/// which would make two parts of one program disagree about what can be read.
pub