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
//! Query-time covering set extraction.
//!
//! `build_covering` and `build_covering_inner` produce the minimal set of gram
//! hashes needed to query the index for a literal or regex fragment. Moved here
//! from the parent module to keep `mod.rs` under the 400-line limit.
use ;
// ---------------------------------------------------------------------------
// T013: build_covering -- query-time covering set extraction
// ---------------------------------------------------------------------------
/// Grams classified by boundary reliability.
///
/// When a literal query is verified via `memchr::memmem`, the pattern can
/// match anywhere in a file (substring semantics). Token-aligned grams
/// anchored only by synthetic position-0 / position-len boundaries cannot
/// capture sub-token matches (e.g. literal `parse` misses `reparse`).
///
/// Splitting grams into two tiers lets the query router widen the candidate
/// set when edge-only grams would produce false negatives.
/// Extract the minimal covering set of grams from a query pattern,
/// classified into required and optional tiers.
///
/// Lowercases `input`, detects the same boundary positions as the original
/// token-aligned query path, and emits one gram hash per
/// consecutive-boundary span with length >= `MIN_GRAM_LEN`.
///
/// Each gram is classified:
/// - **required**: BOTH boundaries are real (interior position, or position
/// 0/len with a forced-boundary byte).
/// - **optional**: at least one boundary is synthetic (position 0 or len with
/// a non-forced-boundary endpoint byte).
///
/// Returns `None` if no grams of sufficient length exist (the entire query
/// falls in sub-`MIN_GRAM_LEN` spans). Callers must fall back to full scan.
///
/// # Example
///
/// ```ignore
/// use syntext::__internal::build_covering;
///
/// // "parse_query" has one synthetic boundary for each gram (start/end of query)
/// // so they are optional to prevent false negatives on sub-token matches.
/// let covering = build_covering(b"parse_query").unwrap();
/// assert!(covering.required.is_empty());
/// assert_eq!(covering.optional.len(), 2);
///
/// // "_parse_query_" is fully anchored by forced boundaries at start and end,
/// // so its grams are required.
/// let covering = build_covering(b"_parse_query_").unwrap();
/// assert!(covering.required.len() >= 2);
/// assert!(covering.optional.is_empty());
///
/// // "parse" has no interior boundaries and no forced-edge bytes:
/// // the single gram is optional (unanchored).
/// let covering = build_covering(b"parse").unwrap();
/// assert!(covering.required.is_empty());
/// assert_eq!(covering.optional.len(), 1);
///
/// // Short query: no qualifying grams
/// assert!(build_covering(b"ab").is_none());
/// ```
// ---------------------------------------------------------------------------
// T016: build_covering_inner -- regex-safe gram extraction
// ---------------------------------------------------------------------------
/// Extract covering grams from a regex literal fragment.
///
/// Unlike `build_covering` (which treats position 0 and `len` as boundaries),
/// this function refuses spans that rely on synthetic fragment edges. Interior
/// boundaries are safe, because the current tokenizer's boundary decisions are
/// determined by the adjacent bytes at that position.
///
/// For a regex like `parse_quer[yi]`, the HIR literal "parse_quer" ends
/// mid-token. `build_covering` would emit gram "quer" (ending at synthetic
/// `len` boundary), but "quer" is not a gram in documents where the full
/// token is "query". `build_covering_inner` detects that 'r' (the last byte)
/// is not a forced boundary character and skips the partial span.
///
/// Returns `None` if no interior forced-boundary grams exist (caller should
/// fall back to full scan).