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
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
//! [`Emit`] — the capability to render captured Rust syntax.
//!
//! # Why this exists
//!
//! The model pairs every element with the syntax it was built from, and
//! generated Rust has to **spell** that syntax: a converter's signature says
//! what the source said. But *reading* the same syntax to decide what a type
//! means is the thing [#211](https://github.com/milyin/prebindgen/issues/211)
//! removed — a decision belongs to `kind`, which cannot disagree with itself
//! the way a spelling can.
//!
//! Those two are the same capability if the model simply hands syntax out, so
//! the difference has to be enforced somewhere. Enforcing it by *measurement* —
//! counting how many places name a door, and failing the build when the count
//! moves — was tried and retired: a count can be walked around without moving
//! (`spell()` → `parse_quote!` recovers a node while naming no door), and it
//! cannot see an out-of-crate adapter at all.
//!
//! So the difference is a **capability**. Syntax is reachable only
//! through this type, this type cannot be constructed outside this crate, and
//! `write_rust` (in the separate `prebindgen-registry` crate, which is where
//! the callbacks below now live) hands one out only to the callbacks whose job
//! is producing Rust. Adapter code that classifies, plans, names or validates
//! never receives one, and a call to a door from there does not compile.
//!
//! # Where one comes from
//!
//! `Prebindgen::on_function` and its four peers, `prerequisites`,
//! `post_process_item`, and the closure `RegistryBuilder::convert_with`
//! calls — all in the separate `prebindgen-registry` crate — a converter is
//! generated Rust, since `ConverterImpl::function` is a complete
//! `syn::ItemFn` the adapter writes. Nothing else.
//!
//! If a helper needs an `&Emit`, that is the helper saying it emits; if
//! threading one to it feels wrong, it is probably deciding something and wants
//! the model instead.
//!
//! # What is closed
//!
//! **Every route from the model to captured syntax, except the ones the
//! registry pipeline itself needs.** Every accessor that hands out a `syn`
//! node — a type's own node and its stripped form, an element's item, an
//! origin's node, the syntax rebuilt from a kind, and the shape-spelling
//! helpers — is crate-internal; nothing outside this crate calls them.
//! `TypeRef::spell`, `Origin::spell`
//! and `Flat::enum_item` are `pub`: the registry pipeline that legitimately
//! calls them (`write_rust`'s emission, and its own tests) is now the separate
//! `prebindgen-registry` crate, and a module-path seal cannot reach across a
//! crate boundary. The `compile_fail` examples on [`Emit`] check what remains
//! closed from outside the crate.
//!
//! Two things stay public because they are not that:
//!
//! * [`Origin::declared_spelling`](super::Origin::declared_spelling) — an
//! adapter declaration's `Origin<syn::Type>` holds a type the **build script**
//! wrote, never captured, which #280 leaves the model no reading for.
//! * [`Field::member`](super::Field::member) and
//! [`Field::bind`](super::Field::bind) — they read the field's `name`
//! and `index`, model facts, no syntax.
//!
//! `Display for TypeRef` renders the **identity**, not the spelling: a message
//! is decision code explaining itself and must not need this capability, and
//! delegating to `spell()` would have handed the captured tokens back out
//! through `format!`.
//!
//! # The residual
//!
//! Two things visibility does not do, both accepted.
//!
//! [`Emit::spell`] yields a `TokenStream`, so emission code can re-parse it and
//! take the node apart. That is deliberate — emission is where syntax belongs —
//! and closing it would mean an emission IR for Rust, mirroring the
//! `kotlin-codegen` crate, which is a much larger piece of work.
//!
//! And nothing stops a *new* door being added: someone can write `pub fn
//! as_syn2` in `flat` tomorrow. The reason that is tolerable is that such a
//! method has to be added inside `flat` **and** surfaced here before an adapter
//! can reach it — a two-file diff in the one module a reviewer of this
//! subsystem already reads.
use TokenStream;
use ;
/// Re-emit a captured `#[prebindgen]` const as a **path-alias** to its
/// source-of-truth: same attributes (doc comments), visibility, name and
/// type, with the initializer replaced by `<source_module>::<ident>`. Used
/// by `Prebindgen::on_const` implementations so consts whose initializers
/// reference source-crate internals (private helpers, upstream constants)
/// still compile in the generated file.
///
/// Lives here rather than beside the `Prebindgen` trait because it is pure
/// syntax rendering with no pipeline dependency, and [`Emit::const_alias`] is
/// its only caller.
/// The capability to render captured Rust syntax.
///
/// Unforgeable outside this crate: the field is private and there is no public
/// constructor, so the only way to hold one is to have been handed one. See the
/// [module docs](self) for where that happens and why.
///
/// Every method here is a *rendering* — it answers "what did the source write",
/// never "what does this mean". The second question is the model's, and its
/// answers ([`TypeRef::kind`], [`TypeRef::key`], the layer readings) need no
/// capability precisely because they cannot be misused into re-deriving a
/// classification.
///
/// # The seal, as compiled assertions
///
/// A doctest builds as its **own crate** against the published API, so these
/// check the property that matters: what an out-of-crate adapter can reach.
/// Each names a route that used to be open.
///
/// An element's item (`E0624` — the method is private):
///
/// ```compile_fail
/// # use prebindgen_flat::{Element, flat};
/// fn leak(e: &Element) -> syn::Item { e.as_syn() }
/// ```
///
/// A declared type's item:
///
/// ```compile_fail
/// # use prebindgen_flat::flat;
/// fn leak(t: &flat::Type) -> syn::Item { t.as_syn() }
/// ```
///
/// A captured function's own node, through its `Origin`:
///
/// ```compile_fail
/// # use prebindgen_flat::flat;
/// fn leak(f: &flat::Function) -> &syn::ItemFn { f.origin.as_syn() }
/// ```
///
/// …and its tokens, which re-parse to the same item — the door under another
/// name, and the one a reviewer found still open when this type was introduced.
/// **No longer closed**: `Origin::spell` is `pub` now that the registry
/// pipeline's own tests, this method's other legitimate caller, are the
/// separate `prebindgen-registry` crate rather than code inside this one:
///
/// ```
/// # use prebindgen_flat::flat;
/// fn leak(f: &flat::Function) -> proc_macro2::TokenStream { f.origin.spell() }
/// ```
///
/// A type's **node** — the door C5 claimed to have closed and did not:
///
/// ```compile_fail
/// # use prebindgen_flat::flat;
/// fn leak(t: &flat::TypeRef) -> &syn::Type { t.as_syn() }
/// ```
///
/// A declared enum's item, by name. **No longer closed**, for the same reason
/// as `Origin::spell` above — `Flat::enum_item` is a registry-pipeline test
/// helper:
///
/// ```
/// # use prebindgen_flat::Flat;
/// fn leak(f: &Flat) -> Option<&syn::ItemEnum> { f.enum_item("E") }
/// ```
///
/// The delimiters a shape was written with — `S { a }` vs `S(a)` vs `S`:
///
/// ```compile_fail
/// # use prebindgen_flat::flat;
/// fn leak(s: &flat::Struct) -> proc_macro2::TokenStream {
/// s.spell(Default::default(), &[])
/// }
/// ```
///
/// ```compile_fail
/// # use prebindgen_flat::flat;
/// fn leak(v: &flat::EnumValue) -> proc_macro2::TokenStream {
/// v.spell(Default::default(), &[])
/// }
/// ```
///
/// A type's spelling. **No longer closed**: `TypeRef::spell` is `pub` now
/// that `write_rust`'s own emission code, this method's other legitimate
/// caller, lives in the separate `prebindgen-registry` crate:
///
/// ```
/// # use prebindgen_flat::flat;
/// fn leak(t: &flat::TypeRef) -> proc_macro2::TokenStream { t.spell() }
/// ```
///
/// …its stripped form, and the kind's reconstruction:
///
/// ```compile_fail
/// # use prebindgen_flat::flat;
/// fn leak(t: &flat::TypeRef) -> syn::Type { t.stripped_syntax() }
/// ```
///
/// ```compile_fail
/// # use prebindgen_flat::flat;
/// fn leak(k: &flat::TypeKind) -> syn::Type { k.to_syn() }
/// ```
///
/// Minting one by naming the struct literal is not available either — the
/// field is private:
///
/// ```compile_fail
/// # use prebindgen_flat::Emit;
/// let forged = Emit { _seal: () };
/// ```