cargo_feature_matrix/
features.rs1use crate::Config;
2use cargo_metadata::Package;
3use derive_more::{AsMut, AsRef, Deref, DerefMut};
4use itertools::Itertools;
5use serde::{Deserialize, Serialize};
6use std::{
7 borrow::Cow,
8 collections::BTreeSet,
9 fmt::{Display, Formatter},
10};
11
12#[derive(
13 Clone, Debug, Default, Deref, DerefMut, AsRef, AsMut, Serialize, Deserialize,
14)]
15#[serde(transparent)]
16pub struct FeatureMatrix<'f>(#[serde(borrow)] BTreeSet<FeatureSet<'f>>);
17
18impl<'f> FeatureMatrix<'f> {
19 pub(crate) fn new(package: &'f Package, config: &'f Config<'f>) -> Self {
20 let mut include = config.include.clone();
21 include.add_transitive_features(package);
22 let include = include;
23
24 extract_seed(package, config)
25 .into_iter()
26 .powerset()
27 .map(FeatureSet::from_iter)
28 .map(|mut set| {
29 set.extend(include.clone());
30 set.add_transitive_features(package);
31 set
32 })
33 .filter(|set| set.is_disjoint(&config.deny))
34 .filter(|set| !config.skip.iter().any(|skip| skip == set))
35 .filter(|set| {
36 !config
37 .conflict
38 .iter()
39 .any(|conflict| set.is_superset(conflict))
40 })
41 .collect()
42 }
43}
44
45fn extract_seed<'f>(
48 package: &'f Package,
49 config: &'f Config<'f>,
50) -> FeatureSet<'f> {
51 if !config.seed.is_empty() {
52 config.seed.clone()
53 } else {
54 package
55 .features
56 .keys()
57 .map(|feature| Feature(Cow::Borrowed(feature)))
58 .filter(|feature| feature.0 != "default")
60 .filter(|feature| !feature.starts_with("dep:"))
61 .filter(|package| !config.deny.iter().contains(package))
63 .filter(|package| !config.include.iter().contains(package))
65 .filter(|feature| {
67 config.include_hidden || !feature.starts_with("__")
68 })
69 .collect()
70 }
71}
72
73#[derive(
74 Clone,
75 Debug,
76 Default,
77 Ord,
78 PartialOrd,
79 Eq,
80 PartialEq,
81 Hash,
82 Deref,
83 DerefMut,
84 AsRef,
85 AsMut,
86 Serialize,
87 Deserialize,
88)]
89#[serde(transparent)]
90pub struct FeatureSet<'f>(BTreeSet<Feature<'f>>);
91
92impl<'f> FeatureSet<'f> {
93 fn add_transitive_features(&mut self, package: &'f Package) {
94 let raw_features = &package.features;
95 let transitive = self
96 .iter()
97 .filter_map(|feature| {
98 raw_features.get(feature.as_ref()).map(|transitives| {
99 transitives
100 .iter()
101 .filter(|transitive| !transitive.starts_with("dep:"))
102 .map(AsRef::as_ref)
103 })
104 })
105 .flatten()
106 .map(Cow::Borrowed)
107 .map(Feature)
108 .collect_vec();
109 self.extend(transitive);
110 }
111}
112
113#[derive(
114 Clone,
115 Debug,
116 Ord,
117 PartialOrd,
118 Eq,
119 PartialEq,
120 Hash,
121 Deref,
122 DerefMut,
123 AsRef,
124 AsMut,
125 Serialize,
126 Deserialize,
127)]
128#[serde(transparent)]
129#[as_ref(forward)]
130#[as_mut(forward)]
131pub struct Feature<'f>(pub(crate) Cow<'f, str>);
132
133impl<'f> FromIterator<FeatureSet<'f>> for FeatureMatrix<'f> {
134 fn from_iter<T: IntoIterator<Item = FeatureSet<'f>>>(iter: T) -> Self {
135 FeatureMatrix(iter.into_iter().collect())
136 }
137}
138
139impl<'f> IntoIterator for FeatureMatrix<'f> {
140 type Item = FeatureSet<'f>;
141 type IntoIter = <<Self as Deref>::Target as IntoIterator>::IntoIter;
142
143 fn into_iter(self) -> Self::IntoIter {
144 self.0.into_iter()
145 }
146}
147
148impl Display for FeatureSet<'_> {
149 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
150 let mut iter = self.iter();
151 if let Some(feature) = iter.next() {
152 Display::fmt(feature, f)?;
153 }
154 for feature in iter {
155 write!(f, ",{}", feature)?;
156 }
157 Ok(())
158 }
159}
160
161impl<'f> FromIterator<Feature<'f>> for FeatureSet<'f> {
162 fn from_iter<T: IntoIterator<Item = Feature<'f>>>(iter: T) -> Self {
163 FeatureSet(iter.into_iter().collect())
164 }
165}
166
167impl<'f> IntoIterator for FeatureSet<'f> {
168 type Item = Feature<'f>;
169 type IntoIter = <<Self as Deref>::Target as IntoIterator>::IntoIter;
170
171 fn into_iter(self) -> Self::IntoIter {
172 self.0.into_iter()
173 }
174}
175
176impl Display for Feature<'_> {
177 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
178 Display::fmt(&self.0, f)
179 }
180}
181
182impl From<String> for Feature<'static> {
183 fn from(s: String) -> Self {
184 Feature(Cow::Owned(s))
185 }
186}