@@ -16,10 +16,20 @@ use std::collections::{HashMap, VecDeque};
16
16
17
17
const DEFAULT_NAME : & str = "default" ;
18
18
19
+ #[ derive( Debug , Clone , Serialize ) ]
20
+ struct DocsFeature {
21
+ name : String ,
22
+ subfeatures : Vec < String > ,
23
+ is_default : bool ,
24
+ }
25
+
26
+ type AllFeatures = HashMap < String , DocsFeature > ;
27
+
19
28
#[ derive( Debug , Clone , Serialize ) ]
20
29
struct FeaturesPage {
21
30
metadata : MetaData ,
22
- features : Option < Vec < Feature > > ,
31
+ all_features : AllFeatures ,
32
+ sorted_features : Option < Vec < String > > ,
23
33
default_len : usize ,
24
34
canonical_url : CanonicalUrl ,
25
35
is_latest_url : bool ,
@@ -66,18 +76,21 @@ pub(crate) async fn build_features_handler(
66
76
. await ?
67
77
. ok_or_else ( || anyhow ! ( "missing release" ) ) ?;
68
78
69
- let mut features = None ;
79
+ let mut all_features = HashMap :: new ( ) ;
80
+ let mut sorted_features = None ;
70
81
let mut default_len = 0 ;
71
82
72
83
if let Some ( raw_features) = row. features {
73
84
let result = order_features_and_count_default_len ( raw_features) ;
74
- features = Some ( result. 0 ) ;
75
- default_len = result. 1 ;
85
+ all_features = result. 0 ;
86
+ sorted_features = Some ( result. 1 ) ;
87
+ default_len = result. 2 ;
76
88
}
77
89
78
90
Ok ( FeaturesPage {
79
91
metadata,
80
- features,
92
+ all_features,
93
+ sorted_features,
81
94
default_len,
82
95
is_latest_url : req_version. is_latest ( ) ,
83
96
canonical_url : CanonicalUrl :: from_path ( format ! ( "/crate/{}/latest/features" , & name) ) ,
@@ -86,40 +99,64 @@ pub(crate) async fn build_features_handler(
86
99
. into_response ( ) )
87
100
}
88
101
89
- fn order_features_and_count_default_len ( raw : Vec < Feature > ) -> ( Vec < Feature > , usize ) {
90
- let mut feature_map = get_feature_map ( raw) ;
91
- let mut features = get_tree_structure_from_default ( & mut feature_map) ;
92
- let mut remaining = Vec :: from_iter ( feature_map. into_values ( ) ) ;
93
- remaining. sort_by_key ( |feature| feature. subfeatures . len ( ) ) ;
102
+ fn order_features_and_count_default_len ( raw : Vec < Feature > ) -> ( AllFeatures , Vec < String > , usize ) {
103
+ let mut all_features = get_all_features ( raw) ;
104
+ let sorted_features = get_sorted_features ( & mut all_features) ;
94
105
95
- let default_len = features . len ( ) ;
106
+ let default_len = all_features . values ( ) . filter ( |f| f . is_default ) . count ( ) ;
96
107
97
- features. extend ( remaining. into_iter ( ) . rev ( ) ) ;
98
- ( features, default_len)
108
+ ( all_features, sorted_features, default_len)
99
109
}
100
110
101
- fn get_tree_structure_from_default ( feature_map : & mut HashMap < String , Feature > ) -> Vec < Feature > {
102
- let mut features = Vec :: new ( ) ;
103
- let mut queue: VecDeque < String > = VecDeque :: new ( ) ;
104
-
105
- queue. push_back ( DEFAULT_NAME . into ( ) ) ;
106
- while !queue. is_empty ( ) {
107
- let name = queue. pop_front ( ) . unwrap ( ) ;
108
- if let Some ( feature) = feature_map. remove ( & name) {
111
+ /// This flags all features as being reachable from `"default"`,
112
+ /// and returns them as a sorted list.
113
+ ///
114
+ /// The sorting order depends on depth-first traversal of the default features,
115
+ /// and alphabetically otherwise.
116
+ fn get_sorted_features ( all_features : & mut AllFeatures ) -> Vec < String > {
117
+ let mut sorted_features = Vec :: new ( ) ;
118
+ let mut working_features: HashMap < & str , & mut DocsFeature > = all_features
119
+ . iter_mut ( )
120
+ . map ( |( k, v) | ( k. as_str ( ) , v) )
121
+ . collect ( ) ;
122
+
123
+ // this does a depth-first traversal starting at the special `"default"` feature
124
+ let mut queue: VecDeque < & str > = VecDeque :: new ( ) ;
125
+ queue. push_back ( DEFAULT_NAME ) ;
126
+
127
+ while let Some ( name) = queue. pop_front ( ) {
128
+ if let Some ( feature) = working_features. remove ( name) {
109
129
feature
110
130
. subfeatures
111
131
. iter ( )
112
- . for_each ( |sub| queue. push_back ( sub. clone ( ) ) ) ;
113
- features. push ( feature) ;
132
+ . for_each ( |sub| queue. push_back ( sub. as_str ( ) ) ) ;
133
+ feature. is_default = true ;
134
+ sorted_features. push ( feature. name . clone ( ) ) ;
114
135
}
115
136
}
116
- features
137
+
138
+ // the rest of the features not reachable from `"default"` are sorted alphabetically
139
+ let mut remaining = Vec :: from_iter ( working_features. into_values ( ) ) ;
140
+ remaining. sort_by ( |f1, f2| f2. name . cmp ( & f1. name ) ) ;
141
+ sorted_features. extend ( remaining. into_iter ( ) . map ( |f| f. name . clone ( ) ) . rev ( ) ) ;
142
+
143
+ sorted_features
117
144
}
118
145
119
- fn get_feature_map ( raw : Vec < Feature > ) -> HashMap < String , Feature > {
146
+ /// Parses the raw [`Feature`] into a map of the more structured [`DocsFeature`].
147
+ fn get_all_features ( raw : Vec < Feature > ) -> AllFeatures {
120
148
raw. into_iter ( )
121
149
. filter ( |feature| !feature. is_private ( ) )
122
- . map ( |feature| ( feature. name . clone ( ) , feature) )
150
+ . map ( |feature| {
151
+ (
152
+ feature. name . clone ( ) ,
153
+ DocsFeature {
154
+ name : feature. name ,
155
+ subfeatures : feature. subfeatures ,
156
+ is_default : false ,
157
+ } ,
158
+ )
159
+ } )
123
160
. collect ( )
124
161
}
125
162
@@ -135,11 +172,11 @@ mod tests {
135
172
let feature2 = Feature :: new ( "feature2" . into ( ) , Vec :: new ( ) ) ;
136
173
137
174
let raw = vec ! [ private1. clone( ) , feature2. clone( ) ] ;
138
- let feature_map = get_feature_map ( raw) ;
175
+ let all_features = get_all_features ( raw) ;
139
176
140
- assert_eq ! ( feature_map . len( ) , 1 ) ;
141
- assert ! ( feature_map . contains_key( & feature2. name) ) ;
142
- assert ! ( !feature_map . contains_key( & private1. name) ) ;
177
+ assert_eq ! ( all_features . len( ) , 1 ) ;
178
+ assert ! ( all_features . contains_key( & feature2. name) ) ;
179
+ assert ! ( !all_features . contains_key( & private1. name) ) ;
143
180
}
144
181
145
182
#[ test]
@@ -160,17 +197,23 @@ mod tests {
160
197
feature2. clone( ) ,
161
198
feature1. clone( ) ,
162
199
] ;
163
- let mut feature_map = get_feature_map ( raw) ;
164
- let default_tree = get_tree_structure_from_default ( & mut feature_map) ;
165
-
166
- assert_eq ! ( feature_map. len( ) , 1 ) ;
167
- assert_eq ! ( default_tree. len( ) , 4 ) ;
168
- assert ! ( feature_map. contains_key( & non_default. name) ) ;
169
- assert ! ( !feature_map. contains_key( & default . name) ) ;
170
- assert_eq ! ( default_tree[ 0 ] , default ) ;
171
- assert_eq ! ( default_tree[ 1 ] , feature1) ;
172
- assert_eq ! ( default_tree[ 2 ] , feature2) ;
173
- assert_eq ! ( default_tree[ 3 ] , feature3) ;
200
+ let mut all_features = get_all_features ( raw) ;
201
+ let sorted_features = get_sorted_features ( & mut all_features) ;
202
+
203
+ assert_eq ! ( all_features. len( ) , 5 ) ;
204
+
205
+ assert_eq ! (
206
+ sorted_features,
207
+ vec![
208
+ "default" . to_string( ) ,
209
+ "feature1" . into( ) ,
210
+ "feature2" . into( ) ,
211
+ "feature3" . into( ) ,
212
+ "non-default" . into( )
213
+ ]
214
+ ) ;
215
+ assert ! ( all_features[ "feature3" ] . is_default) ;
216
+ assert ! ( !all_features[ "non-default" ] . is_default) ;
174
217
}
175
218
176
219
#[ test]
@@ -183,14 +226,16 @@ mod tests {
183
226
let feature3 = Feature :: new ( "feature3" . into ( ) , Vec :: new ( ) ) ;
184
227
185
228
let raw = vec ! [ feature3. clone( ) , feature2. clone( ) , feature1. clone( ) ] ;
186
- let mut feature_map = get_feature_map ( raw) ;
187
- let default_tree = get_tree_structure_from_default ( & mut feature_map) ;
188
-
189
- assert_eq ! ( feature_map. len( ) , 3 ) ;
190
- assert_eq ! ( default_tree. len( ) , 0 ) ;
191
- assert ! ( feature_map. contains_key( & feature1. name) ) ;
192
- assert ! ( feature_map. contains_key( & feature2. name) ) ;
193
- assert ! ( feature_map. contains_key( & feature3. name) ) ;
229
+ let mut all_features = get_all_features ( raw) ;
230
+ let sorted_features = get_sorted_features ( & mut all_features) ;
231
+
232
+ assert_eq ! (
233
+ sorted_features,
234
+ vec![ "feature1" . to_string( ) , "feature2" . into( ) , "feature3" . into( ) ]
235
+ ) ;
236
+ assert ! ( !all_features[ "feature1" ] . is_default) ;
237
+ assert ! ( !all_features[ "feature2" ] . is_default) ;
238
+ assert ! ( !all_features[ "feature3" ] . is_default) ;
194
239
}
195
240
196
241
#[ test]
@@ -199,14 +244,15 @@ mod tests {
199
244
let non_default = Feature :: new ( "non-default" . into ( ) , Vec :: new ( ) ) ;
200
245
201
246
let raw = vec ! [ default . clone( ) , non_default. clone( ) ] ;
202
- let mut feature_map = get_feature_map ( raw) ;
203
- let default_tree = get_tree_structure_from_default ( & mut feature_map) ;
204
-
205
- assert_eq ! ( feature_map. len( ) , 1 ) ;
206
- assert_eq ! ( default_tree. len( ) , 1 ) ;
207
- assert ! ( feature_map. contains_key( & non_default. name) ) ;
208
- assert ! ( !feature_map. contains_key( & default . name) ) ;
209
- assert_eq ! ( default_tree[ 0 ] , default ) ;
247
+ let mut all_features = get_all_features ( raw) ;
248
+ let sorted_features = get_sorted_features ( & mut all_features) ;
249
+
250
+ assert_eq ! (
251
+ sorted_features,
252
+ vec![ "default" . to_string( ) , "non-default" . into( ) ]
253
+ ) ;
254
+ assert ! ( all_features[ "default" ] . is_default) ;
255
+ assert ! ( !all_features[ "non-default" ] . is_default) ;
210
256
}
211
257
212
258
#[ test]
@@ -219,13 +265,14 @@ mod tests {
219
265
let feature3 = Feature :: new ( "feature3" . into ( ) , Vec :: new ( ) ) ;
220
266
221
267
let raw = vec ! [ feature3. clone( ) , feature2. clone( ) , feature1. clone( ) ] ;
222
- let ( features, default_len) = order_features_and_count_default_len ( raw) ;
268
+ let ( _all_features, sorted_features, default_len) =
269
+ order_features_and_count_default_len ( raw) ;
223
270
224
- assert_eq ! ( features. len( ) , 3 ) ;
271
+ assert_eq ! (
272
+ sorted_features,
273
+ vec![ "feature1" . to_string( ) , "feature2" . into( ) , "feature3" . into( ) ]
274
+ ) ;
225
275
assert_eq ! ( default_len, 0 ) ;
226
- assert_eq ! ( features[ 0 ] , feature1) ;
227
- assert_eq ! ( features[ 1 ] , feature2) ;
228
- assert_eq ! ( features[ 2 ] , feature3) ;
229
276
}
230
277
231
278
#[ test]
@@ -234,12 +281,14 @@ mod tests {
234
281
let non_default = Feature :: new ( "non-default" . into ( ) , Vec :: new ( ) ) ;
235
282
236
283
let raw = vec ! [ default . clone( ) , non_default. clone( ) ] ;
237
- let ( features, default_len) = order_features_and_count_default_len ( raw) ;
284
+ let ( _all_features, sorted_features, default_len) =
285
+ order_features_and_count_default_len ( raw) ;
238
286
239
- assert_eq ! ( features. len( ) , 2 ) ;
287
+ assert_eq ! (
288
+ sorted_features,
289
+ vec![ "default" . to_string( ) , "non-default" . into( ) ]
290
+ ) ;
240
291
assert_eq ! ( default_len, 1 ) ;
241
- assert_eq ! ( features[ 0 ] , default ) ;
242
- assert_eq ! ( features[ 1 ] , non_default) ;
243
292
}
244
293
245
294
#[ test]
0 commit comments