devscout_rs/graph/fragment_types.rs
1use serde::{Deserialize, Serialize};
2
3use crate::extract;
4
5use super::ordered::OrderedMap;
6
7// ---------------------------------------------------------------------------
8// Fragments cache schema -- the RAW (unresolved) per-file extraction output,
9// keyed by repo-relative path. Mirrors extract.rs's DefRecord/UsingRecord/
10// RefRecord field-for-field; the serde impls live here rather than on the
11// extractor's own types.
12// ---------------------------------------------------------------------------
13
14/// Field order is significant: id, name, namespace, kind, line, methods, then
15/// the member-fact additions in that exact order -- properties, fields,
16/// methodReturns -- and after those extensionMethods, appended LAST. Each is
17/// omitted entirely when empty, so a type declaring none of them serializes
18/// exactly as it did before those additions.
19#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
20pub struct FragDef {
21 /// The id value.
22 pub id: String,
23 /// The name value.
24 pub name: String,
25 /// The namespace value.
26 pub namespace: String,
27 /// The kind value.
28 pub kind: String,
29 /// The line value.
30 pub line: usize,
31 /// The methods value.
32 pub methods: Vec<String>,
33 #[serde(default, skip_serializing_if = "Vec::is_empty")]
34 /// The properties value.
35 pub properties: Vec<String>,
36 #[serde(default, skip_serializing_if = "Vec::is_empty")]
37 /// The fields value.
38 pub fields: Vec<String>,
39 /// Member name -> declared return type NAME, in FIRST-DECLARATION SOURCE
40 /// ORDER -- deliberately `OrderedMap`, never a `BTreeMap`: this is an
41 /// ordered pair list, and sorting the keys here would break the
42 /// serialized bytes.
43 #[serde(
44 default,
45 rename = "methodReturns",
46 skip_serializing_if = "OrderedMap::is_empty"
47 )]
48 pub method_returns: OrderedMap<String>,
49 /// The extension methods this type declares, in source
50 /// order, deduped by (name, thisType, arityMin, arityMax). Appended after
51 /// `method_returns`, and omitted entirely when empty, so a type declaring
52 /// none keeps its exact prior bytes.
53 #[serde(
54 default,
55 rename = "extensionMethods",
56 skip_serializing_if = "Vec::is_empty"
57 )]
58 pub extension_methods: Vec<FragExtensionMethod>,
59 /// DIRECT base-type identifiers, source
60 /// order, deduped. Appended LAST, after `extension_methods`, omitted when
61 /// empty. A resolution input only: `resolve_graph` strips it (along with
62 /// properties/fields/extensionMethods) before graph.json's def rows, so
63 /// the on-disk def bytes are unchanged.
64 #[serde(default, skip_serializing_if = "Vec::is_empty")]
65 pub bases: Vec<String>,
66 /// The declaring type's own type-parameter names, empty for
67 /// every non-generic declaration. Appended after `bases`, omitted when
68 /// empty. A resolution input, like `bases`: the ctor-DI resolver's
69 /// "is this def itself an open-generic implementation" signal.
70 #[serde(default, rename = "typeParams", skip_serializing_if = "Vec::is_empty")]
71 pub type_params: Vec<String>,
72 /// Per base name that carried a type-argument list, that
73 /// list's generic-arg descriptors relative to `type_params` (`OrderedMap`
74 /// for the same reason `method_returns` is one: the serialized key order
75 /// is significant). Appended after `type_params`, omitted when
76 /// empty.
77 #[serde(
78 default,
79 rename = "baseGenericArgs",
80 skip_serializing_if = "OrderedMap::is_empty"
81 )]
82 pub base_generic_args: OrderedMap<Vec<String>>,
83 /// The methods a test framework would DISCOVER as
84 /// tests, source order, deduped. Appended LAST, after `baseGenericArgs`,
85 /// omitted when empty. Unlike its neighbours this one is NOT stripped by
86 /// `resolve_graph`: it is what `devscout tests` answers from.
87 #[serde(default, rename = "testMethods", skip_serializing_if = "Vec::is_empty")]
88 pub test_methods: Vec<String>,
89 /// Property name -> declared type fact, in source order and
90 /// under the same dedup as `properties`. An `OrderedMap` for the same
91 /// reason `method_returns` is one: the serialized key order is significant.
92 /// Appended LAST, after `test_methods`, omitted when empty. A
93 /// resolution input only, like `properties`/`fields`.
94 #[serde(
95 default,
96 rename = "propertyTypes",
97 skip_serializing_if = "OrderedMap::is_empty"
98 )]
99 pub property_types: OrderedMap<FragFact>,
100 /// Field name -> declared type fact, in source order and
101 /// under the same dedup as `fields`. Mirrors `propertyTypes` field for
102 /// field: an `OrderedMap` for the same reason (the serialized key order
103 /// is significant), a resolution input only, like `properties`/`fields`,
104 /// and this is a purely additive field -- an absent key reads back as
105 /// "no fields typed", the safe default for every fragment cached before
106 /// this field existed, so it joins the schema with no cache-version
107 /// bump. Appended right after `propertyTypes`, omitted when empty.
108 #[serde(
109 default,
110 rename = "fieldTypes",
111 skip_serializing_if = "OrderedMap::is_empty"
112 )]
113 pub field_types: OrderedMap<FragFact>,
114 /// Per method name `methodReturns` also carries an entry for,
115 /// that return type's top-level generic-arg descriptors -- the same
116 /// capture `baseGenericArgs` keeps beside `bases` (see extract.rs's
117 /// `DefRecord`). `methodReturns` itself is left exactly as it always
118 /// was (the bare return-type identifier, "Task" for
119 /// `Task<Order> GetAsync()`) so an UNAWAITED use of the same callee
120 /// keeps reading "Task" unchanged; this is a purely additive sibling
121 /// field, not a reshaping of `methodReturns`, which is what lets it
122 /// join the schema with no cache-version bump -- an absent key reads
123 /// back as "no generic args", the safe default for every fragment
124 /// cached before this field existed. Appended LAST of all, after
125 /// `fieldTypes`, omitted when empty.
126 #[serde(
127 default,
128 rename = "methodReturnArgs",
129 skip_serializing_if = "OrderedMap::is_empty"
130 )]
131 pub method_return_args: OrderedMap<Vec<String>>,
132 /// Declared method names `methods` does not carry because
133 /// `is_recorded_method` gates that list on a literal `public` modifier
134 /// (or `kind == "interface"`, where this list is always empty). Source
135 /// order, no dedup, same as `methods`. A resolution input only, like
136 /// `properties`/`fields`/`bases`: `resolve_graph` strips it before
137 /// graph.json's def rows. Consulted only for hierarchy-internal
138 /// receivers (`base.` and the `this.` shape's own base walk); the
139 /// scored tier keeps reading `methods` alone. Appended LAST of all,
140 /// after `methodReturnArgs`, omitted when empty -- purely additive, so
141 /// an absent key reads back as "no non-public methods", the safe
142 /// default for every fragment cached before this field existed, which
143 /// is what lets it join the schema with no cache-version bump.
144 #[serde(
145 default,
146 rename = "nonPublicMethods",
147 skip_serializing_if = "Vec::is_empty"
148 )]
149 pub non_public_methods: Vec<String>,
150 /// Method name -> the (min, max) argument-count range every overload
151 /// sharing that name accepts, one tuple per overload, in declaration
152 /// order -- covers every method, public and non-public alike (see
153 /// `extract::DefRecord::method_arities`). `max` is -1 for an unbounded
154 /// `params` overload, the same sentinel `FragExtensionMethod::arity_max`
155 /// already uses. An `OrderedMap` for the same reason `methodReturns` is
156 /// one: the serialized key order is significant. Appended LAST of all,
157 /// after `nonPublicMethods`, omitted when empty -- purely additive, so
158 /// an absent key reads back as "no arity facts", the safe default for
159 /// every fragment cached before this field existed, which is what lets
160 /// it join the schema with no cache-version bump.
161 #[serde(
162 default,
163 rename = "methodArities",
164 skip_serializing_if = "OrderedMap::is_empty"
165 )]
166 pub method_arities: OrderedMap<Vec<(usize, i64)>>,
167 /// Method name -> per-overload parameter type descriptors, one
168 /// `Vec<String>` per overload in declaration order -- covers every
169 /// method, public and non-public alike, same method set as
170 /// `methodArities` (see `extract::DefRecord::method_params`). A
171 /// position naming a type parameter of the enclosing method or class is
172 /// recorded as `"*"`; a parameter carrying the `this` modifier is
173 /// written `"this <descriptor>"`. A `delegate` def carries exactly one
174 /// entry here, keyed `"Invoke"`. An `OrderedMap` for the same reason
175 /// `methodArities` is one: the serialized key order is significant.
176 /// Appended LAST of all, after `methodArities`, omitted when empty.
177 /// Joined the schema with the v18 cache bump: a v17 fragment read back
178 /// carries none, and every overload-shape/`this`-marker/callee-slot
179 /// lookup this field backs would silently see no candidates.
180 #[serde(
181 default,
182 rename = "methodParams",
183 skip_serializing_if = "OrderedMap::is_empty"
184 )]
185 pub method_params: OrderedMap<Vec<Vec<String>>>,
186 /// Declared method names carrying the literal `override` modifier,
187 /// source order, deduped. Appended LAST of all, after `method_params`,
188 /// omitted when empty -- purely additive, so an absent key reads back
189 /// as "no overrides", the safe default for every fragment cached before
190 /// this field existed, which is what lets it join the schema with the
191 /// same v19 cache bump `registrations` does rather than a bump of its
192 /// own. Read by the resolver's member-level `overrides` pass to find
193 /// the nearest in-graph base member of the same name and arity.
194 #[serde(
195 default,
196 rename = "overrideMethods",
197 skip_serializing_if = "Vec::is_empty"
198 )]
199 pub override_methods: Vec<String>,
200 /// Per base name that carries a NESTED generic type argument, that
201 /// argument's own recursive descriptor -- see
202 /// `extract::DefRecord::base_type_args`. Appended LAST of all, after
203 /// `overrideMethods`, omitted when empty. Joined the schema with the
204 /// v20 cache bump: a v19 fragment read back carries none, so the inner
205 /// type argument of a nested base (`IConsumer<Batch<T>>`'s `T`) would
206 /// be unrecoverable from the flattened `baseGenericArgs` alone.
207 #[serde(
208 default,
209 rename = "baseTypeArgs",
210 skip_serializing_if = "OrderedMap::is_empty"
211 )]
212 pub base_type_args: OrderedMap<Vec<String>>,
213 /// Every distinct single type argument this type's own properties wrap
214 /// -- see `extract::DefRecord::property_message_args`. Appended LAST of
215 /// all, after `baseTypeArgs`, omitted when empty. Joined the schema
216 /// with the v21 cache bump: a v20 fragment read back carries none, so a
217 /// handler binding its messages on properties rather than on its base
218 /// list would look like it handled nothing.
219 #[serde(
220 default,
221 rename = "propertyMessageArgs",
222 skip_serializing_if = "Vec::is_empty"
223 )]
224 pub property_message_args: Vec<String>,
225 /// Base names (a subset of `bases`) whose message-position argument at
226 /// `baseGenericArgs`' own position 0 is an array type
227 /// (`IConsumer<M[]>`) -- see `extract::DefRecord::array_message_bases`.
228 /// Appended LAST of all, after `propertyMessageArgs`, omitted when
229 /// empty. Joined the schema with the v23 cache bump: a v22 fragment
230 /// read back carries none, so a single message and an array of it would
231 /// read as the same base-list argument and a publish of one would
232 /// silently reach a consumer of the other.
233 #[serde(
234 default,
235 rename = "arrayMessageBases",
236 skip_serializing_if = "Vec::is_empty"
237 )]
238 pub array_message_bases: Vec<String>,
239 #[serde(default, rename = "endLine", skip_serializing_if = "is_zero")]
240 /// The end line value.
241 pub end_line: usize,
242}
243
244/// One two-type-argument DI service registration a file's invocations
245/// record -- see `extract::RegistrationRecord`.
246///
247/// `service` is the first type argument (the interface), `implementation`
248/// the second (the concrete type). Field order (`service`,
249/// `implementation`, `namespace`, `line`) is significant; neither type name
250/// carries its enclosing-namespace qualification here (that is the
251/// resolver's job, against the registration site's OWN using/alias context,
252/// read from `namespace`).
253#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
254pub struct FragRegistration {
255 /// The service (first type argument) name.
256 pub service: String,
257 /// The implementation (second type argument) name.
258 pub implementation: String,
259 /// The registration call's enclosing namespace.
260 pub namespace: String,
261 /// The registration call's 1-based line.
262 pub line: usize,
263}
264
265/// One message-bus publish-site fact a file's invocations record -- see
266/// `extract::PublishRecord`. Field order (`verb`, `message`, `namespace`,
267/// `line`, `outerTypes`, `enclosingMethod`, `argCount`, `enclosingCall`) is
268/// significant; `outerTypes` is omitted when empty, `enclosingMethod` when
269/// absent, `argCount` when zero and `enclosingCall` when absent.
270#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
271pub struct FragPublish {
272 /// The invoked method name.
273 pub verb: String,
274 /// The resolved message-type descriptor.
275 pub message: String,
276 /// The call's enclosing namespace.
277 pub namespace: String,
278 /// The call's 1-based line.
279 pub line: usize,
280 /// Enclosing-type stack (see `FragRef::outer_types`).
281 #[serde(default, rename = "outerTypes", skip_serializing_if = "Vec::is_empty")]
282 pub outer_types: Vec<String>,
283 /// The enclosing method's name, set only when this publish hands on its
284 /// own caller's message -- see `extract::PublishRecord::enclosing_method`.
285 /// Appended LAST, omitted when absent. Joined the schema with the v21
286 /// cache bump.
287 #[serde(
288 default,
289 rename = "enclosingMethod",
290 skip_serializing_if = "Option::is_none"
291 )]
292 pub enclosing_method: Option<String>,
293 /// The call's own argument count -- see `extract::PublishRecord::arg_count`.
294 /// Appended LAST, after `enclosingMethod`, omitted when zero. Stays
295 /// within the v22 generation (no accepted or released build has ever
296 /// written v22).
297 #[serde(default, rename = "argCount", skip_serializing_if = "is_zero")]
298 pub arg_count: usize,
299 /// The enclosing invocation the call's own lambda sits inside, when it
300 /// sits inside one -- see `extract::PublishRecord::enclosing_call`.
301 /// Appended LAST, after `argCount`, omitted when absent.
302 #[serde(
303 default,
304 rename = "enclosingCall",
305 skip_serializing_if = "Option::is_none"
306 )]
307 pub enclosing_call: Option<FragEnclosingCall>,
308}
309
310/// One publish call's own enclosing-lambda-argument fact -- see
311/// `extract::EnclosingCallFact`. Field order (`verb`, `argPosition`,
312/// `argCount`) is significant.
313#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
314pub struct FragEnclosingCall {
315 /// The enclosing invocation's own callee bare name.
316 pub verb: String,
317 /// The 0-based position the lambda occupies among the enclosing
318 /// invocation's arguments.
319 #[serde(rename = "argPosition")]
320 pub arg_position: usize,
321 /// The enclosing invocation's own total argument count.
322 #[serde(rename = "argCount")]
323 pub arg_count: usize,
324}
325
326/// One one-type-argument handler registration a file's invocations record
327/// -- see `extract::HandlerRegistrationRecord`. Field order (`handler`,
328/// `namespace`, `line`) is significant.
329#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
330pub struct FragHandlerRegistration {
331 /// The registered type's descriptor, as written.
332 pub handler: String,
333 /// The registration call's enclosing namespace.
334 pub namespace: String,
335 /// The registration call's 1-based line.
336 pub line: usize,
337}
338
339/// One declared type fact: the type NAME, plus its top-level
340/// type-argument descriptors when the declaration carried any. Field order
341/// (`type`, `args`) is significant, and `args` is omitted when absent.
342#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
343pub struct FragFact {
344 #[serde(rename = "type")]
345 /// The type name value.
346 pub type_name: String,
347 #[serde(default, skip_serializing_if = "Option::is_none")]
348 /// The args value.
349 pub args: Option<Vec<String>>,
350}
351
352/// One `extensionMethods` entry. Serialized field order (`name`, `thisType`,
353/// `arityMin`, `arityMax`, `thisArgs`) is significant, and serde emits struct
354/// fields in declaration order. The two arity halves are NOT optional: they joined the
355/// schema with the v6 cache rename, so no fragment this reader can meet is
356/// missing them. `arity_max` is signed because -1 is the unbounded-`params`
357/// sentinel.
358#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
359pub struct FragExtensionMethod {
360 /// The name value.
361 pub name: String,
362 #[serde(rename = "thisType")]
363 /// The this type value.
364 pub this_type: String,
365 #[serde(rename = "arityMin")]
366 /// The arity min value.
367 pub arity_min: usize,
368 #[serde(rename = "arityMax")]
369 /// The arity max value.
370 pub arity_max: i64,
371 /// Present only when the this-parameter type is generic (the key is omitted
372 /// key otherwise), so a non-generic entry keeps four fields exactly.
373 #[serde(default, rename = "thisArgs", skip_serializing_if = "Option::is_none")]
374 pub this_args: Option<Vec<String>>,
375}
376
377/// One untyped lambda parameter's callee slot (see extract.rs's `LambdaSlot`).
378///
379/// Field order (`owner`, `member`, `argCount`, `argIndex`,
380/// `arity`, `index`) is significant: serde emits struct fields in
381/// declaration order under `#[serde(rename_all = "camelCase")]`.
382#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
383#[serde(rename_all = "camelCase")]
384pub struct FragLambdaSlot {
385 /// The callee's type-name text.
386 pub owner: String,
387 /// The callee method name.
388 pub member: String,
389 /// The argument count of the callee invocation.
390 pub arg_count: usize,
391 /// The position of the lambda among the callee invocation's arguments.
392 pub arg_index: usize,
393 /// The lambda's own parameter count.
394 pub arity: usize,
395 /// This parameter's position inside the lambda's parameter list.
396 pub index: usize,
397}
398
399#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
400#[serde(untagged)]
401/// Represents `FragUsing`.
402pub enum FragUsing {
403 /// The value value.
404 Alias {
405 /// The alias name.
406 alias: String,
407 /// The aliased target.
408 target: String,
409 /// Whether the directive is global.
410 global: bool,
411 },
412 /// The value value.
413 Plain {
414 /// The imported namespace text.
415 text: String,
416 /// Whether the directive is global.
417 global: bool,
418 },
419}
420
421#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
422/// Represents `FragRef`.
423pub struct FragRef {
424 /// The kind value.
425 pub kind: String,
426 /// The name value.
427 pub name: String,
428 #[serde(default, skip_serializing_if = "Option::is_none")]
429 /// The qualified value.
430 pub qualified: Option<String>,
431 #[serde(default, skip_serializing_if = "Option::is_none")]
432 /// The member value.
433 pub member: Option<String>,
434 /// The line value.
435 pub line: usize,
436 /// Always serialized, including when `null` (imports refs) -- NOT
437 /// `skip_serializing_if`, unlike `qualified`/`member` which are omitted
438 /// entirely when absent. See extract.rs's `RefRecord` doc comment.
439 pub namespace: Option<String>,
440 #[serde(
441 default,
442 rename = "typeArgCount",
443 skip_serializing_if = "Option::is_none"
444 )]
445 /// The type arg count value.
446 pub type_arg_count: Option<usize>,
447 /// Type-certainty flag (see extract.rs's `RefRecord`). Serialized last and
448 /// only when `true`; an absent key reads back as false, which also makes
449 /// an older fragment JSON parse safely.
450 #[serde(default, skip_serializing_if = "is_false")]
451 pub generic: bool,
452 /// Receiver fact (see extract.rs's `RefRecord`). Appended AFTER `generic`,
453 /// and set only when a fact actually fired -- so it serializes last and
454 /// only when present, and an absent key reads back as "no fact", the safe
455 /// default.
456 #[serde(
457 default,
458 rename = "receiverType",
459 skip_serializing_if = "Option::is_none"
460 )]
461 pub receiver_type: Option<String>,
462 /// The callee arg count (see extract.rs's `RefRecord`). Appended AFTER
463 /// `receiverType`, set only when the member access was the callee of an
464 /// invocation -- so it serializes last and only when present, and an
465 /// absent key reads back as "not a call", which is what keeps a property
466 /// read out of the extension tier.
467 #[serde(default, rename = "argCount", skip_serializing_if = "Option::is_none")]
468 pub arg_count: Option<usize>,
469 /// Receiver generic-arg descriptors (see extract.rs's `RefRecord`). Appended
470 /// LAST, after `argCount`, set only when the receiver's DECLARED type was
471 /// generic -- an absent key reads back as "not generic", which is what
472 /// makes a generic-vs-non-generic pairing fail to unify.
473 #[serde(
474 default,
475 rename = "receiverArgs",
476 skip_serializing_if = "Option::is_none"
477 )]
478 pub receiver_args: Option<Vec<String>>,
479 /// Enclosing-type stack (see extract.rs's `RefRecord`). Appended LAST, after
480 /// `receiverArgs`, and set only when non-empty. A Vec rather than an Option
481 /// because empty and absent mean the same thing here -- a ref at namespace
482 /// level and an older cached fragment both read back as "no enclosing
483 /// type", which is what keeps them off the step.
484 #[serde(default, rename = "outerTypes", skip_serializing_if = "Vec::is_empty")]
485 pub outer_types: Vec<String>,
486 /// Generic-arg descriptors for a 'ctor-param' ref (see extract.rs's
487 /// `RefRecord`). Appended LAST of all, after `outerTypes`, and set only when
488 /// the parameter's type was generic.
489 #[serde(default, skip_serializing_if = "Option::is_none")]
490 pub args: Option<Vec<String>>,
491 /// (See extract.rs's `RefRecord`.) The type whose PROPERTY the
492 /// qualifier's last segment is, for a two-segment chain whose head the
493 /// enclosing scope could type. Appended after `args`, and never present
494 /// alongside `receiverType`.
495 #[serde(
496 default,
497 rename = "receiverPropertyOwner",
498 skip_serializing_if = "Option::is_none"
499 )]
500 pub receiver_property_owner: Option<String>,
501 /// (See extract.rs's `RefRecord`.) The type whose METHOD a
502 /// `var x = Q.M(...)` initializer called, and that method's name. Appended
503 /// LAST of all, always as a pair, and never alongside `receiverType`: an
504 /// absent pair reads back as "no call fact", which is what leaves the local
505 /// taken-but-unknown.
506 #[serde(
507 default,
508 rename = "receiverCallOwner",
509 skip_serializing_if = "Option::is_none"
510 )]
511 pub receiver_call_owner: Option<String>,
512 #[serde(
513 default,
514 rename = "receiverCallMember",
515 skip_serializing_if = "Option::is_none"
516 )]
517 /// The receiver call member value.
518 pub receiver_call_member: Option<String>,
519 /// `true` for a `base.` qualifier -- the member lookup starts at the
520 /// enclosing type's bases and never considers the enclosing type
521 /// itself (see `extract.rs`'s `RefRecord`). Appended LAST of all, and
522 /// omitted when `false` -- an absent key reads back as `false`, the
523 /// same as a plain `this.` receiver and as every ref kind that never
524 /// sets it, and also what makes a v15 cached fragment parse safely.
525 #[serde(default, rename = "receiverBase", skip_serializing_if = "is_false")]
526 pub receiver_base: bool,
527 /// `true` when `receiverCallOwner`/`receiverCallMember` came from an
528 /// AWAITED call (see `extract.rs`'s `RefRecord`). Appended LAST of all,
529 /// after `receiverBase`, and omitted when `false` -- an absent key reads
530 /// back as `false`, the same as an unawaited call fact and as every ref
531 /// kind that never sets it, which is also what lets a cached fragment
532 /// from before this field existed parse safely with no cache-version
533 /// bump: it simply reads back as "not awaited", the same answer the
534 /// resolver gave before this field existed.
535 #[serde(default, rename = "receiverAwaited", skip_serializing_if = "is_false")]
536 pub receiver_awaited: bool,
537 /// `true` when this ref's qualifier is a bare identifier for which the
538 /// enclosing MEMBER's own fact table (locals, parameters, lambda
539 /// parameters, patterns, `out` designations) holds ANY entry for the
540 /// name, typed or taken-but-unknown (see `extract.rs`'s `RefRecord` and
541 /// `Scope::has_local_fact`). Read ONLY by the bare-identifier
542 /// field/property fallback: a member-scoped name always shadows a
543 /// same-named field, whether or not anything vouches for its type, so
544 /// that fallback never runs when this is `true`. `false` for every
545 /// dotted or generic qualifier, for `this.`/`base.` (never asked of the
546 /// enclosing scope's local table at all), and for every ref kind but
547 /// `uses-member`. Appended LAST of all, after `receiverAwaited`, and
548 /// omitted when `false` -- an absent key reads back as `false`, the
549 /// same as every ref kind that never sets it, which is also what lets a
550 /// cached fragment from before this field existed parse safely with no
551 /// cache-version bump.
552 #[serde(default, rename = "receiverLocal", skip_serializing_if = "is_false")]
553 pub receiver_local: bool,
554 /// Set when this ref's qualifier is an untyped lambda parameter whose
555 /// type is a delegate parameter of some OTHER callee (see extract.rs's
556 /// `RefRecord`). Never present alongside `receiverType` or
557 /// `receiverCallOwner`. Appended LAST of all, after `receiverLocal`,
558 /// omitted when absent. Joined the schema with the v18 cache bump: a
559 /// v17 fragment read back carries none, and every untyped-lambda
560 /// callee-slot lookup this field backs would silently see no
561 /// candidate.
562 #[serde(
563 default,
564 rename = "receiverLambda",
565 skip_serializing_if = "Option::is_none"
566 )]
567 pub receiver_lambda: Option<FragLambdaSlot>,
568 /// `true` when `receiverType` came off a declaration whose own type
569 /// node carried a `?` (see extract.rs's `RefRecord`). Appended LAST of
570 /// all, after `receiverLambda`, and omitted when `false` -- an absent
571 /// key reads back as `false`, the same as a non-nullable receiver and
572 /// as every ref kind that never sets it. Joined the schema with the
573 /// v20 cache bump: a v19 fragment read back carries none, so a
574 /// `T?` receiver's own `Nullable<T>.Value`/`HasValue`/
575 /// `GetValueOrDefault` unwrap would silently keep resolving against
576 /// `T`'s own same-named member.
577 #[serde(default, rename = "receiverNullable", skip_serializing_if = "is_false")]
578 pub receiver_nullable: bool,
579 /// The parameter count of each delegate-shaped argument of the
580 /// invocation this ref is the callee of -- a lambda literal, or a
581 /// local function passed as a method group (see extract.rs's
582 /// `RefRecord`). Appended LAST of all, after `receiverNullable`,
583 /// omitted when absent. Joined the schema with the v20 cache bump: a
584 /// v19 fragment read back carries none, and a candidate whose delegate
585 /// parameter shape the call's own argument cannot fill would silently
586 /// keep earning a precise edge.
587 #[serde(
588 default,
589 rename = "lambdaArgArity",
590 skip_serializing_if = "Option::is_none"
591 )]
592 pub lambda_arg_arity: Option<Vec<Option<usize>>>,
593}
594
595pub(crate) fn is_false(b: &bool) -> bool {
596 !*b
597}
598
599pub(crate) fn is_zero(n: &usize) -> bool {
600 *n == 0
601}
602
603/// One declared member, with the line its own NAME token sits on.
604///
605/// Field order (`name`, `kind`, `line`, `owner`) is significant, and `owner`
606/// is omitted when empty -- which is how
607/// a markup or resource key, owned by no C# type, serializes with three fields.
608#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
609pub struct FragName {
610 /// The name value.
611 pub name: String,
612 /// The kind value.
613 pub kind: String,
614 /// The line value.
615 pub line: usize,
616 #[serde(default, skip_serializing_if = "String::is_empty")]
617 /// The owner value.
618 pub owner: String,
619}
620
621#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
622/// Represents `Fragment`.
623pub struct Fragment {
624 /// The defs value.
625 pub defs: Vec<FragDef>,
626 /// The usings value.
627 pub usings: Vec<FragUsing>,
628 /// The refs value.
629 pub refs: Vec<FragRef>,
630 /// Appended LAST, after `refs`. Always serialized, like its
631 /// three siblings: a fragment's top-level arrays are a fixed shape, and
632 /// only the fields INSIDE a record follow the omit-when-empty rule.
633 #[serde(default)]
634 pub names: Vec<FragName>,
635 /// The file's two-type-argument DI service registrations -- see
636 /// `FragRegistration`. Appended LAST, after `names`, and omitted when
637 /// empty (unlike its four siblings above, which pre-date the
638 /// omit-when-empty convention): a file recording none serializes exactly
639 /// as it did before this field existed.
640 #[serde(default, skip_serializing_if = "Vec::is_empty")]
641 pub registrations: Vec<FragRegistration>,
642 /// The file's message-bus publish-site facts -- see `FragPublish`.
643 /// Appended LAST, after `registrations`, and omitted when empty.
644 /// Joined the schema with the v20 cache bump: a v19 fragment read back
645 /// carries none, so every publish-site fact from an unchanged file
646 /// would silently disappear from a reused cache.
647 #[serde(default, skip_serializing_if = "Vec::is_empty")]
648 pub publishes: Vec<FragPublish>,
649 /// The file's one-type-argument handler registrations, appended LAST
650 /// after `publishes` and omitted when empty. Joined the schema with the
651 /// v21 cache bump: a v20 fragment read back carries none, so a
652 /// repository's own handler vocabulary would be underivable from a
653 /// reused cache.
654 #[serde(
655 default,
656 rename = "handlerRegistrations",
657 skip_serializing_if = "Vec::is_empty"
658 )]
659 pub handler_registrations: Vec<FragHandlerRegistration>,
660}
661
662/// The two shapes a cached fragment can have. Each rel is keyed to whichever
663/// shape the file's grammar produced; the `ts: 1` tag is what tells them
664/// apart, on disk and at the
665/// resolver's door. Untagged, and TS FIRST: a C#/markup fragment carries no
666/// `ts` key (so the TS arm always fails on it) and a TS fragment carries no
667/// `usings` (so the C# arm always fails on it) -- the discrimination is total
668/// in both directions, never a first-match-wins guess.
669#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
670#[serde(untagged)]
671pub enum AnyFragment {
672 /// Represents `Ts`.
673 Ts(extract::TsFragment),
674 /// Represents `Cs`.
675 Cs(Fragment),
676}
677
678impl From<Fragment> for AnyFragment {
679 fn from(f: Fragment) -> Self {
680 AnyFragment::Cs(f)
681 }
682}
683
684impl From<extract::TsFragment> for AnyFragment {
685 fn from(f: extract::TsFragment) -> Self {
686 AnyFragment::Ts(f)
687 }
688}