1+ use std:: collections:: HashSet ;
12use std:: path:: Path ;
23use toml:: Value ;
34use error:: Result ;
@@ -63,7 +64,16 @@ pub struct Metadata {
6364 pub rustdoc_args : Option < Vec < String > > ,
6465}
6566
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+ }
6777
6878impl Metadata {
6979 pub ( crate ) fn from_source_dir ( source_dir : & Path ) -> Result < Metadata > {
@@ -136,39 +146,21 @@ impl Metadata {
136146 metadata
137147 }
138148 // 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 < ' _ > {
140150 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+
141157 // 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 ( ) ) ;
154161
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 }
172164 }
173165}
174166
@@ -255,10 +247,11 @@ mod test {
255247 #[ test]
256248 fn test_select_targets ( ) {
257249 use crate :: docbuilder:: rustwide_builder:: { HOST_TARGET , TARGETS } ;
250+ use super :: BuildTargets ;
258251
259252 let mut metadata = Metadata :: default ( ) ;
260253 // 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 ( ) ;
262255 assert_eq ! ( default , HOST_TARGET ) ;
263256 // should be equal to TARGETS \ {HOST_TARGET}
264257 for actual in & tier_one {
@@ -274,47 +267,47 @@ mod test {
274267
275268 // unchanged default_target, targets specified to be empty
276269 metadata. targets = Some ( Vec :: new ( ) ) ;
277- let ( default, others) = metadata. targets ( ) ;
270+ let BuildTargets { default_target : default, other_targets : others } = metadata. targets ( ) ;
278271 assert_eq ! ( default , HOST_TARGET ) ;
279272 assert ! ( others. is_empty( ) ) ;
280273
281274 // unchanged default_target, targets non-empty
282275 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 ( ) ;
284277 assert_eq ! ( default , "i686-pc-windows-msvc" ) ;
285278 assert_eq ! ( others. len( ) , 1 ) ;
286279 assert ! ( others. contains( & "i686-apple-darwin" ) ) ;
287280
288281 // make sure that default_target is not built twice
289282 metadata. targets = Some ( vec ! [ HOST_TARGET . into( ) ] ) ;
290- let ( default, others) = metadata. targets ( ) ;
283+ let BuildTargets { default_target : default, other_targets : others } = metadata. targets ( ) ;
291284 assert_eq ! ( default , HOST_TARGET ) ;
292285 assert ! ( others. is_empty( ) ) ;
293286
294287 // make sure that duplicates are removed
295288 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 ( ) ;
297290 assert_eq ! ( default , "i686-pc-windows-msvc" ) ;
298291 assert ! ( others. is_empty( ) ) ;
299292
300293 // make sure that `default_target` always takes priority over `targets`
301294 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 ( ) ;
303296 assert_eq ! ( default , "i686-apple-darwin" ) ;
304297 assert_eq ! ( others. len( ) , 1 ) ;
305298 assert ! ( others. contains( & "i686-pc-windows-msvc" ) ) ;
306299
307300 // make sure that `default_target` takes priority over `HOST_TARGET`
308301 metadata. targets = Some ( vec ! [ ] ) ;
309- let ( default, others) = metadata. targets ( ) ;
302+ let BuildTargets { default_target : default, other_targets : others } = metadata. targets ( ) ;
310303 assert_eq ! ( default , "i686-apple-darwin" ) ;
311304 assert ! ( others. is_empty( ) ) ;
312305
313306 // and if `targets` is unset, it should still be set to `TARGETS`
314307 metadata. targets = None ;
315- let ( default, others) = metadata. targets ( ) ;
308+ let BuildTargets { default_target : default, other_targets : others } = metadata. targets ( ) ;
316309 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 ( ) ;
318311 assert_eq ! ( others, tier_one_targets_no_default) ;
319312 }
320313}
0 commit comments