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
//! Derives collection (`Vec<T>`)-field classification from the crate's own IR instead of
//! trusting a hand-written `alef.toml` `fields_array`/`fields_optional` list to have named
//! every collection-typed result field.
//!
//! Before this module existed, `FieldResolver::is_array`/`is_collection_root` answered purely
//! from `array_fields`/`optional_fields` (`E2eConfig::effective_fields_array`/
//! `effective_fields_optional`). Those sets are populated from element-traversal paths like
//! `choices[0].message` — they tell a resolver a field IS a collection only when the operator
//! also declared how one of its elements is accessed. A bare collection field with no per-
//! element path in the fixture suite at all (e.g. a recursive `List<DataNode> Children` field
//! nothing ever indexes into) has no config signal whatsoever, so `is_collection_root` answered
//! `false` for it — the same gap `ir_enum` closed for enum-typed fields, but for `Vec<T>`.
//!
//! The fix has to be type-driven, not name-driven, for the identical reason `ir_enum` is:
//! the same crate can declare `items: Vec<T>` on one struct and `items: String` on another, so
//! a bare-field-name rule would misclassify one of them regardless of which way it defaults.
//! [`build_ir_collection_map`] therefore keys its answer by `(owner_type, field_name)`, and
//! [`is_collection_path`] only trusts that answer once it has walked the field path from a
//! known root type through the IR's own struct graph to the exact type that owns the leaf
//! segment — mirroring `ir_enum::is_enum_path` exactly.
use ;
use crateTypeDef;
use cratenamed_type;
use ;
use IrCollectionMap;
/// Build the `(type, field) -> is-Vec` / `(type, field) -> next type` maps [`IrCollectionMap`]
/// needs, by inspecting every field of every `TypeDef` this crate declares.
///
/// A field is recorded as collection-typed on its owner when its declared type is `Vec<T>`
/// (`Option<Vec<T>>` counts too — the FFI/binding layer already collapses "absent" into an
/// empty/null collection, so optionality must not hide the field's real shape). A field whose
/// [`named_type`]-resolved name matches another `TypeDef` is additionally recorded as a
/// traversal edge, exactly as `ir_enum::build_ir_enum_map` records struct-to-struct edges, so a
/// multi-segment path like `parent.children` can advance its type cursor one segment at a time
/// before answering the collection question at the leaf.
pub
/// `true` when `ty` is `Vec<T>`, seeing through an `Option` wrapper the same way
/// `named_type` does.
/// Walk `path` from `map.root_type` through `map.field_types`, answering whether the leaf
/// segment's declared type (per [`build_ir_collection_map`]) is a real `Vec<T>`.
///
/// Returns `false` — never "unknown" — whenever the root type is unresolved, a segment names
/// something the IR does not recognize as a field on the current owner type, or `map` was
/// never populated. Every one of those is the pre-existing behaviour for a field with no
/// collection config entry, so this is purely additive: it can only turn a `false` into a
/// `true` when the IR positively confirms the leaf is `Vec`-typed on the exact type the path
/// reaches. Mirrors `ir_enum::is_enum_path` exactly.
pub