@@ -859,55 +859,68 @@ fn compatible(a: &semver::Version, b: &semver::Version) -> bool {
859
859
a. patch == b. patch
860
860
}
861
861
862
- // Returns a pair of (feature dependencies, all used features)
863
- //
864
- // The feature dependencies map is a mapping of package name to list of features
865
- // enabled. Each package should be enabled, and each package should have the
866
- // specified set of features enabled. The boolean indicates whether this
867
- // package was specifically requested (rather than just requesting features
868
- // *within* this package).
869
- //
870
- // The all used features set is the set of features which this local package had
871
- // enabled, which is later used when compiling to instruct the code what
872
- // features were enabled.
873
- fn build_features < ' a > ( s : & ' a Summary , method : & ' a Method )
874
- -> CargoResult < ( HashMap < & ' a str , ( bool , Vec < String > ) > , HashSet < & ' a str > ) > {
875
- let mut deps = HashMap :: new ( ) ;
876
- let mut used = HashSet :: new ( ) ;
877
- let mut visited = HashSet :: new ( ) ;
878
- match * method {
879
- Method :: Everything => {
880
- for key in s. features ( ) . keys ( ) {
881
- add_feature ( s, key, & mut deps, & mut used, & mut visited) ?;
882
- }
883
- for dep in s. dependencies ( ) . iter ( ) . filter ( |d| d. is_optional ( ) ) {
884
- add_feature ( s, dep. name ( ) , & mut deps, & mut used,
885
- & mut visited) ?;
886
- }
862
+ struct Requirements < ' a > {
863
+ summary : & ' a Summary ,
864
+ // The deps map is a mapping of package name to list of features enabled.
865
+ // Each package should be enabled, and each package should have the
866
+ // specified set of features enabled. The boolean indicates whether this
867
+ // package was specifically requested (rather than just requesting features
868
+ // *within* this package).
869
+ deps : HashMap < & ' a str , ( bool , Vec < String > ) > ,
870
+ // The used features set is the set of features which this local package had
871
+ // enabled, which is later used when compiling to instruct the code what
872
+ // features were enabled.
873
+ used : HashSet < & ' a str > ,
874
+ visited : HashSet < & ' a str > ,
875
+ }
876
+
877
+ impl < ' r > Requirements < ' r > {
878
+ fn new < ' a > ( summary : & ' a Summary ) -> Requirements < ' a > {
879
+ Requirements {
880
+ summary,
881
+ deps : HashMap :: new ( ) ,
882
+ used : HashSet :: new ( ) ,
883
+ visited : HashSet :: new ( ) ,
887
884
}
888
- Method :: Required { features : requested_features, .. } => {
889
- for feat in requested_features. iter ( ) {
890
- add_feature ( s, feat, & mut deps, & mut used, & mut visited) ?;
891
- }
885
+ }
886
+
887
+ fn require_crate_feature ( & mut self , package : & ' r str , feat : & ' r str ) {
888
+ self . used . insert ( package) ;
889
+ self . deps . entry ( package)
890
+ . or_insert ( ( false , Vec :: new ( ) ) )
891
+ . 1 . push ( feat. to_string ( ) ) ;
892
+ }
893
+
894
+ fn seen ( & mut self , feat : & ' r str ) -> bool {
895
+ if self . visited . insert ( feat) {
896
+ self . used . insert ( feat) ;
897
+ false
898
+ } else {
899
+ true
892
900
}
893
901
}
894
- match * method {
895
- Method :: Everything |
896
- Method :: Required { uses_default_features : true , .. } => {
897
- if s. features ( ) . get ( "default" ) . is_some ( ) {
898
- add_feature ( s, "default" , & mut deps, & mut used,
899
- & mut visited) ?;
902
+
903
+ fn require_dependency ( & mut self , pkg : & ' r str ) {
904
+ if self . seen ( pkg) {
905
+ return ;
906
+ }
907
+ self . deps . entry ( pkg) . or_insert ( ( false , Vec :: new ( ) ) ) . 0 = true ;
908
+ }
909
+
910
+ fn require_feature ( & mut self , feat : & ' r str ) -> CargoResult < ( ) > {
911
+ if self . seen ( feat) {
912
+ return Ok ( ( ) ) ;
913
+ }
914
+ for f in self . summary . features ( ) . get ( feat) . expect ( "must be a valid feature" ) {
915
+ if f == & feat {
916
+ bail ! ( "Cyclic feature dependency: feature `{}` depends on itself" , feat) ;
900
917
}
918
+ self . add_feature ( f) ?;
901
919
}
902
- Method :: Required { uses_default_features : false , .. } => { }
920
+ Ok ( ( ) )
903
921
}
904
- return Ok ( ( deps, used) ) ;
905
922
906
- fn add_feature < ' a > ( s : & ' a Summary ,
907
- feat : & ' a str ,
908
- deps : & mut HashMap < & ' a str , ( bool , Vec < String > ) > ,
909
- used : & mut HashSet < & ' a str > ,
910
- visited : & mut HashSet < & ' a str > ) -> CargoResult < ( ) > {
923
+ fn add_feature ( & mut self , feat : & ' r str ) -> CargoResult < ( ) > {
911
924
if feat. is_empty ( ) { return Ok ( ( ) ) }
912
925
913
926
// If this feature is of the form `foo/bar`, then we just lookup package
@@ -919,44 +932,53 @@ fn build_features<'a>(s: &'a Summary, method: &'a Method)
919
932
let feat_or_package = parts. next ( ) . unwrap ( ) ;
920
933
match parts. next ( ) {
921
934
Some ( feat) => {
922
- let package = feat_or_package;
923
- used. insert ( package) ;
924
- deps. entry ( package)
925
- . or_insert ( ( false , Vec :: new ( ) ) )
926
- . 1 . push ( feat. to_string ( ) ) ;
935
+ self . require_crate_feature ( feat_or_package, feat) ;
927
936
}
928
937
None => {
929
- let feat = feat_or_package;
930
-
931
- //if this feature has already been added, then just return Ok
932
- if !visited. insert ( feat) {
933
- return Ok ( ( ) ) ;
934
- }
935
-
936
- used. insert ( feat) ;
937
- match s. features ( ) . get ( feat) {
938
- Some ( recursive) => {
939
- // This is a feature, add it recursively.
940
- for f in recursive {
941
- if f == feat {
942
- bail ! ( "Cyclic feature dependency: feature `{}` depends \
943
- on itself", feat) ;
944
- }
945
-
946
- add_feature ( s, f, deps, used, visited) ?;
947
- }
948
- }
949
- None => {
950
- // This is a dependency, mark it as explicitly requested.
951
- deps. entry ( feat) . or_insert ( ( false , Vec :: new ( ) ) ) . 0 = true ;
952
- }
938
+ if self . summary . features ( ) . contains_key ( feat_or_package) {
939
+ self . require_feature ( feat_or_package) ?;
940
+ } else {
941
+ self . require_dependency ( feat_or_package) ;
953
942
}
954
943
}
955
944
}
956
945
Ok ( ( ) )
957
946
}
958
947
}
959
948
949
+ // Takes requested features for a single package from the input Method and
950
+ // recurses to find all requested features, dependencies and requested
951
+ // dependency features in a Requirements object, returning it to the resolver.
952
+ fn build_requirements < ' a , ' b : ' a > ( s : & ' a Summary , method : & ' b Method )
953
+ -> CargoResult < Requirements < ' a > > {
954
+ let mut reqs = Requirements :: new ( s) ;
955
+ match * method {
956
+ Method :: Everything => {
957
+ for key in s. features ( ) . keys ( ) {
958
+ reqs. require_feature ( key) ?;
959
+ }
960
+ for dep in s. dependencies ( ) . iter ( ) . filter ( |d| d. is_optional ( ) ) {
961
+ reqs. require_dependency ( dep. name ( ) ) ;
962
+ }
963
+ }
964
+ Method :: Required { features : requested_features, .. } => {
965
+ for feat in requested_features. iter ( ) {
966
+ reqs. add_feature ( feat) ?;
967
+ }
968
+ }
969
+ }
970
+ match * method {
971
+ Method :: Everything |
972
+ Method :: Required { uses_default_features : true , .. } => {
973
+ if s. features ( ) . get ( "default" ) . is_some ( ) {
974
+ reqs. require_feature ( "default" ) ?;
975
+ }
976
+ }
977
+ Method :: Required { uses_default_features : false , .. } => { }
978
+ }
979
+ return Ok ( reqs) ;
980
+ }
981
+
960
982
impl < ' a > Context < ' a > {
961
983
// Activate this summary by inserting it into our list of known activations.
962
984
//
@@ -1117,18 +1139,18 @@ impl<'a> Context<'a> {
1117
1139
let deps = s. dependencies ( ) ;
1118
1140
let deps = deps. iter ( ) . filter ( |d| d. is_transitive ( ) || dev_deps) ;
1119
1141
1120
- let ( mut feature_deps , used_features ) = build_features ( s, method) ?;
1142
+ let mut reqs = build_requirements ( s, method) ?;
1121
1143
let mut ret = Vec :: new ( ) ;
1122
1144
1123
1145
// Next, collect all actually enabled dependencies and their features.
1124
1146
for dep in deps {
1125
1147
// Skip optional dependencies, but not those enabled through a feature
1126
- if dep. is_optional ( ) && !feature_deps . contains_key ( dep. name ( ) ) {
1148
+ if dep. is_optional ( ) && !reqs . deps . contains_key ( dep. name ( ) ) {
1127
1149
continue
1128
1150
}
1129
1151
// So we want this dependency. Move the features we want from `feature_deps`
1130
1152
// to `ret`.
1131
- let base = feature_deps . remove ( dep. name ( ) ) . unwrap_or ( ( false , vec ! [ ] ) ) ;
1153
+ let base = reqs . deps . remove ( dep. name ( ) ) . unwrap_or ( ( false , vec ! [ ] ) ) ;
1132
1154
if !dep. is_optional ( ) && base. 0 {
1133
1155
self . warnings . push (
1134
1156
format ! ( "Package `{}` does not have feature `{}`. It has a required dependency \
@@ -1151,21 +1173,22 @@ impl<'a> Context<'a> {
1151
1173
// Any remaining entries in feature_deps are bugs in that the package does not actually
1152
1174
// have those dependencies. We classified them as dependencies in the first place
1153
1175
// because there is no such feature, either.
1154
- if !feature_deps. is_empty ( ) {
1155
- let unknown = feature_deps. keys ( ) . map ( |s| & s[ ..] )
1156
- . collect :: < Vec < & str > > ( ) ;
1176
+ if !reqs. deps . is_empty ( ) {
1177
+ let unknown = reqs. deps . keys ( )
1178
+ . map ( |s| & s[ ..] )
1179
+ . collect :: < Vec < & str > > ( ) ;
1157
1180
let features = unknown. join ( ", " ) ;
1158
1181
bail ! ( "Package `{}` does not have these features: `{}`" ,
1159
1182
s. package_id( ) , features)
1160
1183
}
1161
1184
1162
1185
// Record what list of features is active for this package.
1163
- if !used_features . is_empty ( ) {
1186
+ if !reqs . used . is_empty ( ) {
1164
1187
let pkgid = s. package_id ( ) ;
1165
1188
1166
1189
let set = self . resolve_features . entry ( pkgid. clone ( ) )
1167
1190
. or_insert_with ( HashSet :: new) ;
1168
- for feature in used_features {
1191
+ for feature in reqs . used {
1169
1192
if !set. contains ( feature) {
1170
1193
set. insert ( feature. to_string ( ) ) ;
1171
1194
}
0 commit comments