1use crate::{
5 DependencyKind, Error, PackageId,
6 debug_ignore::DebugIgnore,
7 errors::FeatureGraphWarning,
8 graph::{
9 DependencyDirection, FeatureIndexInPackage, FeatureIx, PackageGraph, PackageIx,
10 PackageLink, PackageMetadata,
11 feature::{
12 Cycles, FeatureFilter, FeatureList, WeakDependencies, WeakIndex,
13 build::{FeatureGraphBuildState, FeaturePetgraph},
14 },
15 },
16 petgraph_support::{scc::Sccs, topo::TopoWithCycles},
17 platform::{PlatformStatus, PlatformStatusImpl},
18};
19use ahash::AHashMap;
20use once_cell::sync::OnceCell;
21use petgraph::{
22 algo::has_path_connecting,
23 prelude::*,
24 visit::{EdgeFiltered, IntoNodeReferences},
25};
26use std::{fmt, iter, iter::FromIterator};
27
28impl PackageGraph {
52 pub fn feature_graph(&self) -> FeatureGraph<'_> {
57 let inner = self.get_feature_graph();
58 FeatureGraph {
59 package_graph: self,
60 inner,
61 }
62 }
63
64 pub(super) fn get_feature_graph(&self) -> &FeatureGraphImpl {
65 self.feature_graph
66 .get_or_init(|| FeatureGraphImpl::new(self))
67 }
68}
69
70#[derive(Clone, Copy, Debug)]
74pub struct FeatureGraph<'g> {
75 pub(crate) package_graph: &'g PackageGraph,
76 pub(super) inner: &'g FeatureGraphImpl,
77}
78
79assert_covariant!(FeatureGraph);
80
81impl<'g> FeatureGraph<'g> {
82 pub fn build_warnings(&self) -> &'g [FeatureGraphWarning] {
84 &self.inner.warnings
85 }
86
87 pub fn package_graph(&self) -> &'g PackageGraph {
89 self.package_graph
90 }
91
92 pub fn feature_count(&self) -> usize {
96 self.dep_graph().node_count()
97 }
98
99 pub fn link_count(&self) -> usize {
101 self.dep_graph().edge_count()
102 }
103
104 pub fn contains(&self, feature_id: impl Into<FeatureId<'g>>) -> bool {
106 let feature_id = feature_id.into();
107 FeatureNode::from_id(self, feature_id).is_some()
108 }
109
110 pub fn metadata(
112 &self,
113 feature_id: impl Into<FeatureId<'g>>,
114 ) -> Result<FeatureMetadata<'g>, Error> {
115 let feature_id = feature_id.into();
116 let feature_node = FeatureNode::from_id(self, feature_id)
117 .ok_or_else(|| Error::unknown_feature_id(feature_id))?;
118 self.metadata_for_node(feature_node)
119 .ok_or_else(|| Error::unknown_feature_id(feature_id))
120 }
121
122 pub fn all_features_for(&self, package_id: &PackageId) -> Result<FeatureList<'g>, Error> {
126 let package = self.package_graph.metadata(package_id)?;
127 let dep_graph = self.dep_graph();
128 let features = self
129 .feature_ixs_for_package_ix(package.package_ix())
130 .map(|feature_ix| FeatureId::node_to_feature(package, &dep_graph[feature_ix]));
131 Ok(FeatureList::new(package, features))
132 }
133
134 pub fn is_default_feature<'a>(
144 &self,
145 feature_id: impl Into<FeatureId<'a>>,
146 ) -> Result<bool, Error> {
147 let feature_id = feature_id.into();
148 let default_ix = self.feature_ix(
149 self.package_graph
150 .metadata(feature_id.package_id())?
151 .default_feature_id(),
152 )?;
153 let feature_ix = self.feature_ix(feature_id)?;
154 Ok(self.feature_ix_depends_on_no_conditional(default_ix, feature_ix))
156 }
157
158 pub fn depends_on<'a>(
167 &self,
168 feature_a: impl Into<FeatureId<'a>>,
169 feature_b: impl Into<FeatureId<'a>>,
170 ) -> Result<bool, Error> {
171 let feature_a = feature_a.into();
172 let feature_b = feature_b.into();
173 let a_ix = self.feature_ix(feature_a)?;
174 let b_ix = self.feature_ix(feature_b)?;
175 Ok(self.feature_ix_depends_on(a_ix, b_ix))
176 }
177
178 pub fn directly_depends_on<'a>(
185 &self,
186 feature_a: impl Into<FeatureId<'a>>,
187 feature_b: impl Into<FeatureId<'a>>,
188 ) -> Result<bool, Error> {
189 let feature_a = feature_a.into();
190 let feature_b = feature_b.into();
191 let a_ix = self.feature_ix(feature_a)?;
192 let b_ix = self.feature_ix(feature_b)?;
193 Ok(self.dep_graph().contains_edge(a_ix, b_ix))
194 }
195
196 pub fn cycles(&self) -> Cycles<'g> {
200 Cycles::new(*self)
201 }
202
203 #[doc(hidden)]
209 pub fn verify(&self) -> Result<(), Error> {
210 let feature_set = self.resolve_all();
211 for conditional_link in feature_set.conditional_links(DependencyDirection::Forward) {
212 let (from, to) = conditional_link.endpoints();
213 let is_any = conditional_link.normal().is_present()
214 || conditional_link.build().is_present()
215 || conditional_link.dev().is_present();
216
217 if !is_any {
218 return Err(Error::FeatureGraphInternalError(format!(
219 "{} -> {}: no edge info found",
220 from.feature_id(),
221 to.feature_id()
222 )));
223 }
224 }
225
226 Ok(())
227 }
228
229 pub(super) fn sccs(&self) -> &'g Sccs<FeatureIx> {
231 self.inner.sccs.get_or_init(|| {
232 let edge_filtered =
233 EdgeFiltered::from_fn(self.dep_graph(), |edge| match edge.weight() {
234 FeatureEdge::DependenciesSection(link)
235 | FeatureEdge::NamedFeatureDepColon(link)
236 | FeatureEdge::NamedFeatureWithSlash { link, .. } => !link.dev_only(),
237 FeatureEdge::NamedFeature | FeatureEdge::FeatureToBase => true,
238 });
239 let topo = TopoWithCycles::new(&edge_filtered);
243 Sccs::new(&self.inner.graph, |scc| {
244 topo.sort_nodes(scc);
245 })
246 })
247 }
248
249 fn metadata_impl(&self, feature_id: FeatureId<'g>) -> Option<&'g FeatureMetadataImpl> {
250 let feature_node = FeatureNode::from_id(self, feature_id)?;
251 self.metadata_impl_for_node(&feature_node)
252 }
253
254 pub(in crate::graph) fn metadata_for_ix(
255 &self,
256 feature_ix: NodeIndex<FeatureIx>,
257 ) -> FeatureMetadata<'g> {
258 self.metadata_for_node(self.dep_graph()[feature_ix])
259 .expect("valid feature ix")
260 }
261
262 pub(super) fn metadata_for_node(&self, node: FeatureNode) -> Option<FeatureMetadata<'g>> {
263 let inner = self.metadata_impl_for_node(&node)?;
264 Some(FeatureMetadata {
265 graph: DebugIgnore(*self),
266 node,
267 inner,
268 })
269 }
270
271 #[inline]
272 fn metadata_impl_for_node(&self, node: &FeatureNode) -> Option<&'g FeatureMetadataImpl> {
273 self.inner.map.get(node)
274 }
275
276 pub(super) fn dep_graph(&self) -> &'g FeaturePetgraph {
277 &self.inner.graph
278 }
279
280 pub(super) fn edge_to_conditional_link(
282 &self,
283 source_ix: NodeIndex<FeatureIx>,
284 target_ix: NodeIndex<FeatureIx>,
285 edge_ix: EdgeIndex<FeatureIx>,
286 edge: Option<&'g FeatureEdge>,
287 ) -> Option<(ConditionalLink<'g>, Option<WeakIndex>)> {
288 let edge = edge.unwrap_or_else(|| &self.dep_graph()[edge_ix]);
289
290 match edge {
291 FeatureEdge::NamedFeature | FeatureEdge::FeatureToBase => None,
292 FeatureEdge::DependenciesSection(link) | FeatureEdge::NamedFeatureDepColon(link) => {
293 let link = ConditionalLink::new(*self, source_ix, target_ix, edge_ix, link);
294 let weak_index = None;
296 Some((link, weak_index))
297 }
298 FeatureEdge::NamedFeatureWithSlash { link, weak_index } => {
299 let link = ConditionalLink::new(*self, source_ix, target_ix, edge_ix, link);
300 Some((link, *weak_index))
301 }
302 }
303 }
304
305 fn feature_ix_depends_on(
306 &self,
307 a_ix: NodeIndex<FeatureIx>,
308 b_ix: NodeIndex<FeatureIx>,
309 ) -> bool {
310 has_path_connecting(self.dep_graph(), a_ix, b_ix, None)
311 }
312
313 fn feature_ix_depends_on_no_conditional(
314 &self,
315 a_ix: NodeIndex<FeatureIx>,
316 b_ix: NodeIndex<FeatureIx>,
317 ) -> bool {
318 let edge_filtered =
320 EdgeFiltered::from_fn(self.dep_graph(), |edge_ref| match edge_ref.weight() {
321 FeatureEdge::FeatureToBase | FeatureEdge::NamedFeature => true,
322 FeatureEdge::DependenciesSection(_)
323 | FeatureEdge::NamedFeatureDepColon(_)
324 | FeatureEdge::NamedFeatureWithSlash { .. } => false,
325 });
326 has_path_connecting(&edge_filtered, a_ix, b_ix, None)
327 }
328
329 pub(super) fn feature_ixs_for_package_ix(
330 &self,
331 package_ix: NodeIndex<PackageIx>,
332 ) -> impl Iterator<Item = NodeIndex<FeatureIx>> + use<> {
333 let package_ix = package_ix.index();
334 let base_ix = self.inner.base_ixs[package_ix].index();
335 let next_base_ix = self.inner.base_ixs[package_ix + 1].index();
337
338 (base_ix..next_base_ix).map(NodeIndex::new)
339 }
340
341 pub(super) fn feature_ixs_for_package_ixs<I>(
342 &self,
343 package_ixs: I,
344 ) -> impl Iterator<Item = NodeIndex<FeatureIx>> + 'g + use<'g, I>
345 where
346 I: IntoIterator<Item = NodeIndex<PackageIx>> + 'g,
347 {
348 let this = *self;
350
351 package_ixs
352 .into_iter()
353 .flat_map(move |package_ix| this.feature_ixs_for_package_ix(package_ix))
354 }
355
356 pub(in crate::graph) fn feature_ixs_for_package_ixs_filtered<B>(
357 &self,
358 package_ixs: impl IntoIterator<Item = NodeIndex<PackageIx>>,
359 filter: impl FeatureFilter<'g>,
360 ) -> B
361 where
362 B: FromIterator<NodeIndex<FeatureIx>>,
363 {
364 let mut filter = filter;
365
366 self.feature_ixs_for_package_ixs(package_ixs)
367 .filter(|feature_ix| {
368 let feature_node = &self.dep_graph()[*feature_ix];
369 filter.accept(self, FeatureId::from_node(self.package_graph, feature_node))
370 })
371 .collect()
372 }
373
374 pub(in crate::graph) fn package_ix_for_feature_ix(
375 &self,
376 feature_ix: NodeIndex<FeatureIx>,
377 ) -> NodeIndex<PackageIx> {
378 let feature_node = &self.dep_graph()[feature_ix];
379 feature_node.package_ix()
380 }
381
382 #[allow(dead_code)]
383 pub(super) fn feature_ixs<'a, B>(
384 &self,
385 feature_ids: impl IntoIterator<Item = FeatureId<'g>>,
386 ) -> Result<B, Error>
387 where
388 B: iter::FromIterator<NodeIndex<FeatureIx>>,
389 {
390 feature_ids
391 .into_iter()
392 .map(|feature_id| self.feature_ix(feature_id))
393 .collect()
394 }
395
396 pub(super) fn feature_ix(
397 &self,
398 feature_id: FeatureId<'g>,
399 ) -> Result<NodeIndex<FeatureIx>, Error> {
400 let metadata = self
401 .metadata_impl(feature_id)
402 .ok_or_else(|| Error::unknown_feature_id(feature_id))?;
403 Ok(metadata.feature_ix)
404 }
405}
406
407#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
414pub struct FeatureId<'g> {
415 package_id: &'g PackageId,
416 label: FeatureLabel<'g>,
417}
418
419assert_covariant!(FeatureId);
420
421impl<'g> FeatureId<'g> {
422 pub fn new(package_id: &'g PackageId, label: FeatureLabel<'g>) -> Self {
424 Self { package_id, label }
425 }
426
427 pub fn named(package_id: &'g PackageId, feature_name: &'g str) -> Self {
430 Self {
431 package_id,
432 label: FeatureLabel::Named(feature_name),
433 }
434 }
435
436 pub fn optional_dependency(package_id: &'g PackageId, dep_name: &'g str) -> Self {
438 Self {
439 package_id,
440 label: FeatureLabel::OptionalDependency(dep_name),
441 }
442 }
443
444 pub fn base(package_id: &'g PackageId) -> Self {
446 Self {
447 package_id,
448 label: FeatureLabel::Base,
449 }
450 }
451
452 pub(super) fn from_node(package_graph: &'g PackageGraph, node: &FeatureNode) -> Self {
453 let package_id = &package_graph.dep_graph[node.package_ix];
454 let metadata = package_graph
455 .metadata(package_id)
456 .expect("package ID should have valid metadata");
457 let feature = Self::node_to_feature(metadata, node);
458 Self {
459 package_id,
460 label: feature,
461 }
462 }
463
464 pub(super) fn node_to_feature(
465 metadata: PackageMetadata<'g>,
466 node: &FeatureNode,
467 ) -> FeatureLabel<'g> {
468 metadata.feature_idx_to_label(node.feature_idx)
469 }
470
471 pub fn package_id(&self) -> &'g PackageId {
473 self.package_id
474 }
475
476 pub fn label(&self) -> FeatureLabel<'g> {
478 self.label
479 }
480
481 #[inline]
483 pub fn is_base(&self) -> bool {
484 self.label.kind().is_base()
485 }
486
487 #[inline]
489 pub fn is_optional_dependency(self) -> bool {
490 self.label.kind().is_optional_dependency()
491 }
492
493 #[inline]
495 pub fn is_named(self) -> bool {
496 self.label.kind().is_named()
497 }
498}
499
500impl<'g> From<(&'g PackageId, FeatureLabel<'g>)> for FeatureId<'g> {
501 fn from((package_id, label): (&'g PackageId, FeatureLabel<'g>)) -> Self {
502 FeatureId { package_id, label }
503 }
504}
505
506impl fmt::Display for FeatureId<'_> {
536 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
537 write!(f, "{}/{}", self.package_id, self.label)
538 }
539}
540
541#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
543pub enum FeatureLabel<'g> {
544 Base,
546
547 Named(&'g str),
554
555 OptionalDependency(&'g str),
557}
558
559impl FeatureLabel<'_> {
560 #[inline]
564 pub fn kind(self) -> FeatureKind {
565 match self {
566 Self::Base => FeatureKind::Base,
567 Self::Named(_) => FeatureKind::Named,
568 Self::OptionalDependency(_) => FeatureKind::OptionalDependency,
569 }
570 }
571}
572
573impl fmt::Display for FeatureLabel<'_> {
589 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
590 match self {
591 Self::Base => write!(f, "[base]"),
592 Self::Named(feature_name) => write!(f, "{feature_name}"),
593 Self::OptionalDependency(dep_name) => write!(f, "dep:{dep_name}"),
594 }
595 }
596}
597
598#[derive(Clone, Copy)]
600pub struct FeatureMetadata<'g> {
601 graph: DebugIgnore<FeatureGraph<'g>>,
602 node: FeatureNode,
603 inner: &'g FeatureMetadataImpl,
604}
605
606assert_covariant!(FeatureMetadata);
607
608impl<'g> FeatureMetadata<'g> {
609 pub fn feature_id(&self) -> FeatureId<'g> {
611 FeatureId::from_node(self.graph.package_graph, &self.node)
612 }
613
614 pub fn package_id(&self) -> &'g PackageId {
616 &self.graph.package_graph.dep_graph[self.package_ix()]
617 }
618
619 pub fn package(&self) -> PackageMetadata<'g> {
621 self.graph
622 .package_graph
623 .metadata(self.package_id())
624 .expect("valid package ID")
625 }
626
627 pub fn label(&self) -> FeatureLabel<'g> {
629 self.feature_id().label()
630 }
631
632 #[inline]
637 pub(in crate::graph) fn package_ix(&self) -> NodeIndex<PackageIx> {
638 self.node.package_ix
639 }
640
641 #[inline]
642 pub(in crate::graph) fn feature_ix(&self) -> NodeIndex<FeatureIx> {
643 self.inner.feature_ix
644 }
645}
646
647impl fmt::Debug for FeatureMetadata<'_> {
648 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
649 f.debug_struct("FeatureMetadata")
650 .field("id", &self.feature_id())
651 .finish()
652 }
653}
654
655#[derive(Clone, Debug)]
657pub(in crate::graph) struct FeatureGraphImpl {
658 pub(super) graph: FeaturePetgraph,
659 pub(super) base_ixs: Vec<NodeIndex<FeatureIx>>,
661 pub(super) map: AHashMap<FeatureNode, FeatureMetadataImpl>,
662 pub(super) warnings: Vec<FeatureGraphWarning>,
663 pub(super) sccs: OnceCell<Sccs<FeatureIx>>,
665 pub(super) weak: WeakDependencies,
666}
667
668impl FeatureGraphImpl {
669 pub(super) fn new(package_graph: &PackageGraph) -> Self {
671 let mut build_state = FeatureGraphBuildState::new(package_graph);
672
673 let mut prev_ix = None;
675 for (package_ix, package_id) in package_graph.dep_graph.node_references() {
676 if let Some(prev_ix) = prev_ix {
677 debug_assert_eq!(package_ix.index(), prev_ix + 1, "package ixs are in order");
678 }
679 prev_ix = Some(package_ix.index());
680
681 let metadata = package_graph
682 .metadata(package_id)
683 .expect("valid package ID");
684 build_state.add_nodes(metadata);
685 }
686
687 build_state.end_nodes();
688
689 for metadata in package_graph
691 .resolve_all()
692 .packages(DependencyDirection::Reverse)
693 {
694 build_state.add_named_feature_edges(metadata);
695 }
696
697 for link in package_graph
698 .resolve_all()
699 .links(DependencyDirection::Reverse)
700 {
701 build_state.add_dependency_edges(link);
702 }
703
704 build_state.build()
705 }
706}
707
708#[derive(Copy, Clone)]
737pub struct ConditionalLink<'g> {
738 graph: DebugIgnore<FeatureGraph<'g>>,
739 from: &'g FeatureMetadataImpl,
740 to: &'g FeatureMetadataImpl,
741 edge_ix: EdgeIndex<FeatureIx>,
742 inner: &'g ConditionalLinkImpl,
743}
744
745assert_covariant!(ConditionalLink);
746
747impl<'g> ConditionalLink<'g> {
748 #[allow(dead_code)]
749 pub(super) fn new(
750 graph: FeatureGraph<'g>,
751 source_ix: NodeIndex<FeatureIx>,
752 target_ix: NodeIndex<FeatureIx>,
753 edge_ix: EdgeIndex<FeatureIx>,
754 inner: &'g ConditionalLinkImpl,
755 ) -> Self {
756 let dep_graph = graph.dep_graph();
757 Self {
758 graph: DebugIgnore(graph),
759 from: graph
760 .metadata_impl_for_node(&dep_graph[source_ix])
761 .expect("valid source ix"),
762 to: graph
763 .metadata_impl_for_node(&dep_graph[target_ix])
764 .expect("valid target ix"),
765 edge_ix,
766 inner,
767 }
768 }
769
770 pub fn from(&self) -> FeatureMetadata<'g> {
772 FeatureMetadata {
773 graph: DebugIgnore(self.graph.0),
774 node: self.graph.dep_graph()[self.from.feature_ix],
775 inner: self.from,
776 }
777 }
778
779 pub fn to(&self) -> FeatureMetadata<'g> {
781 FeatureMetadata {
782 graph: DebugIgnore(self.graph.0),
783 node: self.graph.dep_graph()[self.to.feature_ix],
784 inner: self.to,
785 }
786 }
787
788 pub fn endpoints(&self) -> (FeatureMetadata<'g>, FeatureMetadata<'g>) {
790 (self.from(), self.to())
791 }
792
793 pub fn normal(&self) -> PlatformStatus<'g> {
795 PlatformStatus::new(&self.inner.normal)
796 }
797
798 pub fn build(&self) -> PlatformStatus<'g> {
800 PlatformStatus::new(&self.inner.build)
801 }
802
803 pub fn dev(&self) -> PlatformStatus<'g> {
805 PlatformStatus::new(&self.inner.dev)
806 }
807
808 pub fn status_for_kind(&self, kind: DependencyKind) -> PlatformStatus<'g> {
811 match kind {
812 DependencyKind::Normal => self.normal(),
813 DependencyKind::Build => self.build(),
814 DependencyKind::Development => self.dev(),
815 }
816 }
817
818 pub fn dev_only(&self) -> bool {
821 self.inner.dev_only()
822 }
823
824 pub fn package_link(&self) -> PackageLink<'g> {
826 self.graph
827 .package_graph
828 .edge_ix_to_link(self.inner.package_edge_ix)
829 }
830
831 #[allow(dead_code)]
836 pub(super) fn edge_ix(&self) -> EdgeIndex<FeatureIx> {
837 self.edge_ix
838 }
839
840 #[allow(dead_code)]
841 pub(in crate::graph) fn package_edge_ix(&self) -> EdgeIndex<PackageIx> {
842 self.inner.package_edge_ix
843 }
844}
845
846impl fmt::Debug for ConditionalLink<'_> {
847 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
848 f.debug_struct("ConditionalLink")
849 .field("from", &self.from())
850 .field("to", &self.to())
851 .field("normal", &self.normal())
852 .field("build", &self.build())
853 .field("dev", &self.dev())
854 .finish()
855 }
856}
857
858#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
862pub(in crate::graph) struct FeatureNode {
863 package_ix: NodeIndex<PackageIx>,
864 feature_idx: FeatureIndexInPackage,
865}
866
867impl FeatureNode {
868 pub(in crate::graph) fn new(
870 package_ix: NodeIndex<PackageIx>,
871 feature_idx: FeatureIndexInPackage,
872 ) -> Self {
873 Self {
874 package_ix,
875 feature_idx,
876 }
877 }
878
879 pub(in crate::graph) fn base(package_ix: NodeIndex<PackageIx>) -> Self {
881 Self {
882 package_ix,
883 feature_idx: FeatureIndexInPackage::Base,
884 }
885 }
886
887 pub(in crate::graph) fn optional_dep(package_ix: NodeIndex<PackageIx>, dep_idx: usize) -> Self {
888 Self {
889 package_ix,
890 feature_idx: FeatureIndexInPackage::OptionalDependency(dep_idx),
891 }
892 }
893
894 pub(in crate::graph) fn named_feature(
895 package_ix: NodeIndex<PackageIx>,
896 named_idx: usize,
897 ) -> Self {
898 Self {
899 package_ix,
900 feature_idx: FeatureIndexInPackage::Named(named_idx),
901 }
902 }
903
904 fn from_id(feature_graph: &FeatureGraph<'_>, id: FeatureId<'_>) -> Option<Self> {
905 let metadata = feature_graph.package_graph.metadata(id.package_id()).ok()?;
906 Some(FeatureNode::new(
907 metadata.package_ix(),
908 metadata.get_feature_idx(id.label())?,
909 ))
910 }
911
912 pub(super) fn named_features(package: PackageMetadata<'_>) -> impl Iterator<Item = Self> + '_ {
913 let package_ix = package.package_ix();
914 package
915 .named_features_full()
916 .map(move |(feature_idx, _, _)| Self {
917 package_ix,
918 feature_idx,
919 })
920 }
921
922 pub(super) fn optional_deps(package: PackageMetadata<'_>) -> impl Iterator<Item = Self> + '_ {
923 let package_ix = package.package_ix();
924 package
925 .optional_deps_full()
926 .map(move |(feature_idx, _)| Self {
927 package_ix,
928 feature_idx,
929 })
930 }
931
932 pub(in crate::graph) fn package_ix(&self) -> NodeIndex<PackageIx> {
933 self.package_ix
934 }
935
936 pub(in crate::graph) fn package_id_and_feature_label<'g>(
937 &self,
938 graph: &'g PackageGraph,
939 ) -> (&'g PackageId, FeatureLabel<'g>) {
940 let package_id = &graph.dep_graph[self.package_ix];
941 let metadata = graph.metadata(package_id).unwrap();
942 let feature_label = metadata.feature_idx_to_label(self.feature_idx);
943 (package_id, feature_label)
944 }
945}
946
947#[derive(Clone, Debug)]
951#[doc(hidden)]
952pub enum FeatureEdge {
953 FeatureToBase,
955
956 DependenciesSection(ConditionalLinkImpl),
974
975 NamedFeature,
982
983 NamedFeatureDepColon(ConditionalLinkImpl),
990
991 NamedFeatureWithSlash {
1000 link: ConditionalLinkImpl,
1001 weak_index: Option<WeakIndex>,
1002 },
1003}
1004
1005#[derive(Clone, Debug)]
1007#[doc(hidden)]
1008pub struct ConditionalLinkImpl {
1009 pub(super) package_edge_ix: EdgeIndex<PackageIx>,
1010 pub(super) normal: PlatformStatusImpl,
1011 pub(super) build: PlatformStatusImpl,
1012 pub(super) dev: PlatformStatusImpl,
1013}
1014
1015impl ConditionalLinkImpl {
1016 #[inline]
1017 fn dev_only(&self) -> bool {
1018 self.normal.is_never() && self.build.is_never()
1019 }
1020}
1021
1022#[derive(Clone, Debug, Eq, Hash, PartialEq)]
1024pub(super) struct FeatureMetadataImpl {
1025 pub(super) feature_ix: NodeIndex<FeatureIx>,
1026}
1027
1028#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1032pub enum FeatureKind {
1033 Base,
1035
1036 Named,
1043
1044 OptionalDependency,
1046}
1047
1048impl FeatureKind {
1049 #[inline]
1051 pub fn is_base(self) -> bool {
1052 matches!(self, Self::Base)
1053 }
1054
1055 #[inline]
1057 pub fn is_named(self) -> bool {
1058 matches!(self, Self::Named)
1059 }
1060
1061 #[inline]
1063 pub fn is_optional_dependency(self) -> bool {
1064 matches!(self, Self::OptionalDependency)
1065 }
1066}