1
- use std:: { borrow:: Cow , path:: Path } ;
2
-
3
1
use bstr:: { BString , ByteSlice } ;
4
2
use gix_glob:: Pattern ;
5
3
use kstring:: { KString , KStringRef } ;
6
4
5
+ use crate :: search:: refmap:: RefMapKey ;
7
6
use crate :: {
8
7
search:: {
9
- Assignments , AttributeId , Attributes , Match , MatchKind , MatchLocation , Metadata , MetadataCollection , Outcome ,
10
- TrackedAssignment , Value ,
8
+ Assignments , AttributeId , Attributes , MatchKind , Metadata , MetadataCollection , Outcome , TrackedAssignment ,
9
+ Value ,
11
10
} ,
12
- Assignment , NameRef , State ,
11
+ AssignmentRef , NameRef , StateRef ,
13
12
} ;
14
13
15
14
/// Initialization
16
- impl < ' pattern > Outcome < ' pattern > {
15
+ impl Outcome {
17
16
/// Initialize this instance to collect outcomes for all names in `collection`, which represents all possible attributes
18
- /// or macros we may visit.
17
+ /// or macros we may visit, and [`reset`][Self::reset()] it unconditionally .
19
18
///
20
19
/// This must be called after each time `collection` changes.
21
20
pub fn initialize ( & mut self , collection : & MetadataCollection ) {
@@ -74,7 +73,7 @@ impl<'pattern> Outcome<'pattern> {
74
73
}
75
74
76
75
/// Access
77
- impl < ' pattern > Outcome < ' pattern > {
76
+ impl Outcome {
78
77
/// Return an iterator over all filled attributes we were initialized with.
79
78
///
80
79
/// ### Note
@@ -88,56 +87,63 @@ impl<'pattern> Outcome<'pattern> {
88
87
/// the same as what `git` provides.
89
88
/// Ours is in order of declaration, whereas `git` seems to list macros first somehow. Since the values are the same, this
90
89
/// shouldn't be an issue.
91
- pub fn iter < ' a > ( & ' a self ) -> impl Iterator < Item = & ' a Match < ' pattern > > + ' a {
92
- self . matches_by_id . iter ( ) . filter_map ( |item| item. r#match . as_ref ( ) )
90
+ pub fn iter ( & self ) -> impl Iterator < Item = crate :: search:: Match < ' _ > > {
91
+ self . matches_by_id
92
+ . iter ( )
93
+ . filter_map ( |item| item. r#match . as_ref ( ) . map ( |m| m. to_outer ( self ) ) )
93
94
}
94
95
95
96
/// Iterate over all matches of the attribute selection in their original order.
96
- pub fn iter_selected < ' a > ( & ' a self ) -> impl Iterator < Item = Cow < ' a , Match < ' pattern > > > + ' a {
97
+ ///
98
+ /// This only yields values if this instance was initialized with [`Outcome::initialize_with_selection()`].
99
+ pub fn iter_selected ( & self ) -> impl Iterator < Item = crate :: search:: Match < ' _ > > {
97
100
static DUMMY : Pattern = Pattern {
98
101
text : BString :: new ( Vec :: new ( ) ) ,
99
102
mode : gix_glob:: pattern:: Mode :: empty ( ) ,
100
103
first_wildcard_pos : None ,
101
104
} ;
102
105
self . selected . iter ( ) . map ( |( name, id) | {
103
- id. and_then ( |id| self . matches_by_id [ id. 0 ] . r#match . as_ref ( ) )
104
- . map ( Cow :: Borrowed )
105
- . unwrap_or_else ( || {
106
- Cow :: Owned ( Match {
107
- pattern : & DUMMY ,
108
- assignment : Assignment {
109
- name : NameRef :: try_from ( name. as_bytes ( ) . as_bstr ( ) )
110
- . unwrap_or_else ( |_| NameRef ( "invalid" . into ( ) ) )
111
- . to_owned ( ) ,
112
- state : State :: Unspecified ,
113
- } ,
114
- kind : MatchKind :: Attribute { macro_id : None } ,
115
- location : MatchLocation {
116
- source : None ,
117
- sequence_number : 0 ,
118
- } ,
119
- } )
106
+ id. and_then ( |id| self . matches_by_id [ id. 0 ] . r#match . as_ref ( ) . map ( |m| m. to_outer ( self ) ) )
107
+ . unwrap_or_else ( || crate :: search:: Match {
108
+ pattern : & DUMMY ,
109
+ assignment : AssignmentRef {
110
+ name : NameRef :: try_from ( name. as_bytes ( ) . as_bstr ( ) )
111
+ . unwrap_or_else ( |_| NameRef ( "invalid" . into ( ) ) ) ,
112
+ state : StateRef :: Unspecified ,
113
+ } ,
114
+ kind : MatchKind :: Attribute { macro_id : None } ,
115
+ location : crate :: search:: MatchLocation {
116
+ source : None ,
117
+ sequence_number : 0 ,
118
+ } ,
120
119
} )
121
120
} )
122
121
}
123
122
124
123
/// Obtain a match by the order of its attribute, if the order exists in our initialized attribute list and there was a match.
125
- pub fn match_by_id ( & self , id : AttributeId ) -> Option < & Match < ' pattern > > {
126
- self . matches_by_id . get ( id. 0 ) . and_then ( |m| m. r#match . as_ref ( ) )
124
+ pub fn match_by_id ( & self , id : AttributeId ) -> Option < crate :: search:: Match < ' _ > > {
125
+ self . matches_by_id
126
+ . get ( id. 0 )
127
+ . and_then ( |m| m. r#match . as_ref ( ) . map ( |m| m. to_outer ( self ) ) )
128
+ }
129
+
130
+ /// Return `true` if there is nothing more to be done as all attributes were filled.
131
+ pub fn is_done ( & self ) -> bool {
132
+ self . remaining ( ) == 0
127
133
}
128
134
}
129
135
130
136
/// Mutation
131
- impl < ' pattern > Outcome < ' pattern > {
137
+ impl Outcome {
132
138
/// Fill all `attrs` and resolve them recursively if they are macros. Return `true` if there is no attribute left to be resolved and
133
139
/// we are totally done.
134
140
/// `pattern` is what matched a patch and is passed for contextual information,
135
141
/// providing `sequence_number` and `source` as well.
136
142
pub ( crate ) fn fill_attributes < ' a > (
137
143
& mut self ,
138
144
attrs : impl Iterator < Item = & ' a TrackedAssignment > ,
139
- pattern : & ' pattern gix_glob:: Pattern ,
140
- source : Option < & ' pattern Path > ,
145
+ pattern : & gix_glob:: Pattern ,
146
+ source : Option < & std :: path :: PathBuf > ,
141
147
sequence_number : usize ,
142
148
) -> bool {
143
149
self . attrs_stack . extend ( attrs. filter_map ( |attr| {
@@ -155,8 +161,8 @@ impl<'pattern> Outcome<'pattern> {
155
161
let is_macro = !slot. macro_attributes . is_empty ( ) ;
156
162
157
163
slot. r#match = Some ( Match {
158
- pattern,
159
- assignment : assignment . to_owned ( ) ,
164
+ pattern : self . patterns . insert ( pattern ) ,
165
+ assignment : self . assignments . insert_owned ( assignment ) ,
160
166
kind : if is_macro {
161
167
MatchKind :: Macro {
162
168
parent_macro_id : parent_order,
@@ -165,7 +171,7 @@ impl<'pattern> Outcome<'pattern> {
165
171
MatchKind :: Attribute { macro_id : parent_order }
166
172
} ,
167
173
location : MatchLocation {
168
- source,
174
+ source : source . map ( |path| self . source_paths . insert ( path ) ) ,
169
175
sequence_number,
170
176
} ,
171
177
} ) ;
@@ -188,7 +194,7 @@ impl<'pattern> Outcome<'pattern> {
188
194
}
189
195
}
190
196
191
- impl < ' attr > Outcome < ' attr > {
197
+ impl Outcome {
192
198
/// Given a list of `attrs` by order, return true if at least one of them is not set
193
199
pub ( crate ) fn has_unspecified_attributes ( & self , mut attrs : impl Iterator < Item = AttributeId > ) -> bool {
194
200
attrs. any ( |order| self . matches_by_id [ order. 0 ] . r#match . is_none ( ) )
@@ -201,11 +207,6 @@ impl<'attr> Outcome<'attr> {
201
207
. expect ( "BUG: instance must be initialized for each search set" )
202
208
}
203
209
204
- /// Return true if there is nothing more to be done as all attributes were filled.
205
- pub ( crate ) fn is_done ( & self ) -> bool {
206
- self . remaining ( ) == 0
207
- }
208
-
209
210
fn reduce_and_check_if_done ( & mut self , attr : AttributeId ) -> bool {
210
211
if self . selected . is_empty ( )
211
212
|| self
@@ -314,3 +315,51 @@ impl MatchKind {
314
315
}
315
316
}
316
317
}
318
+
319
+ /// A version of `Match` without references.
320
+ #[ derive( Clone , PartialEq , Eq , Debug , Hash , Ord , PartialOrd ) ]
321
+ pub struct Match {
322
+ /// The glob pattern itself, like `/target/*`.
323
+ pub pattern : RefMapKey ,
324
+ /// The key=value pair of the attribute that matched at the pattern. There can be multiple matches per pattern.
325
+ pub assignment : RefMapKey ,
326
+ /// Additional information about the kind of match.
327
+ pub kind : MatchKind ,
328
+ /// Information about the location of the match.
329
+ pub location : MatchLocation ,
330
+ }
331
+
332
+ impl Match {
333
+ fn to_outer < ' a > ( & self , out : & ' a Outcome ) -> crate :: search:: Match < ' a > {
334
+ crate :: search:: Match {
335
+ pattern : out. patterns . resolve ( self . pattern ) . expect ( "pattern still present" ) ,
336
+ assignment : out
337
+ . assignments
338
+ . resolve ( self . assignment )
339
+ . expect ( "assignment present" )
340
+ . as_ref ( ) ,
341
+ kind : self . kind ,
342
+ location : self . location . to_outer ( out) ,
343
+ }
344
+ }
345
+ }
346
+
347
+ /// A version of `MatchLocation` without references.
348
+ #[ derive( Clone , PartialEq , Eq , Debug , Hash , Ord , PartialOrd ) ]
349
+ pub struct MatchLocation {
350
+ /// The path to the source from which the pattern was loaded, or `None` if it was specified by other means.
351
+ pub source : Option < RefMapKey > ,
352
+ /// The line at which the pattern was found in its `source` file, or the occurrence in which it was provided.
353
+ pub sequence_number : usize ,
354
+ }
355
+
356
+ impl MatchLocation {
357
+ fn to_outer < ' a > ( & self , out : & ' a Outcome ) -> crate :: search:: MatchLocation < ' a > {
358
+ crate :: search:: MatchLocation {
359
+ source : self
360
+ . source
361
+ . and_then ( |source| out. source_paths . resolve ( source) . map ( |p| p. as_path ( ) ) ) ,
362
+ sequence_number : self . sequence_number ,
363
+ }
364
+ }
365
+ }
0 commit comments