1
+ use std:: collections:: HashSet ;
1
2
use std:: path:: Path ;
2
3
use toml:: Value ;
3
4
use error:: Result ;
@@ -63,7 +64,16 @@ pub struct Metadata {
63
64
pub rustdoc_args : Option < Vec < String > > ,
64
65
}
65
66
66
-
67
+ /// The targets that should be built for a crate.
68
+ ///
69
+ /// The `default_target` is the target to be used as the home page for that crate.
70
+ ///
71
+ /// # See also
72
+ /// - [`Metadata::targets`](struct.Metadata.html#method.targets)
73
+ pub ( super ) struct BuildTargets < ' a > {
74
+ pub ( super ) default_target : & ' a str ,
75
+ pub ( super ) other_targets : HashSet < & ' a str > ,
76
+ }
67
77
68
78
impl Metadata {
69
79
pub ( crate ) fn from_source_dir ( source_dir : & Path ) -> Result < Metadata > {
@@ -136,39 +146,21 @@ impl Metadata {
136
146
metadata
137
147
}
138
148
// Return (default_target, all other targets that should be built with duplicates removed)
139
- pub ( super ) fn targets ( & self ) -> ( & str , Vec < & str > ) {
149
+ pub ( super ) fn targets ( & self ) -> BuildTargets < ' _ > {
140
150
use super :: rustwide_builder:: { HOST_TARGET , TARGETS } ;
151
+
152
+ let default_target = self . default_target . as_deref ( )
153
+ // Use the first element of `targets` if `default_target` is unset and `targets` is non-empty
154
+ . or_else ( || self . targets . as_ref ( ) . and_then ( |targets| targets. iter ( ) . next ( ) . map ( String :: as_str) ) )
155
+ . unwrap_or ( HOST_TARGET ) ;
156
+
141
157
// Let people opt-in to only having specific targets
142
- // Ideally this would use Iterator instead of Vec so I could collect to a `HashSet`,
143
- // but I had trouble with `chain()` ¯\_(ツ)_/¯
144
- let mut all_targets: Vec < _ > = self . default_target . as_deref ( ) . into_iter ( ) . collect ( ) ;
145
- match & self . targets {
146
- Some ( targets) => all_targets. extend ( targets. iter ( ) . map ( |s| s. as_str ( ) ) ) ,
147
- None if all_targets. is_empty ( ) => {
148
- // Make sure HOST_TARGET is first
149
- all_targets. push ( HOST_TARGET ) ;
150
- all_targets. extend ( TARGETS . iter ( ) . copied ( ) . filter ( |& t| t != HOST_TARGET ) ) ;
151
- }
152
- None => all_targets. extend ( TARGETS . iter ( ) . copied ( ) ) ,
153
- } ;
158
+ let mut targets: HashSet < _ > = self . targets . as_ref ( )
159
+ . map ( |targets| targets. iter ( ) . map ( String :: as_str) . collect ( ) )
160
+ . unwrap_or_else ( || TARGETS . iter ( ) . copied ( ) . collect ( ) ) ;
154
161
155
- // default_target unset and targets set to `[]`
156
- let landing_page = if all_targets. is_empty ( ) {
157
- HOST_TARGET
158
- } else {
159
- // This `swap_remove` has to come before the `sort()` to keep the ordering
160
- // `swap_remove` is ok because ordering doesn't matter except for first element
161
- all_targets. swap_remove ( 0 )
162
- } ;
163
- // Remove duplicates
164
- all_targets. sort ( ) ;
165
- all_targets. dedup ( ) ;
166
- // Remove landing_page so we don't build it twice.
167
- // It wasn't removed during dedup because we called `swap_remove()` first.
168
- if let Ok ( index) = all_targets. binary_search ( & landing_page) {
169
- all_targets. swap_remove ( index) ;
170
- }
171
- ( landing_page, all_targets)
162
+ targets. remove ( & default_target) ;
163
+ BuildTargets { default_target, other_targets : targets }
172
164
}
173
165
}
174
166
@@ -255,10 +247,11 @@ mod test {
255
247
#[ test]
256
248
fn test_select_targets ( ) {
257
249
use crate :: docbuilder:: rustwide_builder:: { HOST_TARGET , TARGETS } ;
250
+ use super :: BuildTargets ;
258
251
259
252
let mut metadata = Metadata :: default ( ) ;
260
253
// unchanged default_target, targets not specified
261
- let ( default, tier_one) = metadata. targets ( ) ;
254
+ let BuildTargets { default_target : default, other_targets : tier_one } = metadata. targets ( ) ;
262
255
assert_eq ! ( default , HOST_TARGET ) ;
263
256
// should be equal to TARGETS \ {HOST_TARGET}
264
257
for actual in & tier_one {
@@ -274,47 +267,47 @@ mod test {
274
267
275
268
// unchanged default_target, targets specified to be empty
276
269
metadata. targets = Some ( Vec :: new ( ) ) ;
277
- let ( default, others) = metadata. targets ( ) ;
270
+ let BuildTargets { default_target : default, other_targets : others } = metadata. targets ( ) ;
278
271
assert_eq ! ( default , HOST_TARGET ) ;
279
272
assert ! ( others. is_empty( ) ) ;
280
273
281
274
// unchanged default_target, targets non-empty
282
275
metadata. targets = Some ( vec ! [ "i686-pc-windows-msvc" . into( ) , "i686-apple-darwin" . into( ) ] ) ;
283
- let ( default, others) = metadata. targets ( ) ;
276
+ let BuildTargets { default_target : default, other_targets : others } = metadata. targets ( ) ;
284
277
assert_eq ! ( default , "i686-pc-windows-msvc" ) ;
285
278
assert_eq ! ( others. len( ) , 1 ) ;
286
279
assert ! ( others. contains( & "i686-apple-darwin" ) ) ;
287
280
288
281
// make sure that default_target is not built twice
289
282
metadata. targets = Some ( vec ! [ HOST_TARGET . into( ) ] ) ;
290
- let ( default, others) = metadata. targets ( ) ;
283
+ let BuildTargets { default_target : default, other_targets : others } = metadata. targets ( ) ;
291
284
assert_eq ! ( default , HOST_TARGET ) ;
292
285
assert ! ( others. is_empty( ) ) ;
293
286
294
287
// make sure that duplicates are removed
295
288
metadata. targets = Some ( vec ! [ "i686-pc-windows-msvc" . into( ) , "i686-pc-windows-msvc" . into( ) ] ) ;
296
- let ( default, others) = metadata. targets ( ) ;
289
+ let BuildTargets { default_target : default, other_targets : others } = metadata. targets ( ) ;
297
290
assert_eq ! ( default , "i686-pc-windows-msvc" ) ;
298
291
assert ! ( others. is_empty( ) ) ;
299
292
300
293
// make sure that `default_target` always takes priority over `targets`
301
294
metadata. default_target = Some ( "i686-apple-darwin" . into ( ) ) ;
302
- let ( default, others) = metadata. targets ( ) ;
295
+ let BuildTargets { default_target : default, other_targets : others } = metadata. targets ( ) ;
303
296
assert_eq ! ( default , "i686-apple-darwin" ) ;
304
297
assert_eq ! ( others. len( ) , 1 ) ;
305
298
assert ! ( others. contains( & "i686-pc-windows-msvc" ) ) ;
306
299
307
300
// make sure that `default_target` takes priority over `HOST_TARGET`
308
301
metadata. targets = Some ( vec ! [ ] ) ;
309
- let ( default, others) = metadata. targets ( ) ;
302
+ let BuildTargets { default_target : default, other_targets : others } = metadata. targets ( ) ;
310
303
assert_eq ! ( default , "i686-apple-darwin" ) ;
311
304
assert ! ( others. is_empty( ) ) ;
312
305
313
306
// and if `targets` is unset, it should still be set to `TARGETS`
314
307
metadata. targets = None ;
315
- let ( default, others) = metadata. targets ( ) ;
308
+ let BuildTargets { default_target : default, other_targets : others } = metadata. targets ( ) ;
316
309
assert_eq ! ( default , "i686-apple-darwin" ) ;
317
- let tier_one_targets_no_default: Vec < _ > = TARGETS . iter ( ) . filter ( |& & t| t != "i686-apple-darwin" ) . copied ( ) . collect ( ) ;
310
+ let tier_one_targets_no_default = TARGETS . iter ( ) . filter ( |& & t| t != "i686-apple-darwin" ) . copied ( ) . collect ( ) ;
318
311
assert_eq ! ( others, tier_one_targets_no_default) ;
319
312
}
320
313
}
0 commit comments