guppy/graph/feature/
feature_list.rs1use crate::{
7 graph::{
8 feature::{FeatureId, FeatureLabel},
9 PackageMetadata,
10 },
11 sorted_set::SortedSet,
12 PackageId,
13};
14use std::{fmt, slice, vec};
15
16#[derive(Clone, Eq, PartialEq)]
22pub struct FeatureList<'g> {
23 package: PackageMetadata<'g>,
24 labels: SortedSet<FeatureLabel<'g>>,
25}
26
27impl<'g> FeatureList<'g> {
28 pub fn new(
30 package: PackageMetadata<'g>,
31 labels: impl IntoIterator<Item = FeatureLabel<'g>>,
32 ) -> Self {
33 Self {
34 package,
35 labels: labels.into_iter().collect(),
36 }
37 }
38
39 pub fn package(&self) -> &PackageMetadata<'g> {
41 &self.package
42 }
43
44 pub fn contains(&self, label: FeatureLabel<'_>) -> bool {
46 self.labels.contains(&label)
47 }
48
49 #[inline]
53 pub fn has_base(&self) -> bool {
54 self.contains(FeatureLabel::Base)
55 }
56
57 #[inline]
59 pub fn has_named_feature(&self, feature_name: &str) -> bool {
60 self.contains(FeatureLabel::Named(feature_name))
61 }
62
63 #[inline]
65 pub fn has_optional_dependency(&self, dep_name: &str) -> bool {
66 self.contains(FeatureLabel::OptionalDependency(dep_name))
67 }
68
69 pub fn labels(&self) -> &[FeatureLabel<'g>] {
73 self.labels.as_slice()
74 }
75
76 pub fn named_features(&self) -> impl Iterator<Item = &'g str> + '_ {
80 self.labels.iter().filter_map(|label| match label {
82 FeatureLabel::Named(feature_name) => Some(*feature_name),
83 _ => None,
84 })
85 }
86
87 pub fn optional_deps(&self) -> impl Iterator<Item = &'g str> + '_ {
91 self.labels.iter().filter_map(|label| match label {
93 FeatureLabel::OptionalDependency(dep_name) => Some(*dep_name),
94 _ => None,
95 })
96 }
97
98 pub fn iter<'a>(&'a self) -> Iter<'g, 'a> {
100 self.into_iter()
101 }
102
103 pub fn display_features<'a>(&'a self) -> DisplayFeatures<'g, 'a> {
105 DisplayFeatures(self.labels())
106 }
107
108 pub fn into_labels(self) -> Vec<FeatureLabel<'g>> {
112 self.labels.into_inner().into_vec()
113 }
114}
115
116impl fmt::Debug for FeatureList<'_> {
117 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
118 f.debug_struct("FeatureList")
119 .field("package", self.package.id())
120 .field("labels", &self.display_features())
121 .finish()
122 }
123}
124
125impl<'g> IntoIterator for FeatureList<'g> {
126 type Item = FeatureId<'g>;
127 type IntoIter = IntoIter<'g>;
128
129 fn into_iter(self) -> Self::IntoIter {
130 IntoIter::new(self)
131 }
132}
133
134impl<'a, 'g> IntoIterator for &'a FeatureList<'g> {
135 type Item = FeatureId<'g>;
136 type IntoIter = Iter<'g, 'a>;
137
138 fn into_iter(self) -> Self::IntoIter {
139 Iter::new(self)
140 }
141}
142
143pub struct IntoIter<'g> {
145 package_id: &'g PackageId,
146 iter: vec::IntoIter<FeatureLabel<'g>>,
147}
148
149impl<'g> IntoIter<'g> {
150 pub fn new(feature_list: FeatureList<'g>) -> Self {
152 Self {
153 package_id: feature_list.package.id(),
154 iter: feature_list.into_labels().into_iter(),
155 }
156 }
157}
158
159impl<'g> Iterator for IntoIter<'g> {
160 type Item = FeatureId<'g>;
161
162 fn next(&mut self) -> Option<Self::Item> {
163 self.iter
164 .next()
165 .map(|label| FeatureId::new(self.package_id, label))
166 }
167}
168
169pub struct Iter<'g, 'a> {
171 package_id: &'g PackageId,
172 iter: slice::Iter<'a, FeatureLabel<'g>>,
173}
174
175impl<'g, 'a> Iter<'g, 'a> {
176 pub fn new(feature_list: &'a FeatureList<'g>) -> Self {
178 Self {
179 package_id: feature_list.package.id(),
180 iter: feature_list.labels().iter(),
181 }
182 }
183}
184
185impl<'g> Iterator for Iter<'g, '_> {
186 type Item = FeatureId<'g>;
187
188 fn next(&mut self) -> Option<Self::Item> {
189 self.iter
190 .next()
191 .map(|&label| FeatureId::new(self.package_id, label))
192 }
193}
194
195#[derive(Clone, Copy)]
199pub struct DisplayFeatures<'g, 'a>(&'a [FeatureLabel<'g>]);
200
201impl fmt::Display for DisplayFeatures<'_, '_> {
202 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
203 let len = self.0.len();
204 for (idx, label) in self.0.iter().enumerate() {
205 write!(f, "{}", label)?;
206 if idx < len - 1 {
207 write!(f, ", ")?;
208 }
209 }
210 Ok(())
211 }
212}
213
214impl fmt::Debug for DisplayFeatures<'_, '_> {
215 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
216 write!(f, "{}", self)
218 }
219}